store_attribute 0.4.1 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- 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 +8 -23
- data/lib/store_attribute/version.rb +1 -1
- data/spec/spec_helper.rb +1 -2
- data/spec/store_attribute/typed_store_spec.rb +21 -21
- data/spec/support/money_type.rb +2 -2
- data/store_attribute.gemspec +2 -2
- metadata +8 -9
- 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: cd2643cf4b1909497a0de3f0d15ed6ca51ba599e
|
4
|
+
data.tar.gz: 607171026ea9b9638e20a920b732bd7258db246a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79e570bd455ecf0f2f7c500725e4a243f4e0d5133c5bdfd45100e10963bbe16623c37396d4a87b7018c74472813efbcfd212cc9d7ebe83c697ca00ad053d338c
|
7
|
+
data.tar.gz: 0c4458f32f0a658d276218894912e3c1c53833dd0cb4e506885bcff00a824beeadda620c89a4d6c09376edd1a262b9396ad317eb275c981d4d08194eb48968da
|
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,26 +18,26 @@ module ActiveRecord
|
|
33
18
|
end
|
34
19
|
|
35
20
|
def add_typed_key(key, type, **options)
|
36
|
-
type = Type.
|
21
|
+
type = ActiveRecord::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
27
|
if hash
|
43
28
|
accessor_types.each do |key, type|
|
44
|
-
hash[key] = type.
|
29
|
+
hash[key] = type.deserialize(hash[key]) if hash.key?(key)
|
45
30
|
end
|
46
31
|
end
|
47
32
|
hash
|
48
33
|
end
|
49
34
|
|
50
|
-
def
|
35
|
+
def serialize(value)
|
51
36
|
if value.is_a?(Hash)
|
52
37
|
typed_casted = {}
|
53
38
|
accessor_types.each do |key, type|
|
54
39
|
k = key_to_cast(value, key)
|
55
|
-
typed_casted[k] = type.
|
40
|
+
typed_casted[k] = type.serialize(value[k]) unless k.nil?
|
56
41
|
end
|
57
42
|
super(value.merge(typed_casted))
|
58
43
|
else
|
@@ -60,11 +45,11 @@ module ActiveRecord
|
|
60
45
|
end
|
61
46
|
end
|
62
47
|
|
63
|
-
def
|
48
|
+
def cast(value)
|
64
49
|
hash = super
|
65
50
|
if hash
|
66
51
|
accessor_types.each do |key, type|
|
67
|
-
hash[key] = type.
|
52
|
+
hash[key] = type.cast(hash[key]) if hash.key?(key)
|
68
53
|
end
|
69
54
|
end
|
70
55
|
hash
|
@@ -75,7 +60,7 @@ module ActiveRecord
|
|
75
60
|
end
|
76
61
|
|
77
62
|
def write(object, attribute, key, value)
|
78
|
-
value = type_for(key).
|
63
|
+
value = type_for(key).cast(value) if typed?(key)
|
79
64
|
store_accessor.write(object, attribute, key, value)
|
80
65
|
end
|
81
66
|
|
data/spec/spec_helper.rb
CHANGED
@@ -31,8 +31,7 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
|
31
31
|
RSpec.configure do |config|
|
32
32
|
config.mock_with :rspec
|
33
33
|
|
34
|
-
config.
|
35
|
-
config.run_all_when_everything_filtered = true
|
34
|
+
config.filter_run_when_matching :focus
|
36
35
|
|
37
36
|
config.example_status_persistence_file_path = "tmp/rspec_examples.txt"
|
38
37
|
|
@@ -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
|
-
ActiveRecord::
|
12
|
+
ActiveRecord::Type.register(:money_type, MoneyType)
|
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,7 +1,7 @@
|
|
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.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
@@ -14,16 +14,16 @@ dependencies:
|
|
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
|