Class: Valuable
- Inherits:
-
Object
- Object
- Valuable
- Defined in:
- lib/valuable.rb
Overview
Valuable is the class from which all classes (who are so inclined) should inherit.
Example:
class Bus < Valuable
has_value :number, :klass => :integer
has_value :color, :default => 'yellow'
has_collection :riders
end
>> Bus.attributes
=> [:number, :color, :riders]
>> bus = Bus.new(:number => '3', :riders => ['GOF', 'Fowler', 'Mort']
>> bus.attributes
=> {:number => 3, :riders => ['GOF', 'Fowler', 'Mort'], :color => 'yellow'}
Class Method Summary collapse
-
.attributes ⇒ Object
Returns an array of the attributes available on this object.
-
.create_accessor_for(name) ⇒ Object
creates a simple accessor method named after the attribute whose value it will provide during the life of the instance.
-
.create_negative_question_for(name, negative) ⇒ Object
In some situations, the opposite of a value may be just as interesting.
-
.create_question_for(name) ⇒ Object
In addition to the normal getter and setter, boolean attributes get a method appended with a ?.
-
.create_setter_for(name, klass, default) ⇒ Object
Creates the method that sets the value of an attribute.
-
.defaults ⇒ Object
Returns a name/value set of the values that will be used on instanciation unless new values are provided.
-
.has_collection(name) ⇒ Object
this is a more intuitive way of marking an attribute as holding a collection.
-
.has_value(name, options = {}) ⇒ Object
Decorator method that lets you specify the attributes for your model.
Instance Method Summary collapse
-
#attributes ⇒ Object
Returns a Hash representing all known values.
- #deep_duplicate_of(value) ⇒ Object
-
#initialize(atts = nil) ⇒ Valuable
constructor
accepts an optional hash that will be used to populate the predefined attributes for this class.
Constructor Details
#initialize(atts = nil) ⇒ Valuable
accepts an optional hash that will be used to populate the predefined attributes for this class.
42 43 44 |
# File 'lib/valuable.rb', line 42 def initialize(atts = nil) atts.each { |name, value| __send__("#{name}=", value ) } if atts end |
Class Method Details
.attributes ⇒ Object
Returns an array of the attributes available on this object.
53 54 55 |
# File 'lib/valuable.rb', line 53 def attributes @attributes ||= [] end |
.create_accessor_for(name) ⇒ Object
creates a simple accessor method named after the attribute whose value it will provide during the life of the instance.
158 159 160 161 162 |
# File 'lib/valuable.rb', line 158 def create_accessor_for(name) define_method name do attributes[name] end end |
.create_negative_question_for(name, negative) ⇒ Object
In some situations, the opposite of a value may be just as interesting.
class Coder < Valuable
has_value :agilist, :klass => Boolean, :negative => :waterfaller
end
monkey = Coder.new(:agilist => false)
>> monkey.waterfaller?
=> true
189 190 191 192 193 |
# File 'lib/valuable.rb', line 189 def create_negative_question_for(name, negative) define_method "#{negative}?" do !attributes[name] end end |
.create_question_for(name) ⇒ Object
In addition to the normal getter and setter, boolean attributes get a method appended with a ?.
class Player < Valuable
has_value :free_agent, :klass => Boolean
end
juan = Player.new(:free_agent => true)
>> juan.free_agent?
=> true
174 175 176 177 178 |
# File 'lib/valuable.rb', line 174 def create_question_for(name) define_method "#{name}?" do attributes[name] end end |
.create_setter_for(name, klass, default) ⇒ Object
Creates the method that sets the value of an attribute. This setter is called both by the constructor. The constructor handles type casting. Setting values via the attributes hash avoids the method defined here.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/valuable.rb', line 113 def create_setter_for(name, klass, default) case klass when NilClass define_method "#{name}=" do |value| attributes[name] = value end when :integer define_method "#{name}=" do |value| value_as_integer = value && value.to_i attributes[name] = value_as_integer end when :string define_method "#{name}=" do |value| value_as_string = value && value.to_s attributes[name] = value_as_string end when :boolean define_method "#{name}=" do |value| attributes[name] = value == '0' ? false : !!value end else define_method "#{name}=" do |value| if value.nil? attributes[name] = nil elsif value.is_a? klass attributes[name] = value else attributes[name] = klass.new(value) end end end end |
.defaults ⇒ Object
Returns a name/value set of the values that will be used on instanciation unless new values are provided.
>> Bus.defaults
=> {:color => 'yellow'}
62 63 64 |
# File 'lib/valuable.rb', line 62 def defaults @defaults ||= {} end |
.has_collection(name) ⇒ Object
this is a more intuitive way of marking an attribute as holding a collection.
class Bus < Valuable
has_value :riders, :default => [] # meh...
has_collection :riders # better!
end
>> bus = Bus.new
>> bus.riders << 'jack'
>> bus.riders
=> ['jack']
207 208 209 |
# File 'lib/valuable.rb', line 207 def has_collection(name) has_value(name, :default => [] ) end |
.has_value(name, options = {}) ⇒ Object
Decorator method that lets you specify the attributes for your model. It accepts an attribute name (a symbol) and an options hash. Valid options are :default, :klass and (when :klass is Boolean) :negative.
:default - for the given attribute, use this value if no other
is provided.
:klass - light weight type casting. Use :integer, :string or
:boolean. Alternately, supply a class.
When a :klassified attribute is set to some new value, if the value is not nil and is not already of that class, the value will be cast to the specified klass. In the case of :integer, it wil be done via .to_i. In the case of a random other class, it will be done via Class.new(value). If the value is nil, it will not be cast.
A good example: PhoneNumber < String is useful if you want numbers to come out the other end properly formatted, when your input may come in as an integer, or string without formatting, or string with bad formatting.
IMPORTANT EXCEPTION
Due to the way Rails handles checkboxes, ‘0’ resolves to FALSE, though it would normally resolve to TRUE.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/valuable.rb', line 92 def has_value(name, ={}) name = name.to_sym attributes << name defaults[name] = [:default] unless [:default].nil? create_accessor_for(name) create_question_for(name) if [:klass] == :boolean create_negative_question_for(name, [:negative]) if [:klass] == :boolean && [:negative] create_setter_for(name, [:klass], [:default]) (name, ) end |
Instance Method Details
#attributes ⇒ Object
Returns a Hash representing all known values. Values are set three ways:
(1) a default value
(2) they were passed to the constructor
Bus.new(:color => 'green')
(3) they were set via their namesake setter
bus.color = 'green'
Values that have not been set and have no default not appear in this collection. Their namesake attribute methods will respond with nil. Always use symbols to access these values.
>> bus = Bus.new(:number => 16) # color has default value 'yellow'
>> bus.attributes
=> {:color => 'yellow', :number => 16}
36 37 38 |
# File 'lib/valuable.rb', line 36 def attributes @attributes ||= deep_duplicate_of(self.class.defaults) end |
#deep_duplicate_of(value) ⇒ Object
46 47 48 |
# File 'lib/valuable.rb', line 46 def deep_duplicate_of(value) Marshal.load(Marshal.dump(value)) end |