store_attribute 0.7.1 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 941970a7a98bfa915d206d2fde758075a81bc610109426e0eaa74859d81bfde7
4
- data.tar.gz: 3bb9f5fa94b6f9f321006172e9f8cb4a4e7c9ba7030364f8468c829989a3f5d7
3
+ metadata.gz: 5de07480a22b55413fe34512b0d36a6572da92390c998dcc1ad7838866667e5c
4
+ data.tar.gz: 78d3d38f95d1f614f6d9233f0a0bfa52b67a65853f741fedbb8ff510e38e6988
5
5
  SHA512:
6
- metadata.gz: ac9e82f2c78173e0054ea97f1c3d1318fd36b671b531b71d3f1e73be96a3247d7565b43cd27b21d3c2f01b6585143eeddb75a9cec99ef43cd77e0d43a3035130
7
- data.tar.gz: edd8234b7dc2c704d8f3086e29641a9ff1fa866f6266341d71c6f566dfb8f72fed3d360b972b0c63c41a5c0a383af645655d75d8beabb731521ab97f4b38a8da
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
- [![Gem Version](https://badge.fury.io/rb/store_attribute.svg)](https://rubygems.org/gems/store_attribute) [![Build Status](https://travis-ci.org/palkan/store_attribute.svg?branch=master)](https://travis-ci.org/palkan/store_attribute)
1
+ [![Cult Of Martians](http://cultofmartians.com/assets/badges/badge.svg)](https://cultofmartians.com/tasks/store-attribute-defaults.html#task)
2
+ [![Gem Version](https://badge.fury.io/rb/store_attribute.svg)](https://rubygems.org/gems/store_attribute)
3
+ ![Build](https://github.com/palkan/store_attribute/workflows/Build/badge.svg)
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.5.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
- alias _orig_store store
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
- _define_accessors_methods(store_name, *keys)
60
+ accessor_prefix, accessor_suffix = _normalize_prefix_suffix(store_name, prefix, suffix)
57
61
 
58
- _define_dirty_tracking_methods(store_name, keys)
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
- _define_accessors_methods(store_name, name)
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
- _define_predicate_method(name) if type == :boolean
126
+ _define_accessors_methods(store_name, name, prefix: prefix, suffix: suffix)
115
127
 
116
- decorate_attribute_type(store_name, "typed_accessor_for_#{name}") do |subtype|
117
- Type::TypedStore.create_from_type(subtype, name, type, **options)
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
- define_method("#{key}=") do |value|
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(key) do
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("#{key}_changed?") do
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("#{key}_change") do
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("#{key}_was") do
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_#{key}?") do
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_#{key}") do
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("#{key}_before_last_save") do
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
@@ -43,6 +43,10 @@ module ActiveRecord
43
43
  hash
44
44
  end
45
45
 
46
+ def changed_in_place?(raw_old_value, new_value)
47
+ raw_old_value != serialize(new_value)
48
+ end
49
+
46
50
  def serialize(value)
47
51
  return super(value) unless value.is_a?(Hash)
48
52
  typed_casted = {}
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StoreAttribute # :nodoc:
4
- VERSION = "0.7.1"
4
+ VERSION = "0.9.1"
5
5
  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.7.1
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: 2020-06-04 00:00:00.000000000 Z
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.4.0
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.0.6
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: []