Ruby从散列中创建方法

时间:2021-03-20 12:53:09

I have the following code I am using to turn a hash collection into methods on my classes (somewhat like active record). The problem I am having is that my setter is not working. I am still quite new to Ruby and believe I've gotten myself turned around a bit.

我有以下代码,用于将散列集合转换为类上的方法(有点像活动记录)。我遇到的问题是我的setter不工作。我对Ruby还是很陌生的,我相信我已经让自己有点好转了。

class TheClass
  def initialize
    @properties = {"my hash"}
    self.extend @properties.to_methods
  end
end

class Hash
  def to_methods
    hash = self
    Module.new do
      hash.each_pair do |key, value|
        define_method key do
          value
        end
        define_method("#{key}=") do |val|
          instance_variable_set("@#{key}", val)
        end
      end
    end
  end
end

The methods are created and I can read them on my class but setting them does not work.

创建了这些方法,我可以在类上读取它们,但是设置它们不行。

myClass = TheClass.new
item = myClass.property # will work.
myClass.property = item # this is what is currently not working.

4 个解决方案

#1


4  

Your getter method always returns the value in the original hash. Setting the instance variable won't change that; you need to make the getter refer to the instance variable. Something like:

getter方法总是返回原始散列中的值。设置实例变量不会改变它;您需要使getter引用实例变量。喜欢的东西:

hash.each_pair do |key, value|
  define_method key do
    instance_variable_get("@#{key}")
  end
  # ... define the setter as before
end

And you also need to set the instance variables at the start, say by putting

您还需要在开始时设置实例变量,比如通过put

@properties.each_pair do |key,val|
  instance_variable_set("@#{key}",val)
end

in the initialize method.

在初始化方法。

Note: I do not guarantee that this is the best way to do it; I am not a Ruby expert. But it does work.

注意:我不能保证这是最好的方法;我不是Ruby专家。但它的工作。

#2


6  

If your goal is to set dynamic properties then you could use OpenStruct.

如果您的目标是设置动态属性,那么您可以使用OpenStruct。

require 'ostruct'

person = OpenStruct.new
person.name = "Jennifer Tilly"
person.age = 52

puts person.name     
# => "Jennifer Tilly"
puts person.phone_number 
# => nil

It even has built-in support to create them from a hash

它甚至内置了从散列创建它们的支持

hash = { :name => "Earth", :population => 6_902_312_042 }
planet = OpenStruct.new(hash)

#3


2  

It works just fine for me (after fixing the obvious syntax errors in your code, of course):

它对我来说很好(当然,在修正了代码中明显的语法错误之后):

myClass.instance_variable_get(:@property) # => nil
myClass.property = 42
myClass.instance_variable_get(:@property) # => 42

Note that in Ruby instance variables are always private and you never define a getter for them, so you cannot actually look at them from the outside (other than via reflection), but that doesn't mean that your code doesn't work, it only means that you cannot see that it works.

请注意,在Ruby实例变量中,变量总是私有的,并且您从来没有为它们定义一个getter,所以您实际上不能从外部(除了通过反射)查看它们,但是这并不意味着您的代码不起作用,它只意味着您看不到它起作用。

#4


0  

This is essentially what I was suggesting with method_missing. I'm not familiar enough with either route to say why or why not to use it which is why I asked above. Essentially this will auto-generate properties for you:

这就是我在method_missing中提出的。我对这两种方式都不太熟悉,不知道为什么或者为什么不使用它,这就是我上面问的原因。本质上,这将自动生成属性为您:

def method_missing sym, *args
   name = sym.to_s
   aname = name.sub("=","")

   self.class.module_eval do 
      attr_accessor aname
   end
  send name, args.first unless aname == name
end

#1


4  

Your getter method always returns the value in the original hash. Setting the instance variable won't change that; you need to make the getter refer to the instance variable. Something like:

getter方法总是返回原始散列中的值。设置实例变量不会改变它;您需要使getter引用实例变量。喜欢的东西:

hash.each_pair do |key, value|
  define_method key do
    instance_variable_get("@#{key}")
  end
  # ... define the setter as before
end

And you also need to set the instance variables at the start, say by putting

您还需要在开始时设置实例变量,比如通过put

@properties.each_pair do |key,val|
  instance_variable_set("@#{key}",val)
end

in the initialize method.

在初始化方法。

Note: I do not guarantee that this is the best way to do it; I am not a Ruby expert. But it does work.

注意:我不能保证这是最好的方法;我不是Ruby专家。但它的工作。

#2


6  

If your goal is to set dynamic properties then you could use OpenStruct.

如果您的目标是设置动态属性,那么您可以使用OpenStruct。

require 'ostruct'

person = OpenStruct.new
person.name = "Jennifer Tilly"
person.age = 52

puts person.name     
# => "Jennifer Tilly"
puts person.phone_number 
# => nil

It even has built-in support to create them from a hash

它甚至内置了从散列创建它们的支持

hash = { :name => "Earth", :population => 6_902_312_042 }
planet = OpenStruct.new(hash)

#3


2  

It works just fine for me (after fixing the obvious syntax errors in your code, of course):

它对我来说很好(当然,在修正了代码中明显的语法错误之后):

myClass.instance_variable_get(:@property) # => nil
myClass.property = 42
myClass.instance_variable_get(:@property) # => 42

Note that in Ruby instance variables are always private and you never define a getter for them, so you cannot actually look at them from the outside (other than via reflection), but that doesn't mean that your code doesn't work, it only means that you cannot see that it works.

请注意,在Ruby实例变量中,变量总是私有的,并且您从来没有为它们定义一个getter,所以您实际上不能从外部(除了通过反射)查看它们,但是这并不意味着您的代码不起作用,它只意味着您看不到它起作用。

#4


0  

This is essentially what I was suggesting with method_missing. I'm not familiar enough with either route to say why or why not to use it which is why I asked above. Essentially this will auto-generate properties for you:

这就是我在method_missing中提出的。我对这两种方式都不太熟悉,不知道为什么或者为什么不使用它,这就是我上面问的原因。本质上,这将自动生成属性为您:

def method_missing sym, *args
   name = sym.to_s
   aname = name.sub("=","")

   self.class.module_eval do 
      attr_accessor aname
   end
  send name, args.first unless aname == name
end