Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access outside scope when using Class.new

Tags:

ruby

Is it possible to somehow access a inside the Class.new scope?

a = 5
Class.new{ def b; a end }.new.b
# NameError: undefined local variable or method `a' for #<#<Class:0x007fa8b15e9ca8>:0x007fa8b15e9af0>
# :in `b'
like image 449
ave Avatar asked Feb 20 '15 12:02

ave


2 Answers

Even though @MarekLipka answer is correct - it is always risky to change variable scope. This works because each block carries the context it has been created in and hence your local variable a suddenly is not that local - it became a 'hidden' global:

a = 5
object = Class.new { define_method('b') { a } }.new
object.b #=> 5

a = 4
object.b #=> 4

This is naturally useful if you want to pass non-duplicable variable by reference (this actually works very alike javascript closures), however in most of the cases it will introduce extremely hard to debug bugs:

a = 5
object = Class.new { define_method('b') { a = a + 1 } }.new
object.b
a #=> 6

It is much cleaner to use instance variable instead:

a = 5

Class.new do
  def initialize(a)
    @a = a 
  end 

  def b
    @a
  end
end.new(a).b  #=> 5
like image 113
BroiSatse Avatar answered Oct 15 '22 14:10

BroiSatse


You can use define_method instead of def keyword and pass block to it (block is closure, so it holds reference to a):

a = 5
Class.new { define_method('b') { a } }.new.b
# => 5
like image 20
Marek Lipka Avatar answered Oct 15 '22 15:10

Marek Lipka