activemodel 7.0.3.1 → 6.1.7.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 +103 -84
- data/MIT-LICENSE +0 -1
- data/README.rdoc +3 -3
- data/lib/active_model/attribute.rb +0 -4
- data/lib/active_model/attribute_methods.rb +82 -67
- data/lib/active_model/attribute_set/builder.rb +10 -1
- data/lib/active_model/attribute_set.rb +1 -4
- data/lib/active_model/attributes.rb +12 -15
- data/lib/active_model/callbacks.rb +3 -3
- data/lib/active_model/conversion.rb +2 -2
- data/lib/active_model/dirty.rb +4 -5
- data/lib/active_model/error.rb +2 -2
- data/lib/active_model/errors.rb +248 -55
- data/lib/active_model/gem_version.rb +4 -4
- data/lib/active_model/locale/en.yml +0 -1
- data/lib/active_model/model.rb +59 -6
- data/lib/active_model/naming.rb +8 -15
- data/lib/active_model/secure_password.rb +1 -1
- data/lib/active_model/serialization.rb +2 -6
- data/lib/active_model/translation.rb +2 -2
- data/lib/active_model/type/date.rb +1 -1
- data/lib/active_model/type/helpers/numeric.rb +1 -9
- data/lib/active_model/type/helpers/time_value.rb +3 -3
- data/lib/active_model/type/integer.rb +1 -4
- data/lib/active_model/type/registry.rb +38 -8
- data/lib/active_model/type/time.rb +1 -1
- data/lib/active_model/type.rb +6 -6
- data/lib/active_model/validations/absence.rb +2 -2
- data/lib/active_model/validations/acceptance.rb +1 -1
- data/lib/active_model/validations/callbacks.rb +1 -1
- data/lib/active_model/validations/clusivity.rb +1 -1
- data/lib/active_model/validations/confirmation.rb +5 -5
- data/lib/active_model/validations/exclusion.rb +3 -3
- data/lib/active_model/validations/format.rb +1 -1
- data/lib/active_model/validations/inclusion.rb +3 -3
- data/lib/active_model/validations/length.rb +2 -2
- data/lib/active_model/validations/numericality.rb +22 -29
- data/lib/active_model/validations/presence.rb +1 -1
- data/lib/active_model/validations/validates.rb +3 -3
- data/lib/active_model/validations/with.rb +4 -4
- data/lib/active_model/validations.rb +12 -12
- data/lib/active_model/validator.rb +5 -5
- data/lib/active_model/version.rb +1 -1
- data/lib/active_model.rb +0 -1
- metadata +9 -12
- data/lib/active_model/api.rb +0 -99
- data/lib/active_model/validations/comparability.rb +0 -29
- data/lib/active_model/validations/comparison.rb +0 -82
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d2706dba9ce622452b7e50ce891f67af2eb27717b37ed0279148ad064ef1c6ce
|
4
|
+
data.tar.gz: 16856f088c941213ab4647ec5041995c8eaadf1ff230e76a98eb4ddd34ce0856
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b234b3e5a18c9831af5d029ee72d91481c4a82f539f4184ca9d274c0d3d13529e8fa3e71ac34a2caaa614b74db98da21432914e2d04212a9232b61b6e585ee7
|
7
|
+
data.tar.gz: 10c2d8a7571fa6340749ccfef90e1f54b423a6f1c259adf6961c0043ccfea04e5400e7f76b733e8d0a0f4d81dfe3c233895aeddc444a28cd87fa01a4ec6e1894
|
data/CHANGELOG.md
CHANGED
@@ -1,188 +1,207 @@
|
|
1
|
-
## Rails
|
1
|
+
## Rails 6.1.7.1 (January 17, 2023) ##
|
2
2
|
|
3
3
|
* No changes.
|
4
4
|
|
5
5
|
|
6
|
-
## Rails
|
6
|
+
## Rails 6.1.7 (September 09, 2022) ##
|
7
7
|
|
8
8
|
* No changes.
|
9
9
|
|
10
10
|
|
11
|
-
## Rails
|
11
|
+
## Rails 6.1.6.1 (July 12, 2022) ##
|
12
12
|
|
13
13
|
* No changes.
|
14
14
|
|
15
15
|
|
16
|
-
## Rails
|
16
|
+
## Rails 6.1.6 (May 09, 2022) ##
|
17
17
|
|
18
18
|
* No changes.
|
19
19
|
|
20
20
|
|
21
|
-
## Rails
|
21
|
+
## Rails 6.1.5.1 (April 26, 2022) ##
|
22
22
|
|
23
23
|
* No changes.
|
24
24
|
|
25
25
|
|
26
|
-
## Rails
|
26
|
+
## Rails 6.1.5 (March 09, 2022) ##
|
27
27
|
|
28
|
-
*
|
28
|
+
* Clear secure password cache if password is set to `nil`
|
29
29
|
|
30
|
+
Before:
|
30
31
|
|
31
|
-
|
32
|
+
user.password = 'something'
|
33
|
+
user.password = nil
|
32
34
|
|
33
|
-
|
35
|
+
user.password # => 'something'
|
34
36
|
|
35
|
-
|
36
|
-
names, leading to conflicts. Adding a new namespace `:active_model_proxy`
|
37
|
-
fixes the issue.
|
37
|
+
Now:
|
38
38
|
|
39
|
-
|
39
|
+
user.password = 'something'
|
40
|
+
user.password = nil
|
40
41
|
|
42
|
+
user.password # => nil
|
41
43
|
|
42
|
-
|
44
|
+
*Markus Doits*
|
43
45
|
|
44
|
-
*
|
46
|
+
* Fix delegation in `ActiveModel::Type::Registry#lookup` and `ActiveModel::Type.lookup`
|
45
47
|
|
48
|
+
Passing a last positional argument `{}` would be incorrectly considered as keyword argument.
|
46
49
|
|
47
|
-
|
50
|
+
*Benoit Daloze*
|
48
51
|
|
49
|
-
*
|
52
|
+
* Fix `to_json` after `changes_applied` for `ActiveModel::Dirty` object.
|
50
53
|
|
54
|
+
*Ryuta Kamizono*
|
51
55
|
|
52
|
-
|
56
|
+
|
57
|
+
## Rails 6.1.4.7 (March 08, 2022) ##
|
53
58
|
|
54
59
|
* No changes.
|
55
60
|
|
56
61
|
|
57
|
-
## Rails
|
62
|
+
## Rails 6.1.4.6 (February 11, 2022) ##
|
58
63
|
|
59
64
|
* No changes.
|
60
65
|
|
61
|
-
## Rails 7.0.0.rc1 (December 06, 2021) ##
|
62
66
|
|
63
|
-
|
67
|
+
## Rails 6.1.4.5 (February 11, 2022) ##
|
64
68
|
|
65
|
-
|
69
|
+
* No changes.
|
66
70
|
|
67
|
-
* Remove support to Marshal and YAML load Rails 5.x error format.
|
68
71
|
|
69
|
-
|
72
|
+
## Rails 6.1.4.4 (December 15, 2021) ##
|
70
73
|
|
71
|
-
*
|
74
|
+
* No changes.
|
72
75
|
|
73
|
-
*Rafael Mendonça França*
|
74
76
|
|
75
|
-
|
77
|
+
## Rails 6.1.4.3 (December 14, 2021) ##
|
76
78
|
|
77
|
-
|
79
|
+
* No changes.
|
78
80
|
|
79
|
-
* Remove deprecated support to `clear` errors from `ActiveModel::Errors#messages`.
|
80
81
|
|
81
|
-
|
82
|
+
## Rails 6.1.4.2 (December 14, 2021) ##
|
82
83
|
|
83
|
-
*
|
84
|
+
* No changes.
|
84
85
|
|
85
|
-
*Rafael Mendonça França*
|
86
86
|
|
87
|
-
|
87
|
+
## Rails 6.1.4.1 (August 19, 2021) ##
|
88
88
|
|
89
|
-
|
89
|
+
* No changes.
|
90
90
|
|
91
|
-
* Remove deprecated `ActiveModel::Errors#keys`.
|
92
91
|
|
93
|
-
|
92
|
+
## Rails 6.1.4 (June 24, 2021) ##
|
94
93
|
|
95
|
-
*
|
94
|
+
* Fix `to_json` for `ActiveModel::Dirty` object.
|
96
95
|
|
97
|
-
|
96
|
+
Exclude +mutations_from_database+ attribute from json as it lead to recursion.
|
98
97
|
|
99
|
-
*
|
98
|
+
*Anil Maurya*
|
100
99
|
|
101
|
-
*Rafael Mendonça França*
|
102
100
|
|
103
|
-
|
101
|
+
## Rails 6.1.3.2 (May 05, 2021) ##
|
104
102
|
|
105
|
-
|
103
|
+
* No changes.
|
106
104
|
|
107
|
-
* Remove deprecated enumeration of `ActiveModel::Errors` instances as a Hash.
|
108
105
|
|
109
|
-
|
106
|
+
## Rails 6.1.3.1 (March 26, 2021) ##
|
110
107
|
|
111
|
-
*
|
108
|
+
* No changes.
|
112
109
|
|
113
|
-
Before:
|
114
110
|
|
115
|
-
|
116
|
-
user.password = nil
|
111
|
+
## Rails 6.1.3 (February 17, 2021) ##
|
117
112
|
|
118
|
-
|
113
|
+
* No changes.
|
119
114
|
|
120
|
-
Now:
|
121
115
|
|
122
|
-
|
123
|
-
user.password = nil
|
116
|
+
## Rails 6.1.2.1 (February 10, 2021) ##
|
124
117
|
|
125
|
-
|
118
|
+
* No changes.
|
126
119
|
|
127
|
-
*Markus Doits*
|
128
120
|
|
129
|
-
## Rails
|
121
|
+
## Rails 6.1.2 (February 09, 2021) ##
|
130
122
|
|
131
123
|
* No changes.
|
132
124
|
|
133
125
|
|
134
|
-
## Rails
|
126
|
+
## Rails 6.1.1 (January 07, 2021) ##
|
135
127
|
|
136
|
-
*
|
128
|
+
* No changes.
|
137
129
|
|
138
|
-
Make `ActiveModel::API` the minimum API to talk with Action Pack and Action View.
|
139
|
-
This will allow adding more functionality to `ActiveModel::Model`.
|
140
130
|
|
141
|
-
|
131
|
+
## Rails 6.1.0 (December 09, 2020) ##
|
142
132
|
|
143
|
-
*
|
133
|
+
* Pass in `base` instead of `base_class` to Error.human_attribute_name
|
144
134
|
|
145
|
-
|
146
|
-
|
135
|
+
This is useful in cases where the `human_attribute_name` method depends
|
136
|
+
on other attributes' values of the class under validation to derive what the
|
137
|
+
attribute name should be.
|
147
138
|
|
148
|
-
*
|
139
|
+
*Filipe Sabella*
|
149
140
|
|
150
|
-
*
|
141
|
+
* Deprecate marshalling load from legacy attributes format.
|
151
142
|
|
152
|
-
|
143
|
+
*Ryuta Kamizono*
|
153
144
|
|
154
|
-
|
145
|
+
* `*_previously_changed?` accepts `:from` and `:to` keyword arguments like `*_changed?`.
|
155
146
|
|
156
|
-
|
147
|
+
topic.update!(status: :archived)
|
148
|
+
topic.status_previously_changed?(from: "active", to: "archived")
|
149
|
+
# => true
|
157
150
|
|
158
|
-
|
151
|
+
*George Claghorn*
|
159
152
|
|
160
|
-
|
153
|
+
* Raise FrozenError when trying to write attributes that aren't backed by the database on an object that is frozen:
|
161
154
|
|
162
|
-
|
155
|
+
class Animal
|
156
|
+
include ActiveModel::Attributes
|
157
|
+
attribute :age
|
158
|
+
end
|
163
159
|
|
164
|
-
|
160
|
+
animal = Animal.new
|
161
|
+
animal.freeze
|
162
|
+
animal.age = 25 # => FrozenError, "can't modify a frozen Animal"
|
165
163
|
|
166
|
-
*
|
164
|
+
*Josh Brody*
|
165
|
+
|
166
|
+
* Add `*_previously_was` attribute methods when dirty tracking. Example:
|
167
167
|
|
168
|
-
|
168
|
+
pirate.update(catchphrase: "Ahoy!")
|
169
|
+
pirate.previous_changes["catchphrase"] # => ["Thar She Blows!", "Ahoy!"]
|
170
|
+
pirate.catchphrase_previously_was # => "Thar She Blows!"
|
169
171
|
|
170
|
-
|
171
|
-
leading to reduced memory retention, and slightly faster load time.
|
172
|
+
*DHH*
|
172
173
|
|
173
|
-
|
174
|
+
* Encapsulate each validation error as an Error object.
|
174
175
|
|
175
|
-
|
176
|
+
The `ActiveModel`’s `errors` collection is now an array of these Error
|
177
|
+
objects, instead of messages/details hash.
|
176
178
|
|
177
|
-
|
179
|
+
For each of these `Error` object, its `message` and `full_message` methods
|
180
|
+
are for generating error messages. Its `details` method would return error’s
|
181
|
+
extra parameters, found in the original `details` hash.
|
178
182
|
|
179
|
-
|
180
|
-
|
183
|
+
The change tries its best at maintaining backward compatibility, however
|
184
|
+
some edge cases won’t be covered, like `errors#first` will return `ActiveModel::Error` and manipulating
|
185
|
+
`errors.messages` and `errors.details` hashes directly will have no effect. Moving forward,
|
186
|
+
please convert those direct manipulations to use provided API methods instead.
|
187
|
+
Please note that `errors#add` now accepts `options` as keyword arguments instead of `Hash` which
|
188
|
+
introduced a change in Ruby 3 to [keyword arguments][kwargs-ann].
|
181
189
|
|
182
|
-
|
190
|
+
[kwargs-ann]: https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/
|
183
191
|
|
184
|
-
|
192
|
+
The list of deprecated methods and their planned future behavioral changes at the next major release are:
|
193
|
+
|
194
|
+
* `errors#slice!` will be removed.
|
195
|
+
* `errors#each` with the `key, value` two-arguments block will stop working, while the `error` single-argument block would return `Error` object.
|
196
|
+
* `errors#values` will be removed.
|
197
|
+
* `errors#keys` will be removed.
|
198
|
+
* `errors#to_xml` will be removed.
|
199
|
+
* `errors#to_h` will be removed, and can be replaced with `errors#to_hash`.
|
200
|
+
* Manipulating `errors` itself as a hash will have no effect (e.g. `errors[:foo] = 'bar'`).
|
201
|
+
* Manipulating the hash returned by `errors#messages` (e.g. `errors.messages[:foo] = 'bar'`) will have no effect.
|
202
|
+
* Manipulating the hash returned by `errors#details` (e.g. `errors.details[:foo].clear`) will have no effect.
|
185
203
|
|
186
204
|
*lulalala*
|
187
205
|
|
188
|
-
|
206
|
+
|
207
|
+
Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/activemodel/CHANGELOG.md) for previous changes.
|
data/MIT-LICENSE
CHANGED
@@ -18,4 +18,3 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
18
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
19
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
20
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
-
|
data/README.rdoc
CHANGED
@@ -16,10 +16,10 @@ Model solves this by defining an explicit API. You can read more about the
|
|
16
16
|
API in <tt>ActiveModel::Lint::Tests</tt>.
|
17
17
|
|
18
18
|
Active Model provides a default module that implements the basic API required
|
19
|
-
to integrate with Action Pack out of the box: <tt>ActiveModel::
|
19
|
+
to integrate with Action Pack out of the box: <tt>ActiveModel::Model</tt>.
|
20
20
|
|
21
21
|
class Person
|
22
|
-
include ActiveModel::
|
22
|
+
include ActiveModel::Model
|
23
23
|
|
24
24
|
attr_accessor :name, :age
|
25
25
|
validates_presence_of :name
|
@@ -32,7 +32,7 @@ to integrate with Action Pack out of the box: <tt>ActiveModel::API</tt>.
|
|
32
32
|
|
33
33
|
It includes model name introspections, conversions, translations and
|
34
34
|
validations, resulting in a class suitable to be used with Action Pack.
|
35
|
-
See <tt>ActiveModel::
|
35
|
+
See <tt>ActiveModel::Model</tt> for more examples.
|
36
36
|
|
37
37
|
Active Model also provides the following functionality to have ORM-like
|
38
38
|
behavior out of the box:
|
@@ -67,7 +67,6 @@ module ActiveModel
|
|
67
67
|
|
68
68
|
NAME_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?=]?\z/
|
69
69
|
CALL_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
|
70
|
-
FORWARD_PARAMETERS = "*args"
|
71
70
|
|
72
71
|
included do
|
73
72
|
class_attribute :attribute_aliases, instance_writer: false, default: {}
|
@@ -106,8 +105,8 @@ module ActiveModel
|
|
106
105
|
# person.name # => "Bob"
|
107
106
|
# person.clear_name
|
108
107
|
# person.name # => nil
|
109
|
-
def attribute_method_prefix(*prefixes
|
110
|
-
self.attribute_method_matchers += prefixes.map! { |prefix| AttributeMethodMatcher.new
|
108
|
+
def attribute_method_prefix(*prefixes)
|
109
|
+
self.attribute_method_matchers += prefixes.map! { |prefix| AttributeMethodMatcher.new prefix: prefix }
|
111
110
|
undefine_attribute_methods
|
112
111
|
end
|
113
112
|
|
@@ -141,8 +140,8 @@ module ActiveModel
|
|
141
140
|
# person.name = 'Bob'
|
142
141
|
# person.name # => "Bob"
|
143
142
|
# person.name_short? # => true
|
144
|
-
def attribute_method_suffix(*suffixes
|
145
|
-
self.attribute_method_matchers += suffixes.map! { |suffix| AttributeMethodMatcher.new
|
143
|
+
def attribute_method_suffix(*suffixes)
|
144
|
+
self.attribute_method_matchers += suffixes.map! { |suffix| AttributeMethodMatcher.new suffix: suffix }
|
146
145
|
undefine_attribute_methods
|
147
146
|
end
|
148
147
|
|
@@ -178,7 +177,7 @@ module ActiveModel
|
|
178
177
|
# person.reset_name_to_default!
|
179
178
|
# person.name # => 'Default Name'
|
180
179
|
def attribute_method_affix(*affixes)
|
181
|
-
self.attribute_method_matchers += affixes.map! { |affix| AttributeMethodMatcher.new
|
180
|
+
self.attribute_method_matchers += affixes.map! { |affix| AttributeMethodMatcher.new prefix: affix[:prefix], suffix: affix[:suffix] }
|
182
181
|
undefine_attribute_methods
|
183
182
|
end
|
184
183
|
|
@@ -208,33 +207,11 @@ module ActiveModel
|
|
208
207
|
# person.nickname_short? # => true
|
209
208
|
def alias_attribute(new_name, old_name)
|
210
209
|
self.attribute_aliases = attribute_aliases.merge(new_name.to_s => old_name.to_s)
|
211
|
-
|
210
|
+
CodeGenerator.batch(self, __FILE__, __LINE__) do |owner|
|
212
211
|
attribute_method_matchers.each do |matcher|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
mangled_name = target_name
|
218
|
-
unless NAME_COMPILABLE_REGEXP.match?(target_name)
|
219
|
-
mangled_name = "__temp__#{target_name.unpack1("h*")}"
|
220
|
-
end
|
221
|
-
|
222
|
-
code_generator.define_cached_method(method_name, as: mangled_name, namespace: :alias_attribute) do |batch|
|
223
|
-
body = if CALL_COMPILABLE_REGEXP.match?(target_name)
|
224
|
-
"self.#{target_name}(#{parameters || ''})"
|
225
|
-
else
|
226
|
-
call_args = [":'#{target_name}'"]
|
227
|
-
call_args << parameters if parameters
|
228
|
-
"send(#{call_args.join(", ")})"
|
229
|
-
end
|
230
|
-
|
231
|
-
modifier = matcher.parameters == FORWARD_PARAMETERS ? "ruby2_keywords " : ""
|
232
|
-
|
233
|
-
batch <<
|
234
|
-
"#{modifier}def #{mangled_name}(#{parameters || ''})" <<
|
235
|
-
body <<
|
236
|
-
"end"
|
237
|
-
end
|
212
|
+
matcher_new = matcher.method_name(new_name).to_s
|
213
|
+
matcher_old = matcher.method_name(old_name).to_s
|
214
|
+
define_proxy_call false, owner, matcher_new, matcher_old
|
238
215
|
end
|
239
216
|
end
|
240
217
|
end
|
@@ -253,7 +230,7 @@ module ActiveModel
|
|
253
230
|
# <tt>ActiveModel::AttributeMethods</tt>.
|
254
231
|
#
|
255
232
|
# To use, pass attribute names (as strings or symbols). Be sure to declare
|
256
|
-
# +define_attribute_methods+ after you define any prefix, suffix
|
233
|
+
# +define_attribute_methods+ after you define any prefix, suffix or affix
|
257
234
|
# methods, or they will not hook in.
|
258
235
|
#
|
259
236
|
# class Person
|
@@ -274,7 +251,7 @@ module ActiveModel
|
|
274
251
|
# end
|
275
252
|
# end
|
276
253
|
def define_attribute_methods(*attr_names)
|
277
|
-
|
254
|
+
CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
|
278
255
|
attr_names.flatten.each { |attr_name| define_attribute_method(attr_name, _owner: owner) }
|
279
256
|
end
|
280
257
|
end
|
@@ -309,7 +286,7 @@ module ActiveModel
|
|
309
286
|
# person.name # => "Bob"
|
310
287
|
# person.name_short? # => true
|
311
288
|
def define_attribute_method(attr_name, _owner: generated_attribute_methods)
|
312
|
-
|
289
|
+
CodeGenerator.batch(_owner, __FILE__, __LINE__) do |owner|
|
313
290
|
attribute_method_matchers.each do |matcher|
|
314
291
|
method_name = matcher.method_name(attr_name)
|
315
292
|
|
@@ -319,7 +296,7 @@ module ActiveModel
|
|
319
296
|
if respond_to?(generate_method, true)
|
320
297
|
send(generate_method, attr_name.to_s, owner: owner)
|
321
298
|
else
|
322
|
-
define_proxy_call
|
299
|
+
define_proxy_call true, owner, method_name, matcher.target, attr_name.to_s
|
323
300
|
end
|
324
301
|
end
|
325
302
|
end
|
@@ -358,6 +335,46 @@ module ActiveModel
|
|
358
335
|
end
|
359
336
|
|
360
337
|
private
|
338
|
+
class CodeGenerator
|
339
|
+
class << self
|
340
|
+
def batch(owner, path, line)
|
341
|
+
if owner.is_a?(CodeGenerator)
|
342
|
+
yield owner
|
343
|
+
else
|
344
|
+
instance = new(owner, path, line)
|
345
|
+
result = yield instance
|
346
|
+
instance.execute
|
347
|
+
result
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
def initialize(owner, path, line)
|
353
|
+
@owner = owner
|
354
|
+
@path = path
|
355
|
+
@line = line
|
356
|
+
@sources = ["# frozen_string_literal: true\n"]
|
357
|
+
@renames = {}
|
358
|
+
end
|
359
|
+
|
360
|
+
def <<(source_line)
|
361
|
+
@sources << source_line
|
362
|
+
end
|
363
|
+
|
364
|
+
def rename_method(old_name, new_name)
|
365
|
+
@renames[old_name] = new_name
|
366
|
+
end
|
367
|
+
|
368
|
+
def execute
|
369
|
+
@owner.module_eval(@sources.join(";"), @path, @line - 1)
|
370
|
+
@renames.each do |old_name, new_name|
|
371
|
+
@owner.alias_method new_name, old_name
|
372
|
+
@owner.undef_method old_name
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
private_constant :CodeGenerator
|
377
|
+
|
361
378
|
def generated_attribute_methods
|
362
379
|
@generated_attribute_methods ||= Module.new.tap { |mod| include mod }
|
363
380
|
end
|
@@ -381,48 +398,42 @@ module ActiveModel
|
|
381
398
|
|
382
399
|
def attribute_method_matchers_matching(method_name)
|
383
400
|
attribute_method_matchers_cache.compute_if_absent(method_name) do
|
384
|
-
attribute_method_matchers.
|
401
|
+
attribute_method_matchers.map { |matcher| matcher.match(method_name) }.compact
|
385
402
|
end
|
386
403
|
end
|
387
404
|
|
388
405
|
# Define a method `name` in `mod` that dispatches to `send`
|
389
|
-
# using the given `extra` args. This falls back on `
|
390
|
-
# if the
|
391
|
-
def define_proxy_call(code_generator, name, target,
|
392
|
-
|
393
|
-
|
394
|
-
|
406
|
+
# using the given `extra` args. This falls back on `define_method`
|
407
|
+
# and `send` if the given names cannot be compiled.
|
408
|
+
def define_proxy_call(include_private, code_generator, name, target, *extra)
|
409
|
+
defn = if NAME_COMPILABLE_REGEXP.match?(name)
|
410
|
+
"def #{name}(*args)"
|
411
|
+
else
|
412
|
+
"define_method(:'#{name}') do |*args|"
|
395
413
|
end
|
396
414
|
|
397
|
-
|
398
|
-
call_args.map!(&:inspect)
|
399
|
-
call_args << parameters if parameters
|
400
|
-
|
401
|
-
body = if CALL_COMPILABLE_REGEXP.match?(target)
|
402
|
-
"self.#{target}(#{call_args.join(", ")})"
|
403
|
-
else
|
404
|
-
call_args.unshift(":'#{target}'")
|
405
|
-
"send(#{call_args.join(", ")})"
|
406
|
-
end
|
415
|
+
extra = (extra.map!(&:inspect) << "*args").join(", ")
|
407
416
|
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
body <<
|
413
|
-
"end"
|
417
|
+
body = if CALL_COMPILABLE_REGEXP.match?(target)
|
418
|
+
"#{"self." unless include_private}#{target}(#{extra})"
|
419
|
+
else
|
420
|
+
"send(:'#{target}', #{extra})"
|
414
421
|
end
|
422
|
+
|
423
|
+
code_generator <<
|
424
|
+
defn <<
|
425
|
+
body <<
|
426
|
+
"end" <<
|
427
|
+
"ruby2_keywords(:'#{name}') if respond_to?(:ruby2_keywords, true)"
|
415
428
|
end
|
416
429
|
|
417
|
-
class AttributeMethodMatcher
|
418
|
-
attr_reader :prefix, :suffix, :target
|
430
|
+
class AttributeMethodMatcher #:nodoc:
|
431
|
+
attr_reader :prefix, :suffix, :target
|
419
432
|
|
420
433
|
AttributeMethodMatch = Struct.new(:target, :attr_name)
|
421
434
|
|
422
|
-
def initialize(
|
423
|
-
@prefix = prefix
|
424
|
-
@suffix = suffix
|
425
|
-
@parameters = parameters.nil? ? FORWARD_PARAMETERS : parameters
|
435
|
+
def initialize(options = {})
|
436
|
+
@prefix, @suffix = options.fetch(:prefix, ""), options.fetch(:suffix, "")
|
426
437
|
@regex = /^(?:#{Regexp.escape(@prefix)})(.*)(?:#{Regexp.escape(@suffix)})$/
|
427
438
|
@target = "#{@prefix}attribute#{@suffix}"
|
428
439
|
@method_name = "#{prefix}%s#{suffix}"
|
@@ -458,7 +469,7 @@ module ActiveModel
|
|
458
469
|
match ? attribute_missing(match, *args, &block) : super
|
459
470
|
end
|
460
471
|
end
|
461
|
-
ruby2_keywords(:method_missing)
|
472
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
462
473
|
|
463
474
|
# +attribute_missing+ is like +method_missing+, but for attributes. When
|
464
475
|
# +method_missing+ is called we check to see if there is a matching
|
@@ -467,7 +478,6 @@ module ActiveModel
|
|
467
478
|
def attribute_missing(match, *args, &block)
|
468
479
|
__send__(match.target, match.attr_name, *args, &block)
|
469
480
|
end
|
470
|
-
ruby2_keywords(:attribute_missing)
|
471
481
|
|
472
482
|
# A +Person+ instance with a +name+ attribute can ask
|
473
483
|
# <tt>person.respond_to?(:name)</tt>, <tt>person.respond_to?(:name=)</tt>,
|
@@ -510,6 +520,10 @@ module ActiveModel
|
|
510
520
|
|
511
521
|
# We want to generate the methods via module_eval rather than
|
512
522
|
# define_method, because define_method is slower on dispatch.
|
523
|
+
# Evaluating many similar methods may use more memory as the instruction
|
524
|
+
# sequences are duplicated and cached (in MRI). define_method may
|
525
|
+
# be slower on dispatch, but if you're careful about the closure
|
526
|
+
# created, then define_method will consume much less memory.
|
513
527
|
#
|
514
528
|
# But sometimes the database might return columns with
|
515
529
|
# characters that are not allowed in normal method names (like
|
@@ -533,6 +547,7 @@ module ActiveModel
|
|
533
547
|
temp_method_name = "__temp__#{safe_name}#{'=' if writer}"
|
534
548
|
attr_name_expr = "::ActiveModel::AttributeMethods::AttrNames::#{const_name}"
|
535
549
|
yield temp_method_name, attr_name_expr
|
550
|
+
owner.rename_method(temp_method_name, method_name)
|
536
551
|
end
|
537
552
|
end
|
538
553
|
end
|
@@ -144,7 +144,16 @@ module ActiveModel
|
|
144
144
|
end
|
145
145
|
|
146
146
|
def marshal_load(values)
|
147
|
-
|
147
|
+
if values.is_a?(Hash)
|
148
|
+
ActiveSupport::Deprecation.warn(<<~MSG)
|
149
|
+
Marshalling load from legacy attributes format is deprecated and will be removed in Rails 7.0.
|
150
|
+
MSG
|
151
|
+
empty_hash = {}.freeze
|
152
|
+
initialize(empty_hash, empty_hash, empty_hash, empty_hash, values)
|
153
|
+
@materialized = true
|
154
|
+
else
|
155
|
+
initialize(*values)
|
156
|
+
end
|
148
157
|
end
|
149
158
|
|
150
159
|
protected
|
@@ -25,10 +25,6 @@ module ActiveModel
|
|
25
25
|
attributes.transform_values(&:value_before_type_cast)
|
26
26
|
end
|
27
27
|
|
28
|
-
def values_for_database
|
29
|
-
attributes.transform_values(&:value_for_database)
|
30
|
-
end
|
31
|
-
|
32
28
|
def to_hash
|
33
29
|
keys.index_with { |name| self[name].value }
|
34
30
|
end
|
@@ -58,6 +54,7 @@ module ActiveModel
|
|
58
54
|
|
59
55
|
def write_cast_value(name, value)
|
60
56
|
@attributes[name] = self[name].with_cast_value(value)
|
57
|
+
value
|
61
58
|
end
|
62
59
|
|
63
60
|
def freeze
|