哈希键作为类中的访问器

发布于 2024-11-03 13:27:18 字数 1210 浏览 1 评论 0原文

我正在开发一个读取一些传感器信息并将其作为哈希值返回的类。我想使用哈希键作为访问器,但我没有太多运气让它工作。到目前为止,以下是我的代码的相关部分:

我已经尝试使用 method_missing 和使用 :define_method 方法。

  attr_reader :sensor_hash

  def method_missing(name, *args, &blk)
    if args.empty? && blk.nil? && @sensor_hash.has_key?(name.to_s)
      @sensor_hash[name.to_s]
    else
      super
    end
  end

  def sensor(*sensor_to_return)
    sensor_output = run_command(this_method_name)
    sensor_output = sensor_output.split("\n")
    sensor_output.map! { |line| line.downcase! }
    unless sensor_to_return.empty?
      sensor_to_return = sensor_to_return.to_s.downcase
      sensor_output = sensor_output.grep(/^#{sensor_to_return}\s/)
    end
    @sensor_hash = Hash.new
    sensor_output.each { |stat| @sensor_hash[stat.split(/\s+\|\s?/)[0].gsub(' ','_').to_sym] = stat.split(/\s?\|\s?/)[1..-1].each { |v| v.strip! } }
    @sensor_hash.each do |k,v|
      puts v.join("\t")
      self.class.send :define_method, k { v.join("\t") }
    end
    return @sensor_hash

返回的数据是以传感器名称作为键的哈希值,值是返回的所有其他内容的数组。我的目标是能够调用 Class.sensor.sensor_name 并获取 Class.sensor[:sensor_name] 的输出。目前,我所能得到的只是一个未定义的方法错误。有人知道我在这里做错了什么吗?

I'm working on a class that reads some sensor information and returns it as a hash. I would like to use the hash keys as accessors, but I'm not having much luck getting it work. Here are the relevant parts of my code so far:

I've tried it both with method_missing and by using the :define_method method.

  attr_reader :sensor_hash

  def method_missing(name, *args, &blk)
    if args.empty? && blk.nil? && @sensor_hash.has_key?(name.to_s)
      @sensor_hash[name.to_s]
    else
      super
    end
  end

  def sensor(*sensor_to_return)
    sensor_output = run_command(this_method_name)
    sensor_output = sensor_output.split("\n")
    sensor_output.map! { |line| line.downcase! }
    unless sensor_to_return.empty?
      sensor_to_return = sensor_to_return.to_s.downcase
      sensor_output = sensor_output.grep(/^#{sensor_to_return}\s/)
    end
    @sensor_hash = Hash.new
    sensor_output.each { |stat| @sensor_hash[stat.split(/\s+\|\s?/)[0].gsub(' ','_').to_sym] = stat.split(/\s?\|\s?/)[1..-1].each { |v| v.strip! } }
    @sensor_hash.each do |k,v|
      puts v.join("\t")
      self.class.send :define_method, k { v.join("\t") }
    end
    return @sensor_hash

The data returned is a hash with the sensor name as the key and and the value is an array of everything else returned. My goal is to be able to call Class.sensor.sensor_name and get the output of Class.sensor[:sensor_name]. Currently, all I'm able to get is an undefined method error. Anybody have any idea what I'm doing wrong here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

べ繥欢鉨o。 2024-11-10 13:27:18

也许 OpenStruct 可以满足您的需求。来自 doc :“它就像一个散列,以不同的方式事实上,它是用哈希值实现的,你可以用一个哈希值来初始化它。”

require 'ostruct'
s=OpenStruct.new({:sensor_name=>'sensor1',:data=>['something',1,[1,2,3]]})
p s.sensor_name
#=> "sensor1"

Maybe OpenStruct does what you want. From the doc :"It is like a hash with a different way to access the data. In fact, it is implemented with a hash, and you can initialize it with one."

require 'ostruct'
s=OpenStruct.new({:sensor_name=>'sensor1',:data=>['something',1,[1,2,3]]})
p s.sensor_name
#=> "sensor1"
歌入人心 2024-11-10 13:27:18

只是一个简单的例子。你有什么理由不对你的哈希值进行猴子补丁吗?

irb(main):001:0> class Hash
irb(main):002:1> def method_missing(name, *args, &blk)
irb(main):003:2>   if self.keys.map(&:to_sym).include? name.to_sym
irb(main):004:3>     return self[name.to_sym]
irb(main):005:3>   else
irb(main):006:3*     super
irb(main):007:3>   end
irb(main):008:2> end
irb(main):009:1> end
=> nil
irb(main):012:0> h = {:hello => 'world'}
=> {:hello=>"world"}
irb(main):013:0> h.hello
=> "world"

Just a quick example. Do you have any reasons to not monkey-patch your Hash?

irb(main):001:0> class Hash
irb(main):002:1> def method_missing(name, *args, &blk)
irb(main):003:2>   if self.keys.map(&:to_sym).include? name.to_sym
irb(main):004:3>     return self[name.to_sym]
irb(main):005:3>   else
irb(main):006:3*     super
irb(main):007:3>   end
irb(main):008:2> end
irb(main):009:1> end
=> nil
irb(main):012:0> h = {:hello => 'world'}
=> {:hello=>"world"}
irb(main):013:0> h.hello
=> "world"
残龙傲雪 2024-11-10 13:27:18

您可以使用缺少方法的包装类,这样您就不必猴子修补Hash

class AccessibleHash
  def initialize(hash)
    @hash = hash
  end

  def method_missing(name, *args, &block)
    sname = name.to_sym
    if @hash.keys.include? sname
      return @hash[sname]
    else
      super
    end
  end
end

或者,如果您正在使用 Rails,它有一些很好的内置对象委托与 SimpleDelegator。这将允许您在哈希值以及其中的任何嵌套哈希值上定义访问器。

class AccessibleHash < SimpleDelegator
  def initialize
    define_accessors(self.keys)
  end

  def define_accessors(keys)
    keys.each do |key|
      defind_accessors(body[key].keys)
      self.define_singleton_method(key) { self[key] }
    end
  end
end

ah = AccessibleHash.new({ some: 'hash', with: { recursive: 'accessors' })
ah.with.recursive == 'accessors'
=> true

这在实例化时的性能会比 method_missing 低,因为它必须在创建后立即在您的委托对象上递归运行。但是,它绝对比 method_missing 更安全,并且比猴子修补 Hash 类更安全。当然,安全性与您的目标相关,如果这就是您的应用程序所做的一切,那么猴子补丁就可以了。

如果您想要没有轨道的递归嵌套访问器,您可以结合上述内容执行类似的操作...

class AccessibleHash
  def initialize(hash)
    @hash = hash
    define_accessors(@hash.keys)
  end

  def define_accessors(keys)
    keys.each do |key|
      @hash[key] = self.class.new(@hash[key]) if @hash.keys.present?

      self.define_singleton_method(key) { self[key] }
    end
  end
end

但是到那时您会变得非常疯狂,并且可能值得重新评估您的解决方案以支持更面向对象的解决方案。如果我在代码审查中看到其中任何一个,它肯定会引发危险信号。 ;)

You could use a wrapper class with method missing so you don't have to monkey patch Hash.

class AccessibleHash
  def initialize(hash)
    @hash = hash
  end

  def method_missing(name, *args, &block)
    sname = name.to_sym
    if @hash.keys.include? sname
      return @hash[sname]
    else
      super
    end
  end
end

Or, if you are working with Rails it has some nice built in object delegation with SimpleDelegator. That would allow you to define accessors on your hash as well as any nested hashes within it.

class AccessibleHash < SimpleDelegator
  def initialize
    define_accessors(self.keys)
  end

  def define_accessors(keys)
    keys.each do |key|
      defind_accessors(body[key].keys)
      self.define_singleton_method(key) { self[key] }
    end
  end
end

ah = AccessibleHash.new({ some: 'hash', with: { recursive: 'accessors' })
ah.with.recursive == 'accessors'
=> true

This would be less performant at instantiation than method_missing, because it has to run recursively over your delegatee object as soon as it's created. However, it's definitely safer than method_missing, and certainly way safer than monkey patching your Hash class. Of course, safety is relative to your goals, If it's all your application does then monkey patch away.

And if you want the recursive, nested accessors without rails you could do something like this with a combination of the above...

class AccessibleHash
  def initialize(hash)
    @hash = hash
    define_accessors(@hash.keys)
  end

  def define_accessors(keys)
    keys.each do |key|
      @hash[key] = self.class.new(@hash[key]) if @hash.keys.present?

      self.define_singleton_method(key) { self[key] }
    end
  end
end

But at that point you're getting pretty crazy and it's probably worth reevaluating your solution in favor of something more Object Oriented. If I saw any of these in a code review it would definitely throw up a red flag. ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文