activemodel 3.0.0.beta

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 (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
+