# Attributes-5.0.0

**URL:** <https://www.ruby-forum.com/t/attributes-5-0-0/119577>\
**Category:** Ruby\
**Created:** [November 8, 2007, 4:31am UTC](https://www.ruby-forum.com/t/attributes-5-0-0/119577 "2007-11-08T04:31:27Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![ara.t.howard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a8b319/32.png) [@ara.t.howard](https://www.ruby-forum.com/u/ara.t.howard)\
**Post date:** [November 8, 2007, 4:31am UTC](https://www.ruby-forum.com/t/attributes-5-0-0/119577/1 "2007-11-08T04:31:27Z")

</div>

NAME  
attributes.rb

INSTALL  
gem install attributes

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

SYNOPSIS  
attributes.rb provides a set of attr\_\* like method with several user  
friendly additions. attributes.rb is similar to the traits.rb  
package but  
sacrifices a few features for simplicity of implementation.

the implementation of attributes.rb borrows many of the best ideas  
from the  
metakoans.rb ruby quiz

```
 http://www.rubyquiz.com/quiz67.html

```

in particular the solutions of Christian N. and Florian  
Gross along  
with concepts from the original traits lib

key features provided by attributes are

```
 - ability to specify default values for attrs and definition

```

time. values  
can be literal objects or blocks, which are evaluated in the  
context of  
self to initialize the variable

```
 - classes remember which attributes they've defined and this

```

information is  
available to client code

```
 - a whole suite of methods is defined by calls to #attributes

```

including  
getter, setter, query (var?) and banger (var! - which forces  
re-initialization from the default value)

```
 - ability to define multiple attributes at once using key =>

```

value pairs

```
 - fast lookup of whether or not a class has defined a certain

```

attribute

```
 - attributes can be defined on objects on a per singleton basis

```

as well

```
 - getters acts as setters if an argument is given to them

```

all this in \< 100 lines of code

HISTORY  
5.0.0  
- added support for block caching. for example

```
     - simple block caching:

         class Filter
           attribute :process
         end

         (( filter = Filter.new )).process{|line| line.upcase}

         lines.each do |line|
           p filter.process.call(line)
         end

     - using block caching to delay block evaluation/class-factory:

         module MigrationDSL
           attribute :migration

           def migration_class
             model = self
             Class.new(::ActiveRecord::Migration) do
               singleton_class =
                 class << self
                   self
                 end
               singleton_class.module_eval{ attribute :model =>

```

model }  
singleton\_class.module\_eval &model.migration  
end  
end  
end

```
         class Table < ActiveRecord::Base
           extend MigrationDSL
         end

         class Jobs < Table
           migration do
             def up
               create_table model.table_name, :primary_key =>

```

model.primary\_key do |t|  
t.column ‘rockin’, :text  
end  
end

```
             def down
               create_table model.table_name
             end
           end
         end

         ...

         JobsMigration = Jobs.migration_class

```

4.1.0  
- 4.0.0 introduced a bug where a query (foo?) would not  
initialize a var -  
4.1.0 fixes that

4.0.0  
- removed dependancy on, and bundle of, pervasives  
- faster. as fast as normal method definition.  
- faster lookup for MyClass.attributes.include?(‘foobar’)

3.7.0  
small patch to use ‘instance\_variable\_defined?’ instead of defined?  
keyword

3.5.0  
migrated to a pervasives based impl to attributes should work on  
any  
object - even blankslate objects

3.3.0

```
 moved to an instance variable-less model using an module level

```

closure for  
the attributes list

SAMPLES

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

~ \> cat samples/a.rb

```
 #
 # basic usage is like attr, but note that attribute defines a

```

suite of methods  
#  
require ‘attributes’

```
   class C
     attribute 'a'
   end

   c = C.new

   c.a = 42
   p c.a #=> 42
   p 'forty-two' if c.a? #=> 'forty-two'

 #
 # attributes works on object too
 #
   o = Object.new
   o.attribute 'answer' => 42
   p o.answer #=> 42

```

~ \> ruby samples/a.rb

```
 42
 "forty-two"
 42

```

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

~ \> cat samples/b.rb

```
 #
 # default values may be given either directly or as a block

```

which will be  
# evaluated in the context of self. in both cases (value or  
block) the  
# default is set only once and only if needed - it’s a lazy  
evaluation. the  
# ‘banger’ method can be used to re-initialize a variable at any  
point whether  
# or not it’s already been initialized.  
#  
require ‘attributes’

```
   class C
     attribute :a => 42
     attribute(:b){ Float a }
   end

   c = C.new
   p c.a #=> 42
   p c.b #=> 42.0

   c.a = 43
   p c.a #=> 43
   c.a!
   p c.a #=> 42

```

~ \> ruby samples/b.rb

```
 42
 42.0
 43
 42

```

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

~ \> cat samples/c.rb

```
 #
 # multiple values may by given, plain names and key/val pairs

```

may be mixed.  
#  
require ‘attributes’

```
   class C
     attributes 'x', 'y' => 0b101000, 'z' => 0b10
   end

   c = C.new
   c.x = c.y + c.z
   p c.x #=> 42

```

~ \> ruby samples/c.rb

```
 42

```

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

~ \> cat samples/d.rb

```
 #
 # a nice feature is that all attributes are enumerated in the

```

class. this,  
# combined with the fact that the getter method is defined so as  
to delegate  
# to the setter when an argument is given, means bulk  
initialization and/or  
# attribute traversal is very easy.  
#  
require ‘attributes’

```
   class C
     attributes %w( x y z )

     def attributes
       self.class.attributes
     end

     def initialize
       attributes.each_with_index{|a,i| send a, i}
     end

     def to_hash
       attributes.inject({}){|h,a| h.update a => send(a)}
     end

     def inspect
       to_hash.inspect
     end
   end

   c = C.new
   p c.attributes
   p c

   c.x 'forty-two'
   p c.x

```

~ \> ruby samples/d.rb

```
 ["x", "y", "z"]
 {"x"=>0, "y"=>1, "z"=>2}
 "forty-two"

```

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

~ \> cat samples/e.rb

```
 #
 # my favourite element of attributes is that getters can also be

```

setters.  
# this allows incredibly clean looking code like  
#  
require ‘attributes’

```
   class Config
     attributes %w( host port)
     def initialize(&block) instance_eval &block end
   end

   conf = Config.new{
     host 'codeforpeople.org'

     port 80
   }

   p conf

```

~ \> ruby samples/e.rb

```
 #<Config:0x1fb58 @port=80, @host="codeforpeople.org">

```

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

~ \> cat samples/f.rb

```
 #
 # of course attributes works as well at class/module level as at

```

instance  
# level  
#  
require ‘attributes’

```
   module Logging
     Level_names = {
       0 => 'INFO',
       # ...
       42 => 'DEBUG',
     }

     class << self
       attribute 'level' => 42
       attribute('level_name'){ Level_names[level] }
     end
   end

 p Logging.level
 p Logging.level_name

```

~ \> ruby samples/f.rb

```
 42
 "DEBUG"

```

enjoy.

a @ [http://codeforpeople.com/](http://codeforpeople.com/)
