Jikku Jose
Jikku Jose

Reputation: 18804

Why can't I access local variable in the class_eval block?

Why am I not able to access the variable vehicle inside the class_eval block:

class Vehicle
  def self.number_of_wheels
    fail 'DEFINE in subclass'
  end

  def self.name
    fail 'DEFINE in subclass'
  end

  def self.define_methods
    number_of_wheels.times do |index|
      define_method("wheel_#{index}") do
        "This is wheel #{index} of #{self.class.name}"
      end
    end
  end
end

klasses = %w(
  tri_cycle
  motor_boat
).map do |vehicle| # THE VARIABLE I WANT TO ACCESS
  klass = Class.new(Vehicle)

  klass.class_eval do
    def self.number_of_wheels
      4
    end

    def self.name
      vehicle # using a string here will work
    end

    define_methods
  end

  klass
end

klasses.map { |k| k.new.wheel_1 } # => 
# ~> -:31:in `name': undefined local variable or method `vehicle' for #<Class:0x007ff6ea181800> (NameError)
# ~>    from -:13:in `block (2 levels) in define_methods'
# ~>    from -:40:in `block in <main>'
# ~>    from -:40:in `map'
# ~>    from -:40:in `<main>'

Upvotes: 1

Views: 675

Answers (1)

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230286

It's so called "scope gate". Local variables go out of scope as soon as definition of method, class or module begins. See this book for more in-depth info: https://pragprog.com/book/ppmetr2/metaprogramming-ruby-2

You can bypass this by using define_method or define_singleton_method (whatever is suitable to you) instead of def syntax (because this would be a method call, not method definition)

Upvotes: 3

Related Questions