$__TRAIT_DEBUG__ = ENV['__TRAIT_DEBUG__'] || ENV['TRAIT_DEBUG'] class Object #--{{{ def singleton_method_added(*a, &b) #--{{{ obj = self obj.__trait_singleton_class.__trait_module_eval{ @__trait_singleton_super = obj } #--}}} end def __trait_singleton_class #--{{{ @__trait_singleton_class ||= class << self;self;end #--}}} end def __trait_singleton? #--{{{ @__is_trait_singleton ||= ((Class === self) and (@__is_trait_singleton ||= (not self.ancestors.include?(self)))) #--}}} end def __trait_search_path #--{{{ #((Class === self and not __trait_singleton?) ? ancestors : [self]) (__trait_singleton? or not respond_to? 'ancestors') ? [self] : ancestors #--}}} end def __trait_arg_filter(*args, &block) #--{{{ pre = nil post = nil validate = nil default = nil names_and_defaults = nil if block and not block.respond_to? :__trait_default block.__trait_singleton_class.class_eval{ attr '__trait_default' } end list, hashes = [ args ].flatten.partition{|arg| not Hash === arg} opts = hashes.inject({}){|accum,h| accum.update h} getopt = lambda do |key| return opts.delete(key) if opts.has_key? key key = "#{ key }" return opts.delete(key) if opts.has_key? key key = key.intern return opts.delete(key) if opts.has_key? key return default end pre = getopt['pre'] post = getopt['post'] validate = getopt['validate'] default = getopt['default'] names_and_defaults = opts raise ArgumentError, "cannot specify both 'default' keyword and 'default' block" if block and default default ||= block list.each{|name| names_and_defaults[name] = default} names = list + (names_and_defaults.keys - list) hooks = {'pre' => pre, 'post' => post, 'validate' => validate} names_and_hooks = names.inject({}){|h, name| h.update name => hooks} { 'names' => names, 'names_and_defaults' => names_and_defaults, 'names_and_hooks' => names_and_hooks, 'hooks' => {'pre' => pre, 'post' => post, 'validate' => validate}, 'pre' => pre, 'post' => post, 'validate' => validate, 'default' => default, } #--}}} end def __trait_instance_method_list #--{{{ @__trait_instance_method_list ||= {'writers' => [], 'readers' => [], } #--}}} end def __trait_singleton_method_list #--{{{ @__trait_singleton_method_list ||= {'writers' => [], 'readers' => [], } #--}}} end def __trait_instance_method_defaults #--{{{ @__trait_instance_method_defaults ||= {} #--}}} end def __trait_singleton_method_defaults #--{{{ @__trait_singleton_method_defaults ||= {} #--}}} end def __trait_instance_method_hooks #--{{{ @__trait_instance_method_hooks ||= Hash::new{ |h,name| h[name] = {'pre' => nil, 'post' => nil, 'validate' => nil} } #--}}} end def __trait_singleton_method_hooks #--{{{ @__trait_singleton_method_hooks ||= Hash::new{ |h,name| h[name] = {'pre' => nil, 'post' => nil, 'validate' => nil} } #--}}} end def __trait_evaluate(*a, &b) #--{{{ ret, sent = nil loop do m = "__trait_evaluate__#{ Thread::current.object_id.abs }__#{ rand 666 }__#{ rand 42 }__" begin __trait_singleton_class.module_eval{ define_method m, &b } ret = send(sent = m, *a) ensure begin __trait_singleton_class.module_eval{ remove_method m } ensure break if sent end end end ret #--}}} end def __trait_define_singleton_reader_traits(*args, &block) #--{{{ argf = __trait_arg_filter args, &block defaults = __trait_singleton_method_defaults list = __trait_singleton_method_list mhooks = __trait_singleton_method_hooks argf['names_and_defaults'].each do |name, default| __trait_singleton_class.__trait_define_reader_trait name, default, defaults, list end argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks} __trait_search_path.map{|ta| ta.__trait_singleton_method_list['readers']}.flatten #--}}} end def __trait_define_singleton_writer_traits(*args, &block) #--{{{ argf = __trait_arg_filter args, &block defaults = __trait_singleton_method_defaults list = __trait_singleton_method_list mhooks = __trait_singleton_method_hooks argf['names_and_defaults'].each do |name, default| __trait_singleton_class.__trait_define_writer_trait name, default, defaults, list end argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks} __trait_search_path.map{|ta| ta.__trait_singleton_method_list['writers']}.flatten #--}}} end def __trait_define_singleton_traits(*args, &block) #--{{{ writers = __trait_define_singleton_writer_traits(*args, &block) readers = __trait_define_singleton_reader_traits(*args, &block) [readers, writers] #--}}} end %w( instance_reader_traits instance_reader_trait reader_traits reader_trait r_traits r_trait has_readers has_reader has_r instance_writer_traits instance_writer_trait writer_traits writer_trait w_traits w_trait has_writers has_writer has_w instance_traits instance_trait traits trait has ).each do |meth| eval <<-def def #{ meth }(*a, &b) __trait_singleton_class.send('#{ meth }', *a, &b) end def end #--}}} end class Class #--{{{ def __trait_singleton_super #--{{{ class_eval{ def __________trait_singleton_super_init;end } unless defined? @__trait_singleton_super @__trait_singleton_super #--}}} end #--}}} end class Module #--{{{ def __trait_module_eval(*a, &b) #--{{{ begin module_eval(*a, &b) rescue Exception => e STDERR.puts([a, b].inspect) if $__TRAIT_DEBUG__ raise end #--}}} end def __trait_define_instance_reader_traits(*args, &block) #--{{{ if __trait_singleton? return(__trait_singleton_super.__trait_define_singleton_reader_traits(*args, &block)) end argf = __trait_arg_filter args, &block defaults = __trait_instance_method_defaults list = __trait_instance_method_list mhooks = __trait_instance_method_hooks argf['names_and_defaults'].each do |name, default| __trait_define_reader_trait name, default, defaults, list end argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks} __trait_search_path.map{|ta| ta.__trait_instance_method_list['readers']}.flatten #--}}} end %w( instance_reader_traits instance_reader_trait reader_traits reader_trait rtraits rtrait r_traits r_trait has_readers has_reader has_r ).each{|meth| alias_method meth, '__trait_define_instance_reader_traits'} def __trait_define_instance_writer_traits(*args, &block) #--{{{ if __trait_singleton? return(__trait_singleton_super.__trait_define_singleton_writer_traits(*args, &block)) end argf = __trait_arg_filter args, &block defaults = __trait_instance_method_defaults list = __trait_instance_method_list mhooks = __trait_instance_method_hooks argf['names_and_defaults'].each do |name, default| __trait_define_writer_trait name, default, defaults, list end argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks} __trait_search_path.map{|ta| ta.__trait_instance_method_list['writers']}.flatten #--}}} end %w( instance_writer_traits instance_writer_trait writer_traits writer_trait wtraits wtrait w_traits w_trait has_writers has_writer has_w ).each{|meth| alias_method meth, '__trait_define_instance_writer_traits'} def __trait_define_instance_traits(*args, &block) #--{{{ writers = __trait_define_instance_writer_traits(*args, &block) readers = __trait_define_instance_reader_traits(*args, &block) [readers, writers] #--}}} end %w( instance_traits instance_trait traits trait has ).each{|meth| alias_method meth, '__trait_define_instance_traits'} def __trait_define_class_reader_traits(*args, &block) #--{{{ __trait_define_singleton_reader_traits(*args, &block) #--}}} end %w( class_reader_traits class_reader_trait class_rtraits class_rtrait class_r_traits class_r_trait class_has_readers class_has_reader class_has_r c_has_readers c_has_reader c_has_r ).each{|meth| alias_method meth, '__trait_define_class_reader_traits'} def __trait_define_class_writer_traits(*args, &block) #--{{{ __trait_define_singleton_writer_traits(*args, &block) #--}}} end %w( class_writer_traits class_writer_trait class_wtraits class_wtrait class_w_traits class_w_trait class_has_writers class_has_writer class_has_w c_has_writers c_has_writer c_has_w ).each{|meth| alias_method meth, '__trait_define_class_writer_traits'} def __trait_define_class_traits(*args, &block) #--{{{ __trait_define_singleton_traits(*args, &block) #--}}} end %w( class_traits class_trait class_has c_has ).each{|meth| alias_method meth, '__trait_define_class_traits'} def __trait_define_reader_trait name, default, defaults, list #--{{{ getter = "#{ name }" setter = "#{ name }=" query = "#{ name }?" defaults[getter] = default if default list['readers'] << getter unless instance_methods.include? getter code = __trait_gen_reader_code name, 'public' __trait_module_eval code end unless instance_methods.include? setter code = __trait_gen_writer_code name, 'private' __trait_module_eval code end unless instance_methods.include? query code = __trait_gen_query_code name, 'public' __trait_module_eval code end #--}}} end def __trait_define_writer_trait name, default, defaults, list #--{{{ reader = "#{ name }" writer = "#{ name }=" query = "#{ name }?" defaults[reader] = default if default list['writers'] << writer unless instance_methods.include? reader code = __trait_gen_reader_code name, 'private' __trait_module_eval code end unless instance_methods.include? writer code = __trait_gen_writer_code name, 'public' __trait_module_eval code end unless instance_methods.include? query code = __trait_gen_query_code name, 'private' __trait_module_eval code end #--}}} end def __trait_gen_reader_code name, access_protection = 'public' #--{{{ s = __trait_singleton? klass = s ? 'self' : 'self.class' defaults = s ? '__trait_singleton_method_defaults' : '__trait_instance_method_defaults' search_ancestors = s ? 'true' : 'false' getter_meth = "#{ name }" setter_meth = "#{ name }=" query_meth = "#{ name }?" ivar = "@#{ name }" getter = "'#{ name }'" setter = "'#{ name }='" reader_code = <<-code def #{ name }(*a, &b) unless a.empty? send('#{ name }=', *a, &b) else unless(defined?(@________#{ name }_set) and @________#{ name }_set) #{ klass }::__trait_search_path.each do |obj| defaults = obj.#{ defaults } if defaults.has_key? '#{ name }' d = defaults['#{ name }'] if d.respond_to? '__trait_default' d = instance_eval &d end return(send('#{ name }=', d)) end end end case self when Class if defined? @#{ name } @#{ name } else __trait_search_path.each do |obj| if self != obj and obj.respond_to? '#{ name }' return(obj.send('#{ name }', *a, &b)) end end return nil end else @#{ name } end end end #{ access_protection } '#{ name }'.intern code puts reader_code if $__TRAIT_DEBUG__ reader_code #--}}} end def __trait_gen_writer_code name, access_protection = 'public' #--{{{ s = __trait_singleton? klass = s ? 'self' : 'self.class' hooks = s ? '__trait_singleton_method_hooks' : '__trait_instance_method_hooks' writer_code = <<-code def #{ name }=(head, *tail) value = tail.empty? ? head : [head] + tail #hooks = #{ klass }::#{ hooks }['#{ name }'] hooks = nil #{ klass }::__trait_search_path.each do |obj| hooks = obj.#{ hooks }['#{ name }'] and break end pre, post, validate = hooks.values_at 'pre', 'post', 'validate' if pre __trait_evaluate value, &pre if pre end if validate valid = __trait_evaluate value, &validate raise ArgumentError, "validation of #{ name }=(\#{ value.inspect }) failed!" unless valid end @#{ name } = value @________#{ name }_set = true if post __trait_evaluate value, &post end @#{ name } end #{ access_protection } '#{ name }='.intern code #--}}} end def __trait_gen_query_code name, access_protection = 'public' #--{{{ query_code = <<-code def #{ name }? send('#{ name }') ? true : false end # #{ access_protection } '#{ name }?'.intern code puts query_code if $__TRAIT_DEBUG__ query_code #--}}} end def __trait_gen_access_protection_code name, access_protection = nil #--{{{ access_protection ||= 'public' access_protection_code = case access_protection when %r/private/ "private '#{ name }'.intern" when %r/protected/ "protected '#{ name }'.intern" else "public '#{ name }'.intern" end puts access_protection_code if $__TRAIT_DEBUG__ access_protection_code #--}}} end #--}}} end