Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Closure doesn't work

Tags:

closures

ruby

If a block is a closure, why does this code does not work, and how to make it work?

def R(arg)
  Class.new do
    def foo
      puts arg
    end
  end
end

class A < R("Hello!")
end

A.new.foo #throws undefined local variable or method `arg' for #<A:0x2840538>
like image 794
Yury Kaspiarovich Avatar asked Feb 18 '10 15:02

Yury Kaspiarovich


People also ask

Why do I struggle with closure?

Some people also have a need to avoid closure. The need to avoid closure is born from a person's desire to avoid commitment or confrontation. In other words, someone avoiding closure doesn't want certain questions answered. They might be afraid of what they'll learn.

Does closure actually help?

Closure is important after a breakup because: Your brain needs an authentic narrative to make sense of what happened. Without closure you might keep going back to a relationship that wasn't working. You could be doomed to repeat the same relationship patterns the next time around without closure.

What does it mean when you don't get closure?

When You Can't Get Closure. In many instances, closure may not be an option. For example, if someone has passed away, you cannot receive closure. If a romantic relationship has ended, the other person may be unwilling or unable to give you the closure you need.


2 Answers

Blocks are closures and arg is indeed available inside the Class.new block. It's just not available inside the foo method because def starts a new scope. If you replace def with define_method, which takes a block, you'll see the result you want:

def R(arg)
    Class.new do
        define_method(:foo) do
           puts arg
        end
    end
end

class A < R("Hello!")
end

A.new.foo # Prints: Hello!
like image 62
sepp2k Avatar answered Sep 18 '22 12:09

sepp2k


If you define the class dynamically, you can alter it as you like:

def R(arg)
  c = Class.new

  # Send the block through as a closure, not as an inline method
  # definition which interprets variables always as local to the block.
  c.send(:define_method, :foo) do
    arg
  end

  c
end

class A < R("Hello!")
end

puts A.new.foo.inspect
# => "Hello!"
like image 32
tadman Avatar answered Sep 18 '22 12:09

tadman