Local variable became nil in an ensure clause - ruby

I've stumbled across a strange behaviour I can't explain. Executing the method
def with_baton
until (baton = Baton.obtain)
sleep(2)
end
result = yield
ensure
baton.release
result
end
which makes sure the block we pass to it doesn't execute in parallel by multiple workers, I sometimes receive the following error:
NoMethodError: undefined method `release' for nil:NilClass
lib/*hidden*/common.rb:172 in ensure in with_baton
lib/*hidden*/common.rb:173 in with_baton
lib/*hidden*/common.rb:7 in get
If the execution went past until it means baton is set. How could it happen that its nil in ensure? By the way, the block executes for about five seconds, and I use Ruby MRI 1.9.3-p547.

your Baton.obtain may raise an error, and in that case baton will be nil
call baton.release if baton

Related

Is there a way to return nil message to user but not interrupt the app in ruby?

I'm trying to find a way to write in GUI for user that there is nothing in the button they just clicked
I've tried a method like `
if #album[#user_choice_album].tracks[10].name == nil
return
`
But it interrupt the program and gave an message instead, while i was expecting it to interrupt the procedure and go to the next one.
test.rb:192:in `draw_now_playing': undefined method `name' for nil:NilClass (NoMethodError)
if (!(#album[#user_choice_album].tracks[10].name))\
It looks like you have tracks stored in an array (without knowing any details about your data structure and model). And when the user requests a track that doesn't exist, it returns nil.
That means there is no point in asking if the name of that track is nil when the whole track is nil.
I guess this should work for you:
if #album[#user_choice_album].tracks[10].nil?
return
Or simplified:
return unless #album[#user_choice_album].tracks[10]

RSpec: Expecting a method to be called causes that method to not actually be called

I have some code that could be represented in very simple terms as:
def method_a(key)
hash = method b(key)
hash.delete(key)
end
def method_b(key)
return { key => 1 }
end
and then an rspec test like
it 'calls method_b'
expect(someClass).to receive(:method_b).with(key)
method_a(key)
end
However I then get an error in the second line of method_a because it's trying to call delete on a nil object. When I debug, I can see that the logic inside method_b is never actually being invoked. It's not failing somewhere in method_b, it's literally not calling it at all. If I get rid of the expect statement in the test, this error goes away. It seems like the expect statement is causing it to just skip over the actual call to method_b, leaving me with a nil value instead of the hash I'm expecting.
Is there a way I can stop it from skipping over method_b, or at least terminate execution once the expect statement is successful, so I don't run into the error on the next line?
When you set a message expectation, it overrides the original code, unless you explicitly tell RSpec not to:
expect(someClass).to receive(:method_b).with(key).and_call_original

Rspec test - keep executing a method until the error message is no longer raised

I'm new to Rspec, so sorry if this is a bad question. In one of the test tests I'm running, I have code which uses a random number generator to determine whether or not a method should be executed. If it cannot be executed, the method raises an error message.
So I need to write a test which continually runs the method on a small array of class objects until it no longer receives the error message. So in effect each class object will eventually successfully execute that method after a few tries.
The array has 6 items. I'm hoping that I need to loop through each one and then use a while loop which then tests whether the error message has been executed, but I haven't got a clue how. Any help gratefully appreciated.
I have something like this at the moment...
def create_planes
6.times do
plane=Plane.new
planes<<plane
end
end
it 'should land each plane' do
create_planes
i = 0
while i<planes.count
begin
airport.plane_land(planes[i])
i++
rescue
next
end
end
expect(airport.plane_count).to eq(6)
end
Generally with RSpec, you'll set up your inputs and test your outputs. You wouldn't execute until an error occurs, you'd execute a known number of lands and then check that the airport's plane changed to what you expect.
it "should maintain a list of landed planes" do
expect {
3.times { airport.plane_land Plane.new }
}.to change { airport.plane_count }.from(0).to(3)
end

Is there a way to get a stack trace from rspec when a method is unexpectedly called more times than specified?

I setup a mock object and told it to expect a check for nil and to return false:
status = double('status')
status.should_receive(:nil?).and_return(false)
I only expect the call to nil? to occur once, but I got an error in my rspec test, saying that status received nil? twice.
Is there a way to get rspec to show where/how each call occurred?
adding the '--backtrace' option did not work.
Try something like this:
status.should_receive(:nil?).twice { puts caller; false }
This tells rspec to allow two invocations and call the associated block each time. Thecaller method generates a full backtrace which you should be able to analyze onstdout. We also returnfalse to stay on the code-path we're testing.
If the two backtraces are hard to distinguish and you're only interested in the second (unexpected) invocation, then set up two successive expectations:
status.should_receive(:nil?).and_return(false)
status.should_receive(:nil?) { puts caller; false }
Here the double will return false on the first invocation and call the block on the second.
Reference for setting responses on expectations:
https://github.com/rspec/rspec-mocks#setting-responses

Ruby Pipe and C Extensions

I have some ruby code (1.9) like
#rd,#wd = IO.pipe
def callback()
puts #wd.class
# do stuff
end
pid = fork do
#rd.close
register_callback(:callback)
end
#wd.close
# do some stuff in parent process
register_callback is a C extension that makes a blocking system call, and upon certain conditions will call the ruby function associated with the symbol passed in.
However, #wd is of type NilClass according to the message I get when I run this program and it tries to access #wd in the callback function, which doesn't make any sense to me. Any help is appreciated.
after you call the register_callback method. The rest of the code continues to execute (as you do the register_callback method call inside fork). So #wd.close runs, before your callback is made. Hence when the callback() method is finally called. #wd is nil (which is the result of #wd.close).

Resources