activemodel 4.2.11.3 → 5.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activemodel might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +84 -93
- data/MIT-LICENSE +1 -1
- data/README.rdoc +8 -16
- data/lib/active_model.rb +3 -2
- data/lib/active_model/attribute_assignment.rb +52 -0
- data/lib/active_model/attribute_methods.rb +16 -16
- data/lib/active_model/callbacks.rb +3 -3
- data/lib/active_model/conversion.rb +3 -3
- data/lib/active_model/dirty.rb +34 -35
- data/lib/active_model/errors.rb +117 -63
- data/lib/active_model/forbidden_attributes_protection.rb +3 -2
- data/lib/active_model/gem_version.rb +5 -5
- data/lib/active_model/lint.rb +32 -28
- data/lib/active_model/locale/en.yml +2 -1
- data/lib/active_model/model.rb +3 -4
- data/lib/active_model/naming.rb +5 -4
- data/lib/active_model/secure_password.rb +2 -9
- data/lib/active_model/serialization.rb +36 -9
- data/lib/active_model/serializers/json.rb +1 -1
- data/lib/active_model/type.rb +59 -0
- data/lib/active_model/type/big_integer.rb +13 -0
- data/lib/active_model/type/binary.rb +50 -0
- data/lib/active_model/type/boolean.rb +21 -0
- data/lib/active_model/type/date.rb +50 -0
- data/lib/active_model/type/date_time.rb +44 -0
- data/lib/active_model/type/decimal.rb +52 -0
- data/lib/active_model/type/decimal_without_scale.rb +11 -0
- data/lib/active_model/type/float.rb +25 -0
- data/lib/active_model/type/helpers.rb +4 -0
- data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +35 -0
- data/lib/active_model/type/helpers/mutable.rb +18 -0
- data/lib/active_model/type/helpers/numeric.rb +34 -0
- data/lib/active_model/type/helpers/time_value.rb +77 -0
- data/lib/active_model/type/immutable_string.rb +29 -0
- data/lib/active_model/type/integer.rb +66 -0
- data/lib/active_model/type/registry.rb +64 -0
- data/lib/active_model/type/string.rb +19 -0
- data/lib/active_model/type/text.rb +11 -0
- data/lib/active_model/type/time.rb +46 -0
- data/lib/active_model/type/unsigned_integer.rb +15 -0
- data/lib/active_model/type/value.rb +112 -0
- data/lib/active_model/validations.rb +35 -3
- data/lib/active_model/validations/absence.rb +1 -1
- data/lib/active_model/validations/acceptance.rb +61 -9
- data/lib/active_model/validations/callbacks.rb +3 -3
- data/lib/active_model/validations/confirmation.rb +16 -4
- data/lib/active_model/validations/exclusion.rb +3 -1
- data/lib/active_model/validations/format.rb +1 -1
- data/lib/active_model/validations/helper_methods.rb +13 -0
- data/lib/active_model/validations/inclusion.rb +3 -3
- data/lib/active_model/validations/length.rb +48 -17
- data/lib/active_model/validations/numericality.rb +12 -13
- data/lib/active_model/validations/validates.rb +1 -1
- data/lib/active_model/validations/with.rb +0 -10
- data/lib/active_model/validator.rb +6 -2
- data/lib/active_model/version.rb +1 -1
- metadata +34 -9
- data/lib/active_model/serializers/xml.rb +0 -238
@@ -3,14 +3,16 @@ module ActiveModel
|
|
3
3
|
module Validations
|
4
4
|
class ConfirmationValidator < EachValidator # :nodoc:
|
5
5
|
def initialize(options)
|
6
|
-
super
|
6
|
+
super({ case_sensitive: true }.merge!(options))
|
7
7
|
setup!(options[:class])
|
8
8
|
end
|
9
9
|
|
10
10
|
def validate_each(record, attribute, value)
|
11
|
-
if (confirmed = record.send("#{attribute}_confirmation"))
|
12
|
-
|
13
|
-
|
11
|
+
if (confirmed = record.send("#{attribute}_confirmation"))
|
12
|
+
unless confirmation_value_equal?(record, attribute, value, confirmed)
|
13
|
+
human_attribute_name = record.class.human_attribute_name(attribute)
|
14
|
+
record.errors.add(:"#{attribute}_confirmation", :confirmation, options.except(:case_sensitive).merge!(attribute: human_attribute_name))
|
15
|
+
end
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
@@ -24,6 +26,14 @@ module ActiveModel
|
|
24
26
|
:"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation=")
|
25
27
|
end.compact)
|
26
28
|
end
|
29
|
+
|
30
|
+
def confirmation_value_equal?(record, attribute, value, confirmed)
|
31
|
+
if !options[:case_sensitive] && value.is_a?(String)
|
32
|
+
value.casecmp(confirmed) == 0
|
33
|
+
else
|
34
|
+
value == confirmed
|
35
|
+
end
|
36
|
+
end
|
27
37
|
end
|
28
38
|
|
29
39
|
module HelperMethods
|
@@ -55,6 +65,8 @@ module ActiveModel
|
|
55
65
|
# Configuration options:
|
56
66
|
# * <tt>:message</tt> - A custom error message (default is: "doesn't match
|
57
67
|
# <tt>%{translated_attribute_name}</tt>").
|
68
|
+
# * <tt>:case_sensitive</tt> - Looks for an exact match. Ignored by
|
69
|
+
# non-text columns (+true+ by default).
|
58
70
|
#
|
59
71
|
# There is also a list of default options supported by every validator:
|
60
72
|
# +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
|
@@ -29,7 +29,9 @@ module ActiveModel
|
|
29
29
|
# Configuration options:
|
30
30
|
# * <tt>:in</tt> - An enumerable object of items that the value shouldn't
|
31
31
|
# be part of. This can be supplied as a proc, lambda or symbol which returns an
|
32
|
-
# enumerable. If the enumerable is a range the test
|
32
|
+
# enumerable. If the enumerable is a numerical, time or datetime range the test
|
33
|
+
# is performed with <tt>Range#cover?</tt>, otherwise with <tt>include?</tt>. When
|
34
|
+
# using a proc or lambda the instance under validation is passed as an argument.
|
33
35
|
# * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
|
34
36
|
# <tt>Range#cover?</tt>, otherwise with <tt>include?</tt>.
|
35
37
|
# * <tt>:message</tt> - Specifies a custom error message (default is: "is
|
@@ -77,7 +77,7 @@ module ActiveModel
|
|
77
77
|
# with: ->(person) { person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\z/i : /\A[a-z][a-z0-9_\-]*\z/i }
|
78
78
|
# end
|
79
79
|
#
|
80
|
-
# Note: use <tt>\A</tt> and <tt>\
|
80
|
+
# Note: use <tt>\A</tt> and <tt>\z</tt> to match the start and end of the
|
81
81
|
# string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
|
82
82
|
#
|
83
83
|
# Due to frequent misuse of <tt>^</tt> and <tt>$</tt>, you need to pass
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
module HelperMethods # :nodoc:
|
4
|
+
private
|
5
|
+
def _merge_attributes(attr_names)
|
6
|
+
options = attr_names.extract_options!.symbolize_keys
|
7
|
+
attr_names.flatten!
|
8
|
+
options[:attributes] = attr_names
|
9
|
+
options
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -28,9 +28,9 @@ module ActiveModel
|
|
28
28
|
# Configuration options:
|
29
29
|
# * <tt>:in</tt> - An enumerable object of available items. This can be
|
30
30
|
# supplied as a proc, lambda or symbol which returns an enumerable. If the
|
31
|
-
# enumerable is a numerical range the test is performed
|
32
|
-
# otherwise with <tt>include?</tt>. When using
|
33
|
-
# under validation is passed as an argument.
|
31
|
+
# enumerable is a numerical, time or datetime range the test is performed
|
32
|
+
# with <tt>Range#cover?</tt>, otherwise with <tt>include?</tt>. When using
|
33
|
+
# a proc or lambda the instance under validation is passed as an argument.
|
34
34
|
# * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
|
35
35
|
# * <tt>:message</tt> - Specifies a custom error message (default is: "is
|
36
36
|
# not included in the list").
|
@@ -1,6 +1,6 @@
|
|
1
|
-
|
1
|
+
require "active_support/core_ext/string/strip"
|
2
2
|
|
3
|
-
|
3
|
+
module ActiveModel
|
4
4
|
module Validations
|
5
5
|
class LengthValidator < EachValidator # :nodoc:
|
6
6
|
MESSAGES = { is: :wrong_length, minimum: :too_short, maximum: :too_long }.freeze
|
@@ -18,6 +18,27 @@ module ActiveModel
|
|
18
18
|
options[:minimum] = 1
|
19
19
|
end
|
20
20
|
|
21
|
+
if options[:tokenizer]
|
22
|
+
ActiveSupport::Deprecation.warn(<<-EOS.strip_heredoc)
|
23
|
+
The `:tokenizer` option is deprecated, and will be removed in Rails 5.1.
|
24
|
+
You can achieve the same functionality by defining an instance method
|
25
|
+
with the value that you want to validate the length of. For example,
|
26
|
+
|
27
|
+
validates_length_of :essay, minimum: 100,
|
28
|
+
tokenizer: ->(str) { str.scan(/\w+/) }
|
29
|
+
|
30
|
+
should be written as
|
31
|
+
|
32
|
+
validates_length_of :words_in_essay, minimum: 100
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def words_in_essay
|
37
|
+
essay.scan(/\w+/)
|
38
|
+
end
|
39
|
+
EOS
|
40
|
+
end
|
41
|
+
|
21
42
|
super
|
22
43
|
end
|
23
44
|
|
@@ -38,7 +59,7 @@ module ActiveModel
|
|
38
59
|
end
|
39
60
|
|
40
61
|
def validate_each(record, attribute, value)
|
41
|
-
value = tokenize(value)
|
62
|
+
value = tokenize(record, value)
|
42
63
|
value_length = value.respond_to?(:length) ? value.length : value.to_s.length
|
43
64
|
errors_options = options.except(*RESERVED_OPTIONS)
|
44
65
|
|
@@ -59,10 +80,14 @@ module ActiveModel
|
|
59
80
|
end
|
60
81
|
|
61
82
|
private
|
62
|
-
|
63
|
-
|
64
|
-
if
|
65
|
-
|
83
|
+
def tokenize(record, value)
|
84
|
+
tokenizer = options[:tokenizer]
|
85
|
+
if tokenizer && value.kind_of?(String)
|
86
|
+
if tokenizer.kind_of?(Proc)
|
87
|
+
tokenizer.call(value)
|
88
|
+
elsif record.respond_to?(tokenizer)
|
89
|
+
record.send(tokenizer, value)
|
90
|
+
end
|
66
91
|
end || value
|
67
92
|
end
|
68
93
|
|
@@ -73,8 +98,9 @@ module ActiveModel
|
|
73
98
|
|
74
99
|
module HelperMethods
|
75
100
|
|
76
|
-
# Validates that the specified
|
77
|
-
# supplied. Only one option can be used at a time
|
101
|
+
# Validates that the specified attributes match the length restrictions
|
102
|
+
# supplied. Only one constraint option can be used at a time apart from
|
103
|
+
# +:minimum+ and +:maximum+ that can be combined together:
|
78
104
|
#
|
79
105
|
# class Person < ActiveRecord::Base
|
80
106
|
# validates_length_of :first_name, maximum: 30
|
@@ -84,18 +110,27 @@ module ActiveModel
|
|
84
110
|
# validates_length_of :user_name, within: 6..20, too_long: 'pick a shorter name', too_short: 'pick a longer name'
|
85
111
|
# validates_length_of :zip_code, minimum: 5, too_short: 'please enter at least 5 characters'
|
86
112
|
# validates_length_of :smurf_leader, is: 4, message: "papa is spelled with 4 characters... don't play me."
|
87
|
-
# validates_length_of :
|
88
|
-
#
|
113
|
+
# validates_length_of :words_in_essay, minimum: 100, too_short: 'Your essay must be at least 100 words.'
|
114
|
+
#
|
115
|
+
# private
|
116
|
+
#
|
117
|
+
# def words_in_essay
|
118
|
+
# essay.scan(/\w+/)
|
119
|
+
# end
|
89
120
|
# end
|
90
121
|
#
|
91
|
-
#
|
122
|
+
# Constraint options:
|
123
|
+
#
|
92
124
|
# * <tt>:minimum</tt> - The minimum size of the attribute.
|
93
125
|
# * <tt>:maximum</tt> - The maximum size of the attribute. Allows +nil+ by
|
94
|
-
# default if not used with
|
126
|
+
# default if not used with +:minimum+.
|
95
127
|
# * <tt>:is</tt> - The exact size of the attribute.
|
96
128
|
# * <tt>:within</tt> - A range specifying the minimum and maximum size of
|
97
129
|
# the attribute.
|
98
130
|
# * <tt>:in</tt> - A synonym (or alias) for <tt>:within</tt>.
|
131
|
+
#
|
132
|
+
# Other options:
|
133
|
+
#
|
99
134
|
# * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
|
100
135
|
# * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
|
101
136
|
# * <tt>:too_long</tt> - The error message if the attribute goes over the
|
@@ -108,10 +143,6 @@ module ActiveModel
|
|
108
143
|
# * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>,
|
109
144
|
# <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate
|
110
145
|
# <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
|
111
|
-
# * <tt>:tokenizer</tt> - Specifies how to split up the attribute string.
|
112
|
-
# (e.g. <tt>tokenizer: ->(str) { str.scan(/\w+/) }</tt> to count words
|
113
|
-
# as in above example). Defaults to <tt>->(value) { value.split(//) }</tt>
|
114
|
-
# which counts individual characters.
|
115
146
|
#
|
116
147
|
# There is also a list of default options supported by every validator:
|
117
148
|
# +:if+, +:unless+, +:on+ and +:strict+.
|
@@ -20,7 +20,7 @@ module ActiveModel
|
|
20
20
|
def validate_each(record, attr_name, value)
|
21
21
|
before_type_cast = :"#{attr_name}_before_type_cast"
|
22
22
|
|
23
|
-
raw_value = record.send(before_type_cast) if record.respond_to?(before_type_cast)
|
23
|
+
raw_value = record.send(before_type_cast) if record.respond_to?(before_type_cast) && record.send(before_type_cast) != value
|
24
24
|
raw_value ||= value
|
25
25
|
|
26
26
|
if record_attribute_changed_in_place?(record, attr_name)
|
@@ -29,16 +29,14 @@ module ActiveModel
|
|
29
29
|
|
30
30
|
return if options[:allow_nil] && raw_value.nil?
|
31
31
|
|
32
|
-
unless
|
32
|
+
unless is_number?(raw_value)
|
33
33
|
record.errors.add(attr_name, :not_a_number, filtered_options(raw_value))
|
34
34
|
return
|
35
35
|
end
|
36
36
|
|
37
|
-
if allow_only_integer?(record)
|
38
|
-
|
39
|
-
|
40
|
-
return
|
41
|
-
end
|
37
|
+
if allow_only_integer?(record) && !is_integer?(raw_value)
|
38
|
+
record.errors.add(attr_name, :not_an_integer, filtered_options(raw_value))
|
39
|
+
return
|
42
40
|
end
|
43
41
|
|
44
42
|
options.slice(*CHECKS.keys).each do |option, option_value|
|
@@ -64,14 +62,15 @@ module ActiveModel
|
|
64
62
|
|
65
63
|
protected
|
66
64
|
|
67
|
-
def
|
68
|
-
Kernel.Float(raw_value) if raw_value !~ /\A0[xX]/
|
65
|
+
def is_number?(raw_value)
|
66
|
+
parsed_value = Kernel.Float(raw_value) if raw_value !~ /\A0[xX]/
|
67
|
+
!parsed_value.nil?
|
69
68
|
rescue ArgumentError, TypeError
|
70
|
-
|
69
|
+
false
|
71
70
|
end
|
72
71
|
|
73
|
-
def
|
74
|
-
|
72
|
+
def is_integer?(raw_value)
|
73
|
+
/\A[+-]?\d+\z/ === raw_value.to_s
|
75
74
|
end
|
76
75
|
|
77
76
|
def filtered_options(value)
|
@@ -114,7 +113,7 @@ module ActiveModel
|
|
114
113
|
# * <tt>:only_integer</tt> - Specifies whether the value has to be an
|
115
114
|
# integer, e.g. an integral value (default is +false+).
|
116
115
|
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is
|
117
|
-
# +false+). Notice that for
|
116
|
+
# +false+). Notice that for fixnum and float columns empty strings are
|
118
117
|
# converted to +nil+.
|
119
118
|
# * <tt>:greater_than</tt> - Specifies the value must be greater than the
|
120
119
|
# supplied value.
|
@@ -115,7 +115,7 @@ module ActiveModel
|
|
115
115
|
key = "#{key.to_s.camelize}Validator"
|
116
116
|
|
117
117
|
begin
|
118
|
-
validator = key.include?('::') ? key.constantize : const_get(key)
|
118
|
+
validator = key.include?('::'.freeze) ? key.constantize : const_get(key)
|
119
119
|
rescue NameError
|
120
120
|
raise ArgumentError, "Unknown validator: '#{key}'"
|
121
121
|
end
|
@@ -1,15 +1,5 @@
|
|
1
1
|
module ActiveModel
|
2
2
|
module Validations
|
3
|
-
module HelperMethods
|
4
|
-
private
|
5
|
-
def _merge_attributes(attr_names)
|
6
|
-
options = attr_names.extract_options!.symbolize_keys
|
7
|
-
attr_names.flatten!
|
8
|
-
options[:attributes] = attr_names
|
9
|
-
options
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
3
|
class WithValidator < EachValidator # :nodoc:
|
14
4
|
def validate_each(record, attr, val)
|
15
5
|
method_name = options[:with]
|
@@ -15,7 +15,7 @@ module ActiveModel
|
|
15
15
|
# class MyValidator < ActiveModel::Validator
|
16
16
|
# def validate(record)
|
17
17
|
# if some_complex_logic
|
18
|
-
# record.errors
|
18
|
+
# record.errors.add(:base, "This record is invalid")
|
19
19
|
# end
|
20
20
|
# end
|
21
21
|
#
|
@@ -127,7 +127,7 @@ module ActiveModel
|
|
127
127
|
# in the options hash invoking the <tt>validate_each</tt> method passing in the
|
128
128
|
# record, attribute and value.
|
129
129
|
#
|
130
|
-
# All Active Model validations are built on top of this validator.
|
130
|
+
# All \Active \Model validations are built on top of this validator.
|
131
131
|
class EachValidator < Validator #:nodoc:
|
132
132
|
attr_reader :attributes
|
133
133
|
|
@@ -163,6 +163,10 @@ module ActiveModel
|
|
163
163
|
# +ArgumentError+ when invalid options are supplied.
|
164
164
|
def check_validity!
|
165
165
|
end
|
166
|
+
|
167
|
+
def should_validate?(record) # :nodoc:
|
168
|
+
!record.persisted? || record.changed? || record.marked_for_destruction?
|
169
|
+
end
|
166
170
|
end
|
167
171
|
|
168
172
|
# +BlockValidator+ is a special +EachValidator+ which receives a block on initialization
|
data/lib/active_model/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require_relative 'gem_version'
|
2
2
|
|
3
3
|
module ActiveModel
|
4
|
-
# Returns the version of the currently loaded
|
4
|
+
# Returns the version of the currently loaded \Active \Model as a <tt>Gem::Version</tt>
|
5
5
|
def self.version
|
6
6
|
gem_version
|
7
7
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activemodel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 5.0.0.beta1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 5.0.0.beta1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: builder
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,6 +50,7 @@ files:
|
|
50
50
|
- MIT-LICENSE
|
51
51
|
- README.rdoc
|
52
52
|
- lib/active_model.rb
|
53
|
+
- lib/active_model/attribute_assignment.rb
|
53
54
|
- lib/active_model/attribute_methods.rb
|
54
55
|
- lib/active_model/callbacks.rb
|
55
56
|
- lib/active_model/conversion.rb
|
@@ -65,9 +66,30 @@ files:
|
|
65
66
|
- lib/active_model/secure_password.rb
|
66
67
|
- lib/active_model/serialization.rb
|
67
68
|
- lib/active_model/serializers/json.rb
|
68
|
-
- lib/active_model/serializers/xml.rb
|
69
69
|
- lib/active_model/test_case.rb
|
70
70
|
- lib/active_model/translation.rb
|
71
|
+
- lib/active_model/type.rb
|
72
|
+
- lib/active_model/type/big_integer.rb
|
73
|
+
- lib/active_model/type/binary.rb
|
74
|
+
- lib/active_model/type/boolean.rb
|
75
|
+
- lib/active_model/type/date.rb
|
76
|
+
- lib/active_model/type/date_time.rb
|
77
|
+
- lib/active_model/type/decimal.rb
|
78
|
+
- lib/active_model/type/decimal_without_scale.rb
|
79
|
+
- lib/active_model/type/float.rb
|
80
|
+
- lib/active_model/type/helpers.rb
|
81
|
+
- lib/active_model/type/helpers/accepts_multiparameter_time.rb
|
82
|
+
- lib/active_model/type/helpers/mutable.rb
|
83
|
+
- lib/active_model/type/helpers/numeric.rb
|
84
|
+
- lib/active_model/type/helpers/time_value.rb
|
85
|
+
- lib/active_model/type/immutable_string.rb
|
86
|
+
- lib/active_model/type/integer.rb
|
87
|
+
- lib/active_model/type/registry.rb
|
88
|
+
- lib/active_model/type/string.rb
|
89
|
+
- lib/active_model/type/text.rb
|
90
|
+
- lib/active_model/type/time.rb
|
91
|
+
- lib/active_model/type/unsigned_integer.rb
|
92
|
+
- lib/active_model/type/value.rb
|
71
93
|
- lib/active_model/validations.rb
|
72
94
|
- lib/active_model/validations/absence.rb
|
73
95
|
- lib/active_model/validations/acceptance.rb
|
@@ -76,6 +98,7 @@ files:
|
|
76
98
|
- lib/active_model/validations/confirmation.rb
|
77
99
|
- lib/active_model/validations/exclusion.rb
|
78
100
|
- lib/active_model/validations/format.rb
|
101
|
+
- lib/active_model/validations/helper_methods.rb
|
79
102
|
- lib/active_model/validations/inclusion.rb
|
80
103
|
- lib/active_model/validations/length.rb
|
81
104
|
- lib/active_model/validations/numericality.rb
|
@@ -96,15 +119,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
119
|
requirements:
|
97
120
|
- - ">="
|
98
121
|
- !ruby/object:Gem::Version
|
99
|
-
version:
|
122
|
+
version: 2.2.2
|
100
123
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
124
|
requirements:
|
102
|
-
- - "
|
125
|
+
- - ">"
|
103
126
|
- !ruby/object:Gem::Version
|
104
|
-
version:
|
127
|
+
version: 1.3.1
|
105
128
|
requirements: []
|
106
|
-
|
129
|
+
rubyforge_project:
|
130
|
+
rubygems_version: 2.5.1
|
107
131
|
signing_key:
|
108
132
|
specification_version: 4
|
109
133
|
summary: A toolkit for building modeling frameworks (part of Rails).
|
110
134
|
test_files: []
|
135
|
+
has_rdoc:
|
@@ -1,238 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/module/attribute_accessors'
|
2
|
-
require 'active_support/core_ext/array/conversions'
|
3
|
-
require 'active_support/core_ext/hash/conversions'
|
4
|
-
require 'active_support/core_ext/hash/slice'
|
5
|
-
require 'active_support/core_ext/time/acts_like'
|
6
|
-
|
7
|
-
module ActiveModel
|
8
|
-
module Serializers
|
9
|
-
# == Active Model XML Serializer
|
10
|
-
module Xml
|
11
|
-
extend ActiveSupport::Concern
|
12
|
-
include ActiveModel::Serialization
|
13
|
-
|
14
|
-
included do
|
15
|
-
extend ActiveModel::Naming
|
16
|
-
end
|
17
|
-
|
18
|
-
class Serializer #:nodoc:
|
19
|
-
class Attribute #:nodoc:
|
20
|
-
attr_reader :name, :value, :type
|
21
|
-
|
22
|
-
def initialize(name, serializable, value)
|
23
|
-
@name, @serializable = name, serializable
|
24
|
-
|
25
|
-
if value.acts_like?(:time) && value.respond_to?(:in_time_zone)
|
26
|
-
value = value.in_time_zone
|
27
|
-
end
|
28
|
-
|
29
|
-
@value = value
|
30
|
-
@type = compute_type
|
31
|
-
end
|
32
|
-
|
33
|
-
def decorations
|
34
|
-
decorations = {}
|
35
|
-
decorations[:encoding] = 'base64' if type == :binary
|
36
|
-
decorations[:type] = (type == :string) ? nil : type
|
37
|
-
decorations[:nil] = true if value.nil?
|
38
|
-
decorations
|
39
|
-
end
|
40
|
-
|
41
|
-
protected
|
42
|
-
|
43
|
-
def compute_type
|
44
|
-
return if value.nil?
|
45
|
-
type = ActiveSupport::XmlMini::TYPE_NAMES[value.class.name]
|
46
|
-
type ||= :string if value.respond_to?(:to_str)
|
47
|
-
type ||= :yaml
|
48
|
-
type
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
class MethodAttribute < Attribute #:nodoc:
|
53
|
-
end
|
54
|
-
|
55
|
-
attr_reader :options
|
56
|
-
|
57
|
-
def initialize(serializable, options = nil)
|
58
|
-
@serializable = serializable
|
59
|
-
@options = options ? options.dup : {}
|
60
|
-
end
|
61
|
-
|
62
|
-
def serializable_hash
|
63
|
-
@serializable.serializable_hash(@options.except(:include))
|
64
|
-
end
|
65
|
-
|
66
|
-
def serializable_collection
|
67
|
-
methods = Array(options[:methods]).map(&:to_s)
|
68
|
-
serializable_hash.map do |name, value|
|
69
|
-
name = name.to_s
|
70
|
-
if methods.include?(name)
|
71
|
-
self.class::MethodAttribute.new(name, @serializable, value)
|
72
|
-
else
|
73
|
-
self.class::Attribute.new(name, @serializable, value)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def serialize
|
79
|
-
require 'builder' unless defined? ::Builder
|
80
|
-
|
81
|
-
options[:indent] ||= 2
|
82
|
-
options[:builder] ||= ::Builder::XmlMarkup.new(indent: options[:indent])
|
83
|
-
|
84
|
-
@builder = options[:builder]
|
85
|
-
@builder.instruct! unless options[:skip_instruct]
|
86
|
-
|
87
|
-
root = (options[:root] || @serializable.model_name.element).to_s
|
88
|
-
root = ActiveSupport::XmlMini.rename_key(root, options)
|
89
|
-
|
90
|
-
args = [root]
|
91
|
-
args << { xmlns: options[:namespace] } if options[:namespace]
|
92
|
-
args << { type: options[:type] } if options[:type] && !options[:skip_types]
|
93
|
-
|
94
|
-
@builder.tag!(*args) do
|
95
|
-
add_attributes_and_methods
|
96
|
-
add_includes
|
97
|
-
add_extra_behavior
|
98
|
-
add_procs
|
99
|
-
yield @builder if block_given?
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
private
|
104
|
-
|
105
|
-
def add_extra_behavior
|
106
|
-
end
|
107
|
-
|
108
|
-
def add_attributes_and_methods
|
109
|
-
serializable_collection.each do |attribute|
|
110
|
-
key = ActiveSupport::XmlMini.rename_key(attribute.name, options)
|
111
|
-
ActiveSupport::XmlMini.to_tag(key, attribute.value,
|
112
|
-
options.merge(attribute.decorations))
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def add_includes
|
117
|
-
@serializable.send(:serializable_add_includes, options) do |association, records, opts|
|
118
|
-
add_associations(association, records, opts)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
# TODO: This can likely be cleaned up to simple use ActiveSupport::XmlMini.to_tag as well.
|
123
|
-
def add_associations(association, records, opts)
|
124
|
-
merged_options = opts.merge(options.slice(:builder, :indent))
|
125
|
-
merged_options[:skip_instruct] = true
|
126
|
-
|
127
|
-
[:skip_types, :dasherize, :camelize].each do |key|
|
128
|
-
merged_options[key] = options[key] if merged_options[key].nil? && !options[key].nil?
|
129
|
-
end
|
130
|
-
|
131
|
-
if records.respond_to?(:to_ary)
|
132
|
-
records = records.to_ary
|
133
|
-
|
134
|
-
tag = ActiveSupport::XmlMini.rename_key(association.to_s, options)
|
135
|
-
type = options[:skip_types] ? { } : { type: "array" }
|
136
|
-
association_name = association.to_s.singularize
|
137
|
-
merged_options[:root] = association_name
|
138
|
-
|
139
|
-
if records.empty?
|
140
|
-
@builder.tag!(tag, type)
|
141
|
-
else
|
142
|
-
@builder.tag!(tag, type) do
|
143
|
-
records.each do |record|
|
144
|
-
if options[:skip_types]
|
145
|
-
record_type = {}
|
146
|
-
else
|
147
|
-
record_class = (record.class.to_s.underscore == association_name) ? nil : record.class.name
|
148
|
-
record_type = { type: record_class }
|
149
|
-
end
|
150
|
-
|
151
|
-
record.to_xml merged_options.merge(record_type)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
else
|
156
|
-
merged_options[:root] = association.to_s
|
157
|
-
|
158
|
-
unless records.class.to_s.underscore == association.to_s
|
159
|
-
merged_options[:type] = records.class.name
|
160
|
-
end
|
161
|
-
|
162
|
-
records.to_xml merged_options
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
def add_procs
|
167
|
-
if procs = options.delete(:procs)
|
168
|
-
Array(procs).each do |proc|
|
169
|
-
if proc.arity == 1
|
170
|
-
proc.call(options)
|
171
|
-
else
|
172
|
-
proc.call(options, @serializable)
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
# Returns XML representing the model. Configuration can be
|
180
|
-
# passed through +options+.
|
181
|
-
#
|
182
|
-
# Without any +options+, the returned XML string will include all the
|
183
|
-
# model's attributes.
|
184
|
-
#
|
185
|
-
# user = User.find(1)
|
186
|
-
# user.to_xml
|
187
|
-
#
|
188
|
-
# <?xml version="1.0" encoding="UTF-8"?>
|
189
|
-
# <user>
|
190
|
-
# <id type="integer">1</id>
|
191
|
-
# <name>David</name>
|
192
|
-
# <age type="integer">16</age>
|
193
|
-
# <created-at type="dateTime">2011-01-30T22:29:23Z</created-at>
|
194
|
-
# </user>
|
195
|
-
#
|
196
|
-
# The <tt>:only</tt> and <tt>:except</tt> options can be used to limit the
|
197
|
-
# attributes included, and work similar to the +attributes+ method.
|
198
|
-
#
|
199
|
-
# To include the result of some method calls on the model use <tt>:methods</tt>.
|
200
|
-
#
|
201
|
-
# To include associations use <tt>:include</tt>.
|
202
|
-
#
|
203
|
-
# For further documentation, see <tt>ActiveRecord::Serialization#to_xml</tt>
|
204
|
-
def to_xml(options = {}, &block)
|
205
|
-
Serializer.new(self, options).serialize(&block)
|
206
|
-
end
|
207
|
-
|
208
|
-
# Sets the model +attributes+ from an XML string. Returns +self+.
|
209
|
-
#
|
210
|
-
# class Person
|
211
|
-
# include ActiveModel::Serializers::Xml
|
212
|
-
#
|
213
|
-
# attr_accessor :name, :age, :awesome
|
214
|
-
#
|
215
|
-
# def attributes=(hash)
|
216
|
-
# hash.each do |key, value|
|
217
|
-
# instance_variable_set("@#{key}", value)
|
218
|
-
# end
|
219
|
-
# end
|
220
|
-
#
|
221
|
-
# def attributes
|
222
|
-
# instance_values
|
223
|
-
# end
|
224
|
-
# end
|
225
|
-
#
|
226
|
-
# xml = { name: 'bob', age: 22, awesome:true }.to_xml
|
227
|
-
# person = Person.new
|
228
|
-
# person.from_xml(xml) # => #<Person:0x007fec5e3b3c40 @age=22, @awesome=true, @name="bob">
|
229
|
-
# person.name # => "bob"
|
230
|
-
# person.age # => 22
|
231
|
-
# person.awesome # => true
|
232
|
-
def from_xml(xml)
|
233
|
-
self.attributes = Hash.from_xml(xml).values.first
|
234
|
-
self
|
235
|
-
end
|
236
|
-
end
|
237
|
-
end
|
238
|
-
end
|