NAME

attributes.rb

INSTALL

gem install attributes

URIS

http://rubyforge.org/projects/codeforpeople/
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 Neukirchen 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

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:0x20080 @port=80, @host="codeforpeople.org">