activemodel 3.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/CHANGELOG +13 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +216 -0
  4. data/lib/active_model.rb +61 -0
  5. data/lib/active_model/attribute_methods.rb +391 -0
  6. data/lib/active_model/callbacks.rb +133 -0
  7. data/lib/active_model/conversion.rb +19 -0
  8. data/lib/active_model/deprecated_error_methods.rb +33 -0
  9. data/lib/active_model/dirty.rb +164 -0
  10. data/lib/active_model/errors.rb +277 -0
  11. data/lib/active_model/lint.rb +89 -0
  12. data/lib/active_model/locale/en.yml +26 -0
  13. data/lib/active_model/naming.rb +60 -0
  14. data/lib/active_model/observing.rb +196 -0
  15. data/lib/active_model/railtie.rb +2 -0
  16. data/lib/active_model/serialization.rb +87 -0
  17. data/lib/active_model/serializers/json.rb +96 -0
  18. data/lib/active_model/serializers/xml.rb +204 -0
  19. data/lib/active_model/test_case.rb +16 -0
  20. data/lib/active_model/translation.rb +60 -0
  21. data/lib/active_model/validations.rb +168 -0
  22. data/lib/active_model/validations/acceptance.rb +51 -0
  23. data/lib/active_model/validations/confirmation.rb +49 -0
  24. data/lib/active_model/validations/exclusion.rb +40 -0
  25. data/lib/active_model/validations/format.rb +64 -0
  26. data/lib/active_model/validations/inclusion.rb +40 -0
  27. data/lib/active_model/validations/length.rb +98 -0
  28. data/lib/active_model/validations/numericality.rb +111 -0
  29. data/lib/active_model/validations/presence.rb +41 -0
  30. data/lib/active_model/validations/validates.rb +108 -0
  31. data/lib/active_model/validations/with.rb +70 -0
  32. data/lib/active_model/validator.rb +160 -0
  33. data/lib/active_model/version.rb +9 -0
  34. metadata +96 -0
@@ -0,0 +1,41 @@
1
+ require 'active_support/core_ext/object/blank'
2
+
3
+ module ActiveModel
4
+ module Validations
5
+ class PresenceValidator < EachValidator
6
+ def validate(record)
7
+ record.errors.add_on_blank(attributes, options[:message])
8
+ end
9
+ end
10
+
11
+ module ClassMethods
12
+ # Validates that the specified attributes are not blank (as defined by Object#blank?). Happens by default on save. Example:
13
+ #
14
+ # class Person < ActiveRecord::Base
15
+ # validates_presence_of :first_name
16
+ # end
17
+ #
18
+ # The first_name attribute must be in the object and it cannot be blank.
19
+ #
20
+ # If you want to validate the presence of a boolean field (where the real values are true and false),
21
+ # you will want to use <tt>validates_inclusion_of :field_name, :in => [true, false]</tt>.
22
+ #
23
+ # This is due to the way Object#blank? handles boolean values: <tt>false.blank? # => true</tt>.
24
+ #
25
+ # Configuration options:
26
+ # * <tt>message</tt> - A custom error message (default is: "can't be blank").
27
+ # * <tt>on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>,
28
+ # <tt>:update</tt>).
29
+ # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
30
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>).
31
+ # The method, proc or string should return or evaluate to a true or false value.
32
+ # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
33
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
34
+ # The method, proc or string should return or evaluate to a true or false value.
35
+ #
36
+ def validates_presence_of(*attr_names)
37
+ validates_with PresenceValidator, _merge_attributes(attr_names)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,108 @@
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
@@ -0,0 +1,70 @@
1
+ module ActiveModel
2
+ module Validations
3
+ module ClassMethods
4
+
5
+ # Passes the record off to the class or classes specified and allows them
6
+ # to add errors based on more complex conditions.
7
+ #
8
+ # class Person
9
+ # include ActiveModel::Validations
10
+ # validates_with MyValidator
11
+ # end
12
+ #
13
+ # class MyValidator < ActiveModel::Validator
14
+ # def validate(record)
15
+ # if some_complex_logic
16
+ # record.errors[:base] << "This record is invalid"
17
+ # end
18
+ # end
19
+ #
20
+ # private
21
+ # def some_complex_logic
22
+ # # ...
23
+ # end
24
+ # end
25
+ #
26
+ # You may also pass it multiple classes, like so:
27
+ #
28
+ # class Person
29
+ # include ActiveModel::Validations
30
+ # validates_with MyValidator, MyOtherValidator, :on => :create
31
+ # end
32
+ #
33
+ # Configuration options:
34
+ # * <tt>on</tt> - Specifies when this validation is active
35
+ # (<tt>:create</tt> or <tt>:update</tt>
36
+ # * <tt>if</tt> - Specifies a method, proc or string to call to determine
37
+ # if the validation should occur (e.g. <tt>:if => :allow_validation</tt>,
38
+ # or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>).
39
+ # The method, proc or string should return or evaluate to a true or false value.
40
+ # * <tt>unless</tt> - Specifies a method, proc or string to call to
41
+ # determine if the validation should not occur
42
+ # (e.g. <tt>:unless => :skip_validation</tt>, or
43
+ # <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
44
+ # The method, proc or string should return or evaluate to a true or false value.
45
+ #
46
+ # If you pass any additional configuration options, they will be passed
47
+ # to the class and available as <tt>options</tt>:
48
+ #
49
+ # class Person
50
+ # include ActiveModel::Validations
51
+ # validates_with MyValidator, :my_custom_key => "my custom value"
52
+ # end
53
+ #
54
+ # class MyValidator < ActiveModel::Validator
55
+ # def validate(record)
56
+ # options[:my_custom_key] # => "my custom value"
57
+ # end
58
+ # end
59
+ #
60
+ def validates_with(*args, &block)
61
+ options = args.extract_options!
62
+ args.each do |klass|
63
+ validator = klass.new(options, &block)
64
+ validator.setup(self) if validator.respond_to?(:setup)
65
+ validate(validator, options)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,160 @@
1
+ module ActiveModel #:nodoc:
2
+ # A simple base class that can be used along with
3
+ # +ActiveModel::Validations::ClassMethods.validates_with+
4
+ #
5
+ # class Person
6
+ # include ActiveModel::Validations
7
+ # validates_with MyValidator
8
+ # end
9
+ #
10
+ # class MyValidator < ActiveModel::Validator
11
+ # def validate(record)
12
+ # if some_complex_logic
13
+ # record.errors[:base] = "This record is invalid"
14
+ # end
15
+ # end
16
+ #
17
+ # private
18
+ # def some_complex_logic
19
+ # # ...
20
+ # end
21
+ # end
22
+ #
23
+ # Any class that inherits from ActiveModel::Validator must implement a method
24
+ # called <tt>validate</tt> which accepts a <tt>record</tt>.
25
+ #
26
+ # class Person
27
+ # include ActiveModel::Validations
28
+ # validates_with MyValidator
29
+ # end
30
+ #
31
+ # class MyValidator < ActiveModel::Validator
32
+ # def validate(record)
33
+ # record # => The person instance being validated
34
+ # options # => Any non-standard options passed to validates_with
35
+ # end
36
+ # end
37
+ #
38
+ # To cause a validation error, you must add to the <tt>record<tt>'s errors directly
39
+ # from within the validators message
40
+ #
41
+ # class MyValidator < ActiveModel::Validator
42
+ # def validate(record)
43
+ # record.errors[:base] << "This is some custom error message"
44
+ # record.errors[:first_name] << "This is some complex validation"
45
+ # # etc...
46
+ # end
47
+ # end
48
+ #
49
+ # To add behavior to the initialize method, use the following signature:
50
+ #
51
+ # class MyValidator < ActiveModel::Validator
52
+ # def initialize(record, options)
53
+ # super
54
+ # @my_custom_field = options[:field_name] || :first_name
55
+ # end
56
+ # end
57
+ #
58
+ # The easiest way to add custom validators for validating individual attributes
59
+ # is with the convenient ActiveModel::EachValidator for example:
60
+ #
61
+ # class TitleValidator < ActiveModel::EachValidator
62
+ # def validate_each(record, attribute, value)
63
+ # record.errors[attribute] << 'must be Mr. Mrs. or Dr.' unless ['Mr.', 'Mrs.', 'Dr.'].include?(value)
64
+ # end
65
+ # end
66
+ #
67
+ # This can now be used in combination with the +validates+ method
68
+ # (see ActiveModel::Validations::ClassMethods.validates for more on this)
69
+ #
70
+ # class Person
71
+ # include ActiveModel::Validations
72
+ # attr_accessor :title
73
+ #
74
+ # validates :title, :presence => true, :title => true
75
+ # end
76
+ #
77
+ # Validator may also define a +setup+ instance method which will get called
78
+ # with the class that using that validator as it's argument. This can be
79
+ # useful when there are prerequisites such as an attr_accessor being present
80
+ # for example:
81
+ #
82
+ # class MyValidator < ActiveModel::Validator
83
+ # def setup(klass)
84
+ # klass.send :attr_accessor, :custom_attribute
85
+ # end
86
+ # end
87
+ #
88
+ class Validator
89
+ attr_reader :options
90
+
91
+ # Accepts options that will be made availible through the +options+ reader.
92
+ def initialize(options)
93
+ @options = options
94
+ end
95
+
96
+ # Override this method in subclasses with validation logic, adding errors
97
+ # to the records +errors+ array where necessary.
98
+ def validate(record)
99
+ raise NotImplementedError
100
+ end
101
+ end
102
+
103
+ # EachValidator is a validator which iterates through the attributes given
104
+ # in the options hash invoking the validate_each method passing in the
105
+ # record, attribute and value.
106
+ #
107
+ # All ActiveModel validations are built on top of this Validator.
108
+ class EachValidator < Validator
109
+ attr_reader :attributes
110
+
111
+ # Returns a new validator instance. All options will be available via the
112
+ # +options+ reader, however the <tt>:attributes</tt> option will be removed
113
+ # and instead be made available through the +attributes+ reader.
114
+ def initialize(options)
115
+ @attributes = Array(options.delete(:attributes))
116
+ raise ":attributes cannot be blank" if @attributes.empty?
117
+ super
118
+ check_validity!
119
+ end
120
+
121
+ # Performs validation on the supplied record. By default this will call
122
+ # +validates_each+ to determine validity therefore subclasses should
123
+ # override +validates_each+ with validation logic.
124
+ def validate(record)
125
+ attributes.each do |attribute|
126
+ value = record.read_attribute_for_validation(attribute)
127
+ next if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
128
+ validate_each(record, attribute, value)
129
+ end
130
+ end
131
+
132
+ # Override this method in subclasses with the validation logic, adding
133
+ # errors to the records +errors+ array where necessary.
134
+ def validate_each(record, attribute, value)
135
+ raise NotImplementedError
136
+ end
137
+
138
+ # Hook method that gets called by the initializer allowing verification
139
+ # that the arguments supplied are valid. You could for example raise an
140
+ # ArgumentError when invalid options are supplied.
141
+ def check_validity!
142
+ end
143
+ end
144
+
145
+ # BlockValidator is a special EachValidator which receives a block on initialization
146
+ # and call this block for each attribute being validated. +validates_each+ uses this
147
+ # Validator.
148
+ class BlockValidator < EachValidator
149
+ def initialize(options, &block)
150
+ @block = block
151
+ super
152
+ end
153
+
154
+ private
155
+
156
+ def validate_each(record, attribute, value)
157
+ @block.call(record, attribute, value)
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,9 @@
1
+ module ActiveModel
2
+ module VERSION #:nodoc:
3
+ MAJOR = 3
4
+ MINOR = 0
5
+ TINY = "0.beta"
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activemodel
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.0.0.beta
5
+ platform: ruby
6
+ authors:
7
+ - David Heinemeier Hansson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-03 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - "="
22
+ - !ruby/object:Gem::Version
23
+ version: 3.0.0.beta
24
+ version:
25
+ description: Extracts common modeling concerns from ActiveRecord to share between similar frameworks like ActiveResource.
26
+ email: david@loudthinking.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - CHANGELOG
35
+ - MIT-LICENSE
36
+ - README
37
+ - lib/active_model/attribute_methods.rb
38
+ - lib/active_model/callbacks.rb
39
+ - lib/active_model/conversion.rb
40
+ - lib/active_model/deprecated_error_methods.rb
41
+ - lib/active_model/dirty.rb
42
+ - lib/active_model/errors.rb
43
+ - lib/active_model/lint.rb
44
+ - lib/active_model/locale/en.yml
45
+ - lib/active_model/naming.rb
46
+ - lib/active_model/observing.rb
47
+ - lib/active_model/railtie.rb
48
+ - lib/active_model/serialization.rb
49
+ - lib/active_model/serializers/json.rb
50
+ - lib/active_model/serializers/xml.rb
51
+ - lib/active_model/test_case.rb
52
+ - lib/active_model/translation.rb
53
+ - lib/active_model/validations/acceptance.rb
54
+ - lib/active_model/validations/confirmation.rb
55
+ - lib/active_model/validations/exclusion.rb
56
+ - lib/active_model/validations/format.rb
57
+ - lib/active_model/validations/inclusion.rb
58
+ - lib/active_model/validations/length.rb
59
+ - lib/active_model/validations/numericality.rb
60
+ - lib/active_model/validations/presence.rb
61
+ - lib/active_model/validations/validates.rb
62
+ - lib/active_model/validations/with.rb
63
+ - lib/active_model/validations.rb
64
+ - lib/active_model/validator.rb
65
+ - lib/active_model/version.rb
66
+ - lib/active_model.rb
67
+ has_rdoc: true
68
+ homepage: http://www.rubyonrails.org
69
+ licenses: []
70
+
71
+ post_install_message:
72
+ rdoc_options: []
73
+
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ version:
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">"
85
+ - !ruby/object:Gem::Version
86
+ version: 1.3.1
87
+ version:
88
+ requirements: []
89
+
90
+ rubyforge_project: activemodel
91
+ rubygems_version: 1.3.5
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: A toolkit for building other modeling frameworks like ActiveRecord
95
+ test_files: []
96
+