method calls and blocks and calling proc

Hey all,

I have a question about this line of code:

  within "#main-menu" do     find("h6", :text => menu).click if menu     click_link link   end

def within(selector, &blk)   new_blk = proc do     begin       scope_selectors.push(selector)       blk.call     ensure       scope_selectors.pop     end   end   super(selector.strip, &new_blk) end

First, when within is called, it obviously passes the string "#main-menu", but does it also pass the block (the content between do and end) as the second argument? The reason why I ask is because notice within requires a second argument: &blk.

Second, we create a proc to convert a code block into an object and store that object into new_blk local variable. Then we call the object in the super argument list, which adds the selector (e.g. "#main-menu") into the scope_selectors array. Then it seems like we call the initial code block (blk.call) adjacent to within(). But the blk code block has not been converted to a proc, so how is it possible to have a callable block then?

Finally, super is only called on a parent class with a method of the same name correct? Because in this case, within() is the only method in entire application. super has another purpose?

Thanks for response.

Hey all, I have a question about this line of code:

within “#main-menu” do find(“h6”, :text => menu).click if menu click_link link end

def within(selector, &blk) new_blk = proc do begin scope_selectors.push(selector) blk.call ensure scope_selectors.pop end end super(selector.strip, &new_blk) end

First, when within is called, it obviously passes the string “#main-menu”, but does it also pass the block (the content between do and end) as the second argument? The reason why I ask is because notice within requires a second argument: &blk.

Yes it does. This is a standard feature/part of ruby. When defining a method, you may always put, as the last entry in the list of parameters, a parameter with the ampersand ‘&’ prefixed to its name. This “captures” (gives you direct access) any block passed to the method by making it available as a Proc instance. Otherwise, any block would still be passed in (if you called #block_given? it would return true) but the only way to “access” it is to call #yield.

So the #within method “captures” any block passed to it and it gets stored as a Proc instance, referenced by blk.

Second, we create a proc to convert a code block into an object and store that object into new_blk local variable. Then we call the object in the super argument list, which adds the selector (e.g. “#main-menu”) into the scope_selectors array.

There is no “call” on the new_blk variable. The entire method definition is pretty much composed of the new Proc’s definition (all except the last line that calls #super). The “&new_blk” entry in #super’s argument list does the inverse of what the ampersand in #within’s method definition does.

In essence, an entry like: “&arg” in a method definition “captures” a block (as a proc) while a similar entry in a method call “sets it free” by making the proc appear just as if you’d passed a normal code block to the method.

Example:

def asdf(&arg) arg.call end

Is “effectively” equivalent to

def asdf yield end

And then:

asdf { puts “hi” }

is effectively equivalent to:

x = proc { puts “hi” } asdf(&x)

Then it seems like we call the initial code block (blk.call)

Yes, inside of the new proc stored in new_blk…

adjacent to within(). But the blk code block has not been converted to a proc,

This was done implicitly by the #within’s method definition parameter list’s “&blk” entry as described above.

so how is it possible to have a callable block then?

Finally, super is only called on a parent class with a method of the same name correct? Because in this case, within() is the only method in entire application. super has another purpose?

I don’t know of any other purpose. Does the “super” line result in a NoMethodError being raised? If not, it’s finding some method up the chain to call. Is there some other gem or library that adds a #within method to Object or some other ruby magic like #method_missing somewhere up the chain?