store_attribute 0.4.1 → 0.8.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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +35 -0
- data/{MIT-LICENSE → LICENSE.txt} +1 -1
- data/README.md +23 -11
- data/lib/store_attribute.rb +4 -2
- data/lib/store_attribute/active_record.rb +3 -1
- data/lib/store_attribute/active_record/store.rb +124 -17
- data/lib/store_attribute/active_record/type/typed_store.rb +45 -38
- data/lib/store_attribute/version.rb +3 -1
- metadata +34 -47
- data/.gitignore +0 -37
- data/.rspec +0 -1
- data/.rubocop.yml +0 -51
- data/.travis.yml +0 -14
- data/Gemfile +0 -11
- data/Rakefile +0 -6
- data/bench/bench.rb +0 -38
- data/bench/setup.rb +0 -67
- data/bin/console +0 -7
- data/bin/setup +0 -8
- data/gemfiles/rails-edge.gemfile +0 -7
- data/gemfiles/rails42.gemfile +0 -5
- data/spec/cases/store_attribute_spec.rb +0 -171
- data/spec/spec_helper.rb +0 -42
- data/spec/store_attribute/typed_store_spec.rb +0 -94
- data/spec/support/money_type.rb +0 -12
- data/spec/support/user.rb +0 -17
- data/store_attribute.gemspec +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a6d0060f9544a3e9e005c149cc189dd6647c0c83493bbb577bb67893e2b5a5fd
|
4
|
+
data.tar.gz: 0f9105dc411953cf7b3342117538e068c9ea7897220d573126bf0d4c01640726
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0521c55632478bc52bfcb03eab0fb9709ec2e63cc59c9eafa1dc3795742c88d7f2caf7019bb3eac3f3232006f49e0c9dc0cec4bcf619154b7f1873ccd7915201
|
7
|
+
data.tar.gz: e6644235407bd7481499dbb4bfc3fb9214ec0805ebf85be79914ddf8179f7b2f9837db1f33760c8af50236608820e0dc976fad74b3f9046e70f5996c86ec251c
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Change log
|
2
|
+
|
3
|
+
## master
|
4
|
+
|
5
|
+
## 0.8.0
|
6
|
+
|
7
|
+
- Add Rails 6.1 compatibility. ([@palkan][])
|
8
|
+
|
9
|
+
- Add support for `prefix` and `suffix` options. ([@palkan][])
|
10
|
+
|
11
|
+
## 0.7.1
|
12
|
+
|
13
|
+
- Fixed bug with `store` called without accessors. ([@ioki-klaus][])
|
14
|
+
|
15
|
+
See [#10](https://github.com/palkan/store_attribute/pull/10).
|
16
|
+
|
17
|
+
## 0.7.0 (2020-03-23)
|
18
|
+
|
19
|
+
- Added dirty tracking methods. ([@glaszig][])
|
20
|
+
|
21
|
+
[PR #8](https://github.com/palkan/store_attribute/pull/8).
|
22
|
+
|
23
|
+
## 0.6.0 (2019-07-24)
|
24
|
+
|
25
|
+
- Added default values support. ([@dreikanter][], [@SumLare][])
|
26
|
+
|
27
|
+
See [PR #7](https://github.com/palkan/store_attribute/pull/7).
|
28
|
+
|
29
|
+
- Start keeping changelog. ([@palkan][])
|
30
|
+
|
31
|
+
[@palkan]: https://github.com/palkan
|
32
|
+
[@dreikanter]: https://github.com/dreikanter
|
33
|
+
[@SumLare]: https://github.com/SumLare
|
34
|
+
[@glaszig]: https://github.com/glaszig
|
35
|
+
[@ioki-klaus]: https://github.com/ioki-klaus
|
data/{MIT-LICENSE → LICENSE.txt}
RENAMED
data/README.md
CHANGED
@@ -1,18 +1,24 @@
|
|
1
|
+
[](https://cultofmartians.com/tasks/store-attribute-defaults.html#task)
|
1
2
|
[](https://rubygems.org/gems/store_attribute) [](https://travis-ci.org/palkan/store_attribute)
|
2
3
|
|
3
4
|
## Store Attribute
|
4
5
|
|
5
6
|
ActiveRecord extension which adds typecasting to store accessors.
|
6
7
|
|
7
|
-
Compatible with
|
8
|
+
Compatible with Rails 4.2 and Rails 5+.
|
8
9
|
|
10
|
+
Extracted from not merged PR to Rails: [rails/rails#18942](https://github.com/rails/rails/pull/18942).
|
9
11
|
|
10
12
|
### Install
|
11
13
|
|
12
14
|
In your Gemfile:
|
13
15
|
|
14
16
|
```ruby
|
15
|
-
|
17
|
+
# for Rails 5+ (6 is supported)
|
18
|
+
gem "store_attribute", "~> 0.5.0"
|
19
|
+
|
20
|
+
# for Rails 4.2
|
21
|
+
gem "store_attribute", "~> 0.4.0"
|
16
22
|
```
|
17
23
|
|
18
24
|
### Usage
|
@@ -20,14 +26,14 @@ gem "store_attribute", "~>0.4.0" # version 0.4.x is for Rails 4.2.x and 0.5.x is
|
|
20
26
|
You can use `store_attribute` method to add additional accessors with a type to an existing store on a model.
|
21
27
|
|
22
28
|
```ruby
|
23
|
-
|
29
|
+
store_attribute(store_name, name, type, options)
|
24
30
|
```
|
25
31
|
|
26
32
|
Where:
|
27
33
|
- `store_name` The name of the store.
|
28
34
|
- `name` The name of the accessor to the store.
|
29
35
|
- `type` A symbol such as `:string` or `:integer`, or a type object to be used for the accessor.
|
30
|
-
- `options` A hash of cast type options such as `precision`, `limit`, `scale`.
|
36
|
+
- `options` (optional) A hash of cast type options such as `precision`, `limit`, `scale`, `default`.
|
31
37
|
|
32
38
|
Type casting occurs every time you write data through accessor or update store itself
|
33
39
|
and when object is loaded from database.
|
@@ -41,30 +47,36 @@ class MegaUser < User
|
|
41
47
|
store_attribute :settings, :ratio, :integer, limit: 1
|
42
48
|
store_attribute :settings, :login_at, :datetime
|
43
49
|
store_attribute :settings, :active, :boolean
|
50
|
+
store_attribute :settings, :color, :string, default: "red"
|
51
|
+
store_attribute :settings, :data, :datetime, default: -> { Time.now }
|
44
52
|
end
|
45
53
|
|
46
|
-
u = MegaUser.new(active: false, login_at:
|
54
|
+
u = MegaUser.new(active: false, login_at: "2015-01-01 00:01", ratio: "63.4608")
|
47
55
|
|
48
56
|
u.login_at.is_a?(DateTime) # => true
|
49
|
-
u.login_at = DateTime.new(2015,1,1,11,0,0)
|
57
|
+
u.login_at = DateTime.new(2015, 1, 1, 11, 0, 0)
|
50
58
|
u.ratio # => 63
|
51
59
|
u.active # => false
|
60
|
+
# Default value is set
|
61
|
+
u.color # => red
|
62
|
+
# A dynamic default can also be provided
|
63
|
+
u.data # => Current time
|
52
64
|
# And we also have a predicate method
|
53
65
|
u.active? # => false
|
54
66
|
u.reload
|
55
67
|
|
56
68
|
# After loading record from db store contains casted data
|
57
|
-
u.settings[
|
69
|
+
u.settings["login_at"] == DateTime.new(2015, 1, 1, 11, 0, 0) # => true
|
58
70
|
|
59
71
|
# If you update store explicitly then the value returned
|
60
72
|
# by accessor isn't type casted
|
61
|
-
u.settings[
|
73
|
+
u.settings["ratio"] = "3.141592653"
|
62
74
|
u.ratio # => "3.141592653"
|
63
75
|
|
64
76
|
# On the other hand, writing through accessor set correct data within store
|
65
|
-
u.ratio = "3.
|
77
|
+
u.ratio = "3.141592653"
|
66
78
|
u.ratio # => 3
|
67
|
-
u.settings[
|
79
|
+
u.settings["ratio"] # => 3
|
68
80
|
```
|
69
81
|
|
70
82
|
You can also specify type using usual `store_accessor` method:
|
@@ -81,4 +93,4 @@ Or through `store`:
|
|
81
93
|
class User < ActiveRecord::Base
|
82
94
|
store :settings, accessors: [:color, :homepage, login_at: :datetime], coder: JSON
|
83
95
|
end
|
84
|
-
```
|
96
|
+
```
|
data/lib/store_attribute.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/store"
|
4
|
+
require "store_attribute/active_record/type/typed_store"
|
3
5
|
|
4
6
|
module ActiveRecord
|
5
7
|
module Store
|
6
8
|
module ClassMethods # :nodoc:
|
9
|
+
alias _orig_store store
|
7
10
|
# Defines store on this model.
|
8
11
|
#
|
9
12
|
# +store_name+ The name of the store.
|
@@ -21,9 +24,18 @@ module ActiveRecord
|
|
21
24
|
# store :settings, accessors: [:color, :homepage, login_at: :datetime], coder: JSON
|
22
25
|
# end
|
23
26
|
def store(store_name, options = {})
|
24
|
-
|
25
|
-
|
27
|
+
accessors = options.delete(:accessors)
|
28
|
+
typed_accessors =
|
29
|
+
if accessors && accessors.last.is_a?(Hash)
|
30
|
+
accessors.pop
|
31
|
+
else
|
32
|
+
{}
|
33
|
+
end
|
34
|
+
|
35
|
+
_orig_store(store_name, options)
|
36
|
+
store_accessor(store_name, *accessors, **typed_accessors) if accessors
|
26
37
|
end
|
38
|
+
|
27
39
|
# Adds additional accessors to an existing store on this model.
|
28
40
|
#
|
29
41
|
# +store_name+ The name of the store.
|
@@ -32,21 +44,29 @@ module ActiveRecord
|
|
32
44
|
#
|
33
45
|
# +typed_keys+ The key-to-type hash of the accesors with type to the store.
|
34
46
|
#
|
47
|
+
# +prefix+ Accessor method name prefix
|
48
|
+
#
|
49
|
+
# +suffix+ Accessor method name suffix
|
50
|
+
#
|
35
51
|
# Examples:
|
36
52
|
#
|
37
53
|
# class SuperUser < User
|
38
54
|
# store_accessor :settings, :privileges, login_at: :datetime
|
39
55
|
# end
|
40
|
-
def store_accessor(store_name, *keys, **typed_keys)
|
56
|
+
def store_accessor(store_name, *keys, prefix: nil, suffix: nil, **typed_keys)
|
41
57
|
keys = keys.flatten
|
42
58
|
typed_keys = typed_keys.except(keys)
|
43
59
|
|
44
|
-
|
60
|
+
accessor_prefix, accessor_suffix = _normalize_prefix_suffix(store_name, prefix, suffix)
|
61
|
+
|
62
|
+
_define_accessors_methods(store_name, *keys, prefix: accessor_prefix, suffix: accessor_suffix)
|
63
|
+
|
64
|
+
_define_dirty_tracking_methods(store_name, keys + typed_keys.keys, prefix: accessor_prefix, suffix: accessor_suffix)
|
45
65
|
|
46
66
|
_prepare_local_stored_attributes(store_name, *keys)
|
47
67
|
|
48
68
|
typed_keys.each do |key, type|
|
49
|
-
store_attribute(store_name, key, type)
|
69
|
+
store_attribute(store_name, key, type, prefix: prefix, suffix: suffix)
|
50
70
|
end
|
51
71
|
end
|
52
72
|
|
@@ -63,6 +83,10 @@ module ActiveRecord
|
|
63
83
|
# +type+ A symbol such as +:string+ or +:integer+, or a type object
|
64
84
|
# to be used for the accessor.
|
65
85
|
#
|
86
|
+
# +prefix+ Accessor method name prefix
|
87
|
+
#
|
88
|
+
# +suffix+ Accessor method name suffix
|
89
|
+
#
|
66
90
|
# +options+ A hash of cast type options such as +precision+, +limit+, +scale+.
|
67
91
|
#
|
68
92
|
# Examples:
|
@@ -70,13 +94,16 @@ module ActiveRecord
|
|
70
94
|
# class MegaUser < User
|
71
95
|
# store_attribute :settings, :ratio, :integer, limit: 1
|
72
96
|
# store_attribute :settings, :login_at, :datetime
|
97
|
+
#
|
98
|
+
# store_attribute :extra, :version, :integer, prefix: :meta
|
73
99
|
# end
|
74
100
|
#
|
75
|
-
# u = MegaUser.new(active: false, login_at: '2015-01-01 00:01', ratio: "63.4608")
|
101
|
+
# u = MegaUser.new(active: false, login_at: '2015-01-01 00:01', ratio: "63.4608", meta_version: "1")
|
76
102
|
#
|
77
103
|
# u.login_at.is_a?(DateTime) # => true
|
78
104
|
# u.login_at = DateTime.new(2015,1,1,11,0,0)
|
79
105
|
# u.ratio # => 63
|
106
|
+
# u.meta_version #=> 1
|
80
107
|
# u.reload
|
81
108
|
#
|
82
109
|
# # After loading record from db store contains casted data
|
@@ -93,13 +120,24 @@ module ActiveRecord
|
|
93
120
|
# u.settings['ratio'] # => 3
|
94
121
|
#
|
95
122
|
# For more examples on using types, see documentation for ActiveRecord::Attributes.
|
96
|
-
def store_attribute(store_name, name, type, **options)
|
97
|
-
|
123
|
+
def store_attribute(store_name, name, type, prefix: nil, suffix: nil, **options)
|
124
|
+
prefix, suffix = _normalize_prefix_suffix(store_name, prefix, suffix)
|
125
|
+
|
126
|
+
_define_accessors_methods(store_name, name, prefix: prefix, suffix: suffix)
|
98
127
|
|
99
|
-
_define_predicate_method(name) if type == :boolean
|
128
|
+
_define_predicate_method(name, prefix: prefix, suffix: suffix) if type == :boolean
|
100
129
|
|
101
|
-
|
102
|
-
|
130
|
+
# Rails >6.0
|
131
|
+
if method(:decorate_attribute_type).parameters.count { |type, _| type == :req } == 1
|
132
|
+
attr_name = store_name.to_s
|
133
|
+
was_type = attributes_to_define_after_schema_loads[attr_name]&.first
|
134
|
+
attribute(attr_name) do |subtype|
|
135
|
+
Type::TypedStore.create_from_type(_lookup_cast_type(attr_name, was_type, {}), name, type, **options)
|
136
|
+
end
|
137
|
+
else
|
138
|
+
decorate_attribute_type(store_name, "typed_accessor_for_#{name}") do |subtype|
|
139
|
+
Type::TypedStore.create_from_type(subtype, name, type, **options)
|
140
|
+
end
|
103
141
|
end
|
104
142
|
|
105
143
|
_prepare_local_stored_attributes(store_name, name)
|
@@ -113,27 +151,96 @@ module ActiveRecord
|
|
113
151
|
self.local_stored_attributes[store_name] |= keys
|
114
152
|
end
|
115
153
|
|
116
|
-
def _define_accessors_methods(store_name, *keys) # :nodoc:
|
154
|
+
def _define_accessors_methods(store_name, *keys, prefix: nil, suffix: nil) # :nodoc:
|
117
155
|
_store_accessors_module.module_eval do
|
118
156
|
keys.each do |key|
|
119
|
-
|
157
|
+
accessor_key = "#{prefix}#{key}#{suffix}"
|
158
|
+
|
159
|
+
define_method("#{accessor_key}=") do |value|
|
120
160
|
write_store_attribute(store_name, key, value)
|
121
161
|
end
|
122
162
|
|
123
|
-
define_method(
|
163
|
+
define_method(accessor_key) do
|
124
164
|
read_store_attribute(store_name, key)
|
125
165
|
end
|
126
166
|
end
|
127
167
|
end
|
128
168
|
end
|
129
169
|
|
130
|
-
def _define_predicate_method(name)
|
170
|
+
def _define_predicate_method(name, prefix: nil, suffix: nil)
|
131
171
|
_store_accessors_module.module_eval do
|
172
|
+
name = "#{prefix}#{name}#{suffix}"
|
173
|
+
|
132
174
|
define_method("#{name}?") do
|
133
175
|
send(name) == true
|
134
176
|
end
|
135
177
|
end
|
136
178
|
end
|
179
|
+
|
180
|
+
def _define_dirty_tracking_methods(store_attribute, keys, prefix: nil, suffix: nil)
|
181
|
+
_store_accessors_module.module_eval do
|
182
|
+
keys.flatten.each do |key|
|
183
|
+
key = key.to_s
|
184
|
+
accessor_key = "#{prefix}#{key}#{suffix}"
|
185
|
+
|
186
|
+
define_method("#{accessor_key}_changed?") do
|
187
|
+
return false unless attribute_changed?(store_attribute)
|
188
|
+
prev_store, new_store = changes[store_attribute]
|
189
|
+
prev_store&.dig(key) != new_store&.dig(key)
|
190
|
+
end
|
191
|
+
|
192
|
+
define_method("#{accessor_key}_change") do
|
193
|
+
return unless attribute_changed?(store_attribute)
|
194
|
+
prev_store, new_store = changes[store_attribute]
|
195
|
+
[prev_store&.dig(key), new_store&.dig(key)]
|
196
|
+
end
|
197
|
+
|
198
|
+
define_method("#{accessor_key}_was") do
|
199
|
+
return unless attribute_changed?(store_attribute)
|
200
|
+
prev_store, _new_store = changes[store_attribute]
|
201
|
+
prev_store&.dig(key)
|
202
|
+
end
|
203
|
+
|
204
|
+
define_method("saved_change_to_#{accessor_key}?") do
|
205
|
+
return false unless saved_change_to_attribute?(store_attribute)
|
206
|
+
prev_store, new_store = saved_change_to_attribute(store_attribute)
|
207
|
+
prev_store&.dig(key) != new_store&.dig(key)
|
208
|
+
end
|
209
|
+
|
210
|
+
define_method("saved_change_to_#{accessor_key}") do
|
211
|
+
return unless saved_change_to_attribute?(store_attribute)
|
212
|
+
prev_store, new_store = saved_change_to_attribute(store_attribute)
|
213
|
+
[prev_store&.dig(key), new_store&.dig(key)]
|
214
|
+
end
|
215
|
+
|
216
|
+
define_method("#{accessor_key}_before_last_save") do
|
217
|
+
return unless saved_change_to_attribute?(store_attribute)
|
218
|
+
prev_store, _new_store = saved_change_to_attribute(store_attribute)
|
219
|
+
prev_store&.dig(key)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def _normalize_prefix_suffix(store_name, prefix, suffix)
|
226
|
+
prefix =
|
227
|
+
case prefix
|
228
|
+
when String, Symbol
|
229
|
+
"#{prefix}_"
|
230
|
+
when TrueClass
|
231
|
+
"#{store_name}_"
|
232
|
+
end
|
233
|
+
|
234
|
+
suffix =
|
235
|
+
case suffix
|
236
|
+
when String, Symbol
|
237
|
+
"_#{suffix}"
|
238
|
+
when TrueClass
|
239
|
+
"_#{store_name}"
|
240
|
+
end
|
241
|
+
|
242
|
+
[prefix, suffix]
|
243
|
+
end
|
137
244
|
end
|
138
245
|
end
|
139
246
|
end
|
@@ -1,22 +1,9 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/type"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
module Type # :nodoc:
|
5
|
-
BASE_TYPES = {
|
6
|
-
boolean: ::ActiveRecord::Type::Boolean,
|
7
|
-
integer: ::ActiveRecord::Type::Integer,
|
8
|
-
string: ::ActiveRecord::Type::String,
|
9
|
-
float: ::ActiveRecord::Type::Float,
|
10
|
-
date: ::ActiveRecord::Type::Date,
|
11
|
-
datetime: ::ActiveRecord::Type::DateTime,
|
12
|
-
decimal: ::ActiveRecord::Type::Decimal
|
13
|
-
}.freeze
|
14
|
-
|
15
|
-
def self.lookup_type(type, options)
|
16
|
-
BASE_TYPES[type.to_sym].try(:new, options) ||
|
17
|
-
ActiveRecord::Base.connection.type_map.lookup(type.to_s, options)
|
18
|
-
end
|
19
|
-
|
20
7
|
class TypedStore < DelegateClass(ActiveRecord::Type::Value) # :nodoc:
|
21
8
|
# Creates +TypedStore+ type instance and specifies type caster
|
22
9
|
# for key.
|
@@ -28,43 +15,57 @@ module ActiveRecord
|
|
28
15
|
|
29
16
|
def initialize(subtype)
|
30
17
|
@accessor_types = {}
|
18
|
+
@defaults = {}
|
31
19
|
@store_accessor = subtype.accessor
|
32
20
|
super(subtype)
|
33
21
|
end
|
34
22
|
|
35
|
-
|
36
|
-
|
37
|
-
|
23
|
+
UNDEFINED = Object.new
|
24
|
+
private_constant :UNDEFINED
|
25
|
+
|
26
|
+
def add_typed_key(key, type, default: UNDEFINED, **options)
|
27
|
+
type = ActiveRecord::Type.lookup(type, **options) if type.is_a?(Symbol)
|
28
|
+
safe_key = key.to_s
|
29
|
+
@accessor_types[safe_key] = type
|
30
|
+
@defaults[safe_key] = default unless default == UNDEFINED
|
38
31
|
end
|
39
32
|
|
40
|
-
def
|
33
|
+
def deserialize(value)
|
41
34
|
hash = super
|
42
|
-
|
43
|
-
|
44
|
-
|
35
|
+
return hash unless hash
|
36
|
+
accessor_types.each do |key, type|
|
37
|
+
if hash.key?(key)
|
38
|
+
hash[key] = type.deserialize(hash[key])
|
39
|
+
elsif defaults.key?(key)
|
40
|
+
hash[key] = get_default(key)
|
45
41
|
end
|
46
42
|
end
|
47
43
|
hash
|
48
44
|
end
|
49
45
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
46
|
+
def serialize(value)
|
47
|
+
return super(value) unless value.is_a?(Hash)
|
48
|
+
typed_casted = {}
|
49
|
+
accessor_types.each do |str_key, type|
|
50
|
+
key = key_to_cast(value, str_key)
|
51
|
+
next unless key
|
52
|
+
if value.key?(key)
|
53
|
+
typed_casted[key] = type.serialize(value[key])
|
54
|
+
elsif defaults.key?(str_key)
|
55
|
+
typed_casted[key] = type.serialize(get_default(str_key))
|
56
56
|
end
|
57
|
-
super(value.merge(typed_casted))
|
58
|
-
else
|
59
|
-
super(value)
|
60
57
|
end
|
58
|
+
super(value.merge(typed_casted))
|
61
59
|
end
|
62
60
|
|
63
|
-
def
|
61
|
+
def cast(value)
|
64
62
|
hash = super
|
65
|
-
|
66
|
-
|
67
|
-
|
63
|
+
return hash unless hash
|
64
|
+
accessor_types.each do |key, type|
|
65
|
+
if hash.key?(key)
|
66
|
+
hash[key] = type.cast(hash[key])
|
67
|
+
elsif defaults.key?(key)
|
68
|
+
hash[key] = get_default(key)
|
68
69
|
end
|
69
70
|
end
|
70
71
|
hash
|
@@ -75,7 +76,7 @@ module ActiveRecord
|
|
75
76
|
end
|
76
77
|
|
77
78
|
def write(object, attribute, key, value)
|
78
|
-
value = type_for(key).
|
79
|
+
value = type_for(key).cast(value) if typed?(key)
|
79
80
|
store_accessor.write(object, attribute, key, value)
|
80
81
|
end
|
81
82
|
|
@@ -87,6 +88,7 @@ module ActiveRecord
|
|
87
88
|
def key_to_cast(val, key)
|
88
89
|
return key if val.key?(key)
|
89
90
|
return key.to_sym if val.key?(key.to_sym)
|
91
|
+
return key if defaults.key?(key)
|
90
92
|
end
|
91
93
|
|
92
94
|
def typed?(key)
|
@@ -97,7 +99,12 @@ module ActiveRecord
|
|
97
99
|
accessor_types.fetch(key.to_s)
|
98
100
|
end
|
99
101
|
|
100
|
-
|
102
|
+
def get_default(key)
|
103
|
+
value = defaults.fetch(key)
|
104
|
+
value.is_a?(Proc) ? value.call : value
|
105
|
+
end
|
106
|
+
|
107
|
+
attr_reader :accessor_types, :defaults, :store_accessor
|
101
108
|
end
|
102
109
|
end
|
103
110
|
end
|