I'm trying to debug with Pry. Most of the times, whenever I use next command to jump over the next line, pry goes to what it seems another frame. For example, watch my code:
Item.where(dst: "book").each do |book|
ott = book.ott
est = extract_es_title(ott) if ott != nil
web_item = Item.find_by(su: GR_BASE_URL+book.id)
binding.pry
end
class Item
include Mongoid::Document
include Mongoid::Timestamps
field :su, as: :source_url
field :ott, as: :other_titles
field :dst, as: :details_structure
end
If I run the code, it stops at the correct breakpoint. However, if I run next once in Pry console, it goes what it seems deeper in the stack instead of jumping to the next line. Here is the code that Pry shows mw once I run next:
645: def yield_document(document, &block)
646: doc = document.respond_to?(:_id) ?
647: document : Factory.from_db(klass, document, criteria.options[:fields])
648: yield(doc)
=> 649: documents.push(doc) if cacheable?
650: end
Why is this behavior? How can I just jump to the next method line?
Thanks in advance.
Use breakpoints:
break 4 then hit CTRL-D or type continue and it should take you to line 4. Generally "next line" is considered the next line of execution, not the next line of your current file.
From docs: https://github.com/nixme/pry-debugger
If you want to go to the next iteration of the each block. You can just move the binding.pry to the beginning of the loop, and run continue each time.
Item.where(dst: "book").each do |book|
binding.pry
ott = book.ott
est = extract_es_title(ott) if ott != nil
web_item = Item.find_by(su: GR_BASE_URL+book.id)
end
Related
What is the difference between next if vs next unless.
My understanding of next if was that next only if variable == value but in the following code, the second next statement isn't working. next if datastore.id == 5 it is bypassing this and proceeding even if the datastore.id == 2 or datastore.id == 3 etc.,
$evm.vmdb(:ManageIQ_Providers_Vmware_InfraManager_Storage).all.each do |datastore|
next if datastore.ems_id == provider.id.to_s
next if datastore.id == 5
dialog_hash[datastore[:id]] = "#{datastore.name} on #{datastore.ext_management_system.name}"
end
But if I change the next if to next unless then it works fine.
$evm.vmdb(:ManageIQ_Providers_Vmware_InfraManager_Storage).all.each do |datastore|
next if datastore.ems_id == provider.id.to_s # Next if works here
next unless datastore.id == 5 # Next unless works here instead of next if
dialog_hash[datastore[:id]] = "#{datastore.name} on #{datastore.ext_management_system.name}"
end
I'll quickly explain next and the difference between if and unless in ruby, and proceed to suggest some things you could try to get your code to work.
if
Code would execute if the condition is true.
unless
Code would execute if the condition is false. It would work the same as:
if !(expression) { ... }
next
The program would skip the rest of the code inside the loop block, and skip to the next iteration.
In your case, if there is a next called in the first line, then the rest of the code wouldn't run.
$evm.vmdb(:ManageIQ_Providers_Vmware_InfraManager_Storage).all.each do |datastore|
next if datastore.ems_id == provider.id.to_s # if this condition is true, don't run rest of the code in this loop, and go to the next datastore
next if datastore.id == 5
dialog_hash[datastore[:id]] = "#{datastore.name} on #{datastore.ext_management_system.name}"
end
Suggestion
It's unclear from your question what you mean by if doesn't work but unless does.
From the first code snippet in the question, the last line of the code. i.e,
dialog_hash[datastore[:id]] = "#{datastore.name} on #{datastore.ext_management_system.name}"
would only run if both of the conditions above are false.
You can check where the data is unexpected, or if your initial conditions are wrong, by debugging the datastore with either a debugger or some puts statements inside the loop.
All the best.
The difference is that
next if condition calls next when the condition is true, but
next unless condition calls next when the condition is false.
When calling next with a condition like datastore.id == 5 doesn't work as expected, then the problem is not the usage of if or unless because they work the opposite way.
Instead, you need to debug why you expect datastore.id == 5 to be true and why it is not. Obviously, the condition datastore.id == 5 can only be true when datastore.id returns the integer 5. If it returns false then datastore.id might return a string with the digit "5".
I suggest adding debug output to your code to dig deeper, like this:
p datastore.id
p datastore.id.class
Additionally to answers, most popular Ruby style guide recommends to use positive instead of negative conditions
# bad
do_something if !some_condition
# good
do_something unless some_condition
Depending on this, you can choose if or unless
#some_instance_var = Concurrent::Hash.new
(0...some.length).each do |idx|
fetch_requests[idx] = Concurrent::Promise.execute do
response = HTTP.get(EXTDATA_URL)
if response.status.success?
... # update #some_instance_var
end
# We're going to disregard GET failures here.
puts "I'm here"
end
end
Concurrent::Promise.all?(fetch_requests).execute.wait # let threads finish gathering all of the unique posts first
puts "how am i out already"
When I run this, the bottom line prints first, so it's not doing what I want of waiting for all the threads in the array to finish its work first, hence I keep getting an empty #some_instance_var to work with below this code. What am I writing wrong?
Never mind, I fixed this. That setup is correct, I just had to use the splat operator * for my fetch_requests array inside the all?().
Concurrent::Promise.all?(*fetch_requests).execute.wait
I guess it wanted multiple args instead of one array.
Here's my code:
begin
items = CSV.read('somefile.csv')
linesAmount = CSV.readlines('somefile.csv').size
counter = 1
while linesAmount >= counter do
fullrow = items[counter]
firstitem = fullrow[0] #This is the line that my code doesn't like.
puts firstitem
counter = counter + 1
end
end
For some ruby doesn't like that one line, where I have firstitem = fullrow[0]. It throws me the undefined method [] error. BUT, in the console, I can still see it printing the firstitem... So it still prints it, but yet throws an error? What's going on?
However, if I take the first three lines in the while loop OUTSIDE of the while loop, and comment out everything in the loop other than the counter line, then I don't get any error. So if that firstitem line appears outside the while loop, the code thinks it's all fine.
Edit: I know that the arrays start from 0, but I specifically wanted counter to not care about the very first line. I forgot to mention that, sorry.
Edit2: Thank you everyone, I solved it by adding -1 after linesAmount, and it works!
Looks like you have an off by one error, you are reading past the end of the items array. If there are 10 lines in the CSV file, the lines will be an array with indexes from 0 to 9, not 1 to 10.
Change your while to look like this
counter = 0
while counter < linesAmount
...
end
However a better approach overall would be to just do the following
CSV.readlines('somefile.csv').each do |line|
puts line
end
CSV.read and CSV.readlines return arrays. If your array contains two values, then size returns 2. But the indexes you need to call are items[0] and items[1]. Therefore this line
items[counter]
throws an error.
Change the line to
items[counter - 1]
and it should work.
Furthermore you can improve your code by using Ruby idioms:
begin
items = CSV.read('somefile.csv')
items.each do |item|
puts item[0]
end
end
ok, Im almost completely new to lua and computercraft but I have alot of creativity. I'm trying to write code that will reprint a variable every second. here is what I have so far:
display = "Loading..."
While true do
sleep(1)
term.clear()
term.setCursorPos(1,1)
print (display)
end
sleep(3)
display = "hello"
I want to use it to render a 2d game, the "display" variable would change often and thus why i want it to be updated every second.
It does indeed refresh every second when I run the code but for some reason I cant seem to get the "display" variable to change after 3 seconds to test it.
What am I doing wrong?
while true is an infinite loop. The script never reaches sleep(3).
Perhaps you want to replace while true with for i=1,3.
I am not experienced in Lua, but this might be a solution: answer on SO
In the UI thread, run:
while ((status=lua_resume(L_coroutine, 0)) == LUA_YIELD) {
semaphore_wait(); /* whatever the appropriate C# call is */
}
"Wait for response" should look something like:
while not results[my_result] do
coroutine.yield()
end
The "incoming message" function should look like the following in Lua:
results[cur_result]=parsed_message
I have a Rails app parsing incoming e-mails on Heroku using the Cloud-mailin add-on. The app recieves a list of prices in an e-mail and inserts them into the database.
This works fine, but if the e-mail contains for instance a signature in the bottom the code fails because it's also trying to parse that text.
Therefor I would like to rewrite the below parsing code to stop when it hits an empty line in the e-mail. All the price data is always at the top of the e-mail.
email_text = params[:plain]
email_text_array = []
email_text.split("\n").each do |email_line|
email_text_array << email_line.split(" ")
end
How do I change the above to stop when it hits an empty line in the email_taxt variable?
Thanks!
You can add a break :
email_text.split("\n").each do |email_line|
break if email_line.blank? # ends loop on first empty line
email_text_array << email_line.split(" ")
end
Does this question help: Is there a "do ... while" loop in Ruby?
Edit 1:
From the above article I think something like this would work:
email_text.split("\n").each do |email_line|
break if email_line.length < 1
email_text_array << email_line.split(" ")
end