何时使用define_singleton_method v define_method

时间:2019-05-12 14:39:11

标签: ruby oop metaprogramming

在对this question用户的一个回答中,mu太短,说明您不希望对象的行为在初始化时发生太大的改变,这很有意义,您应该能够很好地推理出一个对象通过阅读其定义并进行内省,但我想到了这种情况:

french_colors.yml

blue: blue
red: rouge
...

translations.rb

class Translations
  def initialize(language: "french")
    data = YAML.load_file("./translations/#{language}.yml")
    data.each do |k, v|
      define_method k do
        v
      end
    end

    print_french_colors
  end

  def print_french_colors
    puts red
    puts blue
  end
end

初始化后,上述错误与 #=> NoMethodError: undefined method `define_method' for #<C:0x2efae80>

在这里,您将从翻译公司收到的文件中构建所有Translations行为,并希望将其作为实例,并且还希望它基于语言文件是动态的(这只是一个示例)

在初始化中将转换定义和设置为对象的属性,而不是在OP和我试图这样做的初始化中使用define_method,是否更有意义?还是编写方法define_singleton_method来专门处理这种情况?

How to use define_method inside initialize()

2 个答案:

答案 0 :(得分:0)

目前尚不清楚您的最终目标是什么。例如,如果语言不是法语,我不确定为什么会有print_french_colors方法。看来您基本上是想读取yaml文件并使用它来设置一些预定义属性的值。

要做到这一点,我认为使用instance_variable_set而不是define_method会更有意义。这是一个例子。

french.yml

blue: blue
red: rouge

require "yaml"
class Translations
  attr_reader :blue, :red 
  def initialize(language: "french")
    data = YAML.load_file("#{language}.yml")
    data.each do |k, v| 
        if respond_to?(k)
          instance_variable_set("@#{k}",v)    
        else 
          puts "#{k} is not defined"
        end
    end

    print_french_colors
  end

  def print_french_colors
    puts red
    puts blue
  end
end

t = Translations.new 
t.print_french_colors

答案 1 :(得分:-1)

回到您的问题...替换下面的代码块

define_method k do
  v
end

使用

self.class.send(:define_method, k) do
  v
end