activemodel 5.2.4.1 → 6.0.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +115 -66
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -2
- data/lib/active_model.rb +1 -1
- data/lib/active_model/attribute.rb +3 -4
- data/lib/active_model/attribute/user_provided_default.rb +1 -2
- data/lib/active_model/attribute_assignment.rb +1 -1
- data/lib/active_model/attribute_methods.rb +54 -15
- data/lib/active_model/attribute_mutation_tracker.rb +88 -34
- data/lib/active_model/attribute_set.rb +2 -10
- data/lib/active_model/attribute_set/builder.rb +1 -3
- data/lib/active_model/attribute_set/yaml_encoder.rb +1 -2
- data/lib/active_model/attributes.rb +60 -33
- data/lib/active_model/callbacks.rb +10 -7
- data/lib/active_model/conversion.rb +1 -1
- data/lib/active_model/dirty.rb +36 -99
- data/lib/active_model/errors.rb +104 -20
- data/lib/active_model/gem_version.rb +4 -4
- data/lib/active_model/naming.rb +19 -3
- data/lib/active_model/railtie.rb +6 -0
- data/lib/active_model/secure_password.rb +47 -48
- data/lib/active_model/serializers/json.rb +10 -9
- data/lib/active_model/type/binary.rb +1 -1
- data/lib/active_model/type/date.rb +0 -4
- data/lib/active_model/type/date_time.rb +3 -7
- data/lib/active_model/type/float.rb +0 -2
- data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +4 -0
- data/lib/active_model/type/helpers/numeric.rb +9 -2
- data/lib/active_model/type/helpers/time_value.rb +17 -4
- data/lib/active_model/type/integer.rb +7 -19
- data/lib/active_model/type/registry.rb +2 -10
- data/lib/active_model/type/string.rb +2 -2
- data/lib/active_model/type/time.rb +1 -5
- data/lib/active_model/validations.rb +0 -2
- data/lib/active_model/validations/acceptance.rb +33 -25
- data/lib/active_model/validations/clusivity.rb +1 -1
- data/lib/active_model/validations/confirmation.rb +2 -2
- data/lib/active_model/validations/inclusion.rb +1 -1
- data/lib/active_model/validations/length.rb +1 -1
- data/lib/active_model/validations/numericality.rb +2 -2
- data/lib/active_model/validations/validates.rb +2 -2
- data/lib/active_model/validator.rb +1 -1
- metadata +11 -8
@@ -13,10 +13,6 @@ module ActiveModel
|
|
13
13
|
:datetime
|
14
14
|
end
|
15
15
|
|
16
|
-
def serialize(value)
|
17
|
-
super(cast(value))
|
18
|
-
end
|
19
|
-
|
20
16
|
private
|
21
17
|
|
22
18
|
def cast_value(value)
|
@@ -40,9 +36,9 @@ module ActiveModel
|
|
40
36
|
end
|
41
37
|
|
42
38
|
def value_from_multiparameter_assignment(values_hash)
|
43
|
-
|
44
|
-
if
|
45
|
-
raise ArgumentError,
|
39
|
+
missing_parameters = (1..3).select { |key| !values_hash.key?(key) }
|
40
|
+
if missing_parameters.any?
|
41
|
+
raise ArgumentError, "Provided hash #{values_hash} doesn't contain necessary keys: #{missing_parameters}"
|
46
42
|
end
|
47
43
|
super
|
48
44
|
end
|
@@ -5,6 +5,10 @@ module ActiveModel
|
|
5
5
|
module Helpers # :nodoc: all
|
6
6
|
class AcceptsMultiparameterTime < Module
|
7
7
|
def initialize(defaults: {})
|
8
|
+
define_method(:serialize) do |value|
|
9
|
+
super(cast(value))
|
10
|
+
end
|
11
|
+
|
8
12
|
define_method(:cast) do |value|
|
9
13
|
if value.is_a?(Hash)
|
10
14
|
value_from_multiparameter_assignment(value)
|
@@ -4,6 +4,10 @@ module ActiveModel
|
|
4
4
|
module Type
|
5
5
|
module Helpers # :nodoc: all
|
6
6
|
module Numeric
|
7
|
+
def serialize(value)
|
8
|
+
cast(value)
|
9
|
+
end
|
10
|
+
|
7
11
|
def cast(value)
|
8
12
|
value = \
|
9
13
|
case value
|
@@ -22,15 +26,18 @@ module ActiveModel
|
|
22
26
|
private
|
23
27
|
|
24
28
|
def number_to_non_number?(old_value, new_value_before_type_cast)
|
25
|
-
old_value != nil && non_numeric_string?(new_value_before_type_cast)
|
29
|
+
old_value != nil && non_numeric_string?(new_value_before_type_cast.to_s)
|
26
30
|
end
|
27
31
|
|
28
32
|
def non_numeric_string?(value)
|
29
33
|
# 'wibble'.to_i will give zero, we want to make sure
|
30
34
|
# that we aren't marking int zero to string zero as
|
31
35
|
# changed.
|
32
|
-
|
36
|
+
!NUMERIC_REGEX.match?(value)
|
33
37
|
end
|
38
|
+
|
39
|
+
NUMERIC_REGEX = /\A\s*[+-]?\d/
|
40
|
+
private_constant :NUMERIC_REGEX
|
34
41
|
end
|
35
42
|
end
|
36
43
|
end
|
@@ -22,10 +22,17 @@ module ActiveModel
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def apply_seconds_precision(value)
|
25
|
-
return value unless precision && value.respond_to?(:
|
26
|
-
|
25
|
+
return value unless precision && value.respond_to?(:nsec)
|
26
|
+
|
27
|
+
number_of_insignificant_digits = 9 - precision
|
27
28
|
round_power = 10**number_of_insignificant_digits
|
28
|
-
|
29
|
+
rounded_off_nsec = value.nsec % round_power
|
30
|
+
|
31
|
+
if rounded_off_nsec > 0
|
32
|
+
value.change(nsec: value.nsec - rounded_off_nsec)
|
33
|
+
else
|
34
|
+
value
|
35
|
+
end
|
29
36
|
end
|
30
37
|
|
31
38
|
def type_cast_for_schema(value)
|
@@ -58,7 +65,13 @@ module ActiveModel
|
|
58
65
|
# Doesn't handle time zones.
|
59
66
|
def fast_string_to_time(string)
|
60
67
|
if string =~ ISO_DATETIME
|
61
|
-
|
68
|
+
microsec_part = $7
|
69
|
+
if microsec_part && microsec_part.start_with?(".") && microsec_part.length == 7
|
70
|
+
microsec_part[0] = ""
|
71
|
+
microsec = microsec_part.to_i
|
72
|
+
else
|
73
|
+
microsec = (microsec_part.to_r * 1_000_000).to_i
|
74
|
+
end
|
62
75
|
new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec
|
63
76
|
end
|
64
77
|
end
|
@@ -19,39 +19,27 @@ module ActiveModel
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def deserialize(value)
|
22
|
-
return if value.
|
22
|
+
return if value.blank?
|
23
23
|
value.to_i
|
24
24
|
end
|
25
25
|
|
26
26
|
def serialize(value)
|
27
|
-
|
28
|
-
|
29
|
-
ensure_in_range(result)
|
30
|
-
end
|
31
|
-
result
|
27
|
+
return if value.is_a?(::String) && non_numeric_string?(value)
|
28
|
+
ensure_in_range(super)
|
32
29
|
end
|
33
30
|
|
34
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
35
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
36
|
-
protected
|
37
|
-
|
38
|
-
attr_reader :range
|
39
|
-
|
40
31
|
private
|
32
|
+
attr_reader :range
|
41
33
|
|
42
34
|
def cast_value(value)
|
43
|
-
|
44
|
-
when true then 1
|
45
|
-
when false then 0
|
46
|
-
else
|
47
|
-
value.to_i rescue nil
|
48
|
-
end
|
35
|
+
value.to_i rescue nil
|
49
36
|
end
|
50
37
|
|
51
38
|
def ensure_in_range(value)
|
52
|
-
|
39
|
+
if value && !range.cover?(value)
|
53
40
|
raise ActiveModel::RangeError, "#{value} is out of range for #{self.class} with limit #{_limit} bytes"
|
54
41
|
end
|
42
|
+
value
|
55
43
|
end
|
56
44
|
|
57
45
|
def max_value
|
@@ -23,13 +23,8 @@ module ActiveModel
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
27
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
28
|
-
protected
|
29
|
-
|
30
|
-
attr_reader :registrations
|
31
|
-
|
32
26
|
private
|
27
|
+
attr_reader :registrations
|
33
28
|
|
34
29
|
def registration_klass
|
35
30
|
Registration
|
@@ -59,10 +54,7 @@ module ActiveModel
|
|
59
54
|
type_name == name
|
60
55
|
end
|
61
56
|
|
62
|
-
|
63
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
64
|
-
protected
|
65
|
-
|
57
|
+
private
|
66
58
|
attr_reader :name, :block
|
67
59
|
end
|
68
60
|
end
|
@@ -6,17 +6,13 @@ module ActiveModel
|
|
6
6
|
include Helpers::Timezone
|
7
7
|
include Helpers::TimeValue
|
8
8
|
include Helpers::AcceptsMultiparameterTime.new(
|
9
|
-
defaults: { 1 =>
|
9
|
+
defaults: { 1 => 2000, 2 => 1, 3 => 1, 4 => 0, 5 => 0 }
|
10
10
|
)
|
11
11
|
|
12
12
|
def type
|
13
13
|
:time
|
14
14
|
end
|
15
15
|
|
16
|
-
def serialize(value)
|
17
|
-
super(cast(value))
|
18
|
-
end
|
19
|
-
|
20
16
|
def user_input_in_time_zone(value)
|
21
17
|
return unless value.present?
|
22
18
|
|
@@ -17,7 +17,8 @@ module ActiveModel
|
|
17
17
|
private
|
18
18
|
|
19
19
|
def setup!(klass)
|
20
|
-
|
20
|
+
define_attributes = LazilyDefineAttributes.new(attributes)
|
21
|
+
klass.include(define_attributes) unless klass.included_modules.include?(define_attributes)
|
21
22
|
end
|
22
23
|
|
23
24
|
def acceptable_option?(value)
|
@@ -25,50 +26,57 @@ module ActiveModel
|
|
25
26
|
end
|
26
27
|
|
27
28
|
class LazilyDefineAttributes < Module
|
28
|
-
def initialize(
|
29
|
+
def initialize(attributes)
|
30
|
+
@attributes = attributes.map(&:to_s)
|
31
|
+
end
|
32
|
+
|
33
|
+
def included(klass)
|
34
|
+
@lock = Mutex.new
|
35
|
+
mod = self
|
36
|
+
|
29
37
|
define_method(:respond_to_missing?) do |method_name, include_private = false|
|
30
|
-
|
38
|
+
mod.define_on(klass)
|
39
|
+
super(method_name, include_private) || mod.matches?(method_name)
|
31
40
|
end
|
32
41
|
|
33
42
|
define_method(:method_missing) do |method_name, *args, &block|
|
34
|
-
|
35
|
-
|
43
|
+
mod.define_on(klass)
|
44
|
+
if mod.matches?(method_name)
|
36
45
|
send(method_name, *args, &block)
|
37
46
|
else
|
38
47
|
super(method_name, *args, &block)
|
39
48
|
end
|
40
49
|
end
|
41
50
|
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class AttributeDefinition
|
45
|
-
def initialize(attributes)
|
46
|
-
@attributes = attributes.map(&:to_s)
|
47
|
-
end
|
48
51
|
|
49
52
|
def matches?(method_name)
|
50
|
-
attr_name =
|
51
|
-
attributes.
|
53
|
+
attr_name = method_name.to_s.chomp("=")
|
54
|
+
attributes.any? { |name| name == attr_name }
|
52
55
|
end
|
53
56
|
|
54
57
|
def define_on(klass)
|
55
|
-
|
56
|
-
|
57
|
-
klass.send(:attr_reader, *attr_readers)
|
58
|
-
klass.send(:attr_writer, *attr_writers)
|
59
|
-
end
|
58
|
+
@lock&.synchronize do
|
59
|
+
return unless @lock
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
protected
|
61
|
+
attr_readers = attributes.reject { |name| klass.attribute_method?(name) }
|
62
|
+
attr_writers = attributes.reject { |name| klass.attribute_method?("#{name}=") }
|
64
63
|
|
65
|
-
|
64
|
+
attr_reader(*attr_readers)
|
65
|
+
attr_writer(*attr_writers)
|
66
66
|
|
67
|
-
|
67
|
+
remove_method :respond_to_missing?
|
68
|
+
remove_method :method_missing
|
68
69
|
|
69
|
-
|
70
|
-
method_name.to_s.chomp("=")
|
70
|
+
@lock = nil
|
71
71
|
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def ==(other)
|
75
|
+
self.class == other.class && attributes == other.attributes
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
attr_reader :attributes
|
72
80
|
end
|
73
81
|
end
|
74
82
|
|
@@ -32,7 +32,7 @@ module ActiveModel
|
|
32
32
|
@delimiter ||= options[:in] || options[:within]
|
33
33
|
end
|
34
34
|
|
35
|
-
#
|
35
|
+
# After Ruby 2.2, <tt>Range#include?</tt> on non-number-or-time-ish ranges checks all
|
36
36
|
# possible values in the range for equality, which is slower but more accurate.
|
37
37
|
# <tt>Range#cover?</tt> uses the previous logic of comparing a value with the range
|
38
38
|
# endpoints, which is fast but is only accurate on Numeric, Time, Date,
|
@@ -19,11 +19,11 @@ module ActiveModel
|
|
19
19
|
|
20
20
|
private
|
21
21
|
def setup!(klass)
|
22
|
-
klass.
|
22
|
+
klass.attr_reader(*attributes.map do |attribute|
|
23
23
|
:"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation")
|
24
24
|
end.compact)
|
25
25
|
|
26
|
-
klass.
|
26
|
+
klass.attr_writer(*attributes.map do |attribute|
|
27
27
|
:"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation=")
|
28
28
|
end.compact)
|
29
29
|
end
|
@@ -19,7 +19,7 @@ module ActiveModel
|
|
19
19
|
# particular enumerable object.
|
20
20
|
#
|
21
21
|
# class Person < ActiveRecord::Base
|
22
|
-
# validates_inclusion_of :
|
22
|
+
# validates_inclusion_of :role, in: %w( admin contributor )
|
23
23
|
# validates_inclusion_of :age, in: 0..99
|
24
24
|
# validates_inclusion_of :format, in: %w( jpg gif png ), message: "extension %{value} is not included in the list"
|
25
25
|
# validates_inclusion_of :states, in: ->(person) { STATES[person.country] }
|
@@ -32,7 +32,7 @@ module ActiveModel
|
|
32
32
|
value = options[key]
|
33
33
|
|
34
34
|
unless (value.is_a?(Integer) && value >= 0) || value == Float::INFINITY || value.is_a?(Symbol) || value.is_a?(Proc)
|
35
|
-
raise ArgumentError, ":#{key} must be a
|
35
|
+
raise ArgumentError, ":#{key} must be a non-negative Integer, Infinity, Symbol, or Proc"
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -99,11 +99,11 @@ module ActiveModel
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def is_integer?(raw_value)
|
102
|
-
INTEGER_REGEX
|
102
|
+
INTEGER_REGEX.match?(raw_value.to_s)
|
103
103
|
end
|
104
104
|
|
105
105
|
def is_hexadecimal_literal?(raw_value)
|
106
|
-
/\A0[xX]
|
106
|
+
/\A0[xX]/.match?(raw_value.to_s)
|
107
107
|
end
|
108
108
|
|
109
109
|
def filtered_options(value)
|
@@ -63,7 +63,7 @@ module ActiveModel
|
|
63
63
|
# and strings in shortcut form.
|
64
64
|
#
|
65
65
|
# validates :email, format: /@/
|
66
|
-
# validates :
|
66
|
+
# validates :role, inclusion: %(admin contributor)
|
67
67
|
# validates :password, length: 6..20
|
68
68
|
#
|
69
69
|
# When using shortcut form, ranges and arrays are passed to your
|
@@ -116,7 +116,7 @@ module ActiveModel
|
|
116
116
|
key = "#{key.to_s.camelize}Validator"
|
117
117
|
|
118
118
|
begin
|
119
|
-
validator = key.include?("::"
|
119
|
+
validator = key.include?("::") ? key.constantize : const_get(key)
|
120
120
|
rescue NameError
|
121
121
|
raise ArgumentError, "Unknown validator: '#{key}'"
|
122
122
|
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: 6.0.1
|
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: 2019-
|
11
|
+
date: 2019-11-05 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: 6.0.1
|
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: 6.0.1
|
27
27
|
description: A toolkit for building modeling frameworks like Active Record. Rich support
|
28
28
|
for attributes, callbacks, validations, serialization, internationalization, and
|
29
29
|
testing.
|
@@ -97,12 +97,15 @@ files:
|
|
97
97
|
- lib/active_model/validations/with.rb
|
98
98
|
- lib/active_model/validator.rb
|
99
99
|
- lib/active_model/version.rb
|
100
|
-
homepage:
|
100
|
+
homepage: https://rubyonrails.org
|
101
101
|
licenses:
|
102
102
|
- MIT
|
103
103
|
metadata:
|
104
|
-
|
105
|
-
changelog_uri: https://github.com/rails/rails/blob/
|
104
|
+
bug_tracker_uri: https://github.com/rails/rails/issues
|
105
|
+
changelog_uri: https://github.com/rails/rails/blob/v6.0.1/activemodel/CHANGELOG.md
|
106
|
+
documentation_uri: https://api.rubyonrails.org/v6.0.1/
|
107
|
+
mailing_list_uri: https://groups.google.com/forum/#!forum/rubyonrails-talk
|
108
|
+
source_code_uri: https://github.com/rails/rails/tree/v6.0.1/activemodel
|
106
109
|
post_install_message:
|
107
110
|
rdoc_options: []
|
108
111
|
require_paths:
|
@@ -111,7 +114,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
111
114
|
requirements:
|
112
115
|
- - ">="
|
113
116
|
- !ruby/object:Gem::Version
|
114
|
-
version: 2.
|
117
|
+
version: 2.5.0
|
115
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
119
|
requirements:
|
117
120
|
- - ">="
|