Ruby中缺少方法和定义方法

Ruby中缺少方法和定义方法,ruby,Ruby,有以下代码: class MyOpenStruct def initialize(initial_values = {}) @values = initial_values end def _singleton_class class << self self end end def method_missing(name, *args, &block)

有以下代码:

class MyOpenStruct
    def initialize(initial_values = {})
    @values = initial_values
    end

    def _singleton_class
        class << self 
            self
        end 
    end

    def method_missing(name, *args, &block) 
        if name[-1] == "="
            base_name = name[0..-2].intern 
            puts "add_method_to_set"
            self.class.add_method_to_set(base_name)
      @values[base_name] = args[0]
     else
            puts "add_method_to_get"
            self.class.add_method_to_get(base_name)         
        @values[name]
        end 
    end

    def self.add_method_to_get(name)
        define_method(name) do |value|
            @values[name]
        end
    end

    def self.add_method_to_set(name)
        define_method(name) do |value|
            @values[name] = value
        end
    end
end

obj1 = MyOpenStruct.new(name: "Dave") 
obj1.address = "1"

obj2 = MyOpenStruct.new(name: "Dave") 
obj2.address = "2"
类MyOpenStruct
def初始化(初始值={})
@值=初始值
结束
def(单例)类

类@koffeinfrei发现了代码中的一个问题,但我发现了其他一些问题。下面是我认为正确的版本。我还提出了另一种构建代码的方法。我的主要建议是退出实例方法的动态创建,因为这是非常通用的。您甚至可以根据需要将其与其他方法一起放入模块中

您的代码及其修复

class MyOpenStruct
  def initialize(initial_values = {})
  @values = initial_values
  end

  def method_missing(name, *args, &block) 
  puts "in mm, name = #{name}"
    if name[-1] == "="
      base_name = name[/\w+/]
      puts "add_method_to_set: '#{name}'"
      self.class.add_method_to_set(base_name)
      @values[base_name.to_sym] = args[0]
    else
      puts "add_method_to_get: '#{name}'"
      self.class.add_method_to_get(name)         
      @values[name.to_sym]
    end 
  end

  def self.add_method_to_get(name)
    define_method(name.to_sym) do
      @values[name.to_sym]
    end
  end

  def self.add_method_to_set(name)
    define_method((name+'=').to_sym) do |value|
      @values[name.to_sym] = value
    end
  end
end
备选结构

def create_instance_eval(klass, method, &block)
  klass.class_eval { define_method(method, &block) }
end

class MyOpenStruct
  def initialize(initial_values = {})
    @values = initial_values
  end

  def method_missing(name, *args, &block) 
    if name[-1] == "="
      base_name = name[/\w+/]
      method_name = (base_name+'=').to_sym
      puts "create method '#{method_name}'"
      method = create_instance_eval(self.class, method_name) do |value|
          @values[base_name.to_sym] = value
        end
      send(method, args[0])
    else
      method_name = name.to_sym
      puts "create method '#{method_name}'"
      method = create_instance_eval(self.class, method_name) do
        @values[method_name]
      end
      send(method)
    end 
  end
end
示例

MyOpenStruct.instance_methods(false)
  #=> [:method_missing]

obj1 = MyOpenStruct.new(name: "Dave") 
  #=> #<MyOpenStruct:0x00000102805b58 @values={:name=>"Dave"}>
obj1.address = "1"
  # create method 'address='
  #=> "1"

MyOpenStruct.instance_methods(false)
  #=> [:method_missing, :address=]
obj2 = MyOpenStruct.new(name: "Mitzy") 
  #=> #<MyOpenStruct:0x00000101848878 @values={:name=>"Mitzy"}>
obj2.address = 2
  #=> 2

obj2.address
  # create method 'address'
  # => 2

MyOpenStruct.instance_methods(false)
  $#=> [:method_missing, :address=, :address]

obj1.instance_variable_get(:@values)
  #=> {:name=>"Dave", :address=>"1"}
obj2.instance_variable_get(:@values)
  #=> {:name=>"Mitzy", :address=>2}
MyOpenStruct.instance_方法(false)
#=>[:方法_缺失]
obj1=MyOpenStruct.new(名称:“Dave”)
#=>#“Dave”}>
obj1.address=“1”
#创建方法“address=”
#=> "1"
MyOpenStruct.instance_方法(false)
#=>[:方法_缺失,:地址=]
obj2=MyOpenStruct.new(名称:“Mitzy”)
#=>#“米兹”}>
obj2.address=2
#=> 2
obj2.address
#创建方法“地址”
# => 2
MyOpenStruct.instance_方法(false)
$#=>[:方法_缺失,:地址=,:地址]
obj1.instance_variable_get(:@values)
#=>{:name=>“Dave”,:address=>“1”}
obj2.instance_variable_get(:@values)
#=>{:name=>“Mitzy”,:address=>2}

setter方法的方法名称需要有trailing=,因此您需要使用
名称来定义方法,而不是
基本名称

self.class.add_method_to_set(name)

使用一些默认值为初始集播种不是更好吗,比如调用
super({address:'}.merge(initial_values))
内部的
initialize
?如果您需要该功能,我在确定后就这样做了。提示:检查您定义的方法的名称