Hier ist mein Problem. Ich mag Andrea Pavoni 's Möglichkeit, einen verschachtelten Hash zu verwenden, um eine Klasse zu initialisieren.Ruby: initialisiert eine Ruby-Klasse mit einem verschachtelten Hash und einigen vordefinierten Standardwerten
require 'ostruct'
class DeepStruct < OpenStruct
def initialize(hash=nil)
@table = {}
@hash_table = {}
if hash
hash.each do |k,v|
@table[k.to_sym] = (v.is_a?(Hash) ? self.class.new(v) : v)
@hash_table[k.to_sym] = v
new_ostruct_member(k)
end
end
end
def to_h
@hash_table
end
end
Aber ich kann nicht einen Weg umfasst einen Hash (in der Klasse) mit spezifischen Standardwerten finden, so dass das Verhalten wäre wie folgt:
Original-Verhalten ohne Standard (mit oben code):
input_hash = {a: {b: 1}}
new_object = DeepStruct.new hash
new_object.a # => #<DeepStruct b=1>
new_object.a.b # => 1
new_object.a.to_h # => {b: 1}
Mit folgendem default_h innerhalb der Klasse definiert:
default_h = {a: {dc: 2}, dd: {de: 4}}
input_hash und default_h wie folgt fusionieren
{:a=>{:dc=>2, :b=>1}, :dd=>{:de=>4}}
Das Verhalten mit Standard-Hash (tatsächlich deep_merge für verschachtelte Hash verwendet wird) sein sollte:
new_object = DeepStruct.new hash
new_object.a.b # => 1
new_object.a.dc # => 2
new_object.a.to_h # => {:dc=>2, :b=>1}
ich keinen Weg finden können um dieses Verhalten innerhalb der Klasse zu implementieren. Ich würde wirklich jede Hilfe in dieser Angelegenheit schätzen.
Edit: versuchen nun Davids Code in einer Klasse zu verwenden:
class CompMedia
require 'ostruct'
attr_accessor :merged_h
def initialize(hash)
defaults = {a: {dc: 2}, dd: {de: 4}}
@merged_h = {}
deep_update(merged_h, defaults)
deep_update(merged_h, hash)
@merged_h
end
def deep_update(dest, src)
src.each do |key, value|
if value.is_a?(Hash)
dest[key] = {} if !dest[key].is_a?(Hash)
deep_update(dest[key], value)
else
dest[key] = value
end
end
end
def deep_open_struct(hash)
result = OpenStruct.new
hash.each do |key, value|
if value.is_a?(Hash)
result[key] = deep_open_struct(value)
else
result[key] = value
end
end
result
end
end # class CompMedia
input_hash = {a: {b: 1}}
cm = CompMedia.new(input_hash)
object = cm.deep_open_struct(cm.merged_h)
p object.marshal_dump # {:a=>#<OpenStruct dc=2, b=1>, :dd=>#<OpenStruct de=4>}
p object.a # <OpenStruct dc=2, b=1>
p object.a.marshal_dump # {:dc=>2, :b=>1}
p object.a.b # 1
p object.a.dc # 2
p object.dd # <OpenStruct de=4>
Natürlich, ich habe einen Weg gefunden auf einfache Art und Weise die verschachtelten Hash-Elemente aus dem openstruct Objekt abzurufen. Mein Ziel ist es, eine Klasse zu erstellen, die mit einem standardmäßigen (verschachtelten) Hash in der Klasse und einem (verschachtelten) Eingabehash initialisiert wird. Außerdem möchte ich in der Lage sein, Methoden hinzuzufügen, die den Hash innerhalb der Klasse verarbeiten würden. Ich bin noch nicht da.
Auf der anderen Seite konnte ich nur das fusionierte Hash verwenden und diese mit etwas umständlichen Notationen wenn auch funktionieren würden:
class CompMedia
attr_accessor :merged_h
def initialize(hash)
defaults = {a: {dc: 2}, dd: {de: 4}}
@merged_h = {}
deep_update(merged_h, defaults)
deep_update(merged_h, hash)
@merged_h
end
def deep_update(dest, src)
src.each do |key, value|
if value.is_a?(Hash)
dest[key] = {} if !dest[key].is_a?(Hash)
deep_update(dest[key], value)
else
dest[key] = value
end
end
end
def multiply_by(k)
merged_h[:a][:dc] * k
end
end
input_hash = {a: {b: 1}}
cm = CompMedia.new(input_hash)
p cm.merged_h # {:a=>{:dc=>2, :b=>1}, :dd=>{:de=>4}}
p cm.merged_h[:a] # {:dc=>2, :b=>1}
p cm.merged_h[:a][:dc] # 2
p cm.merged_h[:dd] # {:de=>4}
p cm.multiply_by(10) # 20
Ich werde die letzte Version als meine Lösung betrachten, es sei denn jemand den Code macht mit OpenStruct Arbeit, die ich bevorzugen würde.
Danke, das funktioniert, aber ich glaube, ich brauche eine Klasse, die den Standard-Hash enthält, und wird mit dem zusammengeführten Hash (Standard + Eingabe) initialisiert. Der Grund ist, dass ich zusätzliche Methoden hinzufügen möchte, die den Inhalt des Hashes verarbeiten. Ich arbeite mit deinem Code daran und werde es veröffentlichen, wenn ich etwas finde. Warum ist es eine schlechte Idee, OpenStruct zu untergliedern? – JMor
Es sollte nicht zu schwer sein, eine Klasse zu haben, die den Standard-Hash enthält. Sie können den Code in diesem Post unverändert belassen und eine Klasse erstellen, die ihn intern verwendet. –
Ich habe das getan. Aber ich kämpfe mit den Methoden dieser Klasse, die auf den zusammengeführten Hash zugreifen würde – JMor