store_attribute 0.4.1 → 0.5.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/.gitignore +1 -2
- data/.travis.yml +2 -2
- data/Gemfile +1 -1
- data/README.md +11 -5
- data/gemfiles/{rails42.gemfile → rails5.gemfile} +1 -1
- data/lib/store_attribute/active_record/type/typed_store.rb +10 -33
- data/lib/store_attribute/version.rb +1 -1
- data/spec/cases/store_attribute_spec.rb +0 -23
- data/spec/spec_helper.rb +0 -9
- data/spec/store_attribute/typed_store_spec.rb +21 -21
- data/spec/support/money_type.rb +2 -2
- data/spec/support/user.rb +0 -2
- data/store_attribute.gemspec +2 -2
- metadata +9 -10
- data/gemfiles/rails-edge.gemfile +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2fe7ad4819867227ad87556c1656e53d18405c15
|
4
|
+
data.tar.gz: bd6ccc0ef54fe3ea63a5deddae91712b34b9e937
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 09cfe9e9d985bd9d510ca0a5a7d0e5b1be2c02cae61bb99e6954c080c28fccf44d0d82a001e892ee71fc7908e0ce45792831fbbd05a7d397c1f154b6bea90c6b
|
7
|
+
data.tar.gz: 144699139f1f6dbc55c8bd86c4b7cb3335cbcc0d37991cb006a4ac5802bceefdd2b26aa8de7b73f42df00a5280eeada3e50096c1f0bb8cb6519de8916493ebe0
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -4,15 +4,21 @@
|
|
4
4
|
|
5
5
|
ActiveRecord extension which adds typecasting to store accessors.
|
6
6
|
|
7
|
-
Compatible with
|
7
|
+
Compatible with Rails 4.2 and Rails 5.
|
8
8
|
|
9
|
+
<a href="https://evilmartians.com/">
|
10
|
+
<img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
|
9
11
|
|
10
12
|
### Install
|
11
13
|
|
12
14
|
In your Gemfile:
|
13
15
|
|
14
16
|
```ruby
|
15
|
-
|
17
|
+
# for Rails 5
|
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,7 +26,7 @@ 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:
|
@@ -62,7 +68,7 @@ u.settings['ration'] = "3.141592653"
|
|
62
68
|
u.ratio # => "3.141592653"
|
63
69
|
|
64
70
|
# On the other hand, writing through accessor set correct data within store
|
65
|
-
u.ratio = "3.
|
71
|
+
u.ratio = "3.141592653"
|
66
72
|
u.ratio # => 3
|
67
73
|
u.settings['ratio'] # => 3
|
68
74
|
```
|
@@ -81,4 +87,4 @@ Or through `store`:
|
|
81
87
|
class User < ActiveRecord::Base
|
82
88
|
store :settings, accessors: [:color, :homepage, login_at: :datetime], coder: JSON
|
83
89
|
end
|
84
|
-
```
|
90
|
+
```
|
@@ -2,21 +2,6 @@ require 'active_record/type'
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
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
5
|
class TypedStore < DelegateClass(ActiveRecord::Type::Value) # :nodoc:
|
21
6
|
# Creates +TypedStore+ type instance and specifies type caster
|
22
7
|
# for key.
|
@@ -33,38 +18,30 @@ module ActiveRecord
|
|
33
18
|
end
|
34
19
|
|
35
20
|
def add_typed_key(key, type, **options)
|
36
|
-
type = Type.
|
21
|
+
type = ActiveModel::Type.lookup(type, options) if type.is_a?(Symbol)
|
37
22
|
@accessor_types[key.to_s] = type
|
38
23
|
end
|
39
24
|
|
40
|
-
def
|
25
|
+
def deserialize(value)
|
41
26
|
hash = super
|
42
|
-
|
43
|
-
accessor_types.each do |key, type|
|
44
|
-
hash[key] = type.type_cast_from_database(hash[key]) if hash.key?(key)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
hash
|
27
|
+
cast(hash)
|
48
28
|
end
|
49
29
|
|
50
|
-
def
|
51
|
-
if value
|
52
|
-
typed_casted = {}
|
30
|
+
def serialize(value)
|
31
|
+
if value
|
53
32
|
accessor_types.each do |key, type|
|
54
33
|
k = key_to_cast(value, key)
|
55
|
-
|
34
|
+
value[k] = type.serialize(value[k]) unless k.nil?
|
56
35
|
end
|
57
|
-
super(value.merge(typed_casted))
|
58
|
-
else
|
59
|
-
super(value)
|
60
36
|
end
|
37
|
+
super(value)
|
61
38
|
end
|
62
39
|
|
63
|
-
def
|
40
|
+
def cast(value)
|
64
41
|
hash = super
|
65
42
|
if hash
|
66
43
|
accessor_types.each do |key, type|
|
67
|
-
hash[key] = type.
|
44
|
+
hash[key] = type.cast(hash[key]) if hash.key?(key)
|
68
45
|
end
|
69
46
|
end
|
70
47
|
hash
|
@@ -75,7 +52,7 @@ module ActiveRecord
|
|
75
52
|
end
|
76
53
|
|
77
54
|
def write(object, attribute, key, value)
|
78
|
-
value = type_for(key).
|
55
|
+
value = type_for(key).cast(value) if typed?(key)
|
79
56
|
store_accessor.write(object, attribute, key, value)
|
80
57
|
end
|
81
58
|
|
@@ -140,32 +140,9 @@ describe StoreAttribute do
|
|
140
140
|
|
141
141
|
it "typecasts on reload" do
|
142
142
|
jamie = User.create!(custom: { price: '$12' })
|
143
|
-
expect(jamie.reload.price).to eq 1200
|
144
|
-
|
145
143
|
jamie = User.find(jamie.id)
|
146
144
|
|
147
145
|
expect(jamie.price).to eq 1200
|
148
146
|
end
|
149
147
|
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
148
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -30,13 +30,4 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
|
30
30
|
|
31
31
|
RSpec.configure do |config|
|
32
32
|
config.mock_with :rspec
|
33
|
-
|
34
|
-
config.filter_run :focus
|
35
|
-
config.run_all_when_everything_filtered = true
|
36
|
-
|
37
|
-
config.example_status_persistence_file_path = "tmp/rspec_examples.txt"
|
38
|
-
|
39
|
-
if config.files_to_run.one?
|
40
|
-
config.default_formatter = 'doc'
|
41
|
-
end
|
42
33
|
end
|
@@ -14,51 +14,51 @@ describe ActiveRecord::Type::TypedStore do
|
|
14
14
|
context "with json store" do
|
15
15
|
subject { described_class.new(json_type) }
|
16
16
|
|
17
|
-
describe "#
|
17
|
+
describe "#cast" do
|
18
18
|
it "without key types", :aggregate_failures do
|
19
|
-
expect(subject.
|
20
|
-
expect(subject.
|
19
|
+
expect(subject.cast([1, 2])).to eq [1, 2]
|
20
|
+
expect(subject.cast('a' => 'b')).to eq('a' => 'b')
|
21
21
|
end
|
22
22
|
|
23
23
|
it "with type keys" do
|
24
24
|
subject.add_typed_key('date', :date)
|
25
25
|
|
26
26
|
date = ::Date.new(2016, 6, 22)
|
27
|
-
expect(subject.
|
27
|
+
expect(subject.cast(date: '2016-06-22')).to eq('date' => date)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
describe "#
|
31
|
+
describe "#deserialize" do
|
32
32
|
it "without key types", :aggregate_failures do
|
33
|
-
expect(subject.
|
34
|
-
expect(subject.
|
33
|
+
expect(subject.deserialize('[1,2]')).to eq [1, 2]
|
34
|
+
expect(subject.deserialize('{"a":"b"}')).to eq('a' => 'b')
|
35
35
|
end
|
36
36
|
|
37
37
|
it "with type keys" do
|
38
38
|
subject.add_typed_key('date', :date)
|
39
39
|
|
40
40
|
date = ::Date.new(2016, 6, 22)
|
41
|
-
expect(subject.
|
41
|
+
expect(subject.deserialize('{"date":"2016-06-22"}')).to eq('date' => date)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
describe "#
|
45
|
+
describe "#serialize" do
|
46
46
|
it "without key types", :aggregate_failures do
|
47
|
-
expect(subject.
|
48
|
-
expect(subject.
|
47
|
+
expect(subject.serialize([1, 2])).to eq '[1,2]'
|
48
|
+
expect(subject.serialize('a' => 'b')).to eq '{"a":"b"}'
|
49
49
|
end
|
50
50
|
|
51
51
|
it "with type keys" do
|
52
52
|
subject.add_typed_key('date', :date)
|
53
53
|
|
54
54
|
date = ::Date.new(2016, 6, 22)
|
55
|
-
expect(subject.
|
55
|
+
expect(subject.serialize(date: date)).to eq '{"date":"2016-06-22"}'
|
56
56
|
end
|
57
57
|
|
58
58
|
it "with type key with option" do
|
59
59
|
subject.add_typed_key('val', :integer, limit: 1)
|
60
60
|
|
61
|
-
expect { subject.
|
61
|
+
expect { subject.serialize(val: 1024) }.to raise_error(RangeError)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
@@ -69,8 +69,8 @@ describe ActiveRecord::Type::TypedStore do
|
|
69
69
|
|
70
70
|
date = ::Date.new(2016, 6, 22)
|
71
71
|
|
72
|
-
expect(type.
|
73
|
-
expect(new_type.
|
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
74
|
end
|
75
75
|
end
|
76
76
|
end
|
@@ -83,12 +83,12 @@ describe ActiveRecord::Type::TypedStore do
|
|
83
83
|
|
84
84
|
date = ::Date.new(2016, 6, 22)
|
85
85
|
|
86
|
-
expect(subject.
|
87
|
-
expect(subject.
|
88
|
-
expect(subject.
|
89
|
-
expect(subject.
|
90
|
-
expect(subject.
|
91
|
-
expect(subject.
|
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
92
|
end
|
93
93
|
end
|
94
94
|
end
|
data/spec/support/money_type.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class MoneyType < ActiveRecord::Type::Integer
|
2
|
-
def
|
2
|
+
def cast(value)
|
3
3
|
if !value.is_a?(Numeric) && value.include?('$')
|
4
4
|
price_in_dollars = value.delete('$').to_f
|
5
5
|
super(price_in_dollars * 100)
|
@@ -9,4 +9,4 @@ class MoneyType < ActiveRecord::Type::Integer
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
ActiveModel::Type.register(:money_type, MoneyType)
|
data/spec/support/user.rb
CHANGED
@@ -6,8 +6,6 @@ class User < ActiveRecord::Base
|
|
6
6
|
store_accessor :jparams, :version, active: :boolean, salary: :integer
|
7
7
|
store_attribute :jparams, :birthday, :date
|
8
8
|
|
9
|
-
store_attribute :jparams, :inner_json, :json
|
10
|
-
|
11
9
|
store :custom, accessors: [price: :money_type]
|
12
10
|
|
13
11
|
store_accessor :hdata, visible: :boolean
|
data/store_attribute.gemspec
CHANGED
@@ -17,11 +17,11 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.files = `git ls-files`.split($/)
|
18
18
|
s.require_paths = ["lib"]
|
19
19
|
|
20
|
-
s.add_runtime_dependency "activerecord", "
|
20
|
+
s.add_runtime_dependency "activerecord", "~>5.0.0"
|
21
21
|
|
22
22
|
s.add_development_dependency "pg", "~>0.18"
|
23
23
|
s.add_development_dependency "rake", "~> 10.1"
|
24
24
|
s.add_development_dependency "simplecov", ">= 0.3.8"
|
25
25
|
s.add_development_dependency "pry-byebug"
|
26
|
-
s.add_development_dependency "rspec", "~> 3.
|
26
|
+
s.add_development_dependency "rspec", "~> 3.5.0"
|
27
27
|
end
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: store_attribute
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-07-
|
11
|
+
date: 2016-07-02 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:
|
19
|
+
version: 5.0.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:
|
26
|
+
version: 5.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: pg
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 3.
|
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
|
-
version: 3.
|
96
|
+
version: 3.5.0
|
97
97
|
description: ActiveRecord extension which adds typecasting to store accessors
|
98
98
|
email:
|
99
99
|
- dementiev.vm@gmail.com
|
@@ -113,8 +113,7 @@ files:
|
|
113
113
|
- bench/setup.rb
|
114
114
|
- bin/console
|
115
115
|
- bin/setup
|
116
|
-
- gemfiles/
|
117
|
-
- gemfiles/rails42.gemfile
|
116
|
+
- gemfiles/rails5.gemfile
|
118
117
|
- lib/store_attribute.rb
|
119
118
|
- lib/store_attribute/active_record.rb
|
120
119
|
- lib/store_attribute/active_record/store.rb
|