module Attributes Attributes::VERSION = '4.0.0' unless defined? Attributes::VERSION def self.version() Attributes::VERSION end class List < ::Array def << element super self ensure uniq! index! end def index! @index ||= Hash.new each{|element| @index[element] = true} end def include? element @index ||= Hash.new @index[element] ? true : false end def initializers @initializers ||= Hash.new end end def attributes *a, &b unless a.empty? returned = Hash.new hashes, names = a.partition{|x| Hash === x} names_and_defaults = {} hashes.each{|h| names_and_defaults.update h} names.flatten.compact.each{|name| names_and_defaults.update name => nil} initializers = __attributes__.initializers names_and_defaults.each do |name, default| raise NameError, "bad instance variable name '@#{ name }'" if "@#{ name }" =~ %r/[!?=]$/o name = name.to_s initialize = b || lambda { default } initializer = lambda do |this| Object.instance_method('instance_eval').bind(this).call &initialize end initializer_id = initializer.object_id __attributes__.initializers[name] = initializer module_eval <<-code def #{ name }=(value) @#{ name } = value end def #{ name }(*value) return self.#{ name } = value.first unless value.empty? #{ name }! unless defined? @#{ name } @#{ name } end def #{ name }! initializer = ObjectSpace._id2ref #{ initializer_id } self.#{ name } = initializer.call(self) @#{ name } end def #{ name }? defined? @#{ name } and #{ name } end code attributes << name returned[name] = initializer end returned else begin __attribute_list__ rescue NameError singleton_class = class << self self end klass = self singleton_class.module_eval do attribute_list = List.new define_method('attribute_list'){ klass == self ? attribute_list : raise(NameError) } alias_method '__attribute_list__', 'attribute_list' end __attribute_list__ end end end %w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'} end class Object def attributes *a, &b sc = class << self self end sc.attributes *a, &b end %w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'} end class Module include Attributes end