activemodel 6.0.0

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 (67) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +172 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +266 -0
  5. data/lib/active_model.rb +77 -0
  6. data/lib/active_model/attribute.rb +247 -0
  7. data/lib/active_model/attribute/user_provided_default.rb +51 -0
  8. data/lib/active_model/attribute_assignment.rb +57 -0
  9. data/lib/active_model/attribute_methods.rb +517 -0
  10. data/lib/active_model/attribute_mutation_tracker.rb +178 -0
  11. data/lib/active_model/attribute_set.rb +106 -0
  12. data/lib/active_model/attribute_set/builder.rb +124 -0
  13. data/lib/active_model/attribute_set/yaml_encoder.rb +40 -0
  14. data/lib/active_model/attributes.rb +138 -0
  15. data/lib/active_model/callbacks.rb +156 -0
  16. data/lib/active_model/conversion.rb +111 -0
  17. data/lib/active_model/dirty.rb +280 -0
  18. data/lib/active_model/errors.rb +601 -0
  19. data/lib/active_model/forbidden_attributes_protection.rb +31 -0
  20. data/lib/active_model/gem_version.rb +17 -0
  21. data/lib/active_model/lint.rb +118 -0
  22. data/lib/active_model/locale/en.yml +36 -0
  23. data/lib/active_model/model.rb +99 -0
  24. data/lib/active_model/naming.rb +334 -0
  25. data/lib/active_model/railtie.rb +20 -0
  26. data/lib/active_model/secure_password.rb +128 -0
  27. data/lib/active_model/serialization.rb +192 -0
  28. data/lib/active_model/serializers/json.rb +147 -0
  29. data/lib/active_model/translation.rb +70 -0
  30. data/lib/active_model/type.rb +53 -0
  31. data/lib/active_model/type/big_integer.rb +15 -0
  32. data/lib/active_model/type/binary.rb +52 -0
  33. data/lib/active_model/type/boolean.rb +47 -0
  34. data/lib/active_model/type/date.rb +53 -0
  35. data/lib/active_model/type/date_time.rb +47 -0
  36. data/lib/active_model/type/decimal.rb +70 -0
  37. data/lib/active_model/type/float.rb +34 -0
  38. data/lib/active_model/type/helpers.rb +7 -0
  39. data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +45 -0
  40. data/lib/active_model/type/helpers/mutable.rb +20 -0
  41. data/lib/active_model/type/helpers/numeric.rb +44 -0
  42. data/lib/active_model/type/helpers/time_value.rb +81 -0
  43. data/lib/active_model/type/helpers/timezone.rb +19 -0
  44. data/lib/active_model/type/immutable_string.rb +32 -0
  45. data/lib/active_model/type/integer.rb +58 -0
  46. data/lib/active_model/type/registry.rb +62 -0
  47. data/lib/active_model/type/string.rb +26 -0
  48. data/lib/active_model/type/time.rb +47 -0
  49. data/lib/active_model/type/value.rb +126 -0
  50. data/lib/active_model/validations.rb +437 -0
  51. data/lib/active_model/validations/absence.rb +33 -0
  52. data/lib/active_model/validations/acceptance.rb +102 -0
  53. data/lib/active_model/validations/callbacks.rb +122 -0
  54. data/lib/active_model/validations/clusivity.rb +54 -0
  55. data/lib/active_model/validations/confirmation.rb +80 -0
  56. data/lib/active_model/validations/exclusion.rb +49 -0
  57. data/lib/active_model/validations/format.rb +114 -0
  58. data/lib/active_model/validations/helper_methods.rb +15 -0
  59. data/lib/active_model/validations/inclusion.rb +47 -0
  60. data/lib/active_model/validations/length.rb +129 -0
  61. data/lib/active_model/validations/numericality.rb +189 -0
  62. data/lib/active_model/validations/presence.rb +39 -0
  63. data/lib/active_model/validations/validates.rb +174 -0
  64. data/lib/active_model/validations/with.rb +147 -0
  65. data/lib/active_model/validator.rb +183 -0
  66. data/lib/active_model/version.rb +10 -0
  67. metadata +125 -0
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ module Validations
5
+ # == \Active \Model Absence Validator
6
+ class AbsenceValidator < EachValidator #:nodoc:
7
+ def validate_each(record, attr_name, value)
8
+ record.errors.add(attr_name, :present, options) if value.present?
9
+ end
10
+ end
11
+
12
+ module HelperMethods
13
+ # Validates that the specified attributes are blank (as defined by
14
+ # Object#blank?). Happens by default on save.
15
+ #
16
+ # class Person < ActiveRecord::Base
17
+ # validates_absence_of :first_name
18
+ # end
19
+ #
20
+ # The first_name attribute must be in the object and it must be blank.
21
+ #
22
+ # Configuration options:
23
+ # * <tt>:message</tt> - A custom error message (default is: "must be blank").
24
+ #
25
+ # There is also a list of default options supported by every validator:
26
+ # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
27
+ # See <tt>ActiveModel::Validations#validates</tt> for more information
28
+ def validates_absence_of(*attr_names)
29
+ validates_with AbsenceValidator, _merge_attributes(attr_names)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ module Validations
5
+ class AcceptanceValidator < EachValidator # :nodoc:
6
+ def initialize(options)
7
+ super({ allow_nil: true, accept: ["1", true] }.merge!(options))
8
+ setup!(options[:class])
9
+ end
10
+
11
+ def validate_each(record, attribute, value)
12
+ unless acceptable_option?(value)
13
+ record.errors.add(attribute, :accepted, options.except(:accept, :allow_nil))
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def setup!(klass)
20
+ klass.include(LazilyDefineAttributes.new(AttributeDefinition.new(attributes)))
21
+ end
22
+
23
+ def acceptable_option?(value)
24
+ Array(options[:accept]).include?(value)
25
+ end
26
+
27
+ class LazilyDefineAttributes < Module
28
+ def initialize(attribute_definition)
29
+ define_method(:respond_to_missing?) do |method_name, include_private = false|
30
+ super(method_name, include_private) || attribute_definition.matches?(method_name)
31
+ end
32
+
33
+ define_method(:method_missing) do |method_name, *args, &block|
34
+ if attribute_definition.matches?(method_name)
35
+ attribute_definition.define_on(self.class)
36
+ send(method_name, *args, &block)
37
+ else
38
+ super(method_name, *args, &block)
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ class AttributeDefinition
45
+ def initialize(attributes)
46
+ @attributes = attributes.map(&:to_s)
47
+ end
48
+
49
+ def matches?(method_name)
50
+ attr_name = convert_to_reader_name(method_name)
51
+ attributes.include?(attr_name)
52
+ end
53
+
54
+ def define_on(klass)
55
+ attr_readers = attributes.reject { |name| klass.attribute_method?(name) }
56
+ attr_writers = attributes.reject { |name| klass.attribute_method?("#{name}=") }
57
+ klass.define_attribute_methods
58
+ klass.attr_reader(*attr_readers)
59
+ klass.attr_writer(*attr_writers)
60
+ end
61
+
62
+ private
63
+ attr_reader :attributes
64
+
65
+ def convert_to_reader_name(method_name)
66
+ method_name.to_s.chomp("=")
67
+ end
68
+ end
69
+ end
70
+
71
+ module HelperMethods
72
+ # Encapsulates the pattern of wanting to validate the acceptance of a
73
+ # terms of service check box (or similar agreement).
74
+ #
75
+ # class Person < ActiveRecord::Base
76
+ # validates_acceptance_of :terms_of_service
77
+ # validates_acceptance_of :eula, message: 'must be abided'
78
+ # end
79
+ #
80
+ # If the database column does not exist, the +terms_of_service+ attribute
81
+ # is entirely virtual. This check is performed only if +terms_of_service+
82
+ # is not +nil+ and by default on save.
83
+ #
84
+ # Configuration options:
85
+ # * <tt>:message</tt> - A custom error message (default is: "must be
86
+ # accepted").
87
+ # * <tt>:accept</tt> - Specifies a value that is considered accepted.
88
+ # Also accepts an array of possible values. The default value is
89
+ # an array ["1", true], which makes it easy to relate to an HTML
90
+ # checkbox. This should be set to, or include, +true+ if you are validating
91
+ # a database column, since the attribute is typecast from "1" to +true+
92
+ # before validation.
93
+ #
94
+ # There is also a list of default options supported by every validator:
95
+ # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
96
+ # See <tt>ActiveModel::Validations#validates</tt> for more information.
97
+ def validates_acceptance_of(*attr_names)
98
+ validates_with AcceptanceValidator, _merge_attributes(attr_names)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ module Validations
5
+ # == Active \Model \Validation \Callbacks
6
+ #
7
+ # Provides an interface for any class to have +before_validation+ and
8
+ # +after_validation+ callbacks.
9
+ #
10
+ # First, include ActiveModel::Validations::Callbacks from the class you are
11
+ # creating:
12
+ #
13
+ # class MyModel
14
+ # include ActiveModel::Validations::Callbacks
15
+ #
16
+ # before_validation :do_stuff_before_validation
17
+ # after_validation :do_stuff_after_validation
18
+ # end
19
+ #
20
+ # Like other <tt>before_*</tt> callbacks if +before_validation+ throws
21
+ # +:abort+ then <tt>valid?</tt> will not be called.
22
+ module Callbacks
23
+ extend ActiveSupport::Concern
24
+
25
+ included do
26
+ include ActiveSupport::Callbacks
27
+ define_callbacks :validation,
28
+ skip_after_callbacks_if_terminated: true,
29
+ scope: [:kind, :name]
30
+ end
31
+
32
+ module ClassMethods
33
+ # Defines a callback that will get called right before validation.
34
+ #
35
+ # class Person
36
+ # include ActiveModel::Validations
37
+ # include ActiveModel::Validations::Callbacks
38
+ #
39
+ # attr_accessor :name
40
+ #
41
+ # validates_length_of :name, maximum: 6
42
+ #
43
+ # before_validation :remove_whitespaces
44
+ #
45
+ # private
46
+ #
47
+ # def remove_whitespaces
48
+ # name.strip!
49
+ # end
50
+ # end
51
+ #
52
+ # person = Person.new
53
+ # person.name = ' bob '
54
+ # person.valid? # => true
55
+ # person.name # => "bob"
56
+ def before_validation(*args, &block)
57
+ options = args.extract_options!
58
+
59
+ if options.key?(:on)
60
+ options = options.dup
61
+ options[:on] = Array(options[:on])
62
+ options[:if] = Array(options[:if])
63
+ options[:if].unshift ->(o) {
64
+ !(options[:on] & Array(o.validation_context)).empty?
65
+ }
66
+ end
67
+
68
+ set_callback(:validation, :before, *args, options, &block)
69
+ end
70
+
71
+ # Defines a callback that will get called right after validation.
72
+ #
73
+ # class Person
74
+ # include ActiveModel::Validations
75
+ # include ActiveModel::Validations::Callbacks
76
+ #
77
+ # attr_accessor :name, :status
78
+ #
79
+ # validates_presence_of :name
80
+ #
81
+ # after_validation :set_status
82
+ #
83
+ # private
84
+ #
85
+ # def set_status
86
+ # self.status = errors.empty?
87
+ # end
88
+ # end
89
+ #
90
+ # person = Person.new
91
+ # person.name = ''
92
+ # person.valid? # => false
93
+ # person.status # => false
94
+ # person.name = 'bob'
95
+ # person.valid? # => true
96
+ # person.status # => true
97
+ def after_validation(*args, &block)
98
+ options = args.extract_options!
99
+ options = options.dup
100
+ options[:prepend] = true
101
+
102
+ if options.key?(:on)
103
+ options[:on] = Array(options[:on])
104
+ options[:if] = Array(options[:if])
105
+ options[:if].unshift ->(o) {
106
+ !(options[:on] & Array(o.validation_context)).empty?
107
+ }
108
+ end
109
+
110
+ set_callback(:validation, :after, *args, options, &block)
111
+ end
112
+ end
113
+
114
+ private
115
+
116
+ # Overwrite run validations to include callbacks.
117
+ def run_validations!
118
+ _run_validation_callbacks { super }
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/range"
4
+
5
+ module ActiveModel
6
+ module Validations
7
+ module Clusivity #:nodoc:
8
+ ERROR_MESSAGE = "An object with the method #include? or a proc, lambda or symbol is required, " \
9
+ "and must be supplied as the :in (or :within) option of the configuration hash"
10
+
11
+ def check_validity!
12
+ unless delimiter.respond_to?(:include?) || delimiter.respond_to?(:call) || delimiter.respond_to?(:to_sym)
13
+ raise ArgumentError, ERROR_MESSAGE
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def include?(record, value)
20
+ members = if delimiter.respond_to?(:call)
21
+ delimiter.call(record)
22
+ elsif delimiter.respond_to?(:to_sym)
23
+ record.send(delimiter)
24
+ else
25
+ delimiter
26
+ end
27
+
28
+ members.send(inclusion_method(members), value)
29
+ end
30
+
31
+ def delimiter
32
+ @delimiter ||= options[:in] || options[:within]
33
+ end
34
+
35
+ # After Ruby 2.2, <tt>Range#include?</tt> on non-number-or-time-ish ranges checks all
36
+ # possible values in the range for equality, which is slower but more accurate.
37
+ # <tt>Range#cover?</tt> uses the previous logic of comparing a value with the range
38
+ # endpoints, which is fast but is only accurate on Numeric, Time, Date,
39
+ # or DateTime ranges.
40
+ def inclusion_method(enumerable)
41
+ if enumerable.is_a? Range
42
+ case enumerable.first
43
+ when Numeric, Time, DateTime, Date
44
+ :cover?
45
+ else
46
+ :include?
47
+ end
48
+ else
49
+ :include?
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ module Validations
5
+ class ConfirmationValidator < EachValidator # :nodoc:
6
+ def initialize(options)
7
+ super({ case_sensitive: true }.merge!(options))
8
+ setup!(options[:class])
9
+ end
10
+
11
+ def validate_each(record, attribute, value)
12
+ unless (confirmed = record.send("#{attribute}_confirmation")).nil?
13
+ unless confirmation_value_equal?(record, attribute, value, confirmed)
14
+ human_attribute_name = record.class.human_attribute_name(attribute)
15
+ record.errors.add(:"#{attribute}_confirmation", :confirmation, options.except(:case_sensitive).merge!(attribute: human_attribute_name))
16
+ end
17
+ end
18
+ end
19
+
20
+ private
21
+ def setup!(klass)
22
+ klass.attr_reader(*attributes.map do |attribute|
23
+ :"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation")
24
+ end.compact)
25
+
26
+ klass.attr_writer(*attributes.map do |attribute|
27
+ :"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation=")
28
+ end.compact)
29
+ end
30
+
31
+ def confirmation_value_equal?(record, attribute, value, confirmed)
32
+ if !options[:case_sensitive] && value.is_a?(String)
33
+ value.casecmp(confirmed) == 0
34
+ else
35
+ value == confirmed
36
+ end
37
+ end
38
+ end
39
+
40
+ module HelperMethods
41
+ # Encapsulates the pattern of wanting to validate a password or email
42
+ # address field with a confirmation.
43
+ #
44
+ # Model:
45
+ # class Person < ActiveRecord::Base
46
+ # validates_confirmation_of :user_name, :password
47
+ # validates_confirmation_of :email_address,
48
+ # message: 'should match confirmation'
49
+ # end
50
+ #
51
+ # View:
52
+ # <%= password_field "person", "password" %>
53
+ # <%= password_field "person", "password_confirmation" %>
54
+ #
55
+ # The added +password_confirmation+ attribute is virtual; it exists only
56
+ # as an in-memory attribute for validating the password. To achieve this,
57
+ # the validation adds accessors to the model for the confirmation
58
+ # attribute.
59
+ #
60
+ # NOTE: This check is performed only if +password_confirmation+ is not
61
+ # +nil+. To require confirmation, make sure to add a presence check for
62
+ # the confirmation attribute:
63
+ #
64
+ # validates_presence_of :password_confirmation, if: :password_changed?
65
+ #
66
+ # Configuration options:
67
+ # * <tt>:message</tt> - A custom error message (default is: "doesn't match
68
+ # <tt>%{translated_attribute_name}</tt>").
69
+ # * <tt>:case_sensitive</tt> - Looks for an exact match. Ignored by
70
+ # non-text columns (+true+ by default).
71
+ #
72
+ # There is also a list of default options supported by every validator:
73
+ # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
74
+ # See <tt>ActiveModel::Validations#validates</tt> for more information
75
+ def validates_confirmation_of(*attr_names)
76
+ validates_with ConfirmationValidator, _merge_attributes(attr_names)
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/validations/clusivity"
4
+
5
+ module ActiveModel
6
+ module Validations
7
+ class ExclusionValidator < EachValidator # :nodoc:
8
+ include Clusivity
9
+
10
+ def validate_each(record, attribute, value)
11
+ if include?(record, value)
12
+ record.errors.add(attribute, :exclusion, options.except(:in, :within).merge!(value: value))
13
+ end
14
+ end
15
+ end
16
+
17
+ module HelperMethods
18
+ # Validates that the value of the specified attribute is not in a
19
+ # particular enumerable object.
20
+ #
21
+ # class Person < ActiveRecord::Base
22
+ # validates_exclusion_of :username, in: %w( admin superuser ), message: "You don't belong here"
23
+ # validates_exclusion_of :age, in: 30..60, message: 'This site is only for under 30 and over 60'
24
+ # validates_exclusion_of :format, in: %w( mov avi ), message: "extension %{value} is not allowed"
25
+ # validates_exclusion_of :password, in: ->(person) { [person.username, person.first_name] },
26
+ # message: 'should not be the same as your username or first name'
27
+ # validates_exclusion_of :karma, in: :reserved_karmas
28
+ # end
29
+ #
30
+ # Configuration options:
31
+ # * <tt>:in</tt> - An enumerable object of items that the value shouldn't
32
+ # be part of. This can be supplied as a proc, lambda or symbol which returns an
33
+ # enumerable. If the enumerable is a numerical, time or datetime range the test
34
+ # is performed with <tt>Range#cover?</tt>, otherwise with <tt>include?</tt>. When
35
+ # using a proc or lambda the instance under validation is passed as an argument.
36
+ # * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
37
+ # <tt>Range#cover?</tt>, otherwise with <tt>include?</tt>.
38
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is
39
+ # reserved").
40
+ #
41
+ # There is also a list of default options supported by every validator:
42
+ # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
43
+ # See <tt>ActiveModel::Validations#validates</tt> for more information
44
+ def validates_exclusion_of(*attr_names)
45
+ validates_with ExclusionValidator, _merge_attributes(attr_names)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ module Validations
5
+ class FormatValidator < EachValidator # :nodoc:
6
+ def validate_each(record, attribute, value)
7
+ if options[:with]
8
+ regexp = option_call(record, :with)
9
+ record_error(record, attribute, :with, value) if value.to_s !~ regexp
10
+ elsif options[:without]
11
+ regexp = option_call(record, :without)
12
+ record_error(record, attribute, :without, value) if regexp.match?(value.to_s)
13
+ end
14
+ end
15
+
16
+ def check_validity!
17
+ unless options.include?(:with) ^ options.include?(:without) # ^ == xor, or "exclusive or"
18
+ raise ArgumentError, "Either :with or :without must be supplied (but not both)"
19
+ end
20
+
21
+ check_options_validity :with
22
+ check_options_validity :without
23
+ end
24
+
25
+ private
26
+
27
+ def option_call(record, name)
28
+ option = options[name]
29
+ option.respond_to?(:call) ? option.call(record) : option
30
+ end
31
+
32
+ def record_error(record, attribute, name, value)
33
+ record.errors.add(attribute, :invalid, options.except(name).merge!(value: value))
34
+ end
35
+
36
+ def check_options_validity(name)
37
+ if option = options[name]
38
+ if option.is_a?(Regexp)
39
+ if options[:multiline] != true && regexp_using_multiline_anchors?(option)
40
+ raise ArgumentError, "The provided regular expression is using multiline anchors (^ or $), " \
41
+ "which may present a security risk. Did you mean to use \\A and \\z, or forgot to add the " \
42
+ ":multiline => true option?"
43
+ end
44
+ elsif !option.respond_to?(:call)
45
+ raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}"
46
+ end
47
+ end
48
+ end
49
+
50
+ def regexp_using_multiline_anchors?(regexp)
51
+ source = regexp.source
52
+ source.start_with?("^") || (source.end_with?("$") && !source.end_with?("\\$"))
53
+ end
54
+ end
55
+
56
+ module HelperMethods
57
+ # Validates whether the value of the specified attribute is of the correct
58
+ # form, going by the regular expression provided. You can require that the
59
+ # attribute matches the regular expression:
60
+ #
61
+ # class Person < ActiveRecord::Base
62
+ # validates_format_of :email, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create
63
+ # end
64
+ #
65
+ # Alternatively, you can require that the specified attribute does _not_
66
+ # match the regular expression:
67
+ #
68
+ # class Person < ActiveRecord::Base
69
+ # validates_format_of :email, without: /NOSPAM/
70
+ # end
71
+ #
72
+ # You can also provide a proc or lambda which will determine the regular
73
+ # expression that will be used to validate the attribute.
74
+ #
75
+ # class Person < ActiveRecord::Base
76
+ # # Admin can have number as a first letter in their screen name
77
+ # validates_format_of :screen_name,
78
+ # with: ->(person) { person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\z/i : /\A[a-z][a-z0-9_\-]*\z/i }
79
+ # end
80
+ #
81
+ # Note: use <tt>\A</tt> and <tt>\z</tt> to match the start and end of the
82
+ # string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
83
+ #
84
+ # Due to frequent misuse of <tt>^</tt> and <tt>$</tt>, you need to pass
85
+ # the <tt>multiline: true</tt> option in case you use any of these two
86
+ # anchors in the provided regular expression. In most cases, you should be
87
+ # using <tt>\A</tt> and <tt>\z</tt>.
88
+ #
89
+ # You must pass either <tt>:with</tt> or <tt>:without</tt> as an option.
90
+ # In addition, both must be a regular expression or a proc or lambda, or
91
+ # else an exception will be raised.
92
+ #
93
+ # Configuration options:
94
+ # * <tt>:message</tt> - A custom error message (default is: "is invalid").
95
+ # * <tt>:with</tt> - Regular expression that if the attribute matches will
96
+ # result in a successful validation. This can be provided as a proc or
97
+ # lambda returning regular expression which will be called at runtime.
98
+ # * <tt>:without</tt> - Regular expression that if the attribute does not
99
+ # match will result in a successful validation. This can be provided as
100
+ # a proc or lambda returning regular expression which will be called at
101
+ # runtime.
102
+ # * <tt>:multiline</tt> - Set to true if your regular expression contains
103
+ # anchors that match the beginning or end of lines as opposed to the
104
+ # beginning or end of the string. These anchors are <tt>^</tt> and <tt>$</tt>.
105
+ #
106
+ # There is also a list of default options supported by every validator:
107
+ # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
108
+ # See <tt>ActiveModel::Validations#validates</tt> for more information
109
+ def validates_format_of(*attr_names)
110
+ validates_with FormatValidator, _merge_attributes(attr_names)
111
+ end
112
+ end
113
+ end
114
+ end