2

我不确定我是否问对了问题。我可能错误地解决了这个问题,但基本上我在这里遇到了这种情况:

obj = get_user(params)
obj.profile => {:name => "John D", :age => 40, :sex => "male"} #Has to be of class Hash
obj.profile.name => "John D"
obj.profile[:name] => "John D"
obj.profile.job => nil

所以基本上,我必须满足所有这些条件,我什至不确定如何处理这个(我今天刚刚学习了 Ruby)。

请注意访问内部变量的点符号,否则我只会让profile成为符号的散列。所以我尝试了两种方法,这只能让我到达那里

方法 1:将配置文件设为 OpenStruct

所以这允许我使用点符号访问姓名、年龄和性别,如果键不存在,它会自动返回 nil,但是obj.profile的类型是OpenStruct而不是Hash

方法 2:将配置文件设为自己的类

有了这个,我将它们设置为实例变量,如果它们不存在,我可以使用method_missing返回 nil。但是,我再次遇到obj.profile不是正确类型/类的问题

有什么我想念的吗?有没有办法区分

obj.profile
obj.profile.name

在 getter 函数中并返回散列或其他?

我可以更改我的自定义类为配置文件返回的内容,因此它返回一个哈希值吗?

我什至尝试检查obj.profile的 get 函数中的args和 **kwargs ,但它们似乎都没有帮助,或者如果我调用obj.profile.something则填充

4

3 回答 3

1

只需几个哈希键,您就可以轻松定义单例方法,如下所示:

def define_getters(hash)
  hash.instance_eval do
    def name
      get_val(__method__)
    end

    def job
      get_val(__method__)
    end

    def get_val(key)
      self[key.to_sym]
    end
  end
end

profile = person.profile #=> {name: "John Doe", age: 40, gender: "M"}
define_getters(profile)

person.profile.name #=> "John Doe"
person.profile.job #=> nil

也反映更改的值(以防您想知道):

person.profile[:name] = "Ralph Lauren"
person.profile.name #=> "Ralph Lauren"

使用这种方法,您不必重写method_missing、创建继承自的新类Hash或猴子修补Hash类。

但是,为了能够通过方法调用访问未知键并返回nil而不是错误,您必须涉及method_missing.

于 2015-02-20T06:44:08.170 回答
1

如果它绝对必须是Hash

require 'pp'

module JSHash
  refine Hash do
    def method_missing(name, *args, &block)
      if !args.empty? || block
        super(name, *args, &block)
      else
        self[name]
      end
    end
  end
end

using JSHash

profile = {:name => "John D", :age => 40, :sex => "male"}

pp profile.name    # "John D"
pp profile[:name]  # "John D"
pp profile.job     # nil
pp profile.class   # Hash

但最好不要成为 a Hash,除非它绝对需要:

require 'pp'

class Profile < Hash
  def initialize(hash)
    self.merge!(hash)
  end
  def method_missing(name, *args, &block)
    if !args.empty? || block
      super(name, *args, &block)
    else
      self[name]
    end
  end
end

profile = Profile.new({:name => "John D", :age => 40, :sex => "male"})

pp profile.name
pp profile[:name]
pp profile.job
于 2015-02-20T06:19:46.707 回答
1

Hash覆盖将完成您要执行的操作。您需要做的就是将它包含在您已经加载的类文件之一中。

class Hash
  def method_missing(*args)
    if args.size == 1  
      self[args[0].to_sym]
    else
      self[args[0][0..-2].to_sym] = args[1] # last char is chopped because the equal sign is included in the string, print out args[0] to see for yourself
    end
  end
end

请参阅以下 IRB 输出以确认:

1.9.3-p194 :001 > test_hash = {test: "testing"}
 => {:test=>"testing"} 
1.9.3-p194 :002 > test_hash.test
 => "testing" 
1.9.3-p194 :003 > test_hash[:test]
 => "testing" 
1.9.3-p194 :004 > test_hash.should_return_nil
 => nil 
1.9.3-p194 :005 > test_hash.test = "hello"
 => "hello" 
1.9.3-p194 :006 > test_hash[:test]
 => "hello" 
1.9.3-p194 :007 > test_hash[:test] = "success"
 => "success" 
1.9.3-p194 :008 > test_hash.test
 => "success" 
1.9.3-p194 :009 > test_hash.some_new_key = "some value"
 => "some value" 
1.9.3-p194 :011 > test_hash[:some_new_key]
 => "some value" 
于 2015-02-20T06:49:45.750 回答