何时使用 define_singleton_method v define_method

When to use define_singleton_method v define_method

在对 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>

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

在初始化中将翻译定义和设置为对象的属性,而不是像 OP 和我试图做的这样的问题那样在初始化中使用 define_method 更有意义吗?还是说define_singleton_method这个方法就是专门为了处理这种情况而写的?

How to use define_method inside initialize()

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

define_method k do
  v
end

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

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

为了做到这一点,我认为使用 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