class Configurability::Config
A configuration object class for systems with Configurability
Author/s¶ ↑
-
Michael Granger <ged@FaerieMUD.org>
-
Mahlon E. Smith <mahlon@martini.nu>
This class also delegates some of its methods to the underlying struct:
Configurability::Config::Struct#to_hash
-
to_hash (delegated to its internal
Struct
) Configurability::Config::Struct#member?
-
member? (delegated to its internal
Struct
) Configurability::Config::Struct#members
-
members (delegated to its internal
Struct
) Configurability::Config::Struct#merge
-
merge (delegated to its internal
Struct
) Configurability::Config::Struct#merge!
-
merge! (delegated to its internal
Struct
) - Configurability::Config::Struct#each
-
each (delegated to its internal
Struct
) Configurability::Config::Struct#[]
-
[] (delegated to its internal
Struct
) Configurability::Config::Struct#[]=
-
[]= (delegated to its internal
Struct
)
Attributes
the path to the config file, if loaded from a file
The underlying config data structure
The time the configuration was loaded
Public Class Methods
Read and return a Configurability::Config
object from the file at the given path
.
# File lib/configurability/config.rb, line 55 def self::load( path, defaults=nil, &block ) path = Pathname( path ).expand_path source = path.read Configurability.log.debug "Read %d bytes from %s" % [ source.length, path ] return new( source, path, defaults, &block ) end
Recursive hash-merge function. Used as the block argument to a Hash#merge.
# File lib/configurability/config.rb, line 64 def self::merge_complex_hashes( key, oldval, newval ) return oldval.merge( newval, &method(:merge_complex_hashes) ) if oldval.respond_to?( :merge ) && newval.respond_to?( :merge ) return newval end
Create a new Configurability::Config
object. If the optional source
argument is specified, parse the config from it. If one is given, the block will be evaluated in the context of the config object after the config is loaded, unless it accepts an argument, in which case the config object is passed as the argument.
# File lib/configurability/config.rb, line 81 def initialize( source=nil, path=nil, defaults=nil, &block ) # Shift the hash parameter if it shows up as the path if path.is_a?( Hash ) defaults = path path = nil end # Make a deep copy of the defaults before loading so we don't modify # the argument @defaults = defaults ? Marshal.load( Marshal.dump(defaults) ) : nil @time_created = Time.now @path = path if source @struct = self.make_configstruct_from_source( source, @defaults ) else @struct = Configurability::Config::Struct.new( @defaults ) end if block Configurability.log.debug "Block arity is: %p" % [ block.arity ] # A block with an argument is called with the config as the argument # instead of instance_evaled case block.arity when 0, -1 # 1.9 and 1.8, respectively Configurability.log.debug "Instance evaling in the context of %p" % [ self ] self.instance_eval( &block ) else block.call( self ) end end end
Public Instance Methods
Returns true
if the configuration has changed since it was last loaded, either by setting one of its members or changing the file from which it was loaded.
# File lib/configurability/config.rb, line 178 def changed? return self.changed_reason ? true : false end
If the configuration has changed, return the reason. If it hasn't, returns nil.
# File lib/configurability/config.rb, line 185 def changed_reason if @struct.dirty? Configurability.log.debug "Changed_reason: struct was modified" return "Struct was modified" end if self.path && self.is_older_than?( self.path ) Configurability.log.debug "Source file (%s) has changed." % [ self.path ] return "Config source (%s) has been updated since %s" % [ self.path, self.time_created ] end return nil end
Return the config object as a YAML hash
# File lib/configurability/config.rb, line 143 def dump strhash = stringify_keys( self.to_h ) return YAML.dump( strhash ) end
Return a human-readable, compact representation of the configuration suitable for debugging.
# File lib/configurability/config.rb, line 232 def inspect return "#<%s:0x%0x16 loaded from %s; %d sections: %s>" % [ self.class.name, self.object_id * 2, self.path ? self.path : "memory", self.struct.members.length, self.struct.members.join( ', ' ) ] end
Install this config object in any objects that have added Configurability
.
# File lib/configurability/config.rb, line 137 def install Configurability.configure_objects( self ) end
Return true
if the specified file
is newer than the time the receiver was created.
# File lib/configurability/config.rb, line 203 def is_older_than?( path ) return false unless path.exist? st = path.stat Configurability.log.debug "File mtime is: %s, comparison time is: %s" % [ st.mtime, @time_created ] return st.mtime > @time_created end
Reload the configuration from the original source if it has changed. Returns true
if it was reloaded and false
otherwise.
# File lib/configurability/config.rb, line 214 def reload raise "can't reload from an in-memory source" unless self.path if self.changed? self.time_created = Time.now source = self.path.read @struct = self.make_configstruct_from_source( source, @defaults ) self.install return true else return false end end
Returns true
for methods which can be autoloaded
# File lib/configurability/config.rb, line 169 def respond_to?( sym, include_all=false ) return true if @struct.member?( sym.to_s.sub(/(=|\?)$/, '').to_sym ) super end
Write the configuration object using the specified name and any additional args
.
# File lib/configurability/config.rb, line 151 def write( path=@path, *args ) unless path.is_a?( String ) || path.is_a?( Pathname ) args.unshift( path ) path = @path end raise ArgumentError, "No name associated with this config." unless path self.log.info "Writing config to %s with args: %p" % [ path, args ] path = Pathname( path ) path.open( File::WRONLY|File::CREAT|File::TRUNC, *args ) do |ofh| ofh.print( self.dump ) end end
Protected Instance Methods
Delegate logging to the module's Logger.
# File lib/configurability/config.rb, line 286 def log Configurability.logger end
Read in the specified filename
and return a config struct.
# File lib/configurability/config.rb, line 248 def make_configstruct_from_source( source, defaults=nil ) defaults ||= {} mergefunc = Configurability::Config.method( :merge_complex_hashes ) hash = nil if source.is_a?( Hash ) hash = source else hash = if defined?( SafeYAML ) then YAML.load( source, :safe => true ) else YAML.load( source ) end end ihash = symbolify_keys( hash ) idefaults = symbolify_keys( defaults ) mergedhash = idefaults.merge( ihash, &mergefunc ) return Configurability::Config::Struct.new( mergedhash ) end
Handle calls to struct-members
# File lib/configurability/config.rb, line 272 def method_missing( sym, *args ) key = sym.to_s.sub( /(=|\?)$/, '' ).to_sym self.class.class_eval %{ def #{key}; @struct.#{key}; end def #{key}=(arg); @struct.#{key} = arg; end def #{key}?; @struct.#{key}?; end } return self.method( sym ).call( *args ) end