简体   繁体   中英

Ruby class_eval and yield

Man, I'm peeling the layers of the onion today, anyway here's the code

class MyClass
  def initialize(dynamic_methods)
    @arr = Array.new(dynamic_methods)
    @arr.each { |m|
      self.class.class_eval do
        define_method(m) do
          "<#{yield self if block_given?}>" 
        end
      end
    }
    end
end

tmp = MyClass.new ['method1', 'method2', 'method3']
tmp.method1 do |t|
  "here"
end

My problem is that I'm trying to access "here" within define_method(m) when the method is being executed, not when created. The current statement "<#{yield self if block_given?}>" doesn't give me that. And in case you are wondering, I have to keep this part of the code as is but I can make all the changes I want to MyClass.

tmp = MyClass.new ['method1', 'method2', 'method3']
tmp.method1 do |t|
  "here"
end

Can anyone help with the syntax? Thanks in advance for your help.

UPDATE: See below for my answer.

Try replacing

define_method(m) do
  "<#{yield self if block_given?}>" 
end

with:

define_method(m) do |&block|
  "<#{block.call if block}>" 
end

This should work for 1.8.7 and up. You may also try to use module_eval :

self.class.module_eval %Q{
  def #{m}(&block)
    "<\#{block.call if block}>"
  end
}

With a lot of feedback from Sergei and some tinkering on my own, I manage to get it working

class MyClass
  def initialize(dynamic_methods)
    @arr = Array.new(dynamic_methods)
    @arr.each { |m|
      self.class.module_eval %Q{
        def #{m}(&block)
          yield(self) if block_given?
        end
      end
    }
    end
end

tmp = MyClass.new ['method1', 'method2', 'method3']
tmp.method1 do |t|
  "here"
end

As you can tell, there are some minor tweaks to Sergei's suggestions, so thanks for all your help Sergei.

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