# Traits-0.9.2 - better living through metaprogramming

**URL:** <https://www.ruby-forum.com/t/traits-0-9-2-better-living-through-metaprogramming/65816>\
**Category:** Ruby\
**Created:** [August 21, 2006, 5:25pm UTC](https://www.ruby-forum.com/t/traits-0-9-2-better-living-through-metaprogramming/65816 "2006-08-21T17:25:40Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [August 21, 2006, 5:25pm UTC](https://www.ruby-forum.com/t/traits-0-9-2-better-living-through-metaprogramming/65816/1 "2006-08-21T17:25:40Z")

</div>

URLS

[http://rubyforge.org/projects/codeforpeople/](http://rubyforge.org/projects/codeforpeople/)  
[http://codeforpeople.com/lib/ruby/traits](http://codeforpeople.com/lib/ruby/traits)

ABOUT

traits.rb is set of attr\_\* like methods on steroids, caffeine, and  
botox. it  
encourages better living through meta-programming and uniform access  
priciples. traits.rb supports smart inheritence of class attributes  
and a  
fistful of hooks for veryifying and munging attr values.

VERSION

0.9.2

HISTORY

0.9.2  
- fixed a bug where list traits, for example

```
     trait 'letters' => %w[a b c]

   were flattened in a way that exploded trait initialization

 - streamlined TraitInit module

 - added OpenTraits class and otraits method

     conf = otraits{
       port 42
       host 'forty-two'
     }
     p conf.port #=> 42
     p conf.host #=> 'forty-two'
     conf.username 'zaphod'
     p conf #=> {"username"=>"zaphod", "port"=>42, 

```

“host”=\>“forty-two”}

AUTHOR

ara [dot] t [dot] howard [at] noaa [dot] gov

SAMPLES

\<========\< sample/a.rb \>========\>

~ \> cat sample/a.rb

```
 require 'traits'
 #
 # defining a trait is like attr_accessor in the simple case
 #
 class C
   trait :t
 end

 o = C::new
 o.t = 42
 p o.t

 #
 # and can be made even shorter
 #

 class B; has :x; end

 o = B::new
 o.x = 42
 p o.x

```

~ \> ruby sample/a.rb

```
 42
 42

```

\<========\< sample/b.rb \>========\>

~ \> cat sample/b.rb

```
 require 'traits'
 #
 # multiple traits can be defined at once using a list/array of 

```

string/sybmol  
# arguments  
#  
class C  
has :t0, :t1  
has %w( t2 t3 )  
end

```
 obj = C::new
 obj.t0 = 4
 obj.t3 = 2
 print obj.t0, obj.t3, "\n"

```

~ \> ruby sample/b.rb

```
 42

```

\<========\< sample/c.rb \>========\>

~ \> cat sample/c.rb

```
 require 'traits'
 #
 # a hash argument can be used to specify default values
 #
 class C
   has 'a' => 4, :b => 2
 end

 o = C::new
 print o.a, o.b, "\n"

 #
 # and these traits are smartly inherited
 #
 class K < C; end

 o = K::new
 o.a = 40
 p( o.a + o.b ) # note that we pick up a default b from C class here 

```

since it  
# has not been set

```
 o.a = 42
 o.b = nil
 p( o.b || o.a ) # but not here since we've explicitly set it to nil

 #
 # if a block is specifed as the default the initialization of the 

```

default value  
# is deferred until needed which makes for quite natural trait  
definitions. the  
# block is passed ‘self’ so references to the current object can be  
made. (if  
# this were not done ‘self’ in the block would be bound to the  
class!)  
#

```
 class C
   class << self
     has('classname'){ name.upcase }
   end

   has('classname'){ self.class.classname.downcase }
 end

 class B < C; end

 o = C::new
 p C::classname
 p o.classname

 o = B::new
 p B::classname
 p o.classname

```

~ \> ruby sample/c.rb

```
 42
 42
 42
 "C"
 "c"
 "B"
 "b"

```

\<========\< sample/d.rb \>========\>

~ \> cat sample/d.rb

```
 require 'traits'
 #
 # all behaviours work within class scope (metal/singleton-class) to 

```

define  
# class methods  
#  
class C  
class \<\< self  
traits ‘a’ =\> 4, ‘b’ =\> 2  
end  
end

```
 print C::a, C::b, "\n"

 #
 # singleton methods can even be defined on objects
 #

 class << (a = %w[dog cat ostrich])
   has 'category' => 'pets'
 end
 p a.category

 #
 # and modules
 #
 module Mmmm
   class << self; trait 'good' => 'bacon'; end
 end

 p Mmmm.good

```

~ \> ruby sample/d.rb

```
 42
 "pets"
 "bacon"

```

\<========\< sample/e.rb \>========\>

~ \> cat sample/e.rb

```
 require 'traits'
 #
 # shorhands exit to enter 'class << self' in order to define class 

```

traits  
#  
class C  
class\_trait ‘a’ =\> 4  
c\_has :b =\> 2  
end

```
 print C::a, C::b, "\n"

```

~ \> ruby sample/e.rb

```
 42

```

\<========\< sample/f.rb \>========\>

~ \> cat sample/f.rb

```
 require 'traits'
 #
 # as traits are defined they are remembered and can be accessed
 #
 class C
   class_trait :first_class_method
   trait :first_instance_method
 end

 class C
   class_trait :second_class_method
   trait :second_instance_method
 end

 #
 # readers and writers are remembered separatedly
 #
 p C::class_reader_traits
 p C::instance_writer_traits

 #
 # and can be gotten together at class or instance level
 #
 p C::class_traits
 p C::traits

```

~ \> ruby sample/f.rb

```
 ["first_class_method", "second_class_method"]
 ["first_instance_method=", "second_instance_method="]
 [["first_class_method", "first_class_method="], 

```

[“second\_class\_method”, “second\_class\_method=”]]  
[[“first\_instance\_method”, “first\_instance\_method=”],  
[“second\_instance\_method”, “second\_instance\_method=”]]

\<========\< sample/g.rb \>========\>

~ \> cat sample/g.rb

```
 require 'traits'
 #
 # another neat feature is that they are remembered per hierarchy
 #
 class C
   class_traits :base_class_method
   trait :base_instance_method
 end

 class K < C
   class_traits :derived_class_method
   trait :derived_instance_method
 end

 p C::class_traits
 p K::class_traits

```

~ \> ruby sample/g.rb

```
 [["base_class_method", "base_class_method="]]
 [["derived_class_method", "derived_class_method="], 

```

[“base\_class\_method”, “base\_class\_method=”]]

\<========\< sample/h.rb \>========\>

~ \> cat sample/h.rb

```
 require 'traits'
 #
 # a depth first search path is used to find defaults
 #
 class C
   has 'a' => 42
 end
 class K < C; end

 k = K::new
 p k.a

 #
 # once assigned this is short-circuited
 #
 k.a = 'forty-two'
 p k.a

```

~ \> ruby sample/h.rb

```
 42
 "forty-two"

```

\<========\< sample/i.rb \>========\>

~ \> cat sample/i.rb

```
 require 'traits'
 #
 # getters and setters can be defined separately
 #
 class C
   has_r :r
 end
 class D
   has_w :w
 end

 #
 # defining a reader trait still defines __public__ query and 

```

**private** writer  
# methods  
#  
class C  
def using\_private\_writer\_and\_query  
p r?  
self.r = 42  
p r  
end  
end  
C::new.using\_private\_writer\_and\_query

```
 #
 # defining a writer trait still defines __private__ query and 

```

**private** reader  
# methods  
#  
class D  
def using\_private\_reader  
p w?  
self.w = ‘forty-two’  
p w  
end  
end  
D::new.using\_private\_reader

~ \> ruby sample/i.rb

```
 false
 42
 false
 "forty-two"

```

\<========\< sample/j.rb \>========\>

~ \> cat sample/j.rb

```
 require 'traits'
 #
 # getters delegate to setters iff called with arguments
 #
 class AbstractWidget
   class_trait 'color' => 'pinky-green'
   class_trait 'size' => 42
   class_trait 'shape' => 'square'

   # we define instance traits which get their default from the 

```

class  
%w( color size shape ).each{|t| trait(t){self.class.send t}}

```
   def inspect
     "color <#{ color }> size <#{ size }> shape <#{ shape }>"
   end
 end

 class BlueWidget < AbstractWidget
   color 'blue'
   size 420
 end

 p BlueWidget::new

```

~ \> ruby sample/j.rb

```
 color <blue> size <420> shape <square>

```

\<========\< sample/k.rb \>========\>

~ \> cat sample/k.rb

```
 require 'traits'
 #
 # the rememberance of traits can make generic intializers pretty 

```

slick  
#  
class C  
#  
# define class traits with defaults  
#  
class\_traits(  
‘a’ =\> 40,  
‘b’ =\> 1,  
‘c’ =\> 0  
)

```
   #
   # define instance traits whose defaults come from readable class 

```

ones  
#  
class\_rtraits.each{|ct| instance\_trait ct =\> send(ct)}

```
   #
   # any option we respond_to? clobbers defaults
   #
   def initialize opts = {}
     opts.each{|k,v| send(k,v) if respond_to? k}
   end

   #
   # show anything we can read
   #
   def inspect
     self.class.rtraits.inject(0){|n,t| n += send(t)}
   end
 end

 c = C::new 'c' => 1
 p c

```

~ \> ruby sample/k.rb

```
 42

```

\<========\< sample/l.rb \>========\>

~ \> cat sample/l.rb

```
 require 'traits'
 #
 # even defining single methods on object behaves
 #
 a = []

 class << a
   trait 'singleton_class' => class << self;self;end

   class << self
     class_trait 'x' => 42
   end
 end

 p a.singleton_class.x

```

~ \> ruby sample/l.rb

```
 42

```

\<========\< sample/m.rb \>========\>

~ \> cat sample/m.rb

```
 require 'traits'
 #
 # pre and post hooks can be passed a proc or the name of a method, 

```

the arity is  
# detected and the proc/method sent either the value, or the  
name/value pair  
#

```
 class C
   HOOK_A = lambda{|value| puts "HOOK_A : #{ value }"}
   HOOK_B = lambda{|name, value| puts "HOOK_B : #{ name } = #{ value 

```

}"}

```
   def hook_a value
     puts "hook_a : #{ value }"
   end
   def hook_b name, value
     puts "hook_b : #{ name } = #{ value }"
   end

   trait 'x', 'pre' => HOOK_A, 'post' => 'hook_b'
   trait 'y', 'pre' => HOOK_B, 'post' => 'hook_a'
 end

 c = C::new
 c.x = 42
 c.y = 'forty-two'

```

~ \> ruby sample/m.rb

```
 HOOK_A : 42
 hook_b : x = 42
 HOOK_B : y = forty-two
 hook_a : forty-two

```

\<========\< sample/n.rb \>========\>

~ \> cat sample/n.rb

```
 require 'traits'
 #
 # two kinds of in-place modifications are supported : casting and 

```

munging.  
# casting is a hook that requires either a proc or the name of a  
method that  
# will be used to convert the objects type. munging is similar  
execpt the  
# method is called on the object itself. like all hooks, lists may  
be provided  
# instead of a single argument  
#  
# you’ll notice that the hooks and methods defined here are not  
strictly needed,  
# but are for illustration purposes only. note that all hooks  
operate in the  
# context of self - they have access to instance vars, etc., like  
instance\_eval  
#

```
 class C
   INT = lambda{|i| int i}
   def int i
     Integer i
   end
   trait 'a', 'cast' => 'int'
   trait 'b', 'cast' => INT
   trait 'c', 'munge' => 'to_i'
   trait 'd', 'cast' => 'Integer'
   trait 'e', 'munge' => %w( to_i abs )
 end

 c = C::new

 c.a = '42'
 p c.a
 c.b = '42'
 p c.b
 c.c = '42'
 p c.c
 c.d = '42'
 p c.d
 c.e = '-42'
 p c.e

```

~ \> ruby sample/n.rb

```
 42
 42
 42
 42
 42

```

\<========\< sample/p.rb \>========\>

~ \> cat sample/p.rb

```
 require 'traits'
 #
 # the TraitInit module provide a simple method for initializing an 

```

object’s  
# traits from an options hash  
#

```
 class C
   include TraitInit

   LIST_OF_INTS = lambda{|a| Array === a and a.map{|i| Integer === 

```

i}.all?}  
LIST\_OF\_STRINGS = lambda{|a| Array === a and a.map{|s| String ===  
s}.all?}

```
   trait :li, :validate => LIST_OF_INTS
   trait :ls, :validate => LIST_OF_STRINGS

   def initialize opts = {}
     trait_init opts
   end
 end

 c = C::new "li" => [4, 2], "ls" => %w[4 2]
 p c.li
 p c.ls

```

~ \> ruby sample/p.rb

```
 [4, 2]
 ["4", "2"]

```

\<========\< sample/q.rb \>========\>

~ \> cat sample/q.rb

```
 require 'traits'
 #
 # the OpenTraits class is similar to an OpenStruct but, imho, 

```

easier to use.  
# the otraits shorthand can be used to contruct one  
#

```
 #
 # options passed as args dynamically create and init traits
 #
   config = otraits :port => 42
   p config.port

 #
 # any passed block does the same but, via a method missing hood and 

```

traits  
# getter/setters, the syntax is very clean  
#  
config = otraits{  
port 42  
host ‘forty-two’  
}  
p config.port  
p config.host  
config.username ‘zaphod’  
p config

~ \> ruby sample/q.rb

```
 42
 42
 "forty-two"
 {"username"=>"zaphod", "port"=>42, "host"=>"forty-two"}

```

CAVEATS

this library is experimental and subject to change - though it has  
not for  
several versions and much of my code hinges is on it now so you can  
expect the  
interface to be stable in the near future - the only changes planned  
are those  
that fix bugs or add features.

LICENSE

same as ruby’s

-a

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [August 21, 2006, 5:37pm UTC](https://www.ruby-forum.com/t/traits-0-9-2-better-living-through-metaprogramming/65816/2 "2006-08-21T17:37:44Z")

</div>

On 8/21/06, Ara.T.Howard [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> priciples. traits.rb supports smart inheritence of class attributes and a  
> fistful of hooks for veryifying and munging attr values.

This looks beautiful, Ara. I’ll definitely check it out.
