require 'set' # Provides instance method gather and class method property # Allows properties to be Enumerable. module Gather # Evaluate the block and gather options from args. Even if it's nil. # Return self def gather( args = {}, &block ) unless args.nil? args.each do |key,value| self.send( key, value ) end end unless block.nil? if block.arity == -1 instance_eval &block else yield self end end self end # return a hash of the properties def to_hash( properties = self.class.properties ) properties.inject({}) {|s,x| s[x] = send(x); s} end # set all values specified in the hash def merge!( hash ) hash.each {|k,v| send( k, v ) } end # return a new hash merged with the argument def merge( hash ) to_hash.merge( hash ) end def []( symbol ) send( symbol ) end def []=( symbol, value ) send( symbol, value ) end def each( &block ) self.class.properties.each( &block ) end include Enumerable def self.included( base ) base.extend( ClassMethods ) end module ClassMethods # return properties for only this class def own_properties @properties ||= Set.new end # return properties for this class and ancestors def properties own_properties + if superclass.respond_to? :properties superclass.properties else [] end end def property( *symbols ) @stripper_re ||= /^([^\= ]+)\s*\=?\s*$/ symbols.each do |sym| stripped = @stripper_re.match( sym.to_s )[1] own_properties << stripped.to_sym line, st = __LINE__, <<-EOF def #{stripped}(*val, &block) if block.nil? if val.empty? @#{stripped} else @#{stripped} = val.size == 1 ? val[0] : val end else @#{stripped} = block end end def #{stripped}=(*val) @#{stripped} = val.size == 1 ? val[0] : val end EOF class_eval st, __FILE__, line + 1 end end end end