开发者

Ruby: Passing a block to a class macro that defines instance methods

I'm struggling with code that looks like the example below (but actually does something useful). The block that is passed to def_my_method is of course created in the context of the class, when I want to evaluate it in the context of the instance that has the instance method. How do I do this?

module Formatters
  # Really useful methods, included in several classes
  def format_with_stars(str)
    return "*** #{str} ***"
  end
end

class Test
  include Formatters
  STRINGS = ["aa", "bb"]

  def self.def_my_method(method_name, another_parameter, &format_proc)
    define_method(method_name) do
      # In reality, some more complex code here, t开发者_如何转开发hen...
      return STRINGS.map(&format_proc)
    end
  end

  def_my_method(:star_strings, "another_parameter") { |str| format_with_stars(str) }
  # Define other methods
end

tt = Test.new
puts tt.star_strings
# Throws undefined method `format_with_stars' for Test:Class (NoMethodError)


You can use instance_exec to execute the passed block in the right context. Instead of passing &format_proc directly to the call to map, pass a block that calls it using instance exec.

Something like this:

def self.def_my_method(method_name, another_parameter, &format_proc)
  define_method(method_name) do
    # In reality, some more complex code here, then...
    return STRINGS.map{|str| instance_exec(str, &format_proc)}
  end
end

This produces this:

$ ruby tt.rb 
*** aa ***
*** bb ***

for me (where tt.rb is the arbitary name I gave the file), which I think is what you want for this example.



...

class Test
-  include Formatters
+  extend Formatters

...

should do the trick.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜