restful_serializer 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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