store_attribute 0.5.1 → 0.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 +5 -5
- data/CHANGELOG.md +29 -0
- data/{MIT-LICENSE → LICENSE.txt} +1 -1
- data/README.md +18 -13
- data/lib/store_attribute.rb +4 -2
- data/lib/store_attribute/active_record.rb +3 -1
- data/lib/store_attribute/active_record/store.rb +63 -4
- data/lib/store_attribute/active_record/type/typed_store.rb +41 -19
- data/lib/store_attribute/version.rb +3 -1
- metadata +34 -46
- 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/rails5.gemfile +0 -5
- data/spec/cases/store_attribute_spec.rb +0 -171
- data/spec/spec_helper.rb +0 -41
- 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: 941970a7a98bfa915d206d2fde758075a81bc610109426e0eaa74859d81bfde7
|
4
|
+
data.tar.gz: 3bb9f5fa94b6f9f321006172e9f8cb4a4e7c9ba7030364f8468c829989a3f5d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac9e82f2c78173e0054ea97f1c3d1318fd36b671b531b71d3f1e73be96a3247d7565b43cd27b21d3c2f01b6585143eeddb75a9cec99ef43cd77e0d43a3035130
|
7
|
+
data.tar.gz: edd8234b7dc2c704d8f3086e29641a9ff1fa866f6266341d71c6f566dfb8f72fed3d360b972b0c63c41a5c0a383af645655d75d8beabb731521ab97f4b38a8da
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Change log
|
2
|
+
|
3
|
+
## master
|
4
|
+
|
5
|
+
## 0.7.1
|
6
|
+
|
7
|
+
- Fixed bug with `store` called without accessors. ([@ioki-klaus][])
|
8
|
+
|
9
|
+
See [#10](https://github.com/palkan/store_attribute/pull/10).
|
10
|
+
|
11
|
+
## 0.7.0 (2020-03-23)
|
12
|
+
|
13
|
+
- Added dirty tracking methods. ([@glaszig][])
|
14
|
+
|
15
|
+
[PR #8](https://github.com/palkan/store_attribute/pull/8).
|
16
|
+
|
17
|
+
## 0.6.0 (2019-07-24)
|
18
|
+
|
19
|
+
- Added default values support. ([@dreikanter][], [@SumLare][])
|
20
|
+
|
21
|
+
See [PR #7](https://github.com/palkan/store_attribute/pull/7).
|
22
|
+
|
23
|
+
- Start keeping changelog. ([@palkan][])
|
24
|
+
|
25
|
+
[@palkan]: https://github.com/palkan
|
26
|
+
[@dreikanter]: https://github.com/dreikanter
|
27
|
+
[@SumLare]: https://github.com/SumLare
|
28
|
+
[@glaszig]: https://github.com/glaszig
|
29
|
+
[@ioki-klaus]: https://github.com/ioki-klaus
|
data/{MIT-LICENSE → LICENSE.txt}
RENAMED
data/README.md
CHANGED
@@ -4,21 +4,20 @@
|
|
4
4
|
|
5
5
|
ActiveRecord extension which adds typecasting to store accessors.
|
6
6
|
|
7
|
-
Compatible with Rails 4.2 and Rails 5
|
7
|
+
Compatible with Rails 4.2 and Rails 5+.
|
8
8
|
|
9
|
-
|
10
|
-
<img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
|
9
|
+
Extracted from not merged PR to Rails: [rails/rails#18942](https://github.com/rails/rails/pull/18942).
|
11
10
|
|
12
11
|
### Install
|
13
12
|
|
14
13
|
In your Gemfile:
|
15
14
|
|
16
15
|
```ruby
|
17
|
-
# for Rails 5
|
18
|
-
gem "store_attribute", "~>0.5.0"
|
16
|
+
# for Rails 5+ (6 is supported)
|
17
|
+
gem "store_attribute", "~> 0.5.0"
|
19
18
|
|
20
19
|
# for Rails 4.2
|
21
|
-
gem "store_attribute", "~>0.4.0"
|
20
|
+
gem "store_attribute", "~> 0.4.0"
|
22
21
|
```
|
23
22
|
|
24
23
|
### Usage
|
@@ -26,14 +25,14 @@ gem "store_attribute", "~>0.4.0"
|
|
26
25
|
You can use `store_attribute` method to add additional accessors with a type to an existing store on a model.
|
27
26
|
|
28
27
|
```ruby
|
29
|
-
|
28
|
+
store_attribute(store_name, name, type, options)
|
30
29
|
```
|
31
30
|
|
32
31
|
Where:
|
33
32
|
- `store_name` The name of the store.
|
34
33
|
- `name` The name of the accessor to the store.
|
35
34
|
- `type` A symbol such as `:string` or `:integer`, or a type object to be used for the accessor.
|
36
|
-
- `options` A hash of cast type options such as `precision`, `limit`, `scale`.
|
35
|
+
- `options` (optional) A hash of cast type options such as `precision`, `limit`, `scale`, `default`.
|
37
36
|
|
38
37
|
Type casting occurs every time you write data through accessor or update store itself
|
39
38
|
and when object is loaded from database.
|
@@ -47,30 +46,36 @@ class MegaUser < User
|
|
47
46
|
store_attribute :settings, :ratio, :integer, limit: 1
|
48
47
|
store_attribute :settings, :login_at, :datetime
|
49
48
|
store_attribute :settings, :active, :boolean
|
49
|
+
store_attribute :settings, :color, :string, default: "red"
|
50
|
+
store_attribute :settings, :data, :datetime, default: -> { Time.now }
|
50
51
|
end
|
51
52
|
|
52
|
-
u = MegaUser.new(active: false, login_at:
|
53
|
+
u = MegaUser.new(active: false, login_at: "2015-01-01 00:01", ratio: "63.4608")
|
53
54
|
|
54
55
|
u.login_at.is_a?(DateTime) # => true
|
55
|
-
u.login_at = DateTime.new(2015,1,1,11,0,0)
|
56
|
+
u.login_at = DateTime.new(2015, 1, 1, 11, 0, 0)
|
56
57
|
u.ratio # => 63
|
57
58
|
u.active # => false
|
59
|
+
# Default value is set
|
60
|
+
u.color # => red
|
61
|
+
# A dynamic default can also be provided
|
62
|
+
u.data # => Current time
|
58
63
|
# And we also have a predicate method
|
59
64
|
u.active? # => false
|
60
65
|
u.reload
|
61
66
|
|
62
67
|
# After loading record from db store contains casted data
|
63
|
-
u.settings[
|
68
|
+
u.settings["login_at"] == DateTime.new(2015, 1, 1, 11, 0, 0) # => true
|
64
69
|
|
65
70
|
# If you update store explicitly then the value returned
|
66
71
|
# by accessor isn't type casted
|
67
|
-
u.settings[
|
72
|
+
u.settings["ratio"] = "3.141592653"
|
68
73
|
u.ratio # => "3.141592653"
|
69
74
|
|
70
75
|
# On the other hand, writing through accessor set correct data within store
|
71
76
|
u.ratio = "3.141592653"
|
72
77
|
u.ratio # => 3
|
73
|
-
u.settings[
|
78
|
+
u.settings["ratio"] # => 3
|
74
79
|
```
|
75
80
|
|
76
81
|
You can also specify type using usual `store_accessor` method:
|
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.
|
@@ -43,6 +55,9 @@ module ActiveRecord
|
|
43
55
|
|
44
56
|
_define_accessors_methods(store_name, *keys)
|
45
57
|
|
58
|
+
_define_dirty_tracking_methods(store_name, keys)
|
59
|
+
_define_dirty_tracking_methods(store_name, typed_keys.keys)
|
60
|
+
|
46
61
|
_prepare_local_stored_attributes(store_name, *keys)
|
47
62
|
|
48
63
|
typed_keys.each do |key, type|
|
@@ -134,6 +149,50 @@ module ActiveRecord
|
|
134
149
|
end
|
135
150
|
end
|
136
151
|
end
|
152
|
+
|
153
|
+
def _define_dirty_tracking_methods(store_attribute, keys)
|
154
|
+
_store_accessors_module.module_eval do
|
155
|
+
keys.flatten.each do |key|
|
156
|
+
key = key.to_s
|
157
|
+
|
158
|
+
define_method("#{key}_changed?") do
|
159
|
+
return false unless attribute_changed?(store_attribute)
|
160
|
+
prev_store, new_store = changes[store_attribute]
|
161
|
+
prev_store&.dig(key) != new_store&.dig(key)
|
162
|
+
end
|
163
|
+
|
164
|
+
define_method("#{key}_change") do
|
165
|
+
return unless attribute_changed?(store_attribute)
|
166
|
+
prev_store, new_store = changes[store_attribute]
|
167
|
+
[prev_store&.dig(key), new_store&.dig(key)]
|
168
|
+
end
|
169
|
+
|
170
|
+
define_method("#{key}_was") do
|
171
|
+
return unless attribute_changed?(store_attribute)
|
172
|
+
prev_store, _new_store = changes[store_attribute]
|
173
|
+
prev_store&.dig(key)
|
174
|
+
end
|
175
|
+
|
176
|
+
define_method("saved_change_to_#{key}?") do
|
177
|
+
return false unless saved_change_to_attribute?(store_attribute)
|
178
|
+
prev_store, new_store = saved_change_to_attribute(store_attribute)
|
179
|
+
prev_store&.dig(key) != new_store&.dig(key)
|
180
|
+
end
|
181
|
+
|
182
|
+
define_method("saved_change_to_#{key}") do
|
183
|
+
return unless saved_change_to_attribute?(store_attribute)
|
184
|
+
prev_store, new_store = saved_change_to_attribute(store_attribute)
|
185
|
+
[prev_store&.dig(key), new_store&.dig(key)]
|
186
|
+
end
|
187
|
+
|
188
|
+
define_method("#{key}_before_last_save") do
|
189
|
+
return unless saved_change_to_attribute?(store_attribute)
|
190
|
+
prev_store, _new_store = saved_change_to_attribute(store_attribute)
|
191
|
+
prev_store&.dig(key)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
137
196
|
end
|
138
197
|
end
|
139
198
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/type"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
module Type # :nodoc:
|
@@ -13,43 +15,57 @@ module ActiveRecord
|
|
13
15
|
|
14
16
|
def initialize(subtype)
|
15
17
|
@accessor_types = {}
|
18
|
+
@defaults = {}
|
16
19
|
@store_accessor = subtype.accessor
|
17
20
|
super(subtype)
|
18
21
|
end
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
23
31
|
end
|
24
32
|
|
25
33
|
def deserialize(value)
|
26
34
|
hash = super
|
27
|
-
|
28
|
-
|
29
|
-
|
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)
|
30
41
|
end
|
31
42
|
end
|
32
43
|
hash
|
33
44
|
end
|
34
45
|
|
35
46
|
def serialize(value)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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))
|
41
56
|
end
|
42
|
-
super(value.merge(typed_casted))
|
43
|
-
else
|
44
|
-
super(value)
|
45
57
|
end
|
58
|
+
super(value.merge(typed_casted))
|
46
59
|
end
|
47
60
|
|
48
61
|
def cast(value)
|
49
62
|
hash = super
|
50
|
-
|
51
|
-
|
52
|
-
|
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)
|
53
69
|
end
|
54
70
|
end
|
55
71
|
hash
|
@@ -72,6 +88,7 @@ module ActiveRecord
|
|
72
88
|
def key_to_cast(val, key)
|
73
89
|
return key if val.key?(key)
|
74
90
|
return key.to_sym if val.key?(key.to_sym)
|
91
|
+
return key if defaults.key?(key)
|
75
92
|
end
|
76
93
|
|
77
94
|
def typed?(key)
|
@@ -82,7 +99,12 @@ module ActiveRecord
|
|
82
99
|
accessor_types.fetch(key.to_s)
|
83
100
|
end
|
84
101
|
|
85
|
-
|
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
|
86
108
|
end
|
87
109
|
end
|
88
110
|
end
|
metadata
CHANGED
@@ -1,97 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: store_attribute
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 5.0
|
19
|
+
version: '5.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 5.0
|
26
|
+
version: '5.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: pg
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0.18'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.18'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '13.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '13.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: rubocop-md
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.3
|
61
|
+
version: '0.3'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 0.3
|
68
|
+
version: '0.3'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: standard
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: 0.2.0
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: 0.2.0
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rspec
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: 3.5.0
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 3.5.0
|
97
97
|
description: ActiveRecord extension which adds typecasting to store accessors
|
@@ -101,34 +101,23 @@ executables: []
|
|
101
101
|
extensions: []
|
102
102
|
extra_rdoc_files: []
|
103
103
|
files:
|
104
|
-
-
|
105
|
-
-
|
106
|
-
- ".rubocop.yml"
|
107
|
-
- ".travis.yml"
|
108
|
-
- Gemfile
|
109
|
-
- MIT-LICENSE
|
104
|
+
- CHANGELOG.md
|
105
|
+
- LICENSE.txt
|
110
106
|
- README.md
|
111
|
-
- Rakefile
|
112
|
-
- bench/bench.rb
|
113
|
-
- bench/setup.rb
|
114
|
-
- bin/console
|
115
|
-
- bin/setup
|
116
|
-
- gemfiles/rails5.gemfile
|
117
107
|
- lib/store_attribute.rb
|
118
108
|
- lib/store_attribute/active_record.rb
|
119
109
|
- lib/store_attribute/active_record/store.rb
|
120
110
|
- lib/store_attribute/active_record/type/typed_store.rb
|
121
111
|
- lib/store_attribute/version.rb
|
122
|
-
- spec/cases/store_attribute_spec.rb
|
123
|
-
- spec/spec_helper.rb
|
124
|
-
- spec/store_attribute/typed_store_spec.rb
|
125
|
-
- spec/support/money_type.rb
|
126
|
-
- spec/support/user.rb
|
127
|
-
- store_attribute.gemspec
|
128
112
|
homepage: http://github.com/palkan/store_attribute
|
129
113
|
licenses:
|
130
114
|
- MIT
|
131
|
-
metadata:
|
115
|
+
metadata:
|
116
|
+
bug_tracker_uri: http://github.com/palkan/store_attribute/issues
|
117
|
+
changelog_uri: https://github.com/palkan/store_attribute/blob/master/CHANGELOG.md
|
118
|
+
documentation_uri: http://github.com/palkan/store_attribute
|
119
|
+
homepage_uri: http://github.com/palkan/store_attribute
|
120
|
+
source_code_uri: http://github.com/palkan/store_attribute
|
132
121
|
post_install_message:
|
133
122
|
rdoc_options: []
|
134
123
|
require_paths:
|
@@ -137,15 +126,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
137
126
|
requirements:
|
138
127
|
- - ">="
|
139
128
|
- !ruby/object:Gem::Version
|
140
|
-
version:
|
129
|
+
version: 2.4.0
|
141
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
131
|
requirements:
|
143
132
|
- - ">="
|
144
133
|
- !ruby/object:Gem::Version
|
145
134
|
version: '0'
|
146
135
|
requirements: []
|
147
|
-
|
148
|
-
rubygems_version: 2.6.4
|
136
|
+
rubygems_version: 3.0.6
|
149
137
|
signing_key:
|
150
138
|
specification_version: 4
|
151
139
|
summary: ActiveRecord extension which adds typecasting to store accessors
|
data/.gitignore
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
# Numerous always-ignore extensions
|
2
|
-
*.diff
|
3
|
-
*.err
|
4
|
-
*.orig
|
5
|
-
*.log
|
6
|
-
*.rej
|
7
|
-
*.swo
|
8
|
-
*.swp
|
9
|
-
*.vi
|
10
|
-
*~
|
11
|
-
*.sass-cache
|
12
|
-
*.iml
|
13
|
-
.idea/
|
14
|
-
|
15
|
-
# Sublime
|
16
|
-
*.sublime-project
|
17
|
-
*.sublime-workspace
|
18
|
-
|
19
|
-
# OS or Editor folders
|
20
|
-
.DS_Store
|
21
|
-
.cache
|
22
|
-
.project
|
23
|
-
.settings
|
24
|
-
.tmproj
|
25
|
-
Thumbs.db
|
26
|
-
coverage/
|
27
|
-
|
28
|
-
.bundle/
|
29
|
-
*.log
|
30
|
-
*.gem
|
31
|
-
pkg/
|
32
|
-
spec/dummy/log/*.log
|
33
|
-
spec/dummy/tmp/
|
34
|
-
spec/dummy/.sass-cache
|
35
|
-
Gemfile.local
|
36
|
-
Gemfile.lock
|
37
|
-
tmp/
|
data/.rspec
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--color
|
data/.rubocop.yml
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
AllCops:
|
2
|
-
# Include gemspec and Rakefile
|
3
|
-
Include:
|
4
|
-
- 'lib/**/*.rb'
|
5
|
-
- 'lib/**/*.rake'
|
6
|
-
- 'spec/**/*.rb'
|
7
|
-
Exclude:
|
8
|
-
- 'bin/**/*'
|
9
|
-
- 'spec/dummy/**/*'
|
10
|
-
- 'tmp/**/*'
|
11
|
-
- 'bench/**/*'
|
12
|
-
DisplayCopNames: true
|
13
|
-
StyleGuideCopsOnly: false
|
14
|
-
|
15
|
-
Style/AccessorMethodName:
|
16
|
-
Enabled: false
|
17
|
-
|
18
|
-
Style/TrivialAccessors:
|
19
|
-
Enabled: false
|
20
|
-
|
21
|
-
Style/Documentation:
|
22
|
-
Exclude:
|
23
|
-
- 'spec/**/*.rb'
|
24
|
-
|
25
|
-
Style/StringLiterals:
|
26
|
-
Enabled: false
|
27
|
-
|
28
|
-
Style/SpaceInsideStringInterpolation:
|
29
|
-
EnforcedStyle: no_space
|
30
|
-
|
31
|
-
Style/BlockDelimiters:
|
32
|
-
Exclude:
|
33
|
-
- 'spec/**/*.rb'
|
34
|
-
|
35
|
-
Lint/AmbiguousRegexpLiteral:
|
36
|
-
Enabled: false
|
37
|
-
|
38
|
-
Metrics/MethodLength:
|
39
|
-
Exclude:
|
40
|
-
- 'spec/**/*.rb'
|
41
|
-
|
42
|
-
Metrics/LineLength:
|
43
|
-
Max: 100
|
44
|
-
Exclude:
|
45
|
-
- 'spec/**/*.rb'
|
46
|
-
|
47
|
-
Rails/Date:
|
48
|
-
Enabled: false
|
49
|
-
|
50
|
-
Rails/TimeZone:
|
51
|
-
Enabled: false
|
data/.travis.yml
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
cache: bundler
|
3
|
-
|
4
|
-
addons:
|
5
|
-
postgresql: "9.4"
|
6
|
-
|
7
|
-
before_script:
|
8
|
-
- createdb store_attribute_test
|
9
|
-
- psql -U postgres -d store_attribute_test -c 'CREATE EXTENSION IF NOT EXISTS hstore;'
|
10
|
-
|
11
|
-
matrix:
|
12
|
-
include:
|
13
|
-
- rvm: 2.3.1
|
14
|
-
gemfile: gemfiles/rails5.gemfile
|
data/Gemfile
DELETED
data/Rakefile
DELETED
data/bench/bench.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'benchmark/ips'
|
2
|
-
require './setup'
|
3
|
-
|
4
|
-
Benchmark.ips do |x|
|
5
|
-
x.report('SA initialize') do
|
6
|
-
User.new(public: '1', published_at: '2016-01-01', age: '23')
|
7
|
-
end
|
8
|
-
|
9
|
-
x.report('AR-T initialize') do
|
10
|
-
Looser.new(public: '1', published_at: '2016-01-01', age: '23')
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
Benchmark.ips do |x|
|
15
|
-
x.report('SA accessors') do
|
16
|
-
u = User.new
|
17
|
-
u.public = '1'
|
18
|
-
u.published_at = '2016-01-01'
|
19
|
-
u.age = '23'
|
20
|
-
end
|
21
|
-
|
22
|
-
x.report('AR-T accessors') do
|
23
|
-
u = Looser.new
|
24
|
-
u.public = '1'
|
25
|
-
u.published_at = '2016-01-01'
|
26
|
-
u.age = '23'
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
Benchmark.ips do |x|
|
31
|
-
x.report('SA create') do
|
32
|
-
User.create!(public: '1', published_at: '2016-01-01', age: '23')
|
33
|
-
end
|
34
|
-
|
35
|
-
x.report('AR-T create') do
|
36
|
-
Looser.create(public: '1', published_at: '2016-01-01', age: '23')
|
37
|
-
end
|
38
|
-
end
|
data/bench/setup.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
begin
|
2
|
-
require 'bundler/inline'
|
3
|
-
rescue LoadError => e
|
4
|
-
$stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler'
|
5
|
-
raise e
|
6
|
-
end
|
7
|
-
|
8
|
-
gemfile(true) do
|
9
|
-
source 'https://rubygems.org'
|
10
|
-
gem 'activerecord', '~>4.2'
|
11
|
-
gem 'pg'
|
12
|
-
gem 'activerecord-typedstore', require: false
|
13
|
-
gem 'pry-byebug'
|
14
|
-
gem 'benchmark-ips'
|
15
|
-
gem 'memory_profiler'
|
16
|
-
end
|
17
|
-
|
18
|
-
DB_NAME = ENV['DB_NAME'] || 'sa_bench'
|
19
|
-
|
20
|
-
begin
|
21
|
-
system("createdb #{DB_NAME}")
|
22
|
-
rescue
|
23
|
-
$stdout.puts "DB already exists"
|
24
|
-
end
|
25
|
-
|
26
|
-
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
27
|
-
|
28
|
-
require 'active_record'
|
29
|
-
require 'logger'
|
30
|
-
require 'store_attribute'
|
31
|
-
require 'activerecord-typedstore'
|
32
|
-
|
33
|
-
ActiveRecord::Base.establish_connection(adapter: 'postgresql', database: DB_NAME)
|
34
|
-
|
35
|
-
at_exit do
|
36
|
-
ActiveRecord::Base.connection.disconnect!
|
37
|
-
end
|
38
|
-
|
39
|
-
module Bench
|
40
|
-
module_function
|
41
|
-
def setup_db
|
42
|
-
ActiveRecord::Schema.define do
|
43
|
-
create_table :users, force: true do |t|
|
44
|
-
t.jsonb :data
|
45
|
-
end
|
46
|
-
|
47
|
-
create_table :loosers, force: true do |t|
|
48
|
-
t.jsonb :data
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
class User < ActiveRecord::Base
|
55
|
-
store_accessor :data, public: :boolean, published_at: :datetime, age: :integer
|
56
|
-
end
|
57
|
-
|
58
|
-
class Looser < ActiveRecord::Base
|
59
|
-
typed_store :data, coder: JSON do |s|
|
60
|
-
s.boolean :public
|
61
|
-
s.datetime :published_at
|
62
|
-
s.integer :age
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# Run migration only if neccessary
|
67
|
-
Bench.setup_db if ENV['FORCE'].present? || !ActiveRecord::Base.connection.tables.include?('users')
|
data/bin/console
DELETED
data/bin/setup
DELETED
data/gemfiles/rails5.gemfile
DELETED
@@ -1,171 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe StoreAttribute do
|
4
|
-
before do
|
5
|
-
@connection = ActiveRecord::Base.connection
|
6
|
-
|
7
|
-
@connection.transaction do
|
8
|
-
@connection.create_table('users') do |t|
|
9
|
-
t.jsonb :jparams, default: {}, null: false
|
10
|
-
t.text :custom
|
11
|
-
t.hstore :hdata, default: {}, null: false
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
User.reset_column_information
|
16
|
-
end
|
17
|
-
|
18
|
-
after do
|
19
|
-
@connection.drop_table 'users', if_exists: true
|
20
|
-
end
|
21
|
-
|
22
|
-
let(:time) { DateTime.new(2015, 2, 14, 17, 0, 0) }
|
23
|
-
let(:time_str) { '2015-02-14 17:00' }
|
24
|
-
let(:time_str_utc) { '2015-02-14 17:00:00 UTC' }
|
25
|
-
|
26
|
-
context "hstore" do
|
27
|
-
it "typecasts on build" do
|
28
|
-
user = User.new(visible: 't', login_at: time_str)
|
29
|
-
expect(user.visible).to eq true
|
30
|
-
expect(user).to be_visible
|
31
|
-
expect(user.login_at).to eq time
|
32
|
-
end
|
33
|
-
|
34
|
-
it "typecasts on reload" do
|
35
|
-
user = User.new(visible: 't', login_at: time_str)
|
36
|
-
user.save!
|
37
|
-
user = User.find(user.id)
|
38
|
-
|
39
|
-
expect(user.visible).to eq true
|
40
|
-
expect(user).to be_visible
|
41
|
-
expect(user.login_at).to eq time
|
42
|
-
end
|
43
|
-
|
44
|
-
it "works with accessors" do
|
45
|
-
user = User.new
|
46
|
-
user.visible = false
|
47
|
-
user.login_at = time_str
|
48
|
-
user.save!
|
49
|
-
|
50
|
-
user = User.find(user.id)
|
51
|
-
|
52
|
-
expect(user.visible).to be false
|
53
|
-
expect(user).not_to be_visible
|
54
|
-
expect(user.login_at).to eq time
|
55
|
-
|
56
|
-
ron = RawUser.find(user.id)
|
57
|
-
expect(ron.hdata['visible']).to eq 'false'
|
58
|
-
expect(ron.hdata['login_at']).to eq time_str_utc
|
59
|
-
end
|
60
|
-
|
61
|
-
it "handles options" do
|
62
|
-
expect { User.create!(ratio: 1024) }.to raise_error(RangeError)
|
63
|
-
end
|
64
|
-
|
65
|
-
it "YAML roundtrip" do
|
66
|
-
user = User.create!(visible: '0', login_at: time_str)
|
67
|
-
dumped = YAML.load(YAML.dump(user))
|
68
|
-
|
69
|
-
expect(dumped.visible).to be false
|
70
|
-
expect(dumped.login_at).to eq time
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
context "jsonb" do
|
75
|
-
it "typecasts on build" do
|
76
|
-
jamie = User.new(
|
77
|
-
active: 'true',
|
78
|
-
salary: 3.1999,
|
79
|
-
birthday: '2000-01-01'
|
80
|
-
)
|
81
|
-
expect(jamie).to be_active
|
82
|
-
expect(jamie.salary).to eq 3
|
83
|
-
expect(jamie.birthday).to eq Date.new(2000, 1, 1)
|
84
|
-
expect(jamie.jparams['birthday']).to eq Date.new(2000, 1, 1)
|
85
|
-
expect(jamie.jparams['active']).to eq true
|
86
|
-
end
|
87
|
-
|
88
|
-
it "typecasts on reload" do
|
89
|
-
jamie = User.create!(jparams: { 'active' => '1', 'birthday' => '01/01/2000', 'salary' => '3.14' })
|
90
|
-
jamie = User.find(jamie.id)
|
91
|
-
|
92
|
-
expect(jamie).to be_active
|
93
|
-
expect(jamie.salary).to eq 3
|
94
|
-
expect(jamie.birthday).to eq Date.new(2000, 1, 1)
|
95
|
-
expect(jamie.jparams['birthday']).to eq Date.new(2000, 1, 1)
|
96
|
-
expect(jamie.jparams['active']).to eq true
|
97
|
-
end
|
98
|
-
|
99
|
-
it "works with accessors" do
|
100
|
-
john = User.new
|
101
|
-
john.active = 1
|
102
|
-
|
103
|
-
expect(john).to be_active
|
104
|
-
expect(john.jparams['active']).to eq true
|
105
|
-
|
106
|
-
john.jparams = { active: 'true', salary: '123.123', birthday: '01/01/2012' }
|
107
|
-
expect(john).to be_active
|
108
|
-
expect(john.birthday).to eq Date.new(2012, 1, 1)
|
109
|
-
expect(john.salary).to eq 123
|
110
|
-
|
111
|
-
john.save!
|
112
|
-
|
113
|
-
ron = RawUser.find(john.id)
|
114
|
-
expect(ron.jparams['active']).to eq true
|
115
|
-
expect(ron.jparams['birthday']).to eq '2012-01-01'
|
116
|
-
expect(ron.jparams['salary']).to eq 123
|
117
|
-
end
|
118
|
-
|
119
|
-
it "re-typecast old data" do
|
120
|
-
jamie = User.create!
|
121
|
-
User.update_all('jparams = \'{"active":"1", "salary":"12.02"}\'::jsonb')
|
122
|
-
|
123
|
-
jamie = User.find(jamie.id)
|
124
|
-
expect(jamie).to be_active
|
125
|
-
expect(jamie.salary).to eq 12
|
126
|
-
|
127
|
-
jamie.save!
|
128
|
-
|
129
|
-
ron = RawUser.find(jamie.id)
|
130
|
-
expect(ron.jparams['active']).to eq true
|
131
|
-
expect(ron.jparams['salary']).to eq 12
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
context "custom types" do
|
136
|
-
it "typecasts on build" do
|
137
|
-
user = User.new(price: "$1")
|
138
|
-
expect(user.price).to eq 100
|
139
|
-
end
|
140
|
-
|
141
|
-
it "typecasts on reload" do
|
142
|
-
jamie = User.create!(custom: { price: '$12' })
|
143
|
-
expect(jamie.reload.price).to eq 1200
|
144
|
-
|
145
|
-
jamie = User.find(jamie.id)
|
146
|
-
|
147
|
-
expect(jamie.price).to eq 1200
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
context "store subtype" do
|
152
|
-
it "typecasts on build" do
|
153
|
-
user = User.new(inner_json: { x: 1 })
|
154
|
-
expect(user.inner_json).to eq('x' => 1)
|
155
|
-
end
|
156
|
-
|
157
|
-
it "typecasts on update" do
|
158
|
-
user = User.new
|
159
|
-
user.update!(inner_json: { x: 1 })
|
160
|
-
expect(user.inner_json).to eq('x' => 1)
|
161
|
-
|
162
|
-
expect(user.reload.inner_json).to eq('x' => 1)
|
163
|
-
end
|
164
|
-
|
165
|
-
it "typecasts on reload" do
|
166
|
-
jamie = User.create!(inner_json: { x: 1 })
|
167
|
-
jamie = User.find(jamie.id)
|
168
|
-
expect(jamie.inner_json).to eq('x' => 1)
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
-
|
4
|
-
if ENV['COVER']
|
5
|
-
require 'simplecov'
|
6
|
-
SimpleCov.root File.join(File.dirname(__FILE__), '..')
|
7
|
-
SimpleCov.start
|
8
|
-
end
|
9
|
-
|
10
|
-
require 'rspec'
|
11
|
-
require 'pry-byebug'
|
12
|
-
require 'active_record'
|
13
|
-
require 'pg'
|
14
|
-
require 'store_attribute'
|
15
|
-
|
16
|
-
ActiveRecord::Base.establish_connection(
|
17
|
-
adapter: 'postgresql',
|
18
|
-
database: 'store_attribute_test'
|
19
|
-
)
|
20
|
-
connection = ActiveRecord::Base.connection
|
21
|
-
|
22
|
-
unless connection.extension_enabled?('hstore')
|
23
|
-
connection.enable_extension 'hstore'
|
24
|
-
connection.commit_db_transaction
|
25
|
-
end
|
26
|
-
|
27
|
-
connection.reconnect!
|
28
|
-
|
29
|
-
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
30
|
-
|
31
|
-
RSpec.configure do |config|
|
32
|
-
config.mock_with :rspec
|
33
|
-
|
34
|
-
config.filter_run_when_matching :focus
|
35
|
-
|
36
|
-
config.example_status_persistence_file_path = "tmp/rspec_examples.txt"
|
37
|
-
|
38
|
-
if config.files_to_run.one?
|
39
|
-
config.default_formatter = 'doc'
|
40
|
-
end
|
41
|
-
end
|
@@ -1,94 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe ActiveRecord::Type::TypedStore do
|
4
|
-
let(:json_type) { ActiveRecord::Type::Serialized.new(ActiveRecord::Type::Text.new, ActiveRecord::Coders::JSON) }
|
5
|
-
let(:yaml_type) do
|
6
|
-
ActiveRecord::Type::Serialized.new(
|
7
|
-
ActiveRecord::Type::Text.new,
|
8
|
-
ActiveRecord::Store::IndifferentCoder.new(
|
9
|
-
ActiveRecord::Coders::YAMLColumn.new(Hash)
|
10
|
-
)
|
11
|
-
)
|
12
|
-
end
|
13
|
-
|
14
|
-
context "with json store" do
|
15
|
-
subject { described_class.new(json_type) }
|
16
|
-
|
17
|
-
describe "#cast" do
|
18
|
-
it "without key types", :aggregate_failures do
|
19
|
-
expect(subject.cast([1, 2])).to eq [1, 2]
|
20
|
-
expect(subject.cast('a' => 'b')).to eq('a' => 'b')
|
21
|
-
end
|
22
|
-
|
23
|
-
it "with type keys" do
|
24
|
-
subject.add_typed_key('date', :date)
|
25
|
-
|
26
|
-
date = ::Date.new(2016, 6, 22)
|
27
|
-
expect(subject.cast(date: '2016-06-22')).to eq('date' => date)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
describe "#deserialize" do
|
32
|
-
it "without key types", :aggregate_failures do
|
33
|
-
expect(subject.deserialize('[1,2]')).to eq [1, 2]
|
34
|
-
expect(subject.deserialize('{"a":"b"}')).to eq('a' => 'b')
|
35
|
-
end
|
36
|
-
|
37
|
-
it "with type keys" do
|
38
|
-
subject.add_typed_key('date', :date)
|
39
|
-
|
40
|
-
date = ::Date.new(2016, 6, 22)
|
41
|
-
expect(subject.deserialize('{"date":"2016-06-22"}')).to eq('date' => date)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
describe "#serialize" do
|
46
|
-
it "without key types", :aggregate_failures do
|
47
|
-
expect(subject.serialize([1, 2])).to eq '[1,2]'
|
48
|
-
expect(subject.serialize('a' => 'b')).to eq '{"a":"b"}'
|
49
|
-
end
|
50
|
-
|
51
|
-
it "with type keys" do
|
52
|
-
subject.add_typed_key('date', :date)
|
53
|
-
|
54
|
-
date = ::Date.new(2016, 6, 22)
|
55
|
-
expect(subject.serialize(date: date)).to eq '{"date":"2016-06-22"}'
|
56
|
-
end
|
57
|
-
|
58
|
-
it "with type key with option" do
|
59
|
-
subject.add_typed_key('val', :integer, limit: 1)
|
60
|
-
|
61
|
-
expect { subject.serialize(val: 1024) }.to raise_error(RangeError)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
describe ".create_from_type" do
|
66
|
-
it "creates with valid types", :aggregate_failures do
|
67
|
-
type = described_class.create_from_type(json_type, 'date', :date)
|
68
|
-
new_type = described_class.create_from_type(type, 'val', :integer)
|
69
|
-
|
70
|
-
date = ::Date.new(2016, 6, 22)
|
71
|
-
|
72
|
-
expect(type.cast(date: '2016-06-22', val: '1.2')).to eq('date' => date, 'val' => '1.2')
|
73
|
-
expect(new_type.cast(date: '2016-06-22', val: '1.2')).to eq('date' => date, 'val' => 1)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
context "with yaml coder" do
|
79
|
-
let(:subject) { described_class.new(yaml_type) }
|
80
|
-
|
81
|
-
it "works", :aggregate_failures do
|
82
|
-
subject.add_typed_key('date', :date)
|
83
|
-
|
84
|
-
date = ::Date.new(2016, 6, 22)
|
85
|
-
|
86
|
-
expect(subject.cast(date: '2016-06-22')).to eq('date' => date)
|
87
|
-
expect(subject.cast('date' => '2016-06-22')).to eq('date' => date)
|
88
|
-
expect(subject.deserialize("---\n:date: 2016-06-22\n")).to eq('date' => date)
|
89
|
-
expect(subject.deserialize("---\ndate: 2016-06-22\n")).to eq('date' => date)
|
90
|
-
expect(subject.serialize(date: date)).to eq "--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\ndate: 2016-06-22\n"
|
91
|
-
expect(subject.serialize('date' => date)).to eq "--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\ndate: 2016-06-22\n"
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
data/spec/support/money_type.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
class MoneyType < ActiveRecord::Type::Integer
|
2
|
-
def cast(value)
|
3
|
-
if !value.is_a?(Numeric) && value.include?('$')
|
4
|
-
price_in_dollars = value.delete('$').to_f
|
5
|
-
super(price_in_dollars * 100)
|
6
|
-
else
|
7
|
-
super
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
ActiveRecord::Type.register(:money_type, MoneyType)
|
data/spec/support/user.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
class RawUser < ActiveRecord::Base
|
2
|
-
self.table_name = 'users'
|
3
|
-
end
|
4
|
-
|
5
|
-
class User < ActiveRecord::Base
|
6
|
-
store_accessor :jparams, :version, active: :boolean, salary: :integer
|
7
|
-
store_attribute :jparams, :birthday, :date
|
8
|
-
|
9
|
-
store_attribute :jparams, :inner_json, :json
|
10
|
-
|
11
|
-
store :custom, accessors: [price: :money_type]
|
12
|
-
|
13
|
-
store_accessor :hdata, visible: :boolean
|
14
|
-
|
15
|
-
store_attribute :hdata, :ratio, :integer, limit: 1
|
16
|
-
store_attribute :hdata, :login_at, :datetime
|
17
|
-
end
|
data/store_attribute.gemspec
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
$:.push File.expand_path("../lib", __FILE__)
|
2
|
-
|
3
|
-
# Maintain your gem's version:
|
4
|
-
require "store_attribute/version"
|
5
|
-
|
6
|
-
# Describe your gem and declare its dependencies:
|
7
|
-
Gem::Specification.new do |s|
|
8
|
-
s.name = "store_attribute"
|
9
|
-
s.version = StoreAttribute::VERSION
|
10
|
-
s.authors = ["palkan"]
|
11
|
-
s.email = ["dementiev.vm@gmail.com"]
|
12
|
-
s.homepage = "http://github.com/palkan/store_attribute"
|
13
|
-
s.summary = "ActiveRecord extension which adds typecasting to store accessors"
|
14
|
-
s.description = "ActiveRecord extension which adds typecasting to store accessors"
|
15
|
-
s.license = "MIT"
|
16
|
-
|
17
|
-
s.files = `git ls-files`.split($/)
|
18
|
-
s.require_paths = ["lib"]
|
19
|
-
|
20
|
-
s.add_runtime_dependency "activerecord", "~>5.0.0"
|
21
|
-
|
22
|
-
s.add_development_dependency "pg", "~>0.18"
|
23
|
-
s.add_development_dependency "rake", "~> 10.1"
|
24
|
-
s.add_development_dependency "simplecov", ">= 0.3.8"
|
25
|
-
s.add_development_dependency "pry-byebug"
|
26
|
-
s.add_development_dependency "rspec", "~> 3.5.0"
|
27
|
-
end
|