Ruby: передача блока в макрос класса, который определяет методы экземпляра - PullRequest
2 голосов
/ 09 ноября 2010

Я борюсь с кодом, который выглядит как пример ниже (но на самом деле делает что-то полезное). Блок, который передается в def_my_method, конечно же, создается в контексте класса, когда я хочу оценить его в контексте экземпляра, у которого есть метод экземпляра. Как мне это сделать?

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, then...
      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)

Ответы [ 2 ]

3 голосов
/ 09 ноября 2010

Вы можете использовать instance_exec для выполнения переданного блока в правильном контексте.Вместо передачи &format_proc непосредственно на вызов map, передайте блок, который вызывает его, используя экземпляр exec.

Что-то вроде этого:

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

Это приводит к:

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

для меня (где tt.rb - произвольное имя, которое я дал файлу), которое, я думаю, и будет тем, что вы хотите для этого примера.

1 голос
/ 09 ноября 2010

...

class Test
-  include Formatters
+  extend Formatters

...

должен сделать трюк.

...