用Ruby从哈希表创建方法

3

我有以下代码,用于将哈希集合转换为我的类上的方法(有点像Active Record)。我遇到的问题是我的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

我已经创建了方法并且在我的类中可以读取它们,但是设置它们却不起作用。

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

我不是很明白。method_missing 只会告诉我没有这个方法。我想能够像上面的代码那样设置属性,问题在于它不起作用。 - Jeremy B.
使用method_missing,你基本上可以捕获对不存在方法的调用,然后根据方法名称和参数实现你的功能。 - Jeff Swensen
该方法存在,我没有收到错误信息,但它实际上从未设置属性。我不想捕获错误,我想要设置该属性。 - Jeremy B.
谢谢你,乔纳斯。我认为这是一个占位符是很明显的。感谢你的关心。 - Jeremy B.
抱歉,那是一个愚蠢的评论。 - Jonas Elfström
显示剩余2条评论
4个回答

8

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

require 'ostruct'

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

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

甚至还内置了从哈希值创建它们的支持

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

4
您的getter方法始终返回原始哈希中的值。设置实例变量不会更改这一点;您需要使getter引用实例变量。类似于下面的内容:
hash.each_pair do |key, value|
  define_method key do
    instance_variable_get("@#{key}")
  end
  # ... define the setter as before
end

同时,您还需要在开始时设置实例变量,例如通过以下方式:

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

在initialize方法中。

注意:我不能保证这是最好的方法;我不是Ruby专家。但它确实有效。


2

在我看来,这个代码(当然,在修正了你代码中显而易见的语法错误后)完全可用:

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

注意,在Ruby中实例变量始终是私有的,您永远不会为它们定义getter方法,因此您实际上无法从外部查看它们(除非通过反射),但这并不意味着您的代码不起作用,这仅意味着您无法看到它的工作原理。

0

这基本上就是我在 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

method_missing 可以破坏继承层次结构。 - cbz
@cbz,你能不能具体一点,给个例子? - Jeff Swensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接