简体   繁体   中英

Ruby: why instance eval on class creating instance method instead of class method

I want to create class method test dynamically and for that i am using define_method method inside instance_eval . I was expecting below code to create class method test but instead the code is creating instance method test . what could be the reason for this ?? below is my code.

module Accessor
  def define_accessor_for_class(method)
    self.instance_eval do
      define_method :test do
      end
    end
  end
end




class Employee
  extend Accessor
  define_accessor_for_class :name
end


Employee.name = "sanjay"
Employee.name

Employee.instance_methods(false) ==> [:test]
Employee.methods(false) => []

instance_eval changes self , ie the dynamic context for instance variables and receiverless message sends. It does not change the default definee , ie the dynamic context for unqualified method definitions.

In your case, since nothing about your method definition is dynamic, there is no reason to use dynamic metaprogramming at all, you can just use a qualified method definition:

module Accessor
  def define_accessor_for_class(method)
    def self.test; end
  end
end

class Employee
  extend Accessor
  define_accessor_for_class :name
end

Employee.instance_methods(false) #=> []
Employee.methods(false)          #=> [:test]

If, for some reason, you need dynamism, you can use Object#define_singleton_method instead:

module Accessor
  def define_accessor_for_class(method)
    define_singleton_method(:test) do end
  end
end

class Employee
  extend Accessor
  define_accessor_for_class :name
end

Employee.instance_methods(false) #=> []
Employee.methods(false)          #=> [:test]

You will want to use define_singleton_method instead of define_method .

module Accessor
  def define_accessor_for_class(method)
    self.instance_eval do
      define_singleton_method :test do
      end
    end
  end
end

Singleton methods are methods that live in the singleton class and are only available for a single object (unlike regular instance methods that are available to all instances of the class). In your class, it would act like a class method.

Here is the result

Employee.instance_methods(false) #=> []
Employee.methods(false)          #=> [:test]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM