store_attribute 0.7.0 → 0.9.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 +4 -4
- data/CHANGELOG.md +24 -0
- data/README.md +7 -2
- data/lib/store_attribute/active_record/store.rb +96 -23
- data/lib/store_attribute/active_record/type/typed_store.rb +4 -0
- data/lib/store_attribute/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e666327899587f17df5c5196abd1f6094388d08c4ca4c020b9a67f182fa0660
|
4
|
+
data.tar.gz: 6a23e7d6122483843caaa7ae6d2da59e33e0c250c96306839bbb4cac8242ea87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b61d2f76d32c9ddbe3c993896a1826662b8afc881e7b72674ab21d8954e70dbae25630996ab920eeeb752436e433949bec36914d3b6a3278909ca85fce889de5
|
7
|
+
data.tar.gz: 07bb42459a9925b247b6cea363df401c4c9a92787bf6aca1de2bf795575e5895f331a0d4cd983e9b82ee1d27d0a35b47cd6a791314a756fcf78b438e8a25aea0
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,28 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 0.9.0 (2021-08-17) 📉
|
6
|
+
|
7
|
+
- Default values no longer marked as dirty. ([@markedmondson][])
|
8
|
+
|
9
|
+
## 0.8.1 (2020-12-03)
|
10
|
+
|
11
|
+
- Fix adding dirty tracking methods for `store_attribute`. ([@palkan][])
|
12
|
+
|
13
|
+
## 0.8.0
|
14
|
+
|
15
|
+
- Add Rails 6.1 compatibility. ([@palkan][])
|
16
|
+
|
17
|
+
- Add support for `prefix` and `suffix` options. ([@palkan][])
|
18
|
+
|
19
|
+
## 0.7.1
|
20
|
+
|
21
|
+
- Fixed bug with `store` called without accessors. ([@ioki-klaus][])
|
22
|
+
|
23
|
+
See [#10](https://github.com/palkan/store_attribute/pull/10).
|
24
|
+
|
25
|
+
## 0.7.0 (2020-03-23)
|
26
|
+
|
5
27
|
- Added dirty tracking methods. ([@glaszig][])
|
6
28
|
|
7
29
|
[PR #8](https://github.com/palkan/store_attribute/pull/8).
|
@@ -18,3 +40,5 @@
|
|
18
40
|
[@dreikanter]: https://github.com/dreikanter
|
19
41
|
[@SumLare]: https://github.com/SumLare
|
20
42
|
[@glaszig]: https://github.com/glaszig
|
43
|
+
[@ioki-klaus]: https://github.com/ioki-klaus
|
44
|
+
[@markedmondson]: https://github.com/markedmondson
|
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
[](https://cultofmartians.com/tasks/store-attribute-defaults.html#task)
|
2
|
+
[](https://rubygems.org/gems/store_attribute)
|
3
|
+

|
2
4
|
|
3
5
|
## Store Attribute
|
4
6
|
|
@@ -14,7 +16,7 @@ In your Gemfile:
|
|
14
16
|
|
15
17
|
```ruby
|
16
18
|
# for Rails 5+ (6 is supported)
|
17
|
-
gem "store_attribute", "~> 0.
|
19
|
+
gem "store_attribute", "~> 0.8.0"
|
18
20
|
|
19
21
|
# for Rails 4.2
|
20
22
|
gem "store_attribute", "~> 0.4.0"
|
@@ -47,6 +49,7 @@ class MegaUser < User
|
|
47
49
|
store_attribute :settings, :login_at, :datetime
|
48
50
|
store_attribute :settings, :active, :boolean
|
49
51
|
store_attribute :settings, :color, :string, default: "red"
|
52
|
+
store_attribute :settings, :colors, :json, default: ["red", "blue"]
|
50
53
|
store_attribute :settings, :data, :datetime, default: -> { Time.now }
|
51
54
|
end
|
52
55
|
|
@@ -58,6 +61,8 @@ u.ratio # => 63
|
|
58
61
|
u.active # => false
|
59
62
|
# Default value is set
|
60
63
|
u.color # => red
|
64
|
+
# Default array is set
|
65
|
+
u.colors # => ["red", "blue"]
|
61
66
|
# A dynamic default can also be provided
|
62
67
|
u.data # => Current time
|
63
68
|
# And we also have a predicate method
|
@@ -26,7 +26,7 @@ module ActiveRecord
|
|
26
26
|
def store(store_name, options = {})
|
27
27
|
accessors = options.delete(:accessors)
|
28
28
|
typed_accessors =
|
29
|
-
if accessors.last.is_a?(Hash)
|
29
|
+
if accessors && accessors.last.is_a?(Hash)
|
30
30
|
accessors.pop
|
31
31
|
else
|
32
32
|
{}
|
@@ -44,24 +44,48 @@ module ActiveRecord
|
|
44
44
|
#
|
45
45
|
# +typed_keys+ The key-to-type hash of the accesors with type to the store.
|
46
46
|
#
|
47
|
+
# +prefix+ Accessor method name prefix
|
48
|
+
#
|
49
|
+
# +suffix+ Accessor method name suffix
|
50
|
+
#
|
47
51
|
# Examples:
|
48
52
|
#
|
49
53
|
# class SuperUser < User
|
50
54
|
# store_accessor :settings, :privileges, login_at: :datetime
|
51
55
|
# end
|
52
|
-
def store_accessor(store_name, *keys, **typed_keys)
|
56
|
+
def store_accessor(store_name, *keys, prefix: nil, suffix: nil, **typed_keys)
|
53
57
|
keys = keys.flatten
|
54
58
|
typed_keys = typed_keys.except(keys)
|
55
59
|
|
56
|
-
|
60
|
+
accessor_prefix, accessor_suffix = _normalize_prefix_suffix(store_name, prefix, suffix)
|
57
61
|
|
58
|
-
|
59
|
-
_define_dirty_tracking_methods(store_name, typed_keys.keys)
|
62
|
+
_define_accessors_methods(store_name, *keys, prefix: accessor_prefix, suffix: accessor_suffix)
|
60
63
|
|
61
64
|
_prepare_local_stored_attributes(store_name, *keys)
|
62
65
|
|
66
|
+
_store_accessors_module.module_eval do
|
67
|
+
define_method("changes") do
|
68
|
+
return @changes if defined?(@changes)
|
69
|
+
changes = super()
|
70
|
+
self.class.local_stored_attributes.each do |accessor, attributes|
|
71
|
+
next unless attribute_changed?(accessor)
|
72
|
+
|
73
|
+
prev_store, new_store = changes[accessor]
|
74
|
+
prev_store.each do |key, value|
|
75
|
+
if new_store[key] == value
|
76
|
+
changes[accessor][0].except!(key)
|
77
|
+
changes[accessor][1].except!(key)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
@changes = changes
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
_define_dirty_tracking_methods(store_name, keys + typed_keys.keys, prefix: accessor_prefix, suffix: accessor_suffix)
|
86
|
+
|
63
87
|
typed_keys.each do |key, type|
|
64
|
-
store_attribute(store_name, key, type)
|
88
|
+
store_attribute(store_name, key, type, prefix: prefix, suffix: suffix)
|
65
89
|
end
|
66
90
|
end
|
67
91
|
|
@@ -78,6 +102,10 @@ module ActiveRecord
|
|
78
102
|
# +type+ A symbol such as +:string+ or +:integer+, or a type object
|
79
103
|
# to be used for the accessor.
|
80
104
|
#
|
105
|
+
# +prefix+ Accessor method name prefix
|
106
|
+
#
|
107
|
+
# +suffix+ Accessor method name suffix
|
108
|
+
#
|
81
109
|
# +options+ A hash of cast type options such as +precision+, +limit+, +scale+.
|
82
110
|
#
|
83
111
|
# Examples:
|
@@ -85,13 +113,16 @@ module ActiveRecord
|
|
85
113
|
# class MegaUser < User
|
86
114
|
# store_attribute :settings, :ratio, :integer, limit: 1
|
87
115
|
# store_attribute :settings, :login_at, :datetime
|
116
|
+
#
|
117
|
+
# store_attribute :extra, :version, :integer, prefix: :meta
|
88
118
|
# end
|
89
119
|
#
|
90
|
-
# u = MegaUser.new(active: false, login_at: '2015-01-01 00:01', ratio: "63.4608")
|
120
|
+
# u = MegaUser.new(active: false, login_at: '2015-01-01 00:01', ratio: "63.4608", meta_version: "1")
|
91
121
|
#
|
92
122
|
# u.login_at.is_a?(DateTime) # => true
|
93
123
|
# u.login_at = DateTime.new(2015,1,1,11,0,0)
|
94
124
|
# u.ratio # => 63
|
125
|
+
# u.meta_version #=> 1
|
95
126
|
# u.reload
|
96
127
|
#
|
97
128
|
# # After loading record from db store contains casted data
|
@@ -108,16 +139,33 @@ module ActiveRecord
|
|
108
139
|
# u.settings['ratio'] # => 3
|
109
140
|
#
|
110
141
|
# For more examples on using types, see documentation for ActiveRecord::Attributes.
|
111
|
-
def store_attribute(store_name, name, type, **options)
|
112
|
-
|
142
|
+
def store_attribute(store_name, name, type, prefix: nil, suffix: nil, **options)
|
143
|
+
prefix, suffix = _normalize_prefix_suffix(store_name, prefix, suffix)
|
144
|
+
|
145
|
+
_define_accessors_methods(store_name, name, prefix: prefix, suffix: suffix)
|
113
146
|
|
114
|
-
_define_predicate_method(name) if type == :boolean
|
147
|
+
_define_predicate_method(name, prefix: prefix, suffix: suffix) if type == :boolean
|
115
148
|
|
116
|
-
|
117
|
-
|
149
|
+
# Rails >6.0
|
150
|
+
if !respond_to?(:decorate_attribute_type) || method(:decorate_attribute_type).parameters.count { |type, _| type == :req } == 1
|
151
|
+
attr_name = store_name.to_s
|
152
|
+
was_type = attributes_to_define_after_schema_loads[attr_name]&.first
|
153
|
+
attribute(attr_name) do |subtype|
|
154
|
+
if defined?(_lookup_cast_type)
|
155
|
+
Type::TypedStore.create_from_type(_lookup_cast_type(attr_name, was_type, {}), name, type, **options)
|
156
|
+
else
|
157
|
+
Type::TypedStore.create_from_type(subtype, name, type, **options)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
else
|
161
|
+
decorate_attribute_type(store_name, "typed_accessor_for_#{name}") do |subtype|
|
162
|
+
Type::TypedStore.create_from_type(subtype, name, type, **options)
|
163
|
+
end
|
118
164
|
end
|
119
165
|
|
120
166
|
_prepare_local_stored_attributes(store_name, name)
|
167
|
+
|
168
|
+
_define_dirty_tracking_methods(store_name, [name], prefix: prefix, suffix: suffix)
|
121
169
|
end
|
122
170
|
|
123
171
|
def _prepare_local_stored_attributes(store_name, *keys) # :nodoc:
|
@@ -128,64 +176,69 @@ module ActiveRecord
|
|
128
176
|
self.local_stored_attributes[store_name] |= keys
|
129
177
|
end
|
130
178
|
|
131
|
-
def _define_accessors_methods(store_name, *keys) # :nodoc:
|
179
|
+
def _define_accessors_methods(store_name, *keys, prefix: nil, suffix: nil) # :nodoc:
|
132
180
|
_store_accessors_module.module_eval do
|
133
181
|
keys.each do |key|
|
134
|
-
|
182
|
+
accessor_key = "#{prefix}#{key}#{suffix}"
|
183
|
+
|
184
|
+
define_method("#{accessor_key}=") do |value|
|
135
185
|
write_store_attribute(store_name, key, value)
|
136
186
|
end
|
137
187
|
|
138
|
-
define_method(
|
188
|
+
define_method(accessor_key) do
|
139
189
|
read_store_attribute(store_name, key)
|
140
190
|
end
|
141
191
|
end
|
142
192
|
end
|
143
193
|
end
|
144
194
|
|
145
|
-
def _define_predicate_method(name)
|
195
|
+
def _define_predicate_method(name, prefix: nil, suffix: nil)
|
146
196
|
_store_accessors_module.module_eval do
|
197
|
+
name = "#{prefix}#{name}#{suffix}"
|
198
|
+
|
147
199
|
define_method("#{name}?") do
|
148
200
|
send(name) == true
|
149
201
|
end
|
150
202
|
end
|
151
203
|
end
|
152
204
|
|
153
|
-
def _define_dirty_tracking_methods(store_attribute, keys)
|
205
|
+
def _define_dirty_tracking_methods(store_attribute, keys, prefix: nil, suffix: nil)
|
154
206
|
_store_accessors_module.module_eval do
|
155
207
|
keys.flatten.each do |key|
|
156
208
|
key = key.to_s
|
209
|
+
accessor_key = "#{prefix}#{key}#{suffix}"
|
157
210
|
|
158
|
-
define_method("#{
|
211
|
+
define_method("#{accessor_key}_changed?") do
|
159
212
|
return false unless attribute_changed?(store_attribute)
|
160
213
|
prev_store, new_store = changes[store_attribute]
|
161
214
|
prev_store&.dig(key) != new_store&.dig(key)
|
162
215
|
end
|
163
216
|
|
164
|
-
define_method("#{
|
217
|
+
define_method("#{accessor_key}_change") do
|
165
218
|
return unless attribute_changed?(store_attribute)
|
166
219
|
prev_store, new_store = changes[store_attribute]
|
167
220
|
[prev_store&.dig(key), new_store&.dig(key)]
|
168
221
|
end
|
169
222
|
|
170
|
-
define_method("#{
|
223
|
+
define_method("#{accessor_key}_was") do
|
171
224
|
return unless attribute_changed?(store_attribute)
|
172
225
|
prev_store, _new_store = changes[store_attribute]
|
173
226
|
prev_store&.dig(key)
|
174
227
|
end
|
175
228
|
|
176
|
-
define_method("saved_change_to_#{
|
229
|
+
define_method("saved_change_to_#{accessor_key}?") do
|
177
230
|
return false unless saved_change_to_attribute?(store_attribute)
|
178
231
|
prev_store, new_store = saved_change_to_attribute(store_attribute)
|
179
232
|
prev_store&.dig(key) != new_store&.dig(key)
|
180
233
|
end
|
181
234
|
|
182
|
-
define_method("saved_change_to_#{
|
235
|
+
define_method("saved_change_to_#{accessor_key}") do
|
183
236
|
return unless saved_change_to_attribute?(store_attribute)
|
184
237
|
prev_store, new_store = saved_change_to_attribute(store_attribute)
|
185
238
|
[prev_store&.dig(key), new_store&.dig(key)]
|
186
239
|
end
|
187
240
|
|
188
|
-
define_method("#{
|
241
|
+
define_method("#{accessor_key}_before_last_save") do
|
189
242
|
return unless saved_change_to_attribute?(store_attribute)
|
190
243
|
prev_store, _new_store = saved_change_to_attribute(store_attribute)
|
191
244
|
prev_store&.dig(key)
|
@@ -193,6 +246,26 @@ module ActiveRecord
|
|
193
246
|
end
|
194
247
|
end
|
195
248
|
end
|
249
|
+
|
250
|
+
def _normalize_prefix_suffix(store_name, prefix, suffix)
|
251
|
+
prefix =
|
252
|
+
case prefix
|
253
|
+
when String, Symbol
|
254
|
+
"#{prefix}_"
|
255
|
+
when TrueClass
|
256
|
+
"#{store_name}_"
|
257
|
+
end
|
258
|
+
|
259
|
+
suffix =
|
260
|
+
case suffix
|
261
|
+
when String, Symbol
|
262
|
+
"_#{suffix}"
|
263
|
+
when TrueClass
|
264
|
+
"_#{store_name}"
|
265
|
+
end
|
266
|
+
|
267
|
+
[prefix, suffix]
|
268
|
+
end
|
196
269
|
end
|
197
270
|
end
|
198
271
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: store_attribute
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -118,7 +118,7 @@ metadata:
|
|
118
118
|
documentation_uri: http://github.com/palkan/store_attribute
|
119
119
|
homepage_uri: http://github.com/palkan/store_attribute
|
120
120
|
source_code_uri: http://github.com/palkan/store_attribute
|
121
|
-
post_install_message:
|
121
|
+
post_install_message:
|
122
122
|
rdoc_options: []
|
123
123
|
require_paths:
|
124
124
|
- lib
|
@@ -133,8 +133,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
133
|
- !ruby/object:Gem::Version
|
134
134
|
version: '0'
|
135
135
|
requirements: []
|
136
|
-
rubygems_version: 3.
|
137
|
-
signing_key:
|
136
|
+
rubygems_version: 3.2.15
|
137
|
+
signing_key:
|
138
138
|
specification_version: 4
|
139
139
|
summary: ActiveRecord extension which adds typecasting to store accessors
|
140
140
|
test_files: []
|