activemodel 3.0.pre → 3.0.0.rc

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. data/CHANGELOG +44 -1
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +184 -0
  4. data/lib/active_model.rb +29 -19
  5. data/lib/active_model/attribute_methods.rb +167 -46
  6. data/lib/active_model/callbacks.rb +134 -0
  7. data/lib/active_model/conversion.rb +41 -1
  8. data/lib/active_model/deprecated_error_methods.rb +1 -1
  9. data/lib/active_model/dirty.rb +56 -12
  10. data/lib/active_model/errors.rb +205 -46
  11. data/lib/active_model/lint.rb +53 -17
  12. data/lib/active_model/locale/en.yml +26 -23
  13. data/lib/active_model/mass_assignment_security.rb +160 -0
  14. data/lib/active_model/mass_assignment_security/permission_set.rb +40 -0
  15. data/lib/active_model/mass_assignment_security/sanitizer.rb +23 -0
  16. data/lib/active_model/naming.rb +70 -5
  17. data/lib/active_model/observing.rb +40 -16
  18. data/lib/active_model/railtie.rb +2 -0
  19. data/lib/active_model/serialization.rb +59 -0
  20. data/lib/active_model/serializers/json.rb +17 -11
  21. data/lib/active_model/serializers/xml.rb +66 -123
  22. data/lib/active_model/test_case.rb +0 -2
  23. data/lib/active_model/translation.rb +64 -0
  24. data/lib/active_model/validations.rb +150 -68
  25. data/lib/active_model/validations/acceptance.rb +53 -33
  26. data/lib/active_model/validations/callbacks.rb +57 -0
  27. data/lib/active_model/validations/confirmation.rb +41 -23
  28. data/lib/active_model/validations/exclusion.rb +18 -13
  29. data/lib/active_model/validations/format.rb +28 -24
  30. data/lib/active_model/validations/inclusion.rb +18 -13
  31. data/lib/active_model/validations/length.rb +67 -65
  32. data/lib/active_model/validations/numericality.rb +83 -58
  33. data/lib/active_model/validations/presence.rb +10 -8
  34. data/lib/active_model/validations/validates.rb +110 -0
  35. data/lib/active_model/validations/with.rb +90 -23
  36. data/lib/active_model/validator.rb +186 -0
  37. data/lib/active_model/version.rb +3 -2
  38. metadata +79 -20
  39. data/README +0 -21
  40. data/lib/active_model/state_machine.rb +0 -70
  41. data/lib/active_model/state_machine/event.rb +0 -62
  42. data/lib/active_model/state_machine/machine.rb +0 -75
  43. data/lib/active_model/state_machine/state.rb +0 -47
  44. data/lib/active_model/state_machine/state_transition.rb +0 -40
  45. data/lib/active_model/validations_repair_helper.rb +0 -35
data/CHANGELOG CHANGED
@@ -1,4 +1,47 @@
1
- *Edge*
1
+ *Rails 3.0.0 [release candidate] (July 26th, 2010)*
2
+
3
+ * Added ActiveModel::MassAssignmentSecurity [Eric Chapweske, Josh Kalderimis]
4
+
5
+
6
+ *Rails 3.0.0 [beta 4] (June 8th, 2010)*
7
+
8
+ * JSON supports a custom root option: to_json(:root => 'custom') #4515 [Jatinder Singh]
9
+
10
+
11
+ *Rails 3.0.0 [beta 3] (April 13th, 2010)*
12
+
13
+ * No changes
14
+
15
+
16
+ *Rails 3.0.0 [beta 2] (April 1st, 2010)*
17
+
18
+ * #new_record? and #destroyed? were removed from ActiveModel::Lint. Use
19
+ persisted? instead. A model is persisted if it's not a new_record? and it was
20
+ not destroyed? [MG]
21
+
22
+ * Added validations reflection in ActiveModel::Validations [JV]
23
+
24
+ Model.validators
25
+ Model.validators_on(:field)
26
+
27
+ * #to_key was added to ActiveModel::Lint so we can generate DOM IDs for
28
+ AMo objects with composite keys [MG]
29
+
30
+
31
+ *Rails 3.0.0 [beta 1] (February 4, 2010)*
32
+
33
+ * ActiveModel::Observer#add_observer!
34
+
35
+ It has a custom hook to define after_find that should really be in a
36
+ ActiveRecord::Observer subclass:
37
+
38
+ def add_observer!(klass)
39
+ klass.add_observer(self)
40
+ klass.class_eval 'def after_find() end' unless
41
+ klass.respond_to?(:after_find)
42
+ end
43
+
44
+ * Change the ActiveModel::Base.include_root_in_json default to true for Rails 3 [DHH]
2
45
 
3
46
  * Add validates_format_of :without => /regexp/ option. #430 [Elliot Winkler, Peer Allan]
4
47
 
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2009 David Heinemeier Hansson
1
+ Copyright (c) 2004-2010 David Heinemeier Hansson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.rdoc ADDED
@@ -0,0 +1,184 @@
1
+ = Active Model -- model interfaces for Rails
2
+
3
+ Active Model provides a known set of interfaces for usage in model classes.
4
+ They allow for Action Pack helpers to interact with non-ActiveRecord models,
5
+ for example. Active Model also helps building custom ORMs for use outside of
6
+ the Rails framework.
7
+
8
+ Prior to Rails 3.0, if a plugin or gem developer wanted to have an object
9
+ interact with Action Pack helpers, it was required to either copy chunks of
10
+ code from Rails, or monkey patch entire helpers to make them handle objects
11
+ that did not exacly conform to the Active Record interface. This would result
12
+ in code duplication and fragile applications that broke on upgrades.
13
+
14
+ Active Model solves this. You can include functionality from the following
15
+ modules:
16
+
17
+ * Add attribute magic to objects
18
+
19
+ class Person
20
+ include ActiveModel::AttributeMethods
21
+
22
+ attribute_method_prefix 'clear_'
23
+ define_attribute_methods [:name, :age]
24
+
25
+ attr_accessor :name, :age
26
+
27
+ def clear_attribute(attr)
28
+ send("#{attr}=", nil)
29
+ end
30
+ end
31
+
32
+ person.clear_name
33
+ person.clear_age
34
+
35
+ {Learn more}[link:classes/ActiveModel/AttributeMethods.html]
36
+
37
+ * Callbacks for certain operations
38
+
39
+ class Person
40
+ extend ActiveModel::Callbacks
41
+ define_model_callbacks :create
42
+
43
+ def create
44
+ _run_create_callbacks do
45
+ # Your create action methods here
46
+ end
47
+ end
48
+ end
49
+
50
+ This generates +before_create+, +around_create+ and +after_create+
51
+ class methods that wrap your create method.
52
+
53
+ {Learn more}[link:classes/ActiveModel/CallBacks.html]
54
+
55
+ * Tracking value changes
56
+
57
+ The ActiveModel::Dirty module allows for tracking attribute changes:
58
+
59
+ person = Person.new
60
+ person.name # => nil
61
+ person.changed? # => false
62
+ person.name = 'bob'
63
+ person.changed? # => true
64
+ person.changed # => ['name']
65
+ person.changes # => { 'name' => [nil, 'bob'] }
66
+ person.name = 'robert'
67
+ person.save
68
+ person.previous_changes # => {'name' => ['bob, 'robert']}
69
+
70
+ {Learn more}[link:classes/ActiveModel/Dirty.html]
71
+
72
+ * Adding +errors+ interface to objects
73
+
74
+ Exposing error messages allows objects to interact with Action Pack
75
+ helpers seamlessly.
76
+
77
+ class Person
78
+
79
+ def initialize
80
+ @errors = ActiveModel::Errors.new(self)
81
+ end
82
+
83
+ attr_accessor :name
84
+ attr_reader :errors
85
+
86
+ def validate!
87
+ errors.add(:name, "can not be nil") if name == nil
88
+ end
89
+
90
+ def ErrorsPerson.human_attribute_name(attr, options = {})
91
+ "Name"
92
+ end
93
+
94
+ end
95
+
96
+ person.errors.full_messages
97
+ # => ["Name Can not be nil"]
98
+
99
+ person.errors.full_messages
100
+ # => ["Name Can not be nil"]
101
+
102
+ {Learn more}[link:classes/ActiveModel/Errors.html]
103
+
104
+ * Model name introspection
105
+
106
+ class NamedPerson
107
+ extend ActiveModel::Naming
108
+ end
109
+
110
+ NamedPerson.model_name #=> "NamedPerson"
111
+ NamedPerson.model_name.human #=> "Named person"
112
+
113
+ {Learn more}[link:classes/ActiveModel/Naming.html]
114
+
115
+ * Observer support
116
+
117
+ ActiveModel::Observers allows your object to implement the Observer
118
+ pattern in a Rails App and take advantage of all the standard observer
119
+ functions.
120
+
121
+ {Learn more}[link:classes/ActiveModel/Observer.html]
122
+
123
+ * Making objects serializable
124
+
125
+ ActiveModel::Serialization provides a standard interface for your object
126
+ to provide +to_json+ or +to_xml+ serialization.
127
+
128
+ s = SerialPerson.new
129
+ s.serializable_hash # => {"name"=>nil}
130
+ s.to_json # => "{\"name\":null}"
131
+ s.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<serial-person...
132
+
133
+ {Learn more}[link:classes/ActiveModel/Serialization.html]
134
+
135
+ * Internationalization (i18n) support
136
+
137
+ class Person
138
+ extend ActiveModel::Translation
139
+ end
140
+
141
+ Person.human_attribute_name('my_attribute')
142
+ #=> "My attribute"
143
+
144
+ {Learn more}[link:classes/ActiveModel/Translation.html]
145
+
146
+ * Validation support
147
+
148
+ class Person
149
+ include ActiveModel::Validations
150
+
151
+ attr_accessor :first_name, :last_name
152
+
153
+ validates_each :first_name, :last_name do |record, attr, value|
154
+ record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
155
+ end
156
+ end
157
+
158
+ person = Person.new
159
+ person.first_name = 'zoolander'
160
+ person.valid? #=> false
161
+
162
+ {Learn more}[link:classes/ActiveModel/Validations.html]
163
+
164
+ * Custom validators
165
+
166
+ class Person
167
+ include ActiveModel::Validations
168
+ validates_with HasNameValidator
169
+ attr_accessor :name
170
+ end
171
+
172
+ class HasNameValidator < ActiveModel::Validator
173
+ def validate(record)
174
+ record.errors[:name] = "must exist" if record.name.blank?
175
+ end
176
+ end
177
+
178
+ p = ValidatorPerson.new
179
+ p.valid? #=> false
180
+ p.errors.full_messages #=> ["Name must exist"]
181
+ p.name = "Bob"
182
+ p.valid? #=> true
183
+
184
+ {Learn more}[link:classes/ActiveModel/Validator.html]
data/lib/active_model.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2004-2009 David Heinemeier Hansson
2
+ # Copyright (c) 2004-2010 David Heinemeier Hansson
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -21,32 +21,42 @@
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
23
 
24
- activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
25
- $:.unshift(activesupport_path) if File.directory?(activesupport_path)
24
+ activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
25
+ $:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
26
26
  require 'active_support'
27
27
 
28
+
28
29
  module ActiveModel
29
- autoload :AttributeMethods, 'active_model/attribute_methods'
30
- autoload :Conversion, 'active_model/conversion'
31
- autoload :DeprecatedErrorMethods, 'active_model/deprecated_error_methods'
32
- autoload :Dirty, 'active_model/dirty'
33
- autoload :Errors, 'active_model/errors'
34
- autoload :Lint, 'active_model/lint'
30
+ extend ActiveSupport::Autoload
31
+
32
+ autoload :AttributeMethods
33
+ autoload :BlockValidator, 'active_model/validator'
34
+ autoload :Callbacks
35
+ autoload :Conversion
36
+ autoload :DeprecatedErrorMethods
37
+ autoload :Dirty
38
+ autoload :EachValidator, 'active_model/validator'
39
+ autoload :Errors
40
+ autoload :Lint
41
+ autoload :MassAssignmentSecurity
35
42
  autoload :Name, 'active_model/naming'
36
- autoload :Naming, 'active_model/naming'
43
+ autoload :Naming
37
44
  autoload :Observer, 'active_model/observing'
38
- autoload :Observing, 'active_model/observing'
39
- autoload :Serialization, 'active_model/serialization'
40
- autoload :StateMachine, 'active_model/state_machine'
41
- autoload :TestCase, 'active_model/test_case'
42
- autoload :Validations, 'active_model/validations'
43
- autoload :ValidationsRepairHelper, 'active_model/validations_repair_helper'
44
- autoload :VERSION, 'active_model/version'
45
+ autoload :Observing
46
+ autoload :Serialization
47
+ autoload :TestCase
48
+ autoload :Translation
49
+ autoload :VERSION
50
+ autoload :Validations
51
+ autoload :Validator
45
52
 
46
53
  module Serializers
47
- autoload :JSON, 'active_model/serializers/json'
48
- autoload :Xml, 'active_model/serializers/xml'
54
+ extend ActiveSupport::Autoload
55
+
56
+ autoload :JSON
57
+ autoload :Xml
49
58
  end
50
59
  end
51
60
 
61
+ require 'active_support/i18n'
52
62
  I18n.load_path << File.dirname(__FILE__) + '/active_model/locale/en.yml'
@@ -4,39 +4,108 @@ require 'active_support/core_ext/class/inheritable_attributes'
4
4
  module ActiveModel
5
5
  class MissingAttributeError < NoMethodError
6
6
  end
7
-
7
+ # == Active Model Attribute Methods
8
+ #
9
+ # <tt>ActiveModel::AttributeMethods</tt> provides a way to add prefixes and suffixes
10
+ # to your methods as well as handling the creation of Active Record like class methods
11
+ # such as +table_name+.
12
+ #
13
+ # The requirements to implement ActiveModel::AttributeMethods are to:
14
+ #
15
+ # * <tt>include ActiveModel::AttributeMethods</tt> in your object
16
+ # * Call each Attribute Method module method you want to add, such as
17
+ # attribute_method_suffix or attribute_method_prefix
18
+ # * Call <tt>define_attribute_methods</tt> after the other methods are
19
+ # called.
20
+ # * Define the various generic +_attribute+ methods that you have declared
21
+ #
22
+ # A minimal implementation could be:
23
+ #
24
+ # class Person
25
+ # include ActiveModel::AttributeMethods
26
+ #
27
+ # attribute_method_affix :prefix => 'reset_', :suffix => '_to_default!'
28
+ # attribute_method_suffix '_contrived?'
29
+ # attribute_method_prefix 'clear_'
30
+ # define_attribute_methods ['name']
31
+ #
32
+ # attr_accessor :name
33
+ #
34
+ # private
35
+ #
36
+ # def attribute_contrived?(attr)
37
+ # true
38
+ # end
39
+ #
40
+ # def clear_attribute(attr)
41
+ # send("#{attr}=", nil)
42
+ # end
43
+ #
44
+ # def reset_attribute_to_default!(attr)
45
+ # send("#{attr}=", "Default Name")
46
+ # end
47
+ # end
48
+ #
49
+ # Notice that whenever you include ActiveModel::AttributeMethods in your class,
50
+ # it requires you to implement a <tt>attributes</tt> methods which returns a hash
51
+ # with each attribute name in your model as hash key and the attribute value as
52
+ # hash value.
53
+ #
54
+ # Hash keys must be strings.
55
+ #
8
56
  module AttributeMethods
9
57
  extend ActiveSupport::Concern
10
58
 
11
- # Declare and check for suffixed attribute methods.
12
59
  module ClassMethods
13
- # Defines an "attribute" method (like +inheritance_column+ or
14
- # +table_name+). A new (class) method will be created with the
15
- # given name. If a value is specified, the new method will
16
- # return that value (as a string). Otherwise, the given block
17
- # will be used to compute the value of the method.
60
+ # Defines an "attribute" method (like +inheritance_column+ or +table_name+).
61
+ # A new (class) method will be created with the given name. If a value is
62
+ # specified, the new method will return that value (as a string).
63
+ # Otherwise, the given block will be used to compute the value of the
64
+ # method.
18
65
  #
19
- # The original method will be aliased, with the new name being
20
- # prefixed with "original_". This allows the new method to
21
- # access the original value.
66
+ # The original method will be aliased, with the new name being prefixed
67
+ # with "original_". This allows the new method to access the original
68
+ # value.
22
69
  #
23
70
  # Example:
24
71
  #
25
- # class A < ActiveRecord::Base
72
+ # class Person
73
+ #
74
+ # include ActiveModel::AttributeMethods
75
+ #
76
+ # cattr_accessor :primary_key
77
+ # cattr_accessor :inheritance_column
78
+ #
26
79
  # define_attr_method :primary_key, "sysid"
27
80
  # define_attr_method( :inheritance_column ) do
28
81
  # original_inheritance_column + "_id"
29
82
  # end
83
+ #
30
84
  # end
85
+ #
86
+ # Provides you with:
87
+ #
88
+ # AttributePerson.primary_key
89
+ # # => "sysid"
90
+ # AttributePerson.inheritance_column = 'address'
91
+ # AttributePerson.inheritance_column
92
+ # # => 'address_id'
31
93
  def define_attr_method(name, value=nil, &block)
32
- sing = metaclass
33
- sing.send :alias_method, "original_#{name}", name
94
+ sing = singleton_class
95
+ sing.class_eval <<-eorb, __FILE__, __LINE__ + 1
96
+ if method_defined?(:original_#{name})
97
+ undef :original_#{name}
98
+ end
99
+ alias_method :original_#{name}, :#{name}
100
+ eorb
34
101
  if block_given?
35
102
  sing.send :define_method, name, &block
36
103
  else
37
104
  # use eval instead of a block to work around a memory leak in dev
38
105
  # mode in fcgi
39
- sing.class_eval "def #{name}; #{value.to_s.inspect}; end"
106
+ sing.class_eval <<-eorb, __FILE__, __LINE__ + 1
107
+ def #{name}; #{value.to_s.inspect}; end
108
+ eorb
40
109
  end
41
110
  end
42
111
 
@@ -49,24 +118,30 @@ module ActiveModel
49
118
  #
50
119
  # #{prefix}attribute(#{attr}, *args, &block)
51
120
  #
52
- # An <tt>#{prefix}attribute</tt> instance method must exist and accept at least
53
- # the +attr+ argument.
121
+ # An instance method <tt>#{prefix}attribute</tt> must exist and accept
122
+ # at least the +attr+ argument.
54
123
  #
55
124
  # For example:
56
125
  #
57
- # class Person < ActiveRecord::Base
126
+ # class Person
127
+ #
128
+ # include ActiveModel::AttributeMethods
129
+ # attr_accessor :name
58
130
  # attribute_method_prefix 'clear_'
131
+ # define_attribute_methods [:name]
59
132
  #
60
133
  # private
61
- # def clear_attribute(attr)
62
- # ...
63
- # end
134
+ #
135
+ # def clear_attribute(attr)
136
+ # send("#{attr}=", nil)
137
+ # end
64
138
  # end
65
139
  #
66
- # person = Person.find(1)
67
- # person.name # => 'Gem'
140
+ # person = Person.new
141
+ # person.name = "Bob"
142
+ # person.name # => "Bob"
68
143
  # person.clear_name
69
- # person.name # => ''
144
+ # person.name # => nil
70
145
  def attribute_method_prefix(*prefixes)
71
146
  attribute_method_matchers.concat(prefixes.map { |prefix| AttributeMethodMatcher.new :prefix => prefix })
72
147
  undefine_attribute_methods
@@ -86,18 +161,24 @@ module ActiveModel
86
161
  #
87
162
  # For example:
88
163
  #
89
- # class Person < ActiveRecord::Base
164
+ # class Person
165
+ #
166
+ # include ActiveModel::AttributeMethods
167
+ # attr_accessor :name
90
168
  # attribute_method_suffix '_short?'
169
+ # define_attribute_methods [:name]
91
170
  #
92
171
  # private
93
- # def attribute_short?(attr)
94
- # ...
95
- # end
172
+ #
173
+ # def attribute_short?(attr)
174
+ # send(attr).length < 5
175
+ # end
96
176
  # end
97
177
  #
98
- # person = Person.find(1)
99
- # person.name # => 'Gem'
100
- # person.name_short? # => true
178
+ # person = Person.new
179
+ # person.name = "Bob"
180
+ # person.name # => "Bob"
181
+ # person.name_short? # => true
101
182
  def attribute_method_suffix(*suffixes)
102
183
  attribute_method_matchers.concat(suffixes.map { |suffix| AttributeMethodMatcher.new :suffix => suffix })
103
184
  undefine_attribute_methods
@@ -118,16 +199,21 @@ module ActiveModel
118
199
  #
119
200
  # For example:
120
201
  #
121
- # class Person < ActiveRecord::Base
202
+ # class Person
203
+ #
204
+ # include ActiveModel::AttributeMethods
205
+ # attr_accessor :name
122
206
  # attribute_method_affix :prefix => 'reset_', :suffix => '_to_default!'
207
+ # define_attribute_methods [:name]
123
208
  #
124
209
  # private
125
- # def reset_attribute_to_default!(attr)
126
- # ...
127
- # end
210
+ #
211
+ # def reset_attribute_to_default!(attr)
212
+ # ...
213
+ # end
128
214
  # end
129
215
  #
130
- # person = Person.find(1)
216
+ # person = Person.new
131
217
  # person.name # => 'Gem'
132
218
  # person.reset_name_to_default!
133
219
  # person.name # => 'Gemma'
@@ -138,7 +224,7 @@ module ActiveModel
138
224
 
139
225
  def alias_attribute(new_name, old_name)
140
226
  attribute_method_matchers.each do |matcher|
141
- module_eval <<-STR, __FILE__, __LINE__+1
227
+ module_eval <<-STR, __FILE__, __LINE__ + 1
142
228
  def #{matcher.method_name(new_name)}(*args)
143
229
  send(:#{matcher.method_name(old_name)}, *args)
144
230
  end
@@ -146,6 +232,30 @@ module ActiveModel
146
232
  end
147
233
  end
148
234
 
235
+ # Declares a the attributes that should be prefixed and suffixed by
236
+ # ActiveModel::AttributeMethods.
237
+ #
238
+ # To use, pass in an array of attribute names (as strings or symbols),
239
+ # be sure to declare +define_attribute_methods+ after you define any
240
+ # prefix, suffix or affix methods, or they will not hook in.
241
+ #
242
+ # class Person
243
+ #
244
+ # include ActiveModel::AttributeMethods
245
+ # attr_accessor :name, :age, :address
246
+ # attribute_method_prefix 'clear_'
247
+ #
248
+ # # Call to define_attribute_methods must appear after the
249
+ # # attribute_method_prefix, attribute_method_suffix or
250
+ # # attribute_method_affix declares.
251
+ # define_attribute_methods [:name, :age, :address]
252
+ #
253
+ # private
254
+ #
255
+ # def clear_attribute(attr)
256
+ # ...
257
+ # end
258
+ # end
149
259
  def define_attribute_methods(attr_names)
150
260
  return if attribute_methods_generated?
151
261
  attr_names.each do |attr_name|
@@ -156,8 +266,13 @@ module ActiveModel
156
266
  if respond_to?(generate_method)
157
267
  send(generate_method, attr_name)
158
268
  else
159
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__+1
160
- def #{matcher.method_name(attr_name)}(*args)
269
+ method_name = matcher.method_name(attr_name)
270
+
271
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
272
+ if method_defined?(:#{method_name})
273
+ undef :#{method_name}
274
+ end
275
+ def #{method_name}(*args)
161
276
  send(:#{matcher.method_missing_target}, '#{attr_name}', *args)
162
277
  end
163
278
  STR
@@ -168,6 +283,7 @@ module ActiveModel
168
283
  @attribute_methods_generated = true
169
284
  end
170
285
 
286
+ # Removes all the preiously dynamically defined methods from the class
171
287
  def undefine_attribute_methods
172
288
  generated_attribute_methods.module_eval do
173
289
  instance_methods.each { |m| undef_method(m) }
@@ -175,6 +291,7 @@ module ActiveModel
175
291
  @attribute_methods_generated = nil
176
292
  end
177
293
 
294
+ # Returns true if the attribute methods defined have been generated.
178
295
  def generated_attribute_methods #:nodoc:
179
296
  @generated_attribute_methods ||= begin
180
297
  mod = Module.new
@@ -183,6 +300,7 @@ module ActiveModel
183
300
  end
184
301
  end
185
302
 
303
+ # Returns true if the attribute methods defined have been generated.
186
304
  def attribute_methods_generated?
187
305
  @attribute_methods_generated ||= nil
188
306
  end
@@ -226,14 +344,17 @@ module ActiveModel
226
344
  end
227
345
  end
228
346
 
229
- # Allows access to the object attributes, which are held in the <tt>@attributes</tt> hash, as though they
230
- # were first-class methods. So a Person class with a name attribute can use Person#name and
231
- # Person#name= and never directly use the attributes hash -- except for multiple assigns with
232
- # ActiveRecord#attributes=. A Milestone class can also ask Milestone#completed? to test that
233
- # the completed attribute is not +nil+ or 0.
347
+ # Allows access to the object attributes, which are held in the
348
+ # <tt>@attributes</tt> hash, as though they were first-class methods. So a
349
+ # Person class with a name attribute can use Person#name and Person#name=
350
+ # and never directly use the attributes hash -- except for multiple assigns
351
+ # with ActiveRecord#attributes=. A Milestone class can also ask
352
+ # Milestone#completed? to test that the completed attribute is not +nil+
353
+ # or 0.
234
354
  #
235
- # It's also possible to instantiate related objects, so a Client class belonging to the clients
236
- # table with a +master_id+ foreign key can instantiate master through Client#master.
355
+ # It's also possible to instantiate related objects, so a Client class
356
+ # belonging to the clients table with a +master_id+ foreign key can
357
+ # instantiate master through Client#master.
237
358
  def method_missing(method_id, *args, &block)
238
359
  method_name = method_id.to_s
239
360
  if match = match_attribute_method?(method_name)
@@ -252,7 +373,7 @@ module ActiveModel
252
373
  return true
253
374
  elsif !include_private_methods && super(method, true)
254
375
  # If we're here then we haven't found among non-private methods
255
- # but found among all methods. Which means that given method is private.
376
+ # but found among all methods. Which means that the given method is private.
256
377
  return false
257
378
  elsif match_attribute_method?(method.to_s)
258
379
  return true