store_attribute 0.7.1 → 0.9.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 +20 -1
- data/README.md +7 -2
- data/lib/store_attribute/active_record/store.rb +95 -23
- data/lib/store_attribute/active_record/type/typed_store.rb +4 -0
- data/lib/store_attribute/version.rb +1 -1
- metadata +7 -35
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5de07480a22b55413fe34512b0d36a6572da92390c998dcc1ad7838866667e5c
|
|
4
|
+
data.tar.gz: 78d3d38f95d1f614f6d9233f0a0bfa52b67a65853f741fedbb8ff510e38e6988
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3831baa1c5de7d7dee01dfe5ee0be5a1478b95a2e110c37e1c9ebd405c1246e300cc4eadbbf0b3e83742c8ea258db7399ddd0dc3df10c8797e7b911428bbd3e9
|
|
7
|
+
data.tar.gz: 774eb359b1ba5e02022f7e931089990f0d169116cbd8f9c725bc7f8bfa8189dce9c649ca3b7b3face0eccbca13b73dbb2a1028ab6f282dfe797b65adffab627c
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
## master
|
|
4
4
|
|
|
5
|
+
## 0.9.1
|
|
6
|
+
|
|
7
|
+
- Fix bug with dirty nullable stores. ([@palkan][])
|
|
8
|
+
|
|
9
|
+
## 0.9.0 (2021-08-17) 📉
|
|
10
|
+
|
|
11
|
+
- Default values no longer marked as dirty. ([@markedmondson][])
|
|
12
|
+
|
|
13
|
+
## 0.8.1 (2020-12-03)
|
|
14
|
+
|
|
15
|
+
- Fix adding dirty tracking methods for `store_attribute`. ([@palkan][])
|
|
16
|
+
|
|
17
|
+
## 0.8.0
|
|
18
|
+
|
|
19
|
+
- Add Rails 6.1 compatibility. ([@palkan][])
|
|
20
|
+
|
|
21
|
+
- Add support for `prefix` and `suffix` options. ([@palkan][])
|
|
22
|
+
|
|
5
23
|
## 0.7.1
|
|
6
24
|
|
|
7
25
|
- Fixed bug with `store` called without accessors. ([@ioki-klaus][])
|
|
@@ -26,4 +44,5 @@
|
|
|
26
44
|
[@dreikanter]: https://github.com/dreikanter
|
|
27
45
|
[@SumLare]: https://github.com/SumLare
|
|
28
46
|
[@glaszig]: https://github.com/glaszig
|
|
29
|
-
[@ioki-klaus]: https://github.com/ioki-klaus
|
|
47
|
+
[@ioki-klaus]: https://github.com/ioki-klaus
|
|
48
|
+
[@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
|
|
@@ -6,7 +6,7 @@ require "store_attribute/active_record/type/typed_store"
|
|
|
6
6
|
module ActiveRecord
|
|
7
7
|
module Store
|
|
8
8
|
module ClassMethods # :nodoc:
|
|
9
|
-
|
|
9
|
+
alias_method :_orig_store, :store
|
|
10
10
|
# Defines store on this model.
|
|
11
11
|
#
|
|
12
12
|
# +store_name+ The name of the store.
|
|
@@ -44,24 +44,29 @@ 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
|
+
_define_dirty_tracking_methods(store_name, keys + typed_keys.keys, prefix: accessor_prefix, suffix: accessor_suffix)
|
|
67
|
+
|
|
63
68
|
typed_keys.each do |key, type|
|
|
64
|
-
store_attribute(store_name, key, type)
|
|
69
|
+
store_attribute(store_name, key, type, prefix: prefix, suffix: suffix)
|
|
65
70
|
end
|
|
66
71
|
end
|
|
67
72
|
|
|
@@ -78,6 +83,10 @@ module ActiveRecord
|
|
|
78
83
|
# +type+ A symbol such as +:string+ or +:integer+, or a type object
|
|
79
84
|
# to be used for the accessor.
|
|
80
85
|
#
|
|
86
|
+
# +prefix+ Accessor method name prefix
|
|
87
|
+
#
|
|
88
|
+
# +suffix+ Accessor method name suffix
|
|
89
|
+
#
|
|
81
90
|
# +options+ A hash of cast type options such as +precision+, +limit+, +scale+.
|
|
82
91
|
#
|
|
83
92
|
# Examples:
|
|
@@ -85,13 +94,16 @@ module ActiveRecord
|
|
|
85
94
|
# class MegaUser < User
|
|
86
95
|
# store_attribute :settings, :ratio, :integer, limit: 1
|
|
87
96
|
# store_attribute :settings, :login_at, :datetime
|
|
97
|
+
#
|
|
98
|
+
# store_attribute :extra, :version, :integer, prefix: :meta
|
|
88
99
|
# end
|
|
89
100
|
#
|
|
90
|
-
# 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")
|
|
91
102
|
#
|
|
92
103
|
# u.login_at.is_a?(DateTime) # => true
|
|
93
104
|
# u.login_at = DateTime.new(2015,1,1,11,0,0)
|
|
94
105
|
# u.ratio # => 63
|
|
106
|
+
# u.meta_version #=> 1
|
|
95
107
|
# u.reload
|
|
96
108
|
#
|
|
97
109
|
# # After loading record from db store contains casted data
|
|
@@ -108,16 +120,33 @@ module ActiveRecord
|
|
|
108
120
|
# u.settings['ratio'] # => 3
|
|
109
121
|
#
|
|
110
122
|
# For more examples on using types, see documentation for ActiveRecord::Attributes.
|
|
111
|
-
def store_attribute(store_name, name, type, **options)
|
|
112
|
-
|
|
123
|
+
def store_attribute(store_name, name, type, prefix: nil, suffix: nil, **options)
|
|
124
|
+
prefix, suffix = _normalize_prefix_suffix(store_name, prefix, suffix)
|
|
113
125
|
|
|
114
|
-
|
|
126
|
+
_define_accessors_methods(store_name, name, prefix: prefix, suffix: suffix)
|
|
115
127
|
|
|
116
|
-
|
|
117
|
-
|
|
128
|
+
_define_predicate_method(name, prefix: prefix, suffix: suffix) if type == :boolean
|
|
129
|
+
|
|
130
|
+
# Rails >6.0
|
|
131
|
+
if !respond_to?(:decorate_attribute_type) || 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
|
+
if defined?(_lookup_cast_type)
|
|
136
|
+
Type::TypedStore.create_from_type(_lookup_cast_type(attr_name, was_type, {}), name, type, **options)
|
|
137
|
+
else
|
|
138
|
+
Type::TypedStore.create_from_type(subtype, name, type, **options)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
else
|
|
142
|
+
decorate_attribute_type(store_name, "typed_accessor_for_#{name}") do |subtype|
|
|
143
|
+
Type::TypedStore.create_from_type(subtype, name, type, **options)
|
|
144
|
+
end
|
|
118
145
|
end
|
|
119
146
|
|
|
120
147
|
_prepare_local_stored_attributes(store_name, name)
|
|
148
|
+
|
|
149
|
+
_define_dirty_tracking_methods(store_name, [name], prefix: prefix, suffix: suffix)
|
|
121
150
|
end
|
|
122
151
|
|
|
123
152
|
def _prepare_local_stored_attributes(store_name, *keys) # :nodoc:
|
|
@@ -128,64 +157,87 @@ module ActiveRecord
|
|
|
128
157
|
self.local_stored_attributes[store_name] |= keys
|
|
129
158
|
end
|
|
130
159
|
|
|
131
|
-
def _define_accessors_methods(store_name, *keys) # :nodoc:
|
|
160
|
+
def _define_accessors_methods(store_name, *keys, prefix: nil, suffix: nil) # :nodoc:
|
|
132
161
|
_store_accessors_module.module_eval do
|
|
133
162
|
keys.each do |key|
|
|
134
|
-
|
|
163
|
+
accessor_key = "#{prefix}#{key}#{suffix}"
|
|
164
|
+
|
|
165
|
+
define_method("#{accessor_key}=") do |value|
|
|
135
166
|
write_store_attribute(store_name, key, value)
|
|
136
167
|
end
|
|
137
168
|
|
|
138
|
-
define_method(
|
|
169
|
+
define_method(accessor_key) do
|
|
139
170
|
read_store_attribute(store_name, key)
|
|
140
171
|
end
|
|
141
172
|
end
|
|
142
173
|
end
|
|
143
174
|
end
|
|
144
175
|
|
|
145
|
-
def _define_predicate_method(name)
|
|
176
|
+
def _define_predicate_method(name, prefix: nil, suffix: nil)
|
|
146
177
|
_store_accessors_module.module_eval do
|
|
178
|
+
name = "#{prefix}#{name}#{suffix}"
|
|
179
|
+
|
|
147
180
|
define_method("#{name}?") do
|
|
148
181
|
send(name) == true
|
|
149
182
|
end
|
|
150
183
|
end
|
|
151
184
|
end
|
|
152
185
|
|
|
153
|
-
def _define_dirty_tracking_methods(store_attribute, keys)
|
|
186
|
+
def _define_dirty_tracking_methods(store_attribute, keys, prefix: nil, suffix: nil)
|
|
154
187
|
_store_accessors_module.module_eval do
|
|
188
|
+
define_method("changes") do
|
|
189
|
+
return @changes if defined?(@changes)
|
|
190
|
+
changes = super()
|
|
191
|
+
self.class.local_stored_attributes.each do |accessor, attributes|
|
|
192
|
+
next unless attribute_changed?(accessor)
|
|
193
|
+
|
|
194
|
+
prev_store, new_store = changes[accessor]
|
|
195
|
+
|
|
196
|
+
prev_store&.each do |key, value|
|
|
197
|
+
if new_store[key] == value
|
|
198
|
+
prev_store.except!(key)
|
|
199
|
+
new_store&.except!(key)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
@changes = changes
|
|
204
|
+
end
|
|
205
|
+
|
|
155
206
|
keys.flatten.each do |key|
|
|
156
207
|
key = key.to_s
|
|
208
|
+
accessor_key = "#{prefix}#{key}#{suffix}"
|
|
157
209
|
|
|
158
|
-
define_method("#{
|
|
210
|
+
define_method("#{accessor_key}_changed?") do
|
|
159
211
|
return false unless attribute_changed?(store_attribute)
|
|
160
212
|
prev_store, new_store = changes[store_attribute]
|
|
161
213
|
prev_store&.dig(key) != new_store&.dig(key)
|
|
162
214
|
end
|
|
163
215
|
|
|
164
|
-
define_method("#{
|
|
216
|
+
define_method("#{accessor_key}_change") do
|
|
165
217
|
return unless attribute_changed?(store_attribute)
|
|
166
218
|
prev_store, new_store = changes[store_attribute]
|
|
167
219
|
[prev_store&.dig(key), new_store&.dig(key)]
|
|
168
220
|
end
|
|
169
221
|
|
|
170
|
-
define_method("#{
|
|
222
|
+
define_method("#{accessor_key}_was") do
|
|
171
223
|
return unless attribute_changed?(store_attribute)
|
|
172
224
|
prev_store, _new_store = changes[store_attribute]
|
|
173
225
|
prev_store&.dig(key)
|
|
174
226
|
end
|
|
175
227
|
|
|
176
|
-
define_method("saved_change_to_#{
|
|
228
|
+
define_method("saved_change_to_#{accessor_key}?") do
|
|
177
229
|
return false unless saved_change_to_attribute?(store_attribute)
|
|
178
230
|
prev_store, new_store = saved_change_to_attribute(store_attribute)
|
|
179
231
|
prev_store&.dig(key) != new_store&.dig(key)
|
|
180
232
|
end
|
|
181
233
|
|
|
182
|
-
define_method("saved_change_to_#{
|
|
234
|
+
define_method("saved_change_to_#{accessor_key}") do
|
|
183
235
|
return unless saved_change_to_attribute?(store_attribute)
|
|
184
236
|
prev_store, new_store = saved_change_to_attribute(store_attribute)
|
|
185
237
|
[prev_store&.dig(key), new_store&.dig(key)]
|
|
186
238
|
end
|
|
187
239
|
|
|
188
|
-
define_method("#{
|
|
240
|
+
define_method("#{accessor_key}_before_last_save") do
|
|
189
241
|
return unless saved_change_to_attribute?(store_attribute)
|
|
190
242
|
prev_store, _new_store = saved_change_to_attribute(store_attribute)
|
|
191
243
|
prev_store&.dig(key)
|
|
@@ -193,6 +245,26 @@ module ActiveRecord
|
|
|
193
245
|
end
|
|
194
246
|
end
|
|
195
247
|
end
|
|
248
|
+
|
|
249
|
+
def _normalize_prefix_suffix(store_name, prefix, suffix)
|
|
250
|
+
prefix =
|
|
251
|
+
case prefix
|
|
252
|
+
when String, Symbol
|
|
253
|
+
"#{prefix}_"
|
|
254
|
+
when TrueClass
|
|
255
|
+
"#{store_name}_"
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
suffix =
|
|
259
|
+
case suffix
|
|
260
|
+
when String, Symbol
|
|
261
|
+
"_#{suffix}"
|
|
262
|
+
when TrueClass
|
|
263
|
+
"_#{store_name}"
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
[prefix, suffix]
|
|
267
|
+
end
|
|
196
268
|
end
|
|
197
269
|
end
|
|
198
270
|
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.1
|
|
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-09-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -52,34 +52,6 @@ dependencies:
|
|
|
52
52
|
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '13.0'
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: rubocop-md
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - "~>"
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '0.3'
|
|
62
|
-
type: :development
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - "~>"
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: '0.3'
|
|
69
|
-
- !ruby/object:Gem::Dependency
|
|
70
|
-
name: standard
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - "~>"
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: 0.2.0
|
|
76
|
-
type: :development
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - "~>"
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: 0.2.0
|
|
83
55
|
- !ruby/object:Gem::Dependency
|
|
84
56
|
name: rspec
|
|
85
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -118,7 +90,7 @@ metadata:
|
|
|
118
90
|
documentation_uri: http://github.com/palkan/store_attribute
|
|
119
91
|
homepage_uri: http://github.com/palkan/store_attribute
|
|
120
92
|
source_code_uri: http://github.com/palkan/store_attribute
|
|
121
|
-
post_install_message:
|
|
93
|
+
post_install_message:
|
|
122
94
|
rdoc_options: []
|
|
123
95
|
require_paths:
|
|
124
96
|
- lib
|
|
@@ -126,15 +98,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
126
98
|
requirements:
|
|
127
99
|
- - ">="
|
|
128
100
|
- !ruby/object:Gem::Version
|
|
129
|
-
version: 2.
|
|
101
|
+
version: 2.5.0
|
|
130
102
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
103
|
requirements:
|
|
132
104
|
- - ">="
|
|
133
105
|
- !ruby/object:Gem::Version
|
|
134
106
|
version: '0'
|
|
135
107
|
requirements: []
|
|
136
|
-
rubygems_version: 3.
|
|
137
|
-
signing_key:
|
|
108
|
+
rubygems_version: 3.2.22
|
|
109
|
+
signing_key:
|
|
138
110
|
specification_version: 4
|
|
139
111
|
summary: ActiveRecord extension which adds typecasting to store accessors
|
|
140
112
|
test_files: []
|