I’m reading the Eloquent Ruby book (awesome book so far) and don’t understand one section that talks about blocs, params, and scope. Here’s the code…
class SomeApplication
# Rest of the class omitted...
def do_something
with_logging('load', nil) { @doc = Document.load( 'book' ) }
# Do something with the document...
with_logging('save', @doc) { |the_object| the_object.save }
end
def with_logging(description, the_object)
begin
@logger.debug( "Starting #{description}" )
yield( the_object )
@logger.debug( "Completed #{description}" )
rescue
@logger.error( "#{description} failed!!")
raise
end
end
end
The book says the code is more complex than it needs to be because @doc is automatically visible inside the code block. So there’s no need to pass it down as an argument.
I don’t understand which param he’s talking about, the @doc or |the_object|. What would this code look like after changing it to remove the unnecessary complexity?
Or does it mean that the @doc that was created in with_logging('load', nil) is what is still visible? Even if that’s the case I’m not sure how the with_logging method at the bottom would access it.
@docis an instance variable. It is defined within the scope of an object (in this case, the instance of the classSomeApplication), and is typically used to store a value that “belongs” to the instance. Instance variables are always available to the instance methods of an object. They are not available outside the object, unless you make them into attributes.Your confusion re: the example probably stems from the roundabout way in which the author is passing the value from the method
do_somethingto the methodwith_logging. Whenwith_loggingis called, it receives two arguments,'save'and@doc. Inwith_loggingthe local variabledescriptionis set to'save', and the local variablethe_objectis set to@doc. Thenyieldis called with the argumentthe_object, This passesthe_objectto the code block defined in the second call towith_logging, which you can think of as sort of anonymous function. But of course, as the author points out,@docwas already set in the first call towith_logging, so it is unnecessary to pass it around as an argument. He could have written the second function call as:and the first as:
then call
yieldwith no arguments, and the effect would be the same.