flex_columns 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/flex_columns/contents/flex_column_contents_base.rb +18 -0
- data/lib/flex_columns/has_flex_columns.rb +43 -1
- data/lib/flex_columns/version.rb +1 -1
- data/spec/flex_columns/system/basic_system_spec.rb +51 -0
- data/spec/flex_columns/unit/contents/flex_column_contents_base_spec.rb +11 -0
- data/spec/flex_columns/unit/has_flex_columns_spec.rb +63 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2875989d866789ac577e31552738fa6466139eb0
|
4
|
+
data.tar.gz: 0976a94f461db06c5157dce3e0831ff5ce07c1c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c6605b81107eacb261547aaa2f0f1ebd5110f65b09ff7166c2f15cb104019e2fc696db59dfc72f4e796359b81ed3dca6f62baff7d857d3cfe35535e5fda1b105
|
7
|
+
data.tar.gz: 61c57838d0b1b06a19775e8f00f70edbdecf56d6fc8a4185d5ebed273a40c1cbd91e324e7c797c55fb92b4fa1449dfd2efaf7076a3a3133cee7bc5ea4941830f
|
@@ -71,6 +71,24 @@ module FlexColumns
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
+
# See the comment above FlexColumns::HasFlexColumns#read_attribute_for_serialization -- this is responsible for
|
75
|
+
# correctly turning a flex-column object into a hash for serializing *the entire enclosing ActiveRecord model*.
|
76
|
+
#
|
77
|
+
# Most importantly, this method has NOTHING to do with our internal 'serialize a column as JSON' mechanisms. It
|
78
|
+
# is ONLY called if you try to serialize the enclosing ActiveRecord instance.
|
79
|
+
def to_hash_for_serialization
|
80
|
+
@column_data.to_hash
|
81
|
+
end
|
82
|
+
|
83
|
+
# Make sure this flex-column object itself is smart enough to turn itself into JSON correctly.
|
84
|
+
#
|
85
|
+
# Most importantly, this method has NOTHING to do with our internal 'serialize a column as JSON' mechanisms. It
|
86
|
+
# is ONLY called if you try to serialize something that in turn points directly to (i.e., not via the enclosing
|
87
|
+
# ActiveRecord object) this flex-column object.
|
88
|
+
def as_json(options = { })
|
89
|
+
to_hash_for_serialization
|
90
|
+
end
|
91
|
+
|
74
92
|
# Returns a Hash, appropriate for integration into the payload of an ActiveSupport::Notification call, that
|
75
93
|
# describes the model instance we're created from (or raw String, if that's the case). This is used by the
|
76
94
|
# calls made to ActiveSupport::Notifications when a flex-column object is serialized or deserialized, and is used
|
@@ -66,10 +66,47 @@ module FlexColumns
|
|
66
66
|
out
|
67
67
|
end
|
68
68
|
|
69
|
+
# When ActiveRecord serializes an entire ActiveRecord object (for example, if you call #to_json on it), it
|
70
|
+
# reads each column individually using this method -- which, in the default implementation, just calls #send.
|
71
|
+
# (Well, it's actually *aliased* to #send, but it has the same effect.)
|
72
|
+
#
|
73
|
+
# However, if you're serializing an ActiveRecord model that contains a flex column, you almost certainly just
|
74
|
+
# want that to behave as if the flex_column is a Hash, and serialize it that way. So we override it to do just
|
75
|
+
# that right here.
|
76
|
+
def read_attribute_for_serialization(attribute_name)
|
77
|
+
if self.class._has_flex_column_named?(attribute_name)
|
78
|
+
_flex_column_object_for(attribute_name).to_hash_for_serialization
|
79
|
+
else
|
80
|
+
super(attribute_name)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# See above. We're actually overriding *both* methods, because #read_attribute_for_serialization doesn't exist
|
85
|
+
# in ActiveRecord 3.0.x.
|
86
|
+
def as_json(options = { })
|
87
|
+
flex_column_names = self.class._all_flex_column_names
|
88
|
+
out = super(:except => flex_column_names)
|
89
|
+
|
90
|
+
flex_columns_hash = { }
|
91
|
+
flex_column_names.each do |column_name|
|
92
|
+
hash = _flex_column_object_for(column_name).to_hash_for_serialization
|
93
|
+
flex_columns_hash[column_name] = hash unless hash.empty?
|
94
|
+
end
|
95
|
+
|
96
|
+
if include_root_in_json && out.keys.length == 1
|
97
|
+
out[out.keys.first].merge!(flex_columns_hash)
|
98
|
+
else
|
99
|
+
out.merge!(flex_columns_hash)
|
100
|
+
end
|
101
|
+
|
102
|
+
out
|
103
|
+
end
|
104
|
+
|
69
105
|
# When you reload a model object, we should reload its flex-column objects, too.
|
70
106
|
def reload(*args)
|
71
|
-
super(*args)
|
107
|
+
out = super(*args)
|
72
108
|
@_flex_column_objects = { }
|
109
|
+
out
|
73
110
|
end
|
74
111
|
|
75
112
|
# This little-know ActiveRecord method gets called to produce a string for #inspect for a particular attribute.
|
@@ -114,6 +151,11 @@ module FlexColumns
|
|
114
151
|
_flex_column_classes.map(&:column_name)
|
115
152
|
end
|
116
153
|
|
154
|
+
# Does this model have a flex column with the given name?
|
155
|
+
def _has_flex_column_named?(column_name)
|
156
|
+
_all_flex_column_names.include?(_flex_column_normalize_name(column_name))
|
157
|
+
end
|
158
|
+
|
117
159
|
# Normalizes the name of a flex column, so we're consistent when using it for things like hash keys, no matter
|
118
160
|
# how the client specifies it to us.
|
119
161
|
def _flex_column_normalize_name(flex_column_name)
|
data/lib/flex_columns/version.rb
CHANGED
@@ -250,6 +250,57 @@ describe "FlexColumns basic operations" do
|
|
250
250
|
output['foo'].should == 47.2
|
251
251
|
end
|
252
252
|
|
253
|
+
it "should allow you to call #reload, and return that same record" do
|
254
|
+
user = ::User.new
|
255
|
+
user.name = 'User 1'
|
256
|
+
user.wants_email = [ 1, 2, 3 ]
|
257
|
+
user.save!
|
258
|
+
|
259
|
+
user.name = 'User 2'
|
260
|
+
user.wants_email = 'bonko'
|
261
|
+
|
262
|
+
new_user = user.reload
|
263
|
+
new_user.name.should == 'User 1'
|
264
|
+
new_user.wants_email.should == [ 1, 2, 3 ]
|
265
|
+
new_user.id.should == user.id
|
266
|
+
|
267
|
+
user.name.should == 'User 1'
|
268
|
+
user.wants_email.should == [ 1, 2, 3 ]
|
269
|
+
|
270
|
+
new_user.should be(user)
|
271
|
+
end
|
272
|
+
|
273
|
+
# JSON.dump() simply doesn't work at all with ActiveRecord objects in earlier ActiveRecord versions; see:
|
274
|
+
# http://stackoverflow.com/questions/8406924/json-dump-on-any-activerecord-object-fails
|
275
|
+
if ActiveRecord::VERSION::MAJOR >= 4 ||
|
276
|
+
(ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR >= 1)
|
277
|
+
it "should let you turn an entire ActiveRecord object into JSON properly, treating a flex column as a Hash" do
|
278
|
+
user = ::User.new
|
279
|
+
user.id = 12345
|
280
|
+
user.name = 'User 1'
|
281
|
+
user.wants_email = [ 1, 2, 3 ]
|
282
|
+
|
283
|
+
$stderr.puts "ATTRIBUTES: #{user.attributes.keys.sort.inspect}"
|
284
|
+
|
285
|
+
user_json = JSON.dump(user)
|
286
|
+
parsed = JSON.parse(user_json)
|
287
|
+
|
288
|
+
# ActiveRecord::Base.include_root_in_json may default to different things in different versions of
|
289
|
+
# ActiveRecord; here, we accept JSON in either format.
|
290
|
+
base = parsed
|
291
|
+
base = parsed['user'] if base.keys == %w{user}
|
292
|
+
|
293
|
+
base.keys.sort.should == %w{id name user_attributes more_attributes}.sort
|
294
|
+
base['id'].should == 12345
|
295
|
+
base['name'].should == 'User 1'
|
296
|
+
h = base['user_attributes']
|
297
|
+
h.class.should == Hash
|
298
|
+
h.keys.sort.should == %w{wants_email}
|
299
|
+
h['wants_email'].should == [ 1, 2, 3 ]
|
300
|
+
[ nil, { } ].include?(base['more_attributes']).should be
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
253
304
|
it "should remove keys entirely when they're set to nil, but not if they're set to false" do
|
254
305
|
define_model_class(:User, 'flexcols_spec_users') do
|
255
306
|
flex_column :user_attributes do
|
@@ -173,6 +173,17 @@ describe FlexColumns::Contents::FlexColumnContentsBase do
|
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
176
|
+
describe "JSON serialization" do
|
177
|
+
it "should return ColumnData#to_hash_for_serialization for #to_hash_for_serialization and #as_json" do
|
178
|
+
expect_column_data_creation(@json_string)
|
179
|
+
@instance = @klass.new(@model_instance)
|
180
|
+
|
181
|
+
allow(@column_data).to receive(:to_hash).and_return({ :a => :b, :c => :d })
|
182
|
+
@instance.to_hash_for_serialization.should == { :a => :b, :c => :d }
|
183
|
+
@instance.as_json.should == { :a => :b, :c => :d }
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
176
187
|
describe "#before_save!" do
|
177
188
|
it "should do nothing if created with a raw string" do
|
178
189
|
expect_column_data_creation(@json_string)
|
@@ -163,6 +163,57 @@ describe FlexColumns::HasFlexColumns do
|
|
163
163
|
@klass.flex_column(:bar)
|
164
164
|
end
|
165
165
|
|
166
|
+
describe "#read_attribute_for_serialization" do
|
167
|
+
it "should call through to the flex-column object for flex columns, and flex columns only" do
|
168
|
+
@superclass.class_eval do
|
169
|
+
def read_attribute_for_serialization(attribute_name)
|
170
|
+
"rafs_#{attribute_name}_rafs"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
instance = @klass.new
|
175
|
+
|
176
|
+
fcc_foo_instance = double("fcc_foo_instance")
|
177
|
+
expect(@fcc_foo).to receive(:new).once.with(instance).and_return(fcc_foo_instance)
|
178
|
+
hash_for_serialization = double("hash_for_serialization")
|
179
|
+
expect(fcc_foo_instance).to receive(:to_hash_for_serialization).once.with().and_return(hash_for_serialization)
|
180
|
+
|
181
|
+
instance.read_attribute_for_serialization('foo').should be(hash_for_serialization)
|
182
|
+
instance.read_attribute_for_serialization('baz').should == "rafs_baz_rafs"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "#as_json" do
|
187
|
+
it "should call through to the flex-column object for flex columns, and flex columns only" do
|
188
|
+
@superclass.class_eval do
|
189
|
+
def as_json(options)
|
190
|
+
@superclass_as_json_options ||= [ ]
|
191
|
+
@superclass_as_json_options << options
|
192
|
+
{ :z => 123, :bbb => 456}
|
193
|
+
end
|
194
|
+
end
|
195
|
+
instance = @klass.new
|
196
|
+
|
197
|
+
fcc_foo_instance = double("fcc_foo_instance")
|
198
|
+
expect(@fcc_foo).to receive(:new).once.with(instance).and_return(fcc_foo_instance)
|
199
|
+
expect(fcc_foo_instance).to receive(:to_hash_for_serialization).once.with().and_return({ :aaa => 111, :bbb => 222 })
|
200
|
+
|
201
|
+
fcc_bar_instance = double("fcc_bar_instance")
|
202
|
+
expect(@fcc_bar).to receive(:new).once.with(instance).and_return(fcc_bar_instance)
|
203
|
+
expect(fcc_bar_instance).to receive(:to_hash_for_serialization).once.with().and_return({ :aaa => 234, :ccc => 'xxx' })
|
204
|
+
|
205
|
+
allow(instance).to receive(:include_root_in_json).with().and_return(false)
|
206
|
+
|
207
|
+
instance.as_json.should == { :z => 123, :bbb => 456,
|
208
|
+
:foo => { :aaa => 111, :bbb => 222 },
|
209
|
+
:bar => { :aaa => 234, :ccc => 'xxx' }
|
210
|
+
}
|
211
|
+
instance.instance_variable_get("@superclass_as_json_options").should == [
|
212
|
+
{ :except => [ :foo, :bar ] }
|
213
|
+
]
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
166
217
|
it "should return the same DynamicMethodsModule every time" do
|
167
218
|
@klass._flex_column_dynamic_methods_module.should be(@dmm)
|
168
219
|
@klass._flex_column_dynamic_methods_module.should be(@dmm)
|
@@ -282,11 +333,12 @@ describe FlexColumns::HasFlexColumns do
|
|
282
333
|
instance._flex_column_object_for(' bAr ').should be(fcc_bar_instance)
|
283
334
|
end
|
284
335
|
|
285
|
-
it "should re-create flex-column objects on reload, and call super" do
|
336
|
+
it "should re-create flex-column objects on reload, and call super and return its value" do
|
286
337
|
@superclass.class_eval do
|
287
338
|
def reload
|
288
339
|
@reloads ||= 0
|
289
340
|
@reloads += 1
|
341
|
+
:reload_return_yo
|
290
342
|
end
|
291
343
|
|
292
344
|
def reloads
|
@@ -308,7 +360,7 @@ describe FlexColumns::HasFlexColumns do
|
|
308
360
|
instance._flex_column_object_for(:bar).should be(fcc_bar_instance)
|
309
361
|
|
310
362
|
instance.reloads.should == 0
|
311
|
-
instance.reload
|
363
|
+
instance.reload.should == :reload_return_yo
|
312
364
|
instance.reloads.should == 1
|
313
365
|
|
314
366
|
fcc_foo_instance_2 = double("fcc_foo_instance_2")
|
@@ -324,6 +376,15 @@ describe FlexColumns::HasFlexColumns do
|
|
324
376
|
@klass._all_flex_column_names.sort_by(&:to_s).should == [ :foo, :bar ].sort_by(&:to_s)
|
325
377
|
end
|
326
378
|
|
379
|
+
it "should answer whether a flex-column name has been defined" do
|
380
|
+
@klass._has_flex_column_named?(:foo).should be
|
381
|
+
@klass._has_flex_column_named?('foo').should be
|
382
|
+
@klass._has_flex_column_named?(:bar).should be
|
383
|
+
@klass._has_flex_column_named?('bar').should be
|
384
|
+
@klass._has_flex_column_named?(:baz).should_not be
|
385
|
+
@klass._has_flex_column_named?('baz').should_not be
|
386
|
+
end
|
387
|
+
|
327
388
|
it "should normalize column names properly" do
|
328
389
|
@klass._flex_column_normalize_name(:baz).should == :baz
|
329
390
|
@klass._flex_column_normalize_name(:' bAz ').should == :baz
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flex_columns
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Geweke
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|