3 votes

Les clés de hachage comme accesseurs dans une classe

Je travaille sur une classe qui lit les informations d'un capteur et les renvoie sous forme de hash. J'aimerais utiliser les clés de hachage comme accesseurs, mais je n'ai pas beaucoup de chance d'y parvenir. Voici les parties pertinentes de mon code jusqu'à présent :

Je l'ai essayé à la fois avec method_missing et en utilisant la fonction :define_method método.

  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

Les données renvoyées sont un hachage avec le nom du capteur comme clé et la valeur est un tableau de tout ce qui est renvoyé. Mon objectif est de pouvoir appeler Class.sensor.sensor_name et obtenir la sortie de Class.sensor[:sensor_name] . Actuellement, tout ce que j'arrive à obtenir est une erreur de méthode non définie. Quelqu'un a-t-il une idée de ce que je fais de mal ici ?

5voto

steenslag Points 29662

Peut-être qu'OpenStruct fait ce que vous voulez. De la doc : "C'est comme un hachage avec une manière différente d'accéder aux données. En fait, il est implémenté avec un hash, et vous pouvez l'initialiser avec un."

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

3voto

Vlad Khomich Points 3296

Un exemple rapide. Avez-vous des raisons de ne pas rafistoler votre 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"

0voto

sammms Points 197

Vous pourriez utiliser une classe enveloppante avec des méthodes manquantes afin de ne pas avoir à faire de patchs de singe. 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

Ou, si vous travaillez avec Rails, il y a une délégation d'objet intégrée avec SimpleDelegator . Cela vous permettrait de définir des accesseurs sur votre hachage ainsi que sur tout hachage imbriqué dans celui-ci.

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

Cela serait moins performant lors de l'instanciation que method_missing car il doit être exécuté récursivement sur votre objet délégué dès qu'il est créé. Cependant, c'est définitivement plus sûr que method_missing et certainement beaucoup plus sûr que le singe Parcheando votre Hash classe. Bien sûr, la sécurité est relative à vos objectifs. Si votre application ne fait que ça, alors laissez le singe faire son travail.

Et si vous voulez les accesseurs récursifs et imbriqués sans rails, vous pouvez faire quelque chose comme ceci avec une combinaison des éléments ci-dessus...

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

Mais à ce stade, vous devenez assez fou et il est probablement utile de réévaluer votre solution en faveur de quelque chose de plus orienté objet. Si je voyais l'un de ces éléments lors d'une revue de code, je lancerais certainement un drapeau rouge ;)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X