Hash-wrapper that allows struct-like accessor calls on nested hashes.
Create a new ConfigStruct using the values from the given hash
if specified.
# File lib/configurability/config.rb, line 381
def initialize( hash=nil )
hash ||= {}
@hash = symbolify_keys( hash )
@dirty = false
end
Return the value associated with the specified key
, or another Configurability::Config::ConfigStruct if key
is a section name.
# File lib/configurability/config.rb, line 402
def []( key )
key = key.untaint.to_sym if key.respond_to?( :to_sym )
# Convert Hashes to Struct on the fly for subsections
@hash[ key ] = self.class.new( @hash[key] ) if @hash[ key ].is_a?( Hash )
return @hash[ key ]
end
Set the value associated with the specified key
to value
.
# File lib/configurability/config.rb, line 413
def []=( key, value )
key = key.untaint.to_sym
self.mark_dirty if @hash[ key ] != value
@hash[ key ] = value
end
Returns true
if the ConfigStruct or any of its sub-structs have changed since it was created.
# File lib/configurability/config.rb, line 428
def dirty?
return true if @dirty
return true if @hash.values.find do |obj|
obj.respond_to?( :dirty? ) && obj.dirty?
end
end
Return a human-readable representation of the Struct
suitable for debugging.
# File lib/configurability/config.rb, line 519
def inspect
return "#<%s:%0x16 %p>" % [
self.class.name,
self.object_id * 2,
@hash,
]
end
Mark the struct has having been modified since its creation.
# File lib/configurability/config.rb, line 421
def mark_dirty
@dirty = true
end
Returns true
if the given name
is the name of a member of the receiver.
# File lib/configurability/config.rb, line 475
def member?( name )
name = name.to_sym if name.respond_to?( :to_sym )
return @hash.key?( name )
end
Returns an Array of Symbols, one for each of the struct's members.
# File lib/configurability/config.rb, line 468
def members
return @hash.keys
end
Return a new Configurability::Config::Struct
which is the result of merging the receiver with the given other
object (a Hash or another Configurability::Config::Struct
).
# File lib/configurability/config.rb, line 513
def merge( other )
self.dup.merge!( other )
end
Merge the specified other
object with this config struct. The other
object can be either a Hash, another Configurability::Config::Struct
, or an Configurability::Config
.
# File lib/configurability/config.rb, line 485
def merge!( other )
mergefunc = Configurability::Config.method( :merge_complex_hashes )
case other
when Hash
@hash = self.to_h.merge( other, &mergefunc )
when Configurability::Config::Struct
@hash = self.to_h.merge( other.to_h, &mergefunc )
when Configurability::Config
@hash = self.to_h.merge( other.struct.to_h, &mergefunc )
else
raise TypeError,
"Don't know how to merge with a %p" % other.class
end
# :TODO: Actually check to see if anything has changed?
@dirty = true
return self
end
Return true
if the receiver responds to the given method. Overridden to grok autoloaded methods.
# File lib/configurability/config.rb, line 460
def respond_to?( sym, priv=false )
key = sym.to_s.sub( /(=|\?)$/, '' ).to_sym
return true if @hash.key?( key )
super
end
Return the receiver's values as a (possibly multi-dimensional) Hash with String keys.
# File lib/configurability/config.rb, line 438
def to_hash
rhash = {}
@hash.each {|k,v|
case v
when Configurability::Config::Struct
rhash[k] = v.to_h
when NilClass, FalseClass, TrueClass, Numeric
# No-op (can't dup)
rhash[k] = v
when Symbol
rhash[k] = v.to_s
else
rhash[k] = v.dup
end
}
return rhash
end
Create a predicate method for the specified key
and return it.
# File lib/configurability/config.rb, line 559
def create_member_predicate( key )
return lambda { self.member?( key ) && self[key] ? true : false }
end
Create a reader method for the specified key
and return it.
# File lib/configurability/config.rb, line 553
def create_member_reader( key )
return lambda { self[key] }
end
Create a writer method for the specified key
and return it.
# File lib/configurability/config.rb, line 565
def create_member_writer( key )
return lambda {|val| self[key] = val }
end
Handle calls to key-methods
# File lib/configurability/config.rb, line 533
def method_missing( sym, *args )
key = sym.to_s.sub( /(=|\?)$/, '' ).to_sym
# Create new methods for this key
reader = self.create_member_reader( key )
writer = self.create_member_writer( key )
predicate = self.create_member_predicate( key )
# ...and install them
self.class.send( :define_method, key, &reader )
self.class.send( :define_method, "#{key}=", &writer )
self.class.send( :define_method, "#{key}?", &predicate )
# Now jump to the requested method in a way that won't come back through
# the proxy method if something didn't get defined
self.method( sym ).call( *args )
end