activerecord-typedstore 0.3.2 → 0.4.0

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
  SHA1:
3
- metadata.gz: 8790af5ac7b68a121e6d5cd21305421b49b5799c
4
- data.tar.gz: 0afe8bfce070b6f1d87f5c3f39334870ce9decc2
3
+ metadata.gz: 960e7c0f770dab59201ece58bcfa91927216eeea
4
+ data.tar.gz: 5a9f38f6153167050d7e5a57bfcba6fb717dd9e6
5
5
  SHA512:
6
- metadata.gz: 10d34e86b936c3c9d1f85dd35c6d2414f18c0c4346784f39ce9e4e741c02b23a8657fed819b8ed39a63c9ffb5d36b8b78b559dd2a877e1be64352a5e3b9b9cc8
7
- data.tar.gz: d9954012cc7fbec9501a19b7b10e8091c9d3447fc7413cbd09023d822e75f7a00ee505c3712720bac1b8de8d47d6a9ad8b4f5c7f1ca6265a09b454f0328c1621
6
+ metadata.gz: 363573dd39996321d853554cc49c1712966a515e8260bfaa9e6b6bf2763b8d5600b516e76559eff1e480c4527f43f472e403573b9a44b5b986307550345a3455
7
+ data.tar.gz: 2b7945d7a87685f0178cca67c84eb662feb21cafe2d944a4883265917508dacf70f75bb1cffef473338dd870c5f44c3069f2f16f2cc4cf3c34c0e66ce077707f
data/.travis.yml CHANGED
@@ -4,6 +4,7 @@ rvm:
4
4
  gemfile:
5
5
  - gemfiles/Gemfile.ar-3.2
6
6
  - gemfiles/Gemfile.ar-4.0
7
+ - gemfiles/Gemfile.ar-4.1
7
8
  - gemfiles/Gemfile.ar-edge
8
9
 
9
10
  before_script:
@@ -12,3 +13,7 @@ before_script:
12
13
  env:
13
14
  - TIMEZONE_AWARE=1 POSTGRES=1 MYSQL=1 POSTGRES_URL=$(curl http://api.postgression.com)
14
15
  - TIMEZONE_AWARE=0 POSTGRES=1 MYSQL=1 POSTGRES_URL=$(curl http://api.postgression.com)
16
+
17
+ matrix:
18
+ allow_failures:
19
+ - gemfile: gemfiles/Gemfile.ar-edge
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Build Status](https://secure.travis-ci.org/byroot/activerecord-typedstore.png)](http://travis-ci.org/byroot/activerecord-typedstore)
4
4
  [![Code Climate](https://codeclimate.com/github/byroot/activerecord-typedstore.png)](https://codeclimate.com/github/byroot/activerecord-typedstore)
5
5
  [![Coverage Status](https://coveralls.io/repos/byroot/activerecord-typedstore/badge.png)](https://coveralls.io/r/byroot/activerecord-typedstore)
6
+ [![Gem Version](https://badge.fury.io/rb/activerecord-typedstore.png)](http://badge.fury.io/rb/activerecord-typedstore)
6
7
 
7
8
  [ActiveRecord::Store](http://api.rubyonrails.org/classes/ActiveRecord/Store.html) but with typed attributes.
8
9
 
@@ -78,6 +79,19 @@ shop.save
78
79
  shop.reload
79
80
  shop.settings[:unknown] # => 'Hello World'
80
81
 
82
+ # If you only want type casting and default handling without accessors
83
+
84
+ # you can disable them store wide
85
+ typed_store :settings, accessors: false do |s|
86
+ # ...
87
+ end
88
+
89
+ # or on a per attribute basis
90
+ typed_store :settings do |s|
91
+ s.integer :age
92
+ s.string :postal_code, accessor: false
93
+ end
94
+
81
95
  ```
82
96
 
83
97
  Type casting rules and attribute behavior are exactly the same as a for real database columns.
@@ -92,8 +106,3 @@ If not, please fill an issue.
92
106
  3. Commit your changes (`git commit -am 'Add some feature'`)
93
107
  4. Push to the branch (`git push origin my-new-feature`)
94
108
  5. Create new Pull Request
95
-
96
- ## TODO
97
-
98
- - HStore support with ActiveRecord 4.1.0.beta (master)
99
- - Handle casting and default at the store layer, so accessors are not mandatory anymore. See #4
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'activerecord', '~> 4.1.0.beta1'
4
+ gem 'bundler', '~> 1.3'
5
+ gem 'rake'
6
+ gem 'rspec'
7
+ gem 'sqlite3'
8
+ gem 'pg', '~> 0.11'
9
+ gem 'mysql2'
10
+ gem 'database_cleaner'
11
+ gem 'coveralls', require: false
12
+ gem 'debugger'
@@ -1,3 +1,24 @@
1
+ class ActiveRecord::Store::IndifferentCoder
2
+ # Backport from rails 4.0
3
+ def initialize(coder_or_class_name)
4
+ @coder =
5
+ if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump)
6
+ coder_or_class_name
7
+ else
8
+ ActiveRecord::Coders::YAMLColumn.new(coder_or_class_name || Object)
9
+ end
10
+ end
11
+
12
+ def dump(obj)
13
+ @coder.dump self.class.as_indifferent_hash(obj)
14
+ end
15
+
16
+ def load(yaml)
17
+ self.class.as_indifferent_hash @coder.load(yaml)
18
+ end
19
+
20
+ end
21
+
1
22
  module ActiveRecord::TypedStore
2
23
 
3
24
  module AR32Fallbacks
@@ -11,7 +32,7 @@ module ActiveRecord::TypedStore
11
32
  module ClassMethods
12
33
 
13
34
  def typed_store(store_attribute, dsl)
14
- _ar_32_fallback_accessors(store_attribute, dsl.column_names)
35
+ _ar_32_fallback_accessors(store_attribute, dsl.accessors)
15
36
  end
16
37
 
17
38
  protected
@@ -34,9 +55,9 @@ module ActiveRecord::TypedStore
34
55
  attribute_method_matchers_cache.clear
35
56
  end
36
57
 
37
- def _ar_32_fallback_accessors(store_attribute, column_names)
38
- column_names.each do |name|
39
- _ar_32_fallback_accessor(store_attribute, name)
58
+ def _ar_32_fallback_accessors(store_attribute, accessors)
59
+ accessors.each do |accessor|
60
+ _ar_32_fallback_accessor(store_attribute, accessor)
40
61
  end
41
62
  end
42
63
 
@@ -0,0 +1,22 @@
1
+ module ActiveRecord::TypedStore
2
+
3
+ class Coder < ::ActiveRecord::Store::IndifferentCoder
4
+
5
+ class << self
6
+
7
+ def create(store_class)
8
+ Class.new(self) do
9
+ @store_class = store_class
10
+ end
11
+ end
12
+
13
+ def as_indifferent_hash(obj)
14
+ return obj if obj.is_a?(@store_class)
15
+ @store_class.new(obj)
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -10,6 +10,11 @@ module ActiveRecord::TypedStore
10
10
  @default = extract_default(options.fetch(:default, nil))
11
11
  @null = options.fetch(:null, true)
12
12
  @blank = options.fetch(:blank, true)
13
+ @accessor = options.fetch(:accessor, true)
14
+ end
15
+
16
+ def accessor?
17
+ @accessor
13
18
  end
14
19
 
15
20
  def cast(value)
@@ -4,18 +4,19 @@ module ActiveRecord::TypedStore
4
4
 
5
5
  attr_reader :columns
6
6
 
7
- def initialize
7
+ def initialize(accessors=true)
8
+ @accessors = accessors
8
9
  @columns = []
9
10
  yield self
10
11
  end
11
12
 
12
- def column_names
13
- @columns.map(&:name)
13
+ def accessors
14
+ @columns.select(&:accessor?).map(&:name)
14
15
  end
15
16
 
16
17
  [:string, :integer, :float, :decimal, :datetime, :date, :boolean, :any].each do |type|
17
18
  define_method(type) do |name, options={}|
18
- @columns << Column.new(name, type, options)
19
+ @columns << Column.new(name, type, options.reverse_merge(accessor: @accessors))
19
20
  end
20
21
  end
21
22
 
@@ -1,5 +1,6 @@
1
1
  require 'active_record/typed_store/column'
2
2
  require 'active_record/typed_store/dsl'
3
+ require 'active_record/typed_store/typed_hash'
3
4
 
4
5
  module ActiveRecord::TypedStore
5
6
  AR_VERSION = Gem::Version.new(ActiveRecord::VERSION::STRING)
@@ -17,18 +18,15 @@ module ActiveRecord::TypedStore
17
18
  module ClassMethods
18
19
 
19
20
  def typed_store(store_attribute, options={}, &block)
20
- dsl = DSL.new(&block)
21
+ dsl = DSL.new(options.fetch(:accessors, true), &block)
21
22
 
22
- if hstore?(store_attribute)
23
- store_accessor(store_attribute, dsl.column_names)
24
- else
25
- store(store_attribute, options.merge(accessors: dsl.column_names))
26
- end
23
+ serialize store_attribute, create_coder(store_attribute, dsl.columns).new(options[:coder])
24
+ store_accessor(store_attribute, dsl.accessors)
27
25
 
28
26
  register_typed_store_columns(store_attribute, dsl.columns)
29
27
  super(store_attribute, dsl) if defined?(super)
30
28
 
31
- dsl.column_names.each { |c| define_store_attribute_queries(store_attribute, c) }
29
+ dsl.accessors.each { |c| define_store_attribute_queries(store_attribute, c) }
32
30
 
33
31
  dsl
34
32
  end
@@ -40,6 +38,12 @@ module ActiveRecord::TypedStore
40
38
 
41
39
  private
42
40
 
41
+ def create_coder(store_attribute, columns)
42
+ store_class = TypedHash.create(columns)
43
+ const_set("#{store_attribute}_hash".camelize, store_class)
44
+ Coder.create(store_class)
45
+ end
46
+
43
47
  def register_typed_store_columns(store_attribute, columns)
44
48
  self.typed_stores ||= {}
45
49
  self.typed_store_attributes ||= {}
@@ -49,12 +53,16 @@ module ActiveRecord::TypedStore
49
53
  end
50
54
 
51
55
  def define_typed_store_attribute_methods
52
- return unless typed_store_attributes
53
- typed_store_attributes.keys.each do |attribute|
56
+ store_accessors.each do |attribute|
54
57
  define_virtual_attribute_method(attribute)
55
58
  end
56
59
  end
57
60
 
61
+ def store_accessors
62
+ return [] unless typed_store_attributes
63
+ typed_store_attributes.values.select(&:accessor?).map(&:name).map(&:to_s)
64
+ end
65
+
58
66
  def hstore?(store_attribute)
59
67
  columns_hash[store_attribute.to_s].try(:type) == :hstore
60
68
  end
@@ -72,11 +80,6 @@ module ActiveRecord::TypedStore
72
80
 
73
81
  end
74
82
 
75
- def reload(*)
76
- reload_stores!
77
- super
78
- end
79
-
80
83
  protected
81
84
 
82
85
  def write_store_attribute(store_attribute, key, value)
@@ -86,18 +89,12 @@ module ActiveRecord::TypedStore
86
89
  end
87
90
 
88
91
  previous_value = read_store_attribute(store_attribute, key)
89
- casted_value = cast_store_attribute(store_attribute, key, value)
90
- attribute_will_change!(key.to_s) if casted_value != previous_value
91
- super(store_attribute, key, casted_value)
92
+ attribute_will_change!(key.to_s) if value != previous_value
93
+ super
92
94
  end
93
95
 
94
96
  private
95
97
 
96
- def cast_store_attribute(store_attribute, key, value)
97
- column = store_column(store_attribute, key)
98
- column ? column.cast(value) : value
99
- end
100
-
101
98
  def store_column(store_attribute, key)
102
99
  store = store_columns(store_attribute)
103
100
  store && store[key]
@@ -107,43 +104,6 @@ module ActiveRecord::TypedStore
107
104
  self.class.typed_stores.try(:[], store_attribute)
108
105
  end
109
106
 
110
- def if_store_uninitialized(store_attribute)
111
- initialized = "@_#{store_attribute}_initialized"
112
- unless instance_variable_get(initialized)
113
- yield
114
- instance_variable_set(initialized, true)
115
- end
116
- end
117
-
118
- def reload_stores!
119
- return unless self.class.typed_stores
120
- self.class.typed_stores.keys.each do |store_attribute|
121
- instance_variable_set("@_#{store_attribute}_initialized", false)
122
- end
123
- end
124
-
125
- def initialize_store_attribute(store_attribute)
126
- store = defined?(super) ? super : send(store_attribute)
127
- store.tap do |store|
128
- if_store_uninitialized(store_attribute) do
129
- if columns = store_columns(store_attribute)
130
- initialize_store(store, columns.values)
131
- end
132
- end
133
- end
134
- end
135
-
136
- def initialize_store(store, columns)
137
- columns.each do |column|
138
- if store.has_key?(column.name)
139
- store[column.name] = column.cast(store[column.name])
140
- else
141
- store[column.name] = column.default if column.has_default?
142
- end
143
- end
144
- store
145
- end
146
-
147
107
  # heavilly inspired from ActiveRecord::Base#query_attribute
148
108
  def query_store_attribute(store_attribute, key)
149
109
  value = read_store_attribute(store_attribute, key)
@@ -165,7 +125,8 @@ module ActiveRecord::TypedStore
165
125
  end
166
126
 
167
127
  require 'active_record/typed_store/ar_32_fallbacks' if IS_AR_3_2
168
- require 'active_record/typed_store/ar_41_fallbacks' if IS_AR_4_1
128
+ require 'active_record/typed_store/coder'
129
+
169
130
  unless IS_AR_3_2
170
131
  ActiveModel::AttributeMethods::ClassMethods.send(:alias_method, :define_virtual_attribute_method, :define_attribute_method)
171
132
  end
@@ -0,0 +1,63 @@
1
+ module ActiveRecord::TypedStore
2
+
3
+ class TypedHash < HashWithIndifferentAccess
4
+
5
+ class << self
6
+
7
+ attr_reader :columns
8
+
9
+ def create(columns)
10
+ Class.new(self) do
11
+ @columns = columns.index_by { |c| c.name.to_s }
12
+ end
13
+ end
14
+
15
+ end
16
+
17
+ def initialize(constructor={})
18
+ super()
19
+ update(defaults_hash)
20
+ update(constructor) if constructor.is_a?(Hash)
21
+ end
22
+
23
+ def []=(key, value)
24
+ super(key, cast_value(key, value))
25
+ end
26
+ alias_method :store, :[]=
27
+
28
+ def merge!(other_hash)
29
+ other_hash.each_pair do |key, value|
30
+ if block_given? && key?(key)
31
+ value = yield(convert_key(key), self[key], value)
32
+ end
33
+ self[convert_key(key)] = convert_value(value)
34
+ end
35
+ self
36
+ end
37
+ alias_method :update, :merge!
38
+
39
+ private
40
+
41
+ delegate :columns, to: 'self.class'
42
+
43
+ def defaults_hash
44
+ Hash[self.class.columns.values.select(&:has_default?).map { |c| [c.name, c.default] }]
45
+ end
46
+
47
+ def cast_value(key, value)
48
+ key = convert_key(key)
49
+ column = columns[key]
50
+ return value unless columns
51
+
52
+ casted_value = column.cast(value)
53
+
54
+ if casted_value.nil? && !column.null && column.has_default?
55
+ return column.default
56
+ end
57
+
58
+ casted_value
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module TypedStore
3
- VERSION = '0.3.2'
3
+ VERSION = '0.4.0'
4
4
  end
5
5
  end
@@ -0,0 +1,204 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRecord::TypedStore::TypedHash do
4
+
5
+ def create_hash_class(*args)
6
+ described_class.create([ActiveRecord::TypedStore::Column.new(*args)])
7
+ end
8
+
9
+ def build_hash(*args)
10
+ create_hash_class(*args).new
11
+ end
12
+
13
+ let(:hash) { build_hash(*column) }
14
+
15
+ let(:hash_class) { create_hash_class(*column) }
16
+
17
+ context 'nullable column without default' do
18
+
19
+ let(:column) { ['age', :integer] }
20
+
21
+ describe '.new' do
22
+
23
+ it 'apply casting' do
24
+ hash = hash_class.new(age: '24')
25
+ expect(hash[:age]).to be == 24
26
+ end
27
+
28
+ end
29
+
30
+ describe '#initialize' do
31
+
32
+ it 'has nil as default value' do
33
+ expect(hash[:age]).to be_nil
34
+ end
35
+
36
+ end
37
+
38
+ describe '#[]=' do
39
+
40
+ it 'apply casting' do
41
+ hash[:age] = '24'
42
+ expect(hash[:age]).to be == 24
43
+ end
44
+
45
+ it 'can be nil' do
46
+ hash[:age] = nil
47
+ expect(hash[:age]).to be_nil
48
+ end
49
+
50
+ end
51
+
52
+ describe '#merge!' do
53
+
54
+ it 'apply casting' do
55
+ hash.merge!(age: '24')
56
+ expect(hash[:age]).to be == 24
57
+ end
58
+
59
+ it 'can be nil' do
60
+ hash.merge!(age: nil)
61
+ expect(hash[:age]).to be_nil
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ context 'nullable column with default' do
69
+
70
+ let(:column) { ['age', :integer, default: 42] }
71
+
72
+ describe '#initialize' do
73
+
74
+ it 'has the default value' do
75
+ expect(hash[:age]).to be == 42
76
+ end
77
+
78
+ end
79
+
80
+ describe '#[]=' do
81
+
82
+ it 'apply casting' do
83
+ hash[:age] = '24'
84
+ expect(hash[:age]).to be == 24
85
+ end
86
+
87
+ it 'can be nil' do
88
+ hash[:age] = nil
89
+ expect(hash[:age]).to be_nil
90
+ end
91
+
92
+ end
93
+
94
+ describe '#merge!' do
95
+
96
+ it 'apply casting' do
97
+ hash.merge!(age: '24')
98
+ expect(hash[:age]).to be == 24
99
+ end
100
+
101
+ it 'can be nil' do
102
+ hash.merge!(age: nil)
103
+ expect(hash[:age]).to be_nil
104
+ end
105
+
106
+ end
107
+
108
+ end
109
+
110
+ context 'non nullable column with default' do
111
+
112
+ let(:column) { ['age', :integer, null: false, default: 42] }
113
+
114
+ describe '#intialize' do
115
+
116
+ it 'has the default value' do
117
+ expect(hash[:age]).to be == 42
118
+ end
119
+
120
+ end
121
+
122
+ describe '#[]=' do
123
+
124
+ it 'apply casting' do
125
+ hash[:age] = '24'
126
+ expect(hash[:age]).to be == 24
127
+ end
128
+
129
+ it 'cannot be nil' do
130
+ hash[:age] = nil
131
+ expect(hash[:age]).to be == 42
132
+ end
133
+
134
+ end
135
+
136
+ describe '#merge!' do
137
+
138
+ it 'apply casting' do
139
+ hash.merge!(age: '24')
140
+ expect(hash[:age]).to be == 24
141
+ end
142
+
143
+ it 'cannot be nil' do
144
+ hash.merge!(age: nil)
145
+ expect(hash[:age]).to be == 42
146
+ end
147
+
148
+ end
149
+
150
+ end
151
+
152
+ context 'non blankable column with default' do
153
+
154
+ let(:column) { ['source', :string, blank: false, default: 'web'] }
155
+
156
+ describe '#intialize' do
157
+
158
+ it 'has the default value' do
159
+ expect(hash[:source]).to be == 'web'
160
+ end
161
+
162
+ end
163
+
164
+ describe '#[]=' do
165
+
166
+ it 'apply casting' do
167
+ hash[:source] = :mailing
168
+ expect(hash[:source]).to be == 'mailing'
169
+ end
170
+
171
+ it 'cannot be nil' do
172
+ hash[:source] = nil
173
+ expect(hash[:source]).to be == 'web'
174
+ end
175
+
176
+ it 'cannot be blank' do
177
+ hash[:source] = ''
178
+ expect(hash[:source]).to be == 'web'
179
+ end
180
+
181
+ end
182
+
183
+ describe '#merge!' do
184
+
185
+ it 'apply casting' do
186
+ hash.merge!(source: :mailing)
187
+ expect(hash[:source]).to be == 'mailing'
188
+ end
189
+
190
+ it 'cannot be nil' do
191
+ hash.merge!(source: nil)
192
+ expect(hash[:source]).to be == 'web'
193
+ end
194
+
195
+ it 'cannot be blank' do
196
+ hash.merge!(source: '')
197
+ expect(hash[:source]).to be == 'web'
198
+ end
199
+
200
+ end
201
+
202
+ end
203
+
204
+ end
@@ -447,39 +447,6 @@ shared_examples 'a store' do |retain_type=true|
447
447
 
448
448
  let(:model) { described_class.new }
449
449
 
450
- describe 'initialization' do
451
-
452
- it 'is done only once' do
453
- model.should_receive(:initialize_store).once
454
- 3.times do
455
- model.age = (rand * 100).to_i
456
- model.age
457
- end
458
- end
459
-
460
- it 'is done again after a reload' do
461
- model.save
462
-
463
- model.should_receive(:initialize_store).twice
464
- 3.times do
465
- model.age = (rand * 100).to_i
466
- model.age
467
- end
468
- model.reload
469
- 3.times do
470
- model.age = (rand * 100).to_i
471
- model.age
472
- end
473
- end
474
-
475
- it 'is not performe if no store attributes are accessed' do
476
- model.should_not_receive(:initialize_store)
477
- model.update_attributes(untyped_settings: {foo: :bar})
478
- model.update_attributes(untyped_settings: {})
479
- end
480
-
481
- end
482
-
483
450
  describe 'attributes' do
484
451
 
485
452
  it 'retrieve default if assigned nil and null not allowed' do
@@ -494,6 +461,27 @@ shared_examples 'a store' do |retain_type=true|
494
461
 
495
462
  end
496
463
 
464
+ describe 'attributes without accessors' do
465
+
466
+ it 'cannot be accessed as a model attribute' do
467
+ expect(model).to_not respond_to :country
468
+ expect(model).to_not respond_to :country=
469
+ end
470
+
471
+ it 'cannot be queried' do
472
+ expect(model).to_not respond_to :country?
473
+ end
474
+
475
+ it 'cannot be reset' do
476
+ expect(model).to_not respond_to :reset_country!
477
+ end
478
+
479
+ it 'still has casting a default handling' do
480
+ expect(model.settings[:country]).to be == 'Canada'
481
+ end
482
+
483
+ end
484
+
497
485
  describe '`any` attributes' do
498
486
 
499
487
  it 'accept any type' do
@@ -48,6 +48,7 @@ def define_store_columns(t)
48
48
  define_columns(t)
49
49
  t.any :author
50
50
  t.any :source, blank: false, default: 'web'
51
+ t.string :country, blank: false, default: 'Canada', accessor: false
51
52
  end
52
53
 
53
54
  class CreateAllTables < ActiveRecord::Migration
@@ -171,10 +172,23 @@ class JsonTypedStoreModel < ActiveRecord::Base
171
172
  end
172
173
  end
173
174
 
175
+ module MarshalCoder
176
+ extend self
177
+
178
+ def load(serial)
179
+ Marshal.load(Base64.decode64(serial))
180
+ end
181
+
182
+ def dump(value)
183
+ Base64.encode64(Marshal.dump(value))
184
+ end
185
+
186
+ end
187
+
174
188
  class MarshalTypedStoreModel < ActiveRecord::Base
175
189
  establish_connection 'test_sqlite3'
176
190
  store :untyped_settings, accessors: [:title]
177
- typed_store :settings, coder: ColumnCoder.new(Marshal) do |s|
191
+ typed_store :settings, coder: ColumnCoder.new(MarshalCoder) do |s|
178
192
  define_store_columns(s)
179
193
  end
180
194
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-typedstore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-14 00:00:00.000000000 Z
11
+ date: 2013-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -153,15 +153,18 @@ files:
153
153
  - activerecord-typedstore.gemspec
154
154
  - gemfiles/Gemfile.ar-3.2
155
155
  - gemfiles/Gemfile.ar-4.0
156
+ - gemfiles/Gemfile.ar-4.1
156
157
  - gemfiles/Gemfile.ar-edge
157
158
  - lib/active_record/typed_store.rb
158
159
  - lib/active_record/typed_store/ar_32_fallbacks.rb
159
- - lib/active_record/typed_store/ar_41_fallbacks.rb
160
+ - lib/active_record/typed_store/coder.rb
160
161
  - lib/active_record/typed_store/column.rb
161
162
  - lib/active_record/typed_store/dsl.rb
162
163
  - lib/active_record/typed_store/extension.rb
164
+ - lib/active_record/typed_store/typed_hash.rb
163
165
  - lib/active_record/typed_store/version.rb
164
166
  - lib/activerecord-typedstore.rb
167
+ - spec/active_record/typed_store/typed_hash_spec.rb
165
168
  - spec/active_record/typed_store_spec.rb
166
169
  - spec/spec_helper.rb
167
170
  - spec/support/database_cleaner.rb
@@ -191,6 +194,7 @@ signing_key:
191
194
  specification_version: 4
192
195
  summary: ActiveRecord::Store but with type definition
193
196
  test_files:
197
+ - spec/active_record/typed_store/typed_hash_spec.rb
194
198
  - spec/active_record/typed_store_spec.rb
195
199
  - spec/spec_helper.rb
196
200
  - spec/support/database_cleaner.rb
@@ -1,26 +0,0 @@
1
- module ActiveRecord::TypedStore
2
-
3
- module AR41Fallbacks
4
-
5
- private
6
-
7
- module HashAccessorPatch
8
-
9
- def self.extended(hash_accessor)
10
- hash_accessor.singleton_class.alias_method_chain :prepare, :initialization
11
- end
12
-
13
- protected
14
-
15
- def prepare_with_initialization(object, store_attribute)
16
- prepare_without_initialization(object, store_attribute)
17
- object.send(:initialize_store_attribute, store_attribute)
18
- end
19
-
20
- end
21
-
22
- ActiveRecord::Store::HashAccessor.extend(HashAccessorPatch)
23
- ActiveRecord::Store::IndifferentHashAccessor.extend(HashAccessorPatch)
24
- end
25
-
26
- end