activemodel 3.0.20 → 3.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/CHANGELOG +17 -73
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +5 -5
  4. data/lib/active_model.rb +2 -2
  5. data/lib/active_model/attribute_methods.rb +46 -53
  6. data/lib/active_model/callbacks.rb +2 -5
  7. data/lib/active_model/conversion.rb +0 -2
  8. data/lib/active_model/dirty.rb +3 -4
  9. data/lib/active_model/errors.rb +55 -56
  10. data/lib/active_model/lint.rb +2 -2
  11. data/lib/active_model/mass_assignment_security.rb +96 -47
  12. data/lib/active_model/naming.rb +55 -13
  13. data/lib/active_model/observer_array.rb +104 -0
  14. data/lib/active_model/observing.rb +53 -18
  15. data/lib/active_model/secure_password.rb +67 -0
  16. data/lib/active_model/serialization.rb +4 -11
  17. data/lib/active_model/serializers/json.rb +18 -18
  18. data/lib/active_model/serializers/xml.rb +26 -5
  19. data/lib/active_model/translation.rb +4 -11
  20. data/lib/active_model/validations.rb +23 -23
  21. data/lib/active_model/validations/acceptance.rb +3 -5
  22. data/lib/active_model/validations/callbacks.rb +5 -19
  23. data/lib/active_model/validations/confirmation.rb +6 -5
  24. data/lib/active_model/validations/exclusion.rb +27 -3
  25. data/lib/active_model/validations/format.rb +38 -12
  26. data/lib/active_model/validations/inclusion.rb +30 -23
  27. data/lib/active_model/validations/length.rb +3 -1
  28. data/lib/active_model/validations/numericality.rb +4 -2
  29. data/lib/active_model/validations/presence.rb +3 -2
  30. data/lib/active_model/validations/validates.rb +23 -9
  31. data/lib/active_model/validations/with.rb +14 -2
  32. data/lib/active_model/validator.rb +16 -18
  33. data/lib/active_model/version.rb +3 -3
  34. metadata +71 -58
  35. checksums.yaml +0 -7
  36. data/lib/active_model/deprecated_error_methods.rb +0 -33
data/CHANGELOG CHANGED
@@ -1,83 +1,27 @@
1
- ## Rails 3.0.20 (unreleased)
1
+ *Rails 3.1.0 (unreleased)*
2
2
 
3
- * Fix XML serialization of methods that return nil to not be considered as YAML (GH #8853 and GH #492)
3
+ * Add support for proc or lambda as an option for InclusionValidator,
4
+ ExclusionValidator, and FormatValidator [Prem Sichanugrist]
4
5
 
5
- ## Rails 3.0.19 (Jan 8, 2013)
6
+ You can now supply Proc, lambda, or anything that respond to #call in those
7
+ validations, and it will be called with current record as an argument.
8
+ That given proc or lambda must returns an object which respond to #include? for
9
+ InclusionValidator and ExclusionValidator, and returns a regular expression
10
+ object for FormatValidator.
6
11
 
7
- * No changes.
12
+ * Added ActiveModel::SecurePassword to encapsulate dead-simple password usage with BCrypt encryption and salting [DHH]
8
13
 
9
- ## Rails 3.0.18 (Jan 2, 2013)
14
+ * ActiveModel::AttributeMethods allows attributes to be defined on demand [Alexander Uvarov]
10
15
 
11
- * No changes.
12
16
 
13
- ## Rails 3.0.17 (Aug 9, 2012)
17
+ *Rails 3.0.2 (unreleased)*
14
18
 
15
- * No changes.
16
-
17
- ## Rails 3.0.16 (Jul 26, 2012)
18
-
19
- * No changes.
20
-
21
- ## Rails 3.0.14 (Jun 12, 2012)
22
-
23
- * No changes.
24
-
25
- *Rails 3.0.13 (May 31, 2012)*
26
-
27
- * No changes.
28
-
29
- *Rails 3.0.10 (August 16, 2011)*
30
-
31
- *No changes.
32
-
33
-
34
- *Rails 3.0.9 (June 16, 2011)*
35
-
36
- *No changes.
37
-
38
-
39
- *Rails 3.0.8 (June 7, 2011)*
40
-
41
- *No changes.
42
-
43
-
44
- *Rails 3.0.7 (April 18, 2011)*
45
-
46
- *No changes.
47
-
48
-
49
- *Rails 3.0.6 (April 5, 2011)
50
-
51
- * Fix when database column name has some symbolic characters (e.g. Oracle CASE# VARCHAR2(20)) #5818 #6850 [Robert Pankowecki, Santiago Pastorino]
52
-
53
- * Fix length validation for fixnums #6556 [Andriy Tyurnikov]
54
-
55
- * Fix i18n key collision with namespaced models #6448 [yves.senn]
56
-
57
-
58
- *Rails 3.0.5 (February 26, 2011)*
59
-
60
- * No changes.
61
-
62
-
63
- *Rails 3.0.4 (February 8, 2011)*
64
-
65
- * No changes.
66
-
67
-
68
- *Rails 3.0.3 (November 16, 2010)*
69
-
70
- * No changes.
71
-
72
-
73
- *Rails 3.0.2 (November 15, 2010)*
74
-
75
- * No changes.
19
+ * No changes
76
20
 
77
21
 
78
22
  *Rails 3.0.1 (October 15, 2010)*
79
23
 
80
- * No changes.
24
+ * No Changes, just a version bump.
81
25
 
82
26
 
83
27
  *Rails 3.0.0 (August 29, 2010)*
@@ -103,10 +47,10 @@
103
47
  It has a custom hook to define after_find that should really be in a
104
48
  ActiveRecord::Observer subclass:
105
49
 
106
- def add_observer!(klass)
107
- klass.add_observer(self)
108
- klass.class_eval 'def after_find() end' unless klass.respond_to?(:after_find)
109
- end
50
+ def add_observer!(klass)
51
+ klass.add_observer(self)
52
+ klass.class_eval 'def after_find() end' unless klass.respond_to?(:after_find)
53
+ end
110
54
 
111
55
  * Change the ActiveModel::Base.include_root_in_json default to true for Rails 3 [DHH]
112
56
 
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2010 David Heinemeier Hansson
1
+ Copyright (c) 2004-2011 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
@@ -8,7 +8,7 @@ the Rails framework.
8
8
  Prior to Rails 3.0, if a plugin or gem developer wanted to have an object
9
9
  interact with Action Pack helpers, it was required to either copy chunks of
10
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
11
+ that did not exactly conform to the Active Record interface. This would result
12
12
  in code duplication and fragile applications that broke on upgrades.
13
13
 
14
14
  Active Model solves this. You can include functionality from the following
@@ -41,7 +41,7 @@ modules:
41
41
  define_model_callbacks :create
42
42
 
43
43
  def create
44
- _run_create_callbacks do
44
+ run_callbacks :create do
45
45
  # Your create action methods here
46
46
  end
47
47
  end
@@ -84,7 +84,7 @@ modules:
84
84
  attr_reader :errors
85
85
 
86
86
  def validate!
87
- errors.add(:name, "can not be nil") if name == nil
87
+ errors.add(:name, "can not be nil") if name.nil?
88
88
  end
89
89
 
90
90
  def ErrorsPerson.human_attribute_name(attr, options = {})
@@ -94,10 +94,10 @@ modules:
94
94
  end
95
95
 
96
96
  person.errors.full_messages
97
- # => ["Name Can not be nil"]
97
+ # => ["Name can not be nil"]
98
98
 
99
99
  person.errors.full_messages
100
- # => ["Name Can not be nil"]
100
+ # => ["Name can not be nil"]
101
101
 
102
102
  {Learn more}[link:classes/ActiveModel/Errors.html]
103
103
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2004-2010 David Heinemeier Hansson
2
+ # Copyright (c) 2004-2011 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
@@ -33,7 +33,6 @@ module ActiveModel
33
33
  autoload :BlockValidator, 'active_model/validator'
34
34
  autoload :Callbacks
35
35
  autoload :Conversion
36
- autoload :DeprecatedErrorMethods
37
36
  autoload :Dirty
38
37
  autoload :EachValidator, 'active_model/validator'
39
38
  autoload :Errors
@@ -43,6 +42,7 @@ module ActiveModel
43
42
  autoload :Naming
44
43
  autoload :Observer, 'active_model/observing'
45
44
  autoload :Observing
45
+ autoload :SecurePassword
46
46
  autoload :Serialization
47
47
  autoload :TestCase
48
48
  autoload :Translation
@@ -1,5 +1,5 @@
1
1
  require 'active_support/core_ext/hash/keys'
2
- require 'active_support/core_ext/class/inheritable_attributes'
2
+ require 'active_support/core_ext/class/attribute'
3
3
 
4
4
  module ActiveModel
5
5
  class MissingAttributeError < NoMethodError
@@ -56,7 +56,12 @@ module ActiveModel
56
56
  module AttributeMethods
57
57
  extend ActiveSupport::Concern
58
58
 
59
- COMPILABLE_REGEXP = /^[a-zA-Z_]\w*[!?=]?$/
59
+ COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?=]?\z/
60
+
61
+ included do
62
+ class_attribute :attribute_method_matchers, :instance_writer => false
63
+ self.attribute_method_matchers = []
64
+ end
60
65
 
61
66
  module ClassMethods
62
67
  # Defines an "attribute" method (like +inheritance_column+ or +table_name+).
@@ -95,7 +100,7 @@ module ActiveModel
95
100
  def define_attr_method(name, value=nil, &block)
96
101
  sing = singleton_class
97
102
  sing.class_eval <<-eorb, __FILE__, __LINE__ + 1
98
- if method_defined?(:'original_#{name}')
103
+ if method_defined?('original_#{name}')
99
104
  undef :'original_#{name}'
100
105
  end
101
106
  alias_method :'original_#{name}', :'#{name}'
@@ -151,7 +156,7 @@ module ActiveModel
151
156
  # person.clear_name
152
157
  # person.name # => nil
153
158
  def attribute_method_prefix(*prefixes)
154
- attribute_method_matchers.concat(prefixes.map { |prefix| AttributeMethodMatcher.new :prefix => prefix })
159
+ self.attribute_method_matchers += prefixes.map { |prefix| AttributeMethodMatcher.new :prefix => prefix }
155
160
  undefine_attribute_methods
156
161
  end
157
162
 
@@ -188,7 +193,7 @@ module ActiveModel
188
193
  # person.name # => "Bob"
189
194
  # person.name_short? # => true
190
195
  def attribute_method_suffix(*suffixes)
191
- attribute_method_matchers.concat(suffixes.map { |suffix| AttributeMethodMatcher.new :suffix => suffix })
196
+ self.attribute_method_matchers += suffixes.map { |suffix| AttributeMethodMatcher.new :suffix => suffix }
192
197
  undefine_attribute_methods
193
198
  end
194
199
 
@@ -226,7 +231,7 @@ module ActiveModel
226
231
  # person.reset_name_to_default!
227
232
  # person.name # => 'Gemma'
228
233
  def attribute_method_affix(*affixes)
229
- attribute_method_matchers.concat(affixes.map { |affix| AttributeMethodMatcher.new :prefix => affix[:prefix], :suffix => affix[:suffix] })
234
+ self.attribute_method_matchers += affixes.map { |affix| AttributeMethodMatcher.new :prefix => affix[:prefix], :suffix => affix[:suffix] }
230
235
  undefine_attribute_methods
231
236
  end
232
237
 
@@ -249,7 +254,7 @@ module ActiveModel
249
254
  end
250
255
  end
251
256
 
252
- # Declares a the attributes that should be prefixed and suffixed by
257
+ # Declares the attributes that should be prefixed and suffixed by
253
258
  # ActiveModel::AttributeMethods.
254
259
  #
255
260
  # To use, pass in an array of attribute names (as strings or symbols),
@@ -274,41 +279,41 @@ module ActiveModel
274
279
  # end
275
280
  # end
276
281
  def define_attribute_methods(attr_names)
277
- return if attribute_methods_generated?
278
- attr_names.each do |attr_name|
279
- attribute_method_matchers.each do |matcher|
280
- unless instance_method_already_implemented?(matcher.method_name(attr_name))
281
- generate_method = "define_method_#{matcher.prefix}attribute#{matcher.suffix}"
282
+ attr_names.each { |attr_name| define_attribute_method(attr_name) }
283
+ end
282
284
 
283
- if respond_to?(generate_method)
284
- send(generate_method, attr_name)
285
- else
286
- method_name = matcher.method_name(attr_name)
285
+ def define_attribute_method(attr_name)
286
+ attribute_method_matchers.each do |matcher|
287
+ unless instance_method_already_implemented?(matcher.method_name(attr_name))
288
+ generate_method = "define_method_#{matcher.prefix}attribute#{matcher.suffix}"
287
289
 
290
+ if respond_to?(generate_method)
291
+ send(generate_method, attr_name)
292
+ else
293
+ method_name = matcher.method_name(attr_name)
294
+
295
+ generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
296
+ if method_defined?('#{method_name}')
297
+ undef :'#{method_name}'
298
+ end
299
+ RUBY
300
+
301
+ if method_name.to_s =~ COMPILABLE_REGEXP
288
302
  generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
289
- if method_defined?('#{method_name}')
290
- undef :'#{method_name}'
303
+ def #{method_name}(*args)
304
+ send(:#{matcher.method_missing_target}, '#{attr_name}', *args)
305
+ end
306
+ RUBY
307
+ else
308
+ generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
309
+ define_method('#{method_name}') do |*args|
310
+ send('#{matcher.method_missing_target}', '#{attr_name}', *args)
291
311
  end
292
312
  RUBY
293
-
294
- if method_name.to_s =~ COMPILABLE_REGEXP
295
- generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
296
- def #{method_name}(*args)
297
- send(:#{matcher.method_missing_target}, '#{attr_name}', *args)
298
- end
299
- RUBY
300
- else
301
- generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
302
- define_method('#{method_name}') do |*args|
303
- send('#{matcher.method_missing_target}', '#{attr_name}', *args)
304
- end
305
- RUBY
306
- end
307
313
  end
308
314
  end
309
315
  end
310
316
  end
311
- @attribute_methods_generated = true
312
317
  end
313
318
 
314
319
  # Removes all the previously dynamically defined methods from the class
@@ -316,7 +321,6 @@ module ActiveModel
316
321
  generated_attribute_methods.module_eval do
317
322
  instance_methods.each { |m| undef_method(m) }
318
323
  end
319
- @attribute_methods_generated = nil
320
324
  end
321
325
 
322
326
  # Returns true if the attribute methods defined have been generated.
@@ -328,11 +332,6 @@ module ActiveModel
328
332
  end
329
333
  end
330
334
 
331
- # Returns true if the attribute methods defined have been generated.
332
- def attribute_methods_generated?
333
- @attribute_methods_generated ||= nil
334
- end
335
-
336
335
  protected
337
336
  def instance_method_already_implemented?(method_name)
338
337
  method_defined?(method_name)
@@ -340,7 +339,7 @@ module ActiveModel
340
339
 
341
340
  private
342
341
  class AttributeMethodMatcher
343
- attr_reader :prefix, :suffix
342
+ attr_reader :prefix, :suffix, :method_missing_target
344
343
 
345
344
  AttributeMethodMatch = Struct.new(:target, :attr_name)
346
345
 
@@ -348,28 +347,22 @@ module ActiveModel
348
347
  options.symbolize_keys!
349
348
  @prefix, @suffix = options[:prefix] || '', options[:suffix] || ''
350
349
  @regex = /^(#{Regexp.escape(@prefix)})(.+?)(#{Regexp.escape(@suffix)})$/
350
+ @method_missing_target = "#{@prefix}attribute#{@suffix}"
351
+ @method_name = "#{prefix}%s#{suffix}"
351
352
  end
352
353
 
353
354
  def match(method_name)
354
- if matchdata = @regex.match(method_name)
355
- AttributeMethodMatch.new(method_missing_target, matchdata[2])
355
+ if @regex =~ method_name
356
+ AttributeMethodMatch.new(method_missing_target, $2)
356
357
  else
357
358
  nil
358
359
  end
359
360
  end
360
361
 
361
362
  def method_name(attr_name)
362
- "#{prefix}#{attr_name}#{suffix}"
363
- end
364
-
365
- def method_missing_target
366
- :"#{prefix}attribute#{suffix}"
363
+ @method_name % attr_name
367
364
  end
368
365
  end
369
-
370
- def attribute_method_matchers #:nodoc:
371
- read_inheritable_attribute(:attribute_method_matchers) || write_inheritable_attribute(:attribute_method_matchers, [])
372
- end
373
366
  end
374
367
 
375
368
  # Allows access to the object attributes, which are held in the
@@ -418,7 +411,7 @@ module ActiveModel
418
411
  # Returns a struct representing the matching attribute method.
419
412
  # The struct's attributes are prefix, base and suffix.
420
413
  def match_attribute_method?(method_name)
421
- self.class.send(:attribute_method_matchers).each do |method|
414
+ self.class.attribute_method_matchers.each do |method|
422
415
  if (match = method.match(method_name)) && attribute_method?(match.attr_name)
423
416
  return match
424
417
  end
@@ -429,7 +422,7 @@ module ActiveModel
429
422
  # prevent method_missing from calling private methods with #send
430
423
  def guard_private_attribute_method!(method_name, args)
431
424
  if self.class.private_method_defined?(method_name)
432
- raise NoMethodError.new("Attempt to call private method", method_name, args)
425
+ raise NoMethodError.new("Attempt to call private method `#{method_name}'", method_name, args)
433
426
  end
434
427
  end
435
428
 
@@ -24,14 +24,11 @@ module ActiveModel
24
24
  # you want callbacks on in a block so that the callbacks get a chance to fire:
25
25
  #
26
26
  # def create
27
- # _run_create_callbacks do
27
+ # run_callbacks :create do
28
28
  # # Your create action methods here
29
29
  # end
30
30
  # end
31
31
  #
32
- # The _run_<method_name>_callbacks methods are dynamically created when you extend
33
- # the <tt>ActiveModel::Callbacks</tt> module.
34
- #
35
32
  # Then in your class, you can use the +before_create+, +after_create+ and +around_create+
36
33
  # methods, just as you would in an Active Record module.
37
34
  #
@@ -102,7 +99,7 @@ module ActiveModel
102
99
  define_callbacks(callback, options)
103
100
 
104
101
  types.each do |type|
105
- send(:"_define_#{type}_model_callback", self, callback)
102
+ send("_define_#{type}_model_callback", self, callback)
106
103
  end
107
104
  end
108
105
  end
@@ -3,8 +3,6 @@ module ActiveModel
3
3
  #
4
4
  # Handles default conversions: to_model, to_key and to_param.
5
5
  #
6
- # == Example
7
- #
8
6
  # Let's take for example this non persisted object.
9
7
  #
10
8
  # class ContactMessage
@@ -1,5 +1,4 @@
1
1
  require 'active_model/attribute_methods'
2
- require 'active_support/concern'
3
2
  require 'active_support/hash_with_indifferent_access'
4
3
  require 'active_support/core_ext/object/duplicable'
5
4
 
@@ -9,7 +8,7 @@ module ActiveModel
9
8
  # Provides a way to track changes in your object in the same way as
10
9
  # Active Record does.
11
10
  #
12
- # The requirements to implement ActiveModel::Dirty are to:
11
+ # The requirements for implementing ActiveModel::Dirty are:
13
12
  #
14
13
  # * <tt>include ActiveModel::Dirty</tt> in your object
15
14
  # * Call <tt>define_attribute_methods</tt> passing each method you want to
@@ -94,7 +93,7 @@ module ActiveModel
94
93
  attribute_method_affix :prefix => 'reset_', :suffix => '!'
95
94
  end
96
95
 
97
- # Do any attributes have unsaved changes?
96
+ # Returns true if any attribute have unsaved changes, false otherwise.
98
97
  # person.changed? # => false
99
98
  # person.name = 'bob'
100
99
  # person.changed? # => true
@@ -115,7 +114,7 @@ module ActiveModel
115
114
  # person.name = 'bob'
116
115
  # person.changes # => { 'name' => ['bill', 'bob'] }
117
116
  def changes
118
- changed.inject(HashWithIndifferentAccess.new){ |h, attr| h[attr] = attribute_change(attr); h }
117
+ HashWithIndifferentAccess[changed.map { |attr| [attr, attribute_change(attr)] }]
119
118
  end
120
119
 
121
120
  # Map of attributes that were changed when the model was saved.