restful_serializer 0.1.3 → 0.1.4

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.
@@ -0,0 +1,494 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ describe Restful::Configuration do
4
+
5
+ describe "configurable equality" do
6
+ class TestConfigurable
7
+ include Restful::Configuration::Configurable
8
+ option :name
9
+ option :subs, :type => :hash, :element_type => 'SubConfigurable'
10
+ option :defaulted, :default => :a_default
11
+
12
+ # * :name
13
+ # * :options => hash of options
14
+ def initialize(*args)
15
+ options = args.extract_options!
16
+ super(options.merge(:name => args.shift))
17
+ end
18
+ end
19
+
20
+ class SubConfigurable
21
+ include Restful::Configuration::Configurable
22
+ option :name
23
+ option :stuff, :type => :array
24
+
25
+ def initialize(*args)
26
+ super(:name => args.shift, :stuff => args)
27
+ end
28
+
29
+ end
30
+
31
+ before(:each) do
32
+ @test = TestConfigurable.new(:test)
33
+ @equal = TestConfigurable.new(:test)
34
+ @different = TestConfigurable.new(:dif)
35
+ end
36
+
37
+ it "should be reflexive" do
38
+ @test.should == @test
39
+ @test.should equal(@test)
40
+ end
41
+
42
+ it "should be symetric" do
43
+ @test.should == @equal
44
+ @test.should_not equal(@equal)
45
+ @equal.should == @test
46
+ @equal.should_not equal(@test)
47
+ end
48
+
49
+ it "should handle inequality" do
50
+ @test.should_not == @different
51
+ @different.should_not == @test
52
+ end
53
+
54
+ it "should provide a hash" do
55
+ @test.hash.should == @test.hash
56
+ @test.hash.should == @equal.hash
57
+ @test.hash.should_not == @different.hash
58
+ end
59
+
60
+ it "should convert to a hash" do
61
+ @test.to_hash.should == {
62
+ :name => :test,
63
+ :subs => {},
64
+ :defaulted => :a_default,
65
+ }
66
+ end
67
+
68
+ it "should convert to a hash and skip empty containers" do
69
+ @test.to_hash(:ignore_empty => true).should == {
70
+ :name => :test,
71
+ :defaulted => :a_default,
72
+ }
73
+ end
74
+
75
+ it "should convert to a hash and skip defaulted values" do
76
+ @test.to_hash(:skip_defaults => true).should == {
77
+ :name => :test,
78
+ :subs => {},
79
+ }
80
+ end
81
+
82
+ it "should not skip options explicitly set to their default value" do
83
+ @test.defaulted = :a_default
84
+ @test.to_hash(:skip_defaults => true).should == {
85
+ :subs => {},
86
+ :name => :test,
87
+ :defaulted => :a_default,
88
+ }
89
+ test2 = TestConfigurable.new(:test, :defaulted => :a_default)
90
+ test2.to_hash(:skip_defaults => true).should == {
91
+ :subs => {},
92
+ :name => :test,
93
+ :defaulted => :a_default,
94
+ }
95
+ end
96
+
97
+ it "should convert to a hash and skip both" do
98
+ @test.to_hash(:skip_defaults => true, :ignore_empty => true).should == {
99
+ :name => :test,
100
+ }
101
+ end
102
+
103
+ describe "with nested configurables" do
104
+ before(:each) do
105
+ @test = TestConfigurable.register(:test) do |conf|
106
+ conf.subs[:sub1] = (@sub1 = SubConfigurable.new(:sub1, 1,2,3))
107
+ conf.subs[:sub2] = (@sub2 = SubConfigurable.new(:sub2, 1,2,3))
108
+ conf.subs[:sub3] = (@sub3 = SubConfigurable.new(:sub3, 4,5,6))
109
+ end
110
+ @equal = TestConfigurable.register(:test,
111
+ :subs => {
112
+ :sub1 => { :name => :sub1, :stuff => [1,2,3]},
113
+ :sub2 => { :name => :sub2, :stuff => [1,2,3]},
114
+ :sub3 => { :name => :sub3, :stuff => [4,5,6]},
115
+ }
116
+ )
117
+ @different = TestConfigurable.register(:dif) do |conf|
118
+ conf.subs[:difsub1] = (@difsub1 = SubConfigurable.new(:difsub1, 8,9,0))
119
+ conf.subs[:sub2] = (@difsub2 = SubConfigurable.new(:sub2, 8,9,0))
120
+ end
121
+ end
122
+
123
+ it "should still follow equality semantics" do
124
+ @test.should == @test
125
+ @test.should equal(@test)
126
+ @test.should == @equal
127
+ @test.should_not equal(@equal)
128
+ @equal.should == @test
129
+ @equal.should_not equal(@test)
130
+ @test.should_not == @different
131
+ @different.should_not == @test
132
+ @test.hash.should == @test.hash
133
+ @test.hash.should == @equal.hash
134
+ @test.hash.should_not == @different.hash
135
+ end
136
+
137
+ it "should provide a deep clone" do
138
+ clone = @test.deep_clone
139
+ clone.should == @test
140
+ clone.should == @equal
141
+ clone.should_not equal(@test)
142
+ clone.send(:config).should_not equal(@test.send(:config))
143
+ clone.name = 'foo'
144
+ @test.name.should_not == 'foo'
145
+ clone.subs[:sub1].should == @sub1
146
+ clone.subs[:sub1].name == 'bar'
147
+ @sub1.name.should_not == 'bar'
148
+ end
149
+
150
+ it "should provide a deep merge" do
151
+ merged = @test.deep_merge!(@different)
152
+ merged.name.should == @different.name
153
+ merged.subs[:sub1].should == @sub1
154
+ merged.subs[:sub2].stuff.should == @sub2.stuff + @difsub2.stuff
155
+ merged.subs[:sub3].should == @sub3
156
+ merged.subs[:difsub1].should == @difsub1
157
+ end
158
+
159
+ it "should raise errors if attempt to deep merge with different options" do
160
+ @test.deep_merge!(nil).should == @test
161
+ lambda { @test.deep_merge!(@sub1) }.should raise_error(ArgumentError)
162
+ lambda { @test.deep_merge!(:frotz => :spaniel) }.should raise_error(ArgumentError)
163
+ end
164
+
165
+ end
166
+ end
167
+
168
+ describe Restful::Configuration::Option do
169
+
170
+ it "should construct an Option" do
171
+ opt = Restful::Configuration::Option.new(:foo, :type => :array)
172
+ opt.name.should == :foo
173
+ opt.type.should == Array
174
+ end
175
+
176
+ it "should accept an element type parameter" do
177
+ opt = Restful::Configuration::Option.new(:foo, :type => :array, :element_type => :symbol)
178
+ opt.element_type.should == Symbol
179
+ end
180
+
181
+ it "should accept a default parameter" do
182
+ opt = Restful::Configuration::Option.new(:foo, :default => false)
183
+ opt.default.should == false
184
+ end
185
+
186
+ it "should provide a new option instance" do
187
+ opt = Restful::Configuration::Option.new(:foo, :type => :array)
188
+ opt.initialized.should == []
189
+ end
190
+
191
+ it "should provide a new defaulted instance" do
192
+ opt = Restful::Configuration::Option.new(:foo, :default => false)
193
+ opt.initialized.should == false
194
+ end
195
+
196
+ it "should provide nil for no type or default" do
197
+ opt = Restful::Configuration::Option.new(:foo)
198
+ opt.initialized.should be_nil
199
+ end
200
+ end
201
+
202
+ describe Restful::Configuration::WebService do
203
+
204
+ before(:each) do
205
+ @ws = Restful::Configuration::WebService.new('Foo Service')
206
+ end
207
+
208
+ it "should construct a WebService configuration" do
209
+ @ws.should be_kind_of(Restful::Configuration::WebService)
210
+ @ws.name.should == 'Foo Service'
211
+ end
212
+
213
+ it "should initialize options" do
214
+ @ws.api_prefix.should be_nil
215
+ @ws.default_url_options.should == {}
216
+ @ws.resources.should == {}
217
+ end
218
+
219
+ it "should allow resources to be registered" do
220
+ @ws.register_resource(:gizmo, :url_for => 'the_gizmo') do |resource|
221
+ resource.associations[:widget] = nil
222
+ end
223
+ (gizmo = @ws.resources[:gizmo]).should_not be_nil
224
+ gizmo.url_for.should == 'the_gizmo'
225
+ gizmo.associations.should == { :widget => nil }
226
+ end
227
+
228
+ it "should initialize from a hash" do
229
+ ws = Restful::Configuration::WebService.new(:a_service,
230
+ :api_prefix => 'prefix',
231
+ :default_url_options => {:host => 'the_host.com'},
232
+ :resources => {
233
+ :r1 => {
234
+ :serialization => {
235
+ :only => :id
236
+ }
237
+ }
238
+ }
239
+ )
240
+ ws.api_prefix.should == 'prefix'
241
+ ws.resources.size.should == 1
242
+ ws.to_hash(:ignore_empty => true).should == {
243
+ :name => :a_service,
244
+ :api_prefix => 'prefix',
245
+ :default_url_options => {:host => 'the_host.com'},
246
+ :resources => {
247
+ :r1 => {
248
+ :name_method => :name,
249
+ :url_for => nil,
250
+ :no_inherited_options => false,
251
+ :shallow => false,
252
+ :serialization => {
253
+ :only => [:id]
254
+ },
255
+ },
256
+ },
257
+ }
258
+ end
259
+
260
+ it "should automatically symbolize keys" do
261
+ ws = Restful::Configuration::WebService.new('a service',
262
+ 'api_prefix' => 'prefix',
263
+ 'default_url_options' => { 'host' => 'a_host.com'}
264
+ )
265
+ ws.api_prefix.should == 'prefix'
266
+ ws.default_url_options == { 'host' => 'bar' }
267
+ ws.to_hash(:ignore_empty => true).should == {
268
+ :name => 'a service',
269
+ :api_prefix => 'prefix',
270
+ :default_url_options => { :host => 'a_host.com'},
271
+ }
272
+ end
273
+
274
+ it "should convert to a hash of web service configuration" do
275
+ @ws.to_hash.should == {
276
+ :name => 'Foo Service',
277
+ :api_prefix => nil,
278
+ :default_url_options => {},
279
+ :resources => {},
280
+ }
281
+ @ws.register_resource(:gizmo, :url_for => 'the_gizmo') do |resource|
282
+ resource.associations[:widget] = nil
283
+ end
284
+ (config_hash = @ws.to_hash).should == {
285
+ :name => 'Foo Service',
286
+ :api_prefix => nil,
287
+ :default_url_options => {},
288
+ :resources => {
289
+ :gizmo => {
290
+ :name_method => :name,
291
+ :url_for => 'the_gizmo',
292
+ :associations => { :widget => nil },
293
+ :serialization => {
294
+ :only => [],
295
+ :except => [],
296
+ :methods => [],
297
+ :include => {},
298
+ },
299
+ :no_inherited_options => false,
300
+ :shallow => false,
301
+ },
302
+ },
303
+ }
304
+ @ws.resources.should_not equal(config_hash[:resources])
305
+ @ws.resources[:gizmo].serialization.should_not equal(config_hash[:resources][:gizmo][:serialization])
306
+ @ws.resources[:gizmo].serialization.only.should_not equal(config_hash[:resources][:gizmo][:serialization][:only])
307
+
308
+ @ws.to_hash(:ignore_empty => true).should == {
309
+ :name => 'Foo Service',
310
+ :api_prefix => nil,
311
+ :resources => {
312
+ :gizmo => {
313
+ :name_method => :name,
314
+ :url_for => 'the_gizmo',
315
+ :associations => { :widget => nil },
316
+ :no_inherited_options => false,
317
+ :shallow => false,
318
+ },
319
+ },
320
+ }
321
+ end
322
+ end
323
+
324
+ describe Restful::Configuration::Resource do
325
+
326
+ before(:each) do
327
+ @res = Restful::Configuration::Resource.new()
328
+ end
329
+
330
+ it "should construct a Resource configuration" do
331
+ @res.should be_kind_of(Restful::Configuration::Resource)
332
+ end
333
+
334
+ it "should initialize options" do
335
+ @res.url_for.should be_nil
336
+ @res.associations.should == {}
337
+ @res.serialization.should be_kind_of(Restful::Configuration::ARSerialization)
338
+ @res.no_inherited_options.should == false
339
+ @res.shallow.should == false
340
+ end
341
+
342
+ it "should allow serialization to be configured by a block" do
343
+ @res.serialization do |serial|
344
+ serial.only = [:foo, :bar]
345
+ end
346
+ @res.serialization.only.should == [:foo, :bar]
347
+ end
348
+
349
+ it "should convert to a hash of resource configuration" do
350
+ @res.to_hash.should == {
351
+ :name_method => :name,
352
+ :url_for => nil,
353
+ :associations => {},
354
+ :serialization => {
355
+ :only => [],
356
+ :except => [],
357
+ :methods => [],
358
+ :include => {},
359
+ },
360
+ :no_inherited_options => false,
361
+ :shallow => false,
362
+ }
363
+ end
364
+
365
+ it "should automatically symbolize keys" do
366
+ res = Restful::Configuration::Resource.new(
367
+ 'url_for' => 'biscuit',
368
+ 'associations' => { 'bob' => 'bobby' },
369
+ 'shallow' => true
370
+ )
371
+ res.url_for.should == 'biscuit'
372
+ res.associations.should == { :bob => 'bobby' }
373
+ res.shallow.should == true
374
+ res.to_hash(:ignore_empty => true).should == {
375
+ :name_method => :name,
376
+ :url_for => 'biscuit',
377
+ :associations => { :bob => 'bobby' },
378
+ :no_inherited_options => false,
379
+ :shallow => true,
380
+ }
381
+ end
382
+
383
+ it "should convert to a hash of resource configuration ignoring empty containers" do
384
+ @res.to_hash(:ignore_empty => true).should == {
385
+ :name_method => :name,
386
+ :url_for => nil,
387
+ :no_inherited_options => false,
388
+ :shallow => false,
389
+ }
390
+ end
391
+ end
392
+
393
+ describe Restful::Configuration::ARSerialization do
394
+
395
+ before(:each) do
396
+ @ars = Restful::Configuration::ARSerialization.new
397
+ end
398
+
399
+ it "should construct an ARSerialization configuration" do
400
+ @ars.should be_kind_of(Restful::Configuration::ARSerialization)
401
+ @ars.should be_kind_of(Restful::Configuration::Configurator)
402
+ @ars.class.should respond_to(:register)
403
+ end
404
+
405
+ it "should initialize attribute structures" do
406
+ @ars.only.should == []
407
+ @ars.except.should == []
408
+ @ars.methods.should == []
409
+ @ars.include.should == {}
410
+ end
411
+
412
+ it "should initialize from a hash" do
413
+ ars = Restful::Configuration::ARSerialization.new(
414
+ :only => [:foo, :bar],
415
+ :methods => :bob
416
+ )
417
+ ars.only.should == [:foo, :bar]
418
+ ars.methods.should == [:bob]
419
+ ars.to_hash(:ignore_empty => true).should == {
420
+ :only => [:foo, :bar],
421
+ :methods => [:bob],
422
+ }
423
+ end
424
+
425
+ it "should allow included arserializations" do
426
+ @ars.includes(:another) do |serial|
427
+ serial.only = [:foo, :bar]
428
+ end
429
+ (inc = @ars.include[:another]).should_not be_nil
430
+ inc.only.should == [:foo, :bar]
431
+ end
432
+
433
+ it "should allow deeply nested included arserializations" do
434
+ @ars.includes(:another) do |serial|
435
+ serial.only = [:foo, :bar]
436
+ serial.includes(:leaf) do |leaf_serial|
437
+ leaf_serial.except << :not_me
438
+ end
439
+ end
440
+ (inc = @ars.include[:another]).should_not be_nil
441
+ inc.only.should == [:foo, :bar]
442
+ (leaf = inc.include[:leaf]).should_not be_nil
443
+ leaf.except.should == [:not_me]
444
+ end
445
+
446
+ it "should convert to a hash" do
447
+ @ars.to_hash.should == {
448
+ :only => [],
449
+ :except => [],
450
+ :methods => [],
451
+ :include => {}
452
+ }
453
+ @ars = Restful::Configuration::ARSerialization.register do |serial|
454
+ serial.only = [:foo, :bar]
455
+ serial.includes(:another) do |inc|
456
+ inc.except << :not_me
457
+ end
458
+ end
459
+ @ars.to_hash.should == {
460
+ :only => [:foo, :bar],
461
+ :except => [],
462
+ :methods => [],
463
+ :include => {
464
+ :another => {
465
+ :only => [],
466
+ :except => [:not_me],
467
+ :methods => [],
468
+ :include => {},
469
+ },
470
+ },
471
+ }
472
+ end
473
+
474
+ it "should convert to a hash, ignoring options with empty containers" do
475
+ @ars.to_hash(:ignore_empty => true).should == { }
476
+ @ars = Restful::Configuration::ARSerialization.register do |serial|
477
+ serial.only = [:foo, :bar]
478
+ serial.includes(:another) do |inc|
479
+ inc.except << :not_me
480
+ end
481
+ end
482
+ @ars.to_hash(:ignore_empty => true).should == {
483
+ :only => [:foo, :bar],
484
+ :include => {
485
+ :another => {
486
+ :except => [:not_me],
487
+ },
488
+ },
489
+ }
490
+
491
+ end
492
+ end
493
+
494
+ end
data/spec/restful_spec.rb CHANGED
@@ -2,75 +2,159 @@ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
2
 
3
3
  describe Restful do
4
4
 
5
- it "should have an api_prefix accessor" do
6
- Restful.api_prefix.should be_nil
7
- Restful.api_prefix = 'foo'
8
- Restful.api_prefix.should == 'foo'
5
+ before(:each) do
6
+ Restful.clear
9
7
  end
10
8
 
11
9
  it "should have a default_url_options accessor" do
12
10
  Restful.default_url_options.should == {}
13
11
  end
14
12
 
15
- it "should have a model_configuration accessor" do
16
- Restful.model_configuration.should == {}
13
+ it "should look up registered services" do
14
+ Restful.register_web_service('foo')
15
+ ws = Restful.web_service_configuration(:foo)
16
+ ws.should_not be_nil
17
+ ws.should be_kind_of(Restful::Configuration::WebService)
18
+ ws.name.should == 'foo'
17
19
  end
18
20
 
19
- it "should automatically symbolize keys for model_configuration" do
20
- Restful.model_configuration = { 'foo' => 'bar' }
21
- Restful.model_configuration.should == { :foo => 'bar' }
21
+ it "should lazily inject default_url_options into webservice configurations lacking it" do
22
+ Restful.default_url_options = {:host => 'default-host.com'}
23
+ Restful.register_web_service('foo')
24
+ Restful.register_web_service('bar', :default_url_options => {:host => 'bar.com'})
25
+ foo = Restful.web_service_configuration(:foo)
26
+ foo.default_url_options.should == Restful.default_url_options
27
+ foo.default_url_options.should_not equal(Restful.default_url_options)
28
+ bar = Restful.web_service_configuration(:bar)
29
+ bar.default_url_options.should == {:host => 'bar.com'}
22
30
  end
23
31
 
24
- describe "looking up model configurations" do
32
+ it "should return nil if you request a web service that does not exist" do
33
+ Restful.web_service_configuration(:does_not_exist)
34
+ end
25
35
 
26
- class Super; end
27
- class SubClass < Super; end
36
+ it "should call web_service_configuration for nil key" do
37
+ Restful.web_service_configuration(nil)
38
+ end
28
39
 
40
+ describe "single configuration" do
29
41
  before(:each) do
30
- Restful.model_configuration = {
31
- :super => :super_config,
32
- :sub_class => :sub_class_config,
33
- }
34
- end
35
-
36
- it "should return an empty hash if no configuration" do
37
- Restful.model_configuration_for(nil).should == {}
38
- end
39
-
40
- it "should lookup entries by symbol" do
41
- Restful.model_configuration_for(:super).should == :super_config
42
- end
43
-
44
- it "should lookup entries from a string" do
45
- Restful.model_configuration_for('super').should == :super_config
42
+ configure_foo_service
46
43
  end
47
44
 
48
- it "should lookup entries by Class" do
49
- Restful.model_configuration_for(Super).should == :super_config
50
- Restful.model_configuration_for(SubClass).should == :sub_class_config
45
+ it "should process a full configuration" do
46
+ ws = Restful.web_service_configuration(:foo_web_service).to_hash(:ignore_empty => true)
47
+ ws.should == {
48
+ :api_prefix => "foo_api",
49
+ :name => "Foo Web Service",
50
+ :resources => {
51
+ :bar => {
52
+ :name_method => :name,
53
+ :no_inherited_options => false,
54
+ :shallow => false,
55
+ :serialization => {
56
+ :include => {:foo => {:only => [:column1]}},
57
+ :only => [:id, :bar1, :bar2]
58
+ },
59
+ :url_for => nil,
60
+ :associations => {:foo => nil}
61
+ },
62
+ :sub_bar1 => {
63
+ :name_method => :name,
64
+ :no_inherited_options => false,
65
+ :shallow => false,
66
+ :serialization => {
67
+ :methods => [:interesting_state],
68
+ :only => [:subbar1]
69
+ },
70
+ :url_for => nil,
71
+ },
72
+ :foo => {
73
+ :name_method => :name,
74
+ :no_inherited_options => false,
75
+ :shallow => false,
76
+ :serialization => {:only => [:id, :column1, :column2]},
77
+ :url_for => nil,
78
+ :associations => {:bars => nil}
79
+ },
80
+ :sub_bar2 => {
81
+ :name_method => :name,
82
+ :no_inherited_options => false,
83
+ :shallow => false,
84
+ :serialization => {:only => [:subbar1]},
85
+ :url_for => nil,
86
+ },
87
+ },
88
+ }
51
89
  end
90
+ end
52
91
 
53
- it "should lookup entries by instance class" do
54
- Restful.model_configuration_for(Super.new).should == :super_config
55
- Restful.model_configuration_for(SubClass.new).should == :sub_class_config
92
+ describe "for multiple web services" do
93
+
94
+ it "should allow multiple web services to be configured" do
95
+ configure_foo_service
96
+ configure_another_service
97
+ Restful.registered_web_services.size.should == 2
98
+ Restful.web_service_configuration(:another_service).resource_configuration_for(:another).to_hash(:ignore_empty => true).should == {
99
+ :name_method => :name,
100
+ :url_for => nil,
101
+ :no_inherited_options => false,
102
+ :shallow => false,
103
+ :serialization => {
104
+ :only => [:one, :two],
105
+ },
106
+ }
56
107
  end
57
108
 
58
- describe "with deep structures" do
109
+ end
59
110
 
60
- before(:each) do
61
- Restful.model_configuration = {
62
- :super => { :setting => {:with => :nested_hash } }
111
+ def configure_another_service
112
+ Restful.register_web_service(:another_service,
113
+ :resources => {
114
+ :another => {
115
+ :serialization => {
116
+ :only => [:one, :two],
117
+ },
63
118
  }
64
- end
119
+ }
120
+ )
121
+ end
65
122
 
66
- it "should provide deep clones of model_configuration elements" do
67
- config = Restful.model_configuration_for(:super)
68
- config[:setting][:with] = "changed"
69
- Restful.model_configuration.should == {
70
- :super => { :setting => {:with => :nested_hash } }
71
- }
123
+ def configure_foo_service
124
+ Restful.register_web_service('Foo Web Service') do |config|
125
+
126
+ config.api_prefix = 'foo_api'
127
+
128
+ config.register_resource(:foo,
129
+ :serialization => {
130
+ :only => [:id, :column1, :column2],
131
+ },
132
+ :associations => {:bars => nil}
133
+ )
134
+
135
+ config.register_resource(:bar,
136
+ :serialization => {
137
+ :only => [:id, :bar1, :bar2],
138
+ :include => {
139
+ :foo => { :only => [:column1] }
140
+ },
141
+ },
142
+ :associations => {:foo => nil}
143
+ )
144
+
145
+ config.register_resource(:sub_bar1) do |resource|
146
+ resource.serialization do |serial|
147
+ serial.only << :subbar1
148
+ serial.methods << :interesting_state
149
+ end
150
+ end
151
+
152
+ config.register_resource(:sub_bar2) do |resource|
153
+ resource.serialization do |serial|
154
+ serial.only << :subbar1
155
+ end
156
+ resource.shallow = false
72
157
  end
73
-
74
158
  end
75
159
  end
76
160
  end