Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Adding ActiveModel::AttributeMethods documentation

  • Loading branch information...
commit 8834b2612b7ddda70ee6a685eb0063d3daa8e63d 1 parent e1c15d9
@mikel mikel authored
Showing with 143 additions and 23 deletions.
  1. +23 −2 activemodel/README
  2. +120 −21 activemodel/lib/active_model/attribute_methods.rb
View
25 activemodel/README
@@ -12,9 +12,30 @@ Active Model provides a known set of interfaces that your objects can implement
to then present a common interface to the Action Pack helpers. You can include
functionality from the following modules:
+* Adding attribute magic to your objects
+
+ Add prefixes and suffixes to defined attribute methods...
+
+ class Person
+ include ActiveModel::AttributeMethods
+
+ attribute_method_prefix 'clear_'
+ define_attribute_methods [:name, :age]
+
+ attr_accessor :name, :age
+
+ def clear_attribute(attr)
+ send("#{attr}=", nil)
+ end
+ end
+
+ ...gives you clear_name, clear_age.
+
+ {Learn more}[link:classes/ActiveModel/AttributeMethods.html]
+
* Adding callbacks to your objects
- class MyClass
+ class Person
extend ActiveModel::Callbacks
define_model_callbacks :create
@@ -32,7 +53,7 @@ functionality from the following modules:
* For classes that already look like an Active Record object
- class MyClass
+ class Person
include ActiveModel::Conversion
end
View
141 activemodel/lib/active_model/attribute_methods.rb
@@ -5,10 +5,51 @@ module ActiveModel
class MissingAttributeError < NoMethodError
end
+ # <tt>ActiveModel::AttributeMethods</tt> provides a way to add prefixes and suffixes
+ # to your methods as well as handling the creation of Active Record like class methods
+ # such as +table_name+.
+ #
+ # The requirements to implement ActiveModel::AttributeMethods are:
+ #
+ # * <tt>include ActiveModel::AttributeMethods</tt> in your object
+ # * Call each Attribute Method module method you want to add, such as
+ # attribute_method_suffix or attribute_method_prefix
+ # * Call <tt>define_attribute_methods</tt> after the other methods are
+ # called.
+ # * Define the various generic +_attribute+ methods that you have declared
+ #
+ # A minimal implementation could be:
+ #
+ # class Person
+ #
+ # include ActiveModel::AttributeMethods
+ #
+ # attribute_method_affix :prefix => 'reset_', :suffix => '_to_default!'
+ # attribute_method_suffix '_contrived?'
+ # attribute_method_prefix 'clear_'
+ # define_attribute_methods ['name']
+ #
+ # attr_accessor :name
+ #
+ # private
+ #
+ # def attribute_contrived?(attr)
+ # true
+ # end
+ #
+ # def clear_attribute(attr)
+ # send("#{attr}=", nil)
+ # end
+ #
+ # def reset_attribute_to_default!(attr)
+ # send("#{attr}=", "Default Name")
+ # end
+ #
+ # end
+ #
module AttributeMethods
extend ActiveSupport::Concern
- # Declare and check for suffixed attribute methods.
module ClassMethods
# Defines an "attribute" method (like +inheritance_column+ or
# +table_name+). A new (class) method will be created with the
@@ -22,12 +63,27 @@ module ClassMethods
#
# Example:
#
- # class A < ActiveRecord::Base
+ # class Person
+ #
+ # include ActiveModel::AttributeMethods
+ #
+ # cattr_accessor :primary_key
+ # cattr_accessor :inheritance_column
+ #
# define_attr_method :primary_key, "sysid"
# define_attr_method( :inheritance_column ) do
# original_inheritance_column + "_id"
# end
+ #
# end
+ #
+ # Provivdes you with:
+ #
+ # AttributePerson.primary_key
+ # # => "sysid"
+ # AttributePerson.inheritance_column = 'address'
+ # AttributePerson.inheritance_column
+ # # => 'address_id'
def define_attr_method(name, value=nil, &block)
sing = metaclass
sing.send :alias_method, "original_#{name}", name
@@ -54,19 +110,25 @@ def define_attr_method(name, value=nil, &block)
#
# For example:
#
- # class Person < ActiveRecord::Base
+ # class Person
+ #
+ # include ActiveModel::AttributeMethods
+ # attr_accessor :name
# attribute_method_prefix 'clear_'
+ # define_attribute_methods [:name]
#
# private
- # def clear_attribute(attr)
- # ...
- # end
+ #
+ # def clear_attribute(attr)
+ # send("#{attr}=", nil)
+ # end
# end
#
- # person = Person.find(1)
- # person.name # => 'Gem'
+ # person = Person.new
+ # person.name = "Bob"
+ # person.name # => "Bob"
# person.clear_name
- # person.name # => ''
+ # person.name # => nil
def attribute_method_prefix(*prefixes)
attribute_method_matchers.concat(prefixes.map { |prefix| AttributeMethodMatcher.new :prefix => prefix })
undefine_attribute_methods
@@ -86,18 +148,24 @@ def attribute_method_prefix(*prefixes)
#
# For example:
#
- # class Person < ActiveRecord::Base
+ # class Person
+ #
+ # include ActiveModel::AttributeMethods
+ # attr_accessor :name
# attribute_method_suffix '_short?'
+ # define_attribute_methods [:name]
#
# private
- # def attribute_short?(attr)
- # ...
- # end
+ #
+ # def attribute_short?(attr)
+ # send(attr).length < 5
+ # end
# end
#
- # person = Person.find(1)
- # person.name # => 'Gem'
- # person.name_short? # => true
+ # person = Person.new
+ # person.name = "Bob"
+ # person.name # => "Bob"
+ # person.name_short? # => true
def attribute_method_suffix(*suffixes)
attribute_method_matchers.concat(suffixes.map { |suffix| AttributeMethodMatcher.new :suffix => suffix })
undefine_attribute_methods
@@ -118,16 +186,21 @@ def attribute_method_suffix(*suffixes)
#
# For example:
#
- # class Person < ActiveRecord::Base
+ # class Person
+ #
+ # include ActiveModel::AttributeMethods
+ # attr_accessor :name
# attribute_method_affix :prefix => 'reset_', :suffix => '_to_default!'
+ # define_attribute_methods [:name]
#
# private
- # def reset_attribute_to_default!(attr)
- # ...
- # end
+ #
+ # def reset_attribute_to_default!(attr)
+ # ...
+ # end
# end
#
- # person = Person.find(1)
+ # person = Person.new
# person.name # => 'Gem'
# person.reset_name_to_default!
# person.name # => 'Gemma'
@@ -146,6 +219,30 @@ def #{matcher.method_name(new_name)}(*args)
end
end
+ # Declares a the attributes that should be prefixed and suffixed by
+ # ActiveModel::AttributeMethods.
+ #
+ # To use, pass in an array of attribute names (as strings or symbols),
+ # be sure to declare +define_attribute_methods+ after you define any
+ # prefix, suffix or affix methods, or they will not hook in.
+ #
+ # class Person
+ #
+ # include ActiveModel::AttributeMethods
+ # attr_accessor :name, :age, :address
+ # attribute_method_prefix 'clear_'
+ #
+ # # Call to define_attribute_methods must appear after the
+ # # attribute_method_prefix, attribute_method_suffix or
+ # # attribute_method_affix declares.
+ # define_attribute_methods [:name, :age, :address]
+ #
+ # private
+ #
+ # def clear_attribute(attr)
+ # ...
+ # end
+ # end
def define_attribute_methods(attr_names)
return if attribute_methods_generated?
attr_names.each do |attr_name|
@@ -168,6 +265,7 @@ def #{matcher.method_name(attr_name)}(*args)
@attribute_methods_generated = true
end
+ # Removes all the preiously dynamically defined methods from the class
def undefine_attribute_methods
generated_attribute_methods.module_eval do
instance_methods.each { |m| undef_method(m) }
@@ -183,6 +281,7 @@ def generated_attribute_methods #:nodoc:
end
end
+ # Returns true if the attribute methods defined have been generated.
def attribute_methods_generated?
@attribute_methods_generated ||= nil
end
Please sign in to comment.
Something went wrong with that request. Please try again.