=begin $Title: Accessors $ $Author: transami $ $Date: 2004-10-06 13:56:57 $ = Description The Bill wants more from attributes. = Usage == Using Cast Attribute Accessors # simple type casting attr_reader :a => :to_s # fancy type casting attr_reader :a => 'to_s.capitalize' # a powerful reader! attr_reader :a => fn{ |x| eval x } # a writer that type checks (use type.rb) attr_writer :a => fn{ |x| big4 x } # backwards compatible, cast attributes go at the end attr_accessor :x, :y, :a => :to_s # they can also be grouped attr_accessor [:x, :y] => :to_s == Using Accessor Shorthand A nice shorthand is provided. attr :r, :a, :a=, :w= This is the same as doing attr_reader :r attr_accessor :a attr_writer :w Also attr :b?, :b! creating def b? @b ? true : @b end def b!(x) @b.replace(x) end The shorthand notation can be used with casting too. attr :a => :to_s == Using Return Value Attribute methods now return a list of the methods created. This can then be passed to other useful methods. private attr :a = Authenticate Copyright (C) 2002 T. Sawyer Ruby Distribute License This program is free software. You can distribute/modify this program under the terms of the Ruby Distribute License. =end #require 'facet/hash/update_each' # Modify module attribute methods. # *add define_attribute # *redefine old attr_* methods # *add attr_setter class Module # Create an attribute method for reading an # instance variable. This is the same as the built # in method, which it replaces, but adds casting. # # Casting allows the addition of a method invocation # on the instance variable. It is defined using a hash # parameter, so all castings must come at the end of a # call to attr_reader. # # require 'carat/attr' # # attr_reader :a => :to_s # # _is equivalent to_ # # def a # @a.to_s # end # def attr_reader(*args) made = [] if Hash === args.last args.concat( args.pop.to_a ) end #hargs = (Hash === args.last ? args.pop : {}) args.each { |a,c| a = a.to_s.strip c = ".#{c.to_s.strip}".chomp('.') module_eval %Q{ def #{a}; @#{a}#{c} ; end } made << "#{a}".to_sym } (@__atributes__ ||= []).concat( made ) return *made end # Create an attribute method for writing to an # instance variable. This is the same as the built # in method, which it replaces, but adds casting. # # Casting allows the addition of a method invocation # on the instance variable. It is defined using a hash # parameter, so all castings must come at the end of a # call to attr_writer. # # require 'carat/attr' # # attr_writer :a => :to_s # # _is equivalent to_ # # def a=(x) # @a = x.to_s # end # def attr_writer(*args) made = [] if Hash === args.last args.concat( args.pop.to_a ) end #hargs = (Hash === args.last ? args.pop : {}) args.each { |a,c| a = a.to_s.strip.chomp('=').chomp('!') c = ".#{c.to_s.strip}".chomp('.') module_eval %Q{ def #{a}=(x); @#{a}=x#{c}; end } made << "#{a}=".to_sym } (@__atributes__ ||= []).concat( made ) return *made end # Create an attribute method for writing to an # instance variable. This is the same as the built # in method, which it replaces, but adds casting. # # Casting allows the addition of a method invocation # on the instance variable. It is defined using a hash # parameter, so all castings must come at the end of a # call to attr_writer. # # require 'carat/attr' # # attr_accessor :a => :to_s # # _is equivalent to_ # # def a # @a.to_s # end # # def a=(x) # @a = x.to_s # end # def attr_accessor(*args) made = [] if Hash === args.last args.concat( args.pop.to_a ) end #hargs = (Hash === args.last ? args.pop : {}) args.each { |a,c| a = a.to_s.strip.chomp('=') c = ".#{c.to_s.strip}".chomp('.') module_eval %Q{ def #{a}; @#{a}#{c} ; end } module_eval %Q{ def #{a}=(x); @#{a}=x#{c}; end } made << "#{a}".to_sym made << "#{a}=".to_sym } (@__atributes__ ||= []).concat( made ) return *made end # Create an attribute method for boolean testing # of an instance variable in the form of _var?_. # # require 'facet/module/attr_tester' # # attr_tester :a # # _is equivalent to_ # # def a? # @a ? true : @a # end # # Casting is also supported (see attr_reader). # # attr_tester :a => :evaluate # # _is equivalent to_ # # def a? # @a.evaluate ? true : @a # end # def attr_tester(*args) made = [] if Hash === args.last args.concat( args.pop.to_a ) end #hargs = (Hash === args.last ? args.pop : {}) args.each { |a,c| a = a.to_s.strip.chomp('?') c = ".#{c.to_s.strip}".chomp('.') module_eval %Q{ def #{a}?; @#{a}#{c} ? true : @#{a}#{c}; end } made << "#{a}?".to_sym } (@__atributes__ ||= []).concat made return *made end # Create an attribute method for getting and setting an # instance variable. # # require 'carat/attr' # # attr_setter :a # # _is equivalent to_ # # def a(*args) # if args.size > 0 # @a = args[0] # self # else # @a # end # end # # Casting is supported on both getting and setting. # # attr_setter :a => :to_s # # _is equivalent to_ # # def a(*args) # @a = args[0].to_s if args.size > 0 # @a.to_s # end # def attr_setter(*args) made = [] if Hash === args.last args.concat( args.pop.to_a ) end #hargs = (Hash === args.last ? args.pop : {}) args.each { |a,c| a = a.to_s.strip c = ".#{c.to_s.strip}".chomp('.') module_eval %Q{ def #{a}(*args) args.size > 0 ? ( @#{a}=args[0]#{c} ; self ) : @#{a}#{c} end } made << "#{a}".to_sym } (@__atributes__ ||= []).concat( made ) return *made end # DOES ANYONE USE THIS OLD THING? #alias attribute attr # The wondrful shortcut. def attr(*args) # Allows compatibility with old definition, while also # extending the capabilites to allow multiple parameters. # This form does not allow casting though. if TrueClass === args.last or FalseClass === args.last or NilClass === args.last if args.pop args.concat( args.collect{ |a| a = a.to_s.strip case a[-1,1] when '=' a[0..-2] when '?' "#{a[0..-2]}=" else "#{a}=" end } ) end end # made = [] readers = [] writers = [] testers = [] if Hash === args.last args.concat( args.pop.to_a ) end args.each do |a,c| a = a.to_s.strip t = a.slice(-1,1) m = a.chomp('!').chomp('=').chomp('?') case t when '=' readers << [m,c] writers << [m,c] when '?' testers << [m,c] when '!' writers << [m,c] else readers << [m,c] end end made.concat( [ attr_reader( *readers ) ] ) made.concat( [ attr_writer( *writers ) ] ) made.concat( [ attr_tester( *testers ) ] ) return *made end end