You know, I think that the original post should have worked, as long as the iterator variable wasn't previously declared in the same scope as the iterator. This works:

procs = []
[1, 2, 3].each { | x | procs << Proc.new { puts x } }
procs.each { | p | p.call }

# prints 1, 2, 3

If the iterator variable was used previously then the iterator updates the existing variable instead of creating a new lexically scoped one each time through the loop:

x = nil
procs = []
[1, 2, 3].each { | x | procs << Proc.new { puts x } }
procs.each { | p | p.call }

# prints 3, 3, 3

So it seems that the procs ought to have worked -- as long as there wasn't a previously declared variable of the same name.

I'm wondering if the problem wasn't that the "window" and "image" methods lacked a proper context when the procs were called. That seems to be a much more likely place for problems to arise. (The "Rules of Shoes" section of the manual aids in navigation through the hairiness.)


On Jul 27, 2009, at 5:15 AM, MenTaLguY wrote:

I wasn't terribly clear.  Let me rephrase -- if you do this:

urls.each do |url|
  link url, :click => Proc.new { window { image url } }
end

Then every link will open the same image url (since all the created
Procs reference the same variable, which ends up with the same final
value).  However, if you do this:

def make_image_callback(url)
  Proc.new { window { image url } }
end

image_urls.each do |image_url|
  link image_url, :click => make_image_callback(image_url)
end

Then the links should open the correct images, since each call to
make_image_callback establishes up a separate context for a Proc inside
to capture, rather than all the Procs sharing the same context and
variables.

You could also do the call to link itself inside the helper method (as I
did in my earlier email), but you don't need to.

-mental


Reply via email to