activemodel 3.0.0.beta4 → 3.0.pre

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 (39) hide show
  1. data/CHANGELOG +1 -39
  2. data/MIT-LICENSE +1 -1
  3. data/README +16 -200
  4. data/lib/active_model.rb +19 -28
  5. data/lib/active_model/attribute_methods.rb +27 -142
  6. data/lib/active_model/conversion.rb +1 -37
  7. data/lib/active_model/dirty.rb +12 -51
  8. data/lib/active_model/errors.rb +22 -146
  9. data/lib/active_model/lint.rb +14 -48
  10. data/lib/active_model/locale/en.yml +23 -26
  11. data/lib/active_model/naming.rb +5 -41
  12. data/lib/active_model/observing.rb +16 -35
  13. data/lib/active_model/serialization.rb +0 -57
  14. data/lib/active_model/serializers/json.rb +8 -13
  15. data/lib/active_model/serializers/xml.rb +123 -63
  16. data/lib/active_model/state_machine.rb +70 -0
  17. data/lib/active_model/state_machine/event.rb +62 -0
  18. data/lib/active_model/state_machine/machine.rb +75 -0
  19. data/lib/active_model/state_machine/state.rb +47 -0
  20. data/lib/active_model/state_machine/state_transition.rb +40 -0
  21. data/lib/active_model/test_case.rb +2 -0
  22. data/lib/active_model/validations.rb +62 -125
  23. data/lib/active_model/validations/acceptance.rb +18 -23
  24. data/lib/active_model/validations/confirmation.rb +10 -14
  25. data/lib/active_model/validations/exclusion.rb +13 -15
  26. data/lib/active_model/validations/format.rb +24 -26
  27. data/lib/active_model/validations/inclusion.rb +13 -15
  28. data/lib/active_model/validations/length.rb +65 -61
  29. data/lib/active_model/validations/numericality.rb +58 -76
  30. data/lib/active_model/validations/presence.rb +8 -8
  31. data/lib/active_model/validations/with.rb +22 -90
  32. data/lib/active_model/validations_repair_helper.rb +35 -0
  33. data/lib/active_model/version.rb +2 -3
  34. metadata +19 -63
  35. data/lib/active_model/callbacks.rb +0 -134
  36. data/lib/active_model/railtie.rb +0 -2
  37. data/lib/active_model/translation.rb +0 -60
  38. data/lib/active_model/validations/validates.rb +0 -108
  39. data/lib/active_model/validator.rb +0 -183
@@ -1,2 +0,0 @@
1
- require "active_model"
2
- require "rails"
@@ -1,60 +0,0 @@
1
- require 'active_support/core_ext/hash/reverse_merge'
2
-
3
- module ActiveModel
4
-
5
- # ActiveModel::Translation provides integration between your object and
6
- # the Rails internationalization (i18n) framework.
7
- #
8
- # A minimal implementation could be:
9
- #
10
- # class TranslatedPerson
11
- # extend ActiveModel::Translation
12
- # end
13
- #
14
- # TranslatedPerson.human_attribute_name('my_attribue')
15
- # #=> "My attribute"
16
- #
17
- # This also provides the required class methods for hooking into the
18
- # Rails internationalization API, including being able to define a
19
- # class based i18n_scope and lookup_ancestors to find translations in
20
- # parent classes.
21
- module Translation
22
- include ActiveModel::Naming
23
-
24
- # Returns the i18n_scope for the class. Overwrite if you want custom lookup.
25
- def i18n_scope
26
- :activemodel
27
- end
28
-
29
- # When localizing a string, goes through the lookup returned by this method.
30
- # Used in ActiveModel::Name#human, ActiveModel::Errors#full_messages and
31
- # ActiveModel::Translation#human_attribute_name.
32
- def lookup_ancestors
33
- self.ancestors.select { |x| x.respond_to?(:model_name) }
34
- end
35
-
36
- # Transforms attributes names into a more human format, such as "First name" instead of "first_name".
37
- #
38
- # Person.human_attribute_name("first_name") # => "First name"
39
- #
40
- # Specify +options+ with additional translating options.
41
- def human_attribute_name(attribute, options = {})
42
- defaults = lookup_ancestors.map do |klass|
43
- :"#{self.i18n_scope}.attributes.#{klass.model_name.underscore}.#{attribute}"
44
- end
45
-
46
- defaults << :"attributes.#{attribute}"
47
- defaults << options.delete(:default) if options[:default]
48
- defaults << attribute.to_s.humanize
49
-
50
- options.reverse_merge! :count => 1, :default => defaults
51
- I18n.translate(defaults.shift, options)
52
- end
53
-
54
- # Model.human_name is deprecated. Use Model.model_name.human instead.
55
- def human_name(*args)
56
- ActiveSupport::Deprecation.warn("human_name has been deprecated, please use model_name.human instead", caller[0,5])
57
- model_name.human(*args)
58
- end
59
- end
60
- end
@@ -1,108 +0,0 @@
1
- require 'active_support/core_ext/hash/slice'
2
-
3
- module ActiveModel
4
- module Validations
5
- module ClassMethods
6
- # This method is a shortcut to all default validators and any custom
7
- # validator classes ending in 'Validator'. Note that Rails default
8
- # validators can be overridden inside specific classes by creating
9
- # custom validator classes in their place such as PresenceValidator.
10
- #
11
- # Examples of using the default rails validators:
12
- #
13
- # validates :terms, :acceptance => true
14
- # validates :password, :confirmation => true
15
- # validates :username, :exclusion => { :in => %w(admin superuser) }
16
- # validates :email, :format => { :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create }
17
- # validates :age, :inclusion => { :in => 0..9 }
18
- # validates :first_name, :length => { :maximum => 30 }
19
- # validates :age, :numericality => true
20
- # validates :username, :presence => true
21
- # validates :username, :uniqueness => true
22
- #
23
- # The power of the +validates+ method comes when using cusom validators
24
- # and default validators in one call for a given attribute e.g.
25
- #
26
- # class EmailValidator < ActiveModel::EachValidator
27
- # def validate_each(record, attribute, value)
28
- # record.errors[attribute] << (options[:message] || "is not an email") unless
29
- # value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
30
- # end
31
- # end
32
- #
33
- # class Person
34
- # include ActiveModel::Validations
35
- # attr_accessor :name, :email
36
- #
37
- # validates :name, :presence => true, :uniqueness => true, :length => { :maximum => 100 }
38
- # validates :email, :presence => true, :email => true
39
- # end
40
- #
41
- # Validator classes my also exist within the class being validated
42
- # allowing custom modules of validators to be included as needed e.g.
43
- #
44
- # class Film
45
- # include ActiveModel::Validations
46
- #
47
- # class TitleValidator < ActiveModel::EachValidator
48
- # def validate_each(record, attribute, value)
49
- # record.errors[attribute] << "must start with 'the'" unless =~ /^the/i
50
- # end
51
- # end
52
- #
53
- # validates :name, :title => true
54
- # end
55
- #
56
- # The validators hash can also handle regular expressions, ranges and arrays:
57
- #
58
- # validates :email, :format => /@/
59
- # validates :gender, :inclusion => %w(male female)
60
- # validates :password, :length => 6..20
61
- #
62
- # Finally, the options :if, :unless, :on, :allow_blank and :allow_nil can be given
63
- # to one specific validator:
64
- #
65
- # validates :password, :presence => { :if => :password_required? }, :confirmation => true
66
- #
67
- # Or to all at the same time:
68
- #
69
- # validates :password, :presence => true, :confirmation => true, :if => :password_required?
70
- #
71
- def validates(*attributes)
72
- defaults = attributes.extract_options!
73
- validations = defaults.slice!(:if, :unless, :on, :allow_blank, :allow_nil)
74
-
75
- raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
76
- raise ArgumentError, "Attribute names must be symbols" if attributes.any?{ |attribute| !attribute.is_a?(Symbol) }
77
- raise ArgumentError, "You need to supply at least one validation" if validations.empty?
78
-
79
- defaults.merge!(:attributes => attributes)
80
-
81
- validations.each do |key, options|
82
- begin
83
- validator = const_get("#{key.to_s.camelize}Validator")
84
- rescue NameError
85
- raise ArgumentError, "Unknown validator: '#{key}'"
86
- end
87
-
88
- validates_with(validator, defaults.merge(_parse_validates_options(options)))
89
- end
90
- end
91
-
92
- protected
93
-
94
- def _parse_validates_options(options) #:nodoc:
95
- case options
96
- when TrueClass
97
- {}
98
- when Hash
99
- options
100
- when Regexp
101
- { :with => options }
102
- when Range, Array
103
- { :in => options }
104
- end
105
- end
106
- end
107
- end
108
- end
@@ -1,183 +0,0 @@
1
- require 'active_support/core_ext/array/wrap'
2
- require "active_support/core_ext/module/anonymous"
3
- require 'active_support/core_ext/object/blank'
4
-
5
- module ActiveModel #:nodoc:
6
- # A simple base class that can be used along with
7
- # +ActiveModel::Validations::ClassMethods.validates_with+
8
- #
9
- # class Person
10
- # include ActiveModel::Validations
11
- # validates_with MyValidator
12
- # end
13
- #
14
- # class MyValidator < ActiveModel::Validator
15
- # def validate(record)
16
- # if some_complex_logic
17
- # record.errors[:base] = "This record is invalid"
18
- # end
19
- # end
20
- #
21
- # private
22
- # def some_complex_logic
23
- # # ...
24
- # end
25
- # end
26
- #
27
- # Any class that inherits from ActiveModel::Validator must implement a method
28
- # called <tt>validate</tt> which accepts a <tt>record</tt>.
29
- #
30
- # class Person
31
- # include ActiveModel::Validations
32
- # validates_with MyValidator
33
- # end
34
- #
35
- # class MyValidator < ActiveModel::Validator
36
- # def validate(record)
37
- # record # => The person instance being validated
38
- # options # => Any non-standard options passed to validates_with
39
- # end
40
- # end
41
- #
42
- # To cause a validation error, you must add to the <tt>record<tt>'s errors directly
43
- # from within the validators message
44
- #
45
- # class MyValidator < ActiveModel::Validator
46
- # def validate(record)
47
- # record.errors[:base] << "This is some custom error message"
48
- # record.errors[:first_name] << "This is some complex validation"
49
- # # etc...
50
- # end
51
- # end
52
- #
53
- # To add behavior to the initialize method, use the following signature:
54
- #
55
- # class MyValidator < ActiveModel::Validator
56
- # def initialize(record, options)
57
- # super
58
- # @my_custom_field = options[:field_name] || :first_name
59
- # end
60
- # end
61
- #
62
- # The easiest way to add custom validators for validating individual attributes
63
- # is with the convenient ActiveModel::EachValidator for example:
64
- #
65
- # class TitleValidator < ActiveModel::EachValidator
66
- # def validate_each(record, attribute, value)
67
- # record.errors[attribute] << 'must be Mr. Mrs. or Dr.' unless ['Mr.', 'Mrs.', 'Dr.'].include?(value)
68
- # end
69
- # end
70
- #
71
- # This can now be used in combination with the +validates+ method
72
- # (see ActiveModel::Validations::ClassMethods.validates for more on this)
73
- #
74
- # class Person
75
- # include ActiveModel::Validations
76
- # attr_accessor :title
77
- #
78
- # validates :title, :presence => true, :title => true
79
- # end
80
- #
81
- # Validator may also define a +setup+ instance method which will get called
82
- # with the class that using that validator as it's argument. This can be
83
- # useful when there are prerequisites such as an attr_accessor being present
84
- # for example:
85
- #
86
- # class MyValidator < ActiveModel::Validator
87
- # def setup(klass)
88
- # klass.send :attr_accessor, :custom_attribute
89
- # end
90
- # end
91
- #
92
- # This setup method is only called when used with validation macros or the
93
- # class level <tt>validates_with</tt> method.
94
- #
95
- class Validator
96
- attr_reader :options
97
-
98
- # Returns the kind of the validator.
99
- #
100
- # == Examples
101
- #
102
- # PresenceValidator.kind #=> :presence
103
- # UniquenessValidator.kind #=> :uniqueness
104
- #
105
- def self.kind
106
- @kind ||= name.split('::').last.underscore.sub(/_validator$/, '').to_sym unless anonymous?
107
- end
108
-
109
- # Accepts options that will be made availible through the +options+ reader.
110
- def initialize(options)
111
- @options = options
112
- end
113
-
114
- # Return the kind for this validator.
115
- def kind
116
- self.class.kind
117
- end
118
-
119
- # Override this method in subclasses with validation logic, adding errors
120
- # to the records +errors+ array where necessary.
121
- def validate(record)
122
- raise NotImplementedError
123
- end
124
- end
125
-
126
- # EachValidator is a validator which iterates through the attributes given
127
- # in the options hash invoking the validate_each method passing in the
128
- # record, attribute and value.
129
- #
130
- # All ActiveModel validations are built on top of this Validator.
131
- class EachValidator < Validator
132
- attr_reader :attributes
133
-
134
- # Returns a new validator instance. All options will be available via the
135
- # +options+ reader, however the <tt>:attributes</tt> option will be removed
136
- # and instead be made available through the +attributes+ reader.
137
- def initialize(options)
138
- @attributes = Array.wrap(options.delete(:attributes))
139
- raise ":attributes cannot be blank" if @attributes.empty?
140
- super
141
- check_validity!
142
- end
143
-
144
- # Performs validation on the supplied record. By default this will call
145
- # +validates_each+ to determine validity therefore subclasses should
146
- # override +validates_each+ with validation logic.
147
- def validate(record)
148
- attributes.each do |attribute|
149
- value = record.read_attribute_for_validation(attribute)
150
- next if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
151
- validate_each(record, attribute, value)
152
- end
153
- end
154
-
155
- # Override this method in subclasses with the validation logic, adding
156
- # errors to the records +errors+ array where necessary.
157
- def validate_each(record, attribute, value)
158
- raise NotImplementedError
159
- end
160
-
161
- # Hook method that gets called by the initializer allowing verification
162
- # that the arguments supplied are valid. You could for example raise an
163
- # ArgumentError when invalid options are supplied.
164
- def check_validity!
165
- end
166
- end
167
-
168
- # BlockValidator is a special EachValidator which receives a block on initialization
169
- # and call this block for each attribute being validated. +validates_each+ uses this
170
- # Validator.
171
- class BlockValidator < EachValidator
172
- def initialize(options, &block)
173
- @block = block
174
- super
175
- end
176
-
177
- private
178
-
179
- def validate_each(record, attribute, value)
180
- @block.call(record, attribute, value)
181
- end
182
- end
183
- end