A
Ara.T.Howard
URLS
http://raa.ruby-lang.org/search.rhtml?search=traits
http://codeforpeople.com/lib/ruby/traits
ABOUT
traits.rb aims to be a better set of attr_* methods and encourages better
living through meta-programming and uniform access priciples. traits.rb
supercedes attributes.rb. why? the name is shorter ;-)
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
obj = C::new
obj.t = 42
p obj.t
~ > ruby sample/a.rb
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
traits :t0, :t1
traits %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
traits 'a' => 4, :b => 2
end
obj = C::new
print obj.a, obj.b, "\n"
~ > ruby sample/c.rb
42
<========< sample/d.rb >========>
~ > cat sample/d.rb
require 'traits'
#
# all behaviours work within class scope (metalclass) to define class methods
#
class C
class << self
traits 'a' => 4, 'b' => 2
end
end
print C::a, C::b, "\n"
~ > ruby sample/d.rb
42
<========< sample/e.rb >========>
~ > cat sample/e.rb
require 'traits'
#
# shorhands exit to enter 'class << self' in order to define class traits
#
class C
class_traits 'a' => 4, :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
#
c_getters, c_setters = C::class_traits
p [ c_getters, c_setters ]
getters, setters = C::traits
p [ getters, setters ]
~ > ruby sample/f.rb
["first_class_method", "second_class_method"]
["first_instance_method=", "second_instance_method="]
[["first_class_method", "second_class_method"], ["first_class_method=", "second_class_method="]]
[["first_instance_method", "second_instance_method"], ["first_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", "base_class_method"], ["derived_class_method=", "base_class_method="]]
<========< sample/h.rb >========>
~ > cat sample/h.rb
require 'traits'
#
# a depth first search path to find defaults
#
class C
trait '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
rtrait :r
end
class D
wtrait :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 if called with arguments
#
class AbstractWidget
class_trait 'color' => 'pinky-green'
class_trait 'size' => 42
class_trait 'shape' => 'square'
trait 'color'
trait 'size'
trait 'shape'
def initialize
color self.class.color
size self.class.size
shape self.class.shape
end
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
CAVEATS
this library is experimental and subject to change.
enjoy.
-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| renunciation is not getting rid of the things of this world, but accepting
| that they pass away. --aitken roshi
===============================================================================
http://raa.ruby-lang.org/search.rhtml?search=traits
http://codeforpeople.com/lib/ruby/traits
ABOUT
traits.rb aims to be a better set of attr_* methods and encourages better
living through meta-programming and uniform access priciples. traits.rb
supercedes attributes.rb. why? the name is shorter ;-)
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
obj = C::new
obj.t = 42
p obj.t
~ > ruby sample/a.rb
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
traits :t0, :t1
traits %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
traits 'a' => 4, :b => 2
end
obj = C::new
print obj.a, obj.b, "\n"
~ > ruby sample/c.rb
42
<========< sample/d.rb >========>
~ > cat sample/d.rb
require 'traits'
#
# all behaviours work within class scope (metalclass) to define class methods
#
class C
class << self
traits 'a' => 4, 'b' => 2
end
end
print C::a, C::b, "\n"
~ > ruby sample/d.rb
42
<========< sample/e.rb >========>
~ > cat sample/e.rb
require 'traits'
#
# shorhands exit to enter 'class << self' in order to define class traits
#
class C
class_traits 'a' => 4, :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
#
c_getters, c_setters = C::class_traits
p [ c_getters, c_setters ]
getters, setters = C::traits
p [ getters, setters ]
~ > ruby sample/f.rb
["first_class_method", "second_class_method"]
["first_instance_method=", "second_instance_method="]
[["first_class_method", "second_class_method"], ["first_class_method=", "second_class_method="]]
[["first_instance_method", "second_instance_method"], ["first_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", "base_class_method"], ["derived_class_method=", "base_class_method="]]
<========< sample/h.rb >========>
~ > cat sample/h.rb
require 'traits'
#
# a depth first search path to find defaults
#
class C
trait '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
rtrait :r
end
class D
wtrait :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 if called with arguments
#
class AbstractWidget
class_trait 'color' => 'pinky-green'
class_trait 'size' => 42
class_trait 'shape' => 'square'
trait 'color'
trait 'size'
trait 'shape'
def initialize
color self.class.color
size self.class.size
shape self.class.shape
end
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
CAVEATS
this library is experimental and subject to change.
enjoy.
-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| renunciation is not getting rid of the things of this world, but accepting
| that they pass away. --aitken roshi
===============================================================================