Claudio
Claudio

Reputation: 43

Basic Ruby. Why is this method returning nil?

Hi!

I am expecting #<PrettyThing:0x0055a958175348 @success="anything here">

but I am getting 'anything here' instead. Any idea why?

class Thing
  attr_accessor :success

  def execute
    self.success = execute!
  rescue
    self.success = false
  ensure
    self
  end
end

class PrettyThing < Thing
  def execute!
    'anything here'
  end
end

p PrettyThing.new.execute # => 'anything here'

Upvotes: 1

Views: 888

Answers (2)

jvillian
jvillian

Reputation: 20263

Try:

class Thing
  attr_accessor :success

  def execute
    self.success = execute!
    self
  rescue
    self.success = false
  end
end

class PrettyThing < Thing
  def execute!
    'anything here'
  end
end

p PrettyThing.new.execute # => <PrettyThing:0x0000000379ea48 @success="anything here">

The way you have it written, execute is returning the assignment result of self.success = execute!. By adding self, you return the instance of PrettyThing.

This is handy if you want to chain methods, like:

class Thing
  attr_accessor :success

  def execute
    self.success = execute!
    self
  rescue
    self.success = false
  end

  def foo
    puts 'foo'
  end

end

class PrettyThing < Thing
  def execute!
    'anything here'
  end
end

p PrettyThing.new.execute.foo # => foo

Given your comment, I think I'd probably do it something more like:

class Thing
  attr_accessor :success

  alias success? success

  def foo
    puts 'foo'
  end

end

class PrettyThing < Thing

  def execute
    @success = everything_worked
    self
  end

private

  def everything_worked
    # your logic goes here
    # return true if all is good
    # return false or nil if all is not good
    true
  end

end

pretty_thing = PrettyThing.new.execute
p pretty_thing.success? # => true

If everything_worked returns false or nil, then pretty_thing.success? will also return false or nil.

Upvotes: 3

Garrett Motzner
Garrett Motzner

Reputation: 3230

Ensure is a tricky thing. Normally, it doesn't return a value, and instead the return value from the last executed line of the main or rescue block is returned, unless there was an uncaught error, then the error is returned. But, if you explicitly return, then you will get the return value. This is a bit nonstandard and confusing though, because the intent of the ensure clause is for silent cleanup. It may be better to move your return value outside your begin/rescue block.

Upvotes: 3

Related Questions