seat-belt 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +29 -0
  3. data/.travis.yml +6 -0
  4. data/Changelog.md +55 -0
  5. data/Gemfile +15 -0
  6. data/Guardfile +13 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +705 -0
  9. data/Rakefile +1 -0
  10. data/ext/.gitkeep +0 -0
  11. data/lib/seatbelt.rb +37 -0
  12. data/lib/seatbelt/collections/collection.rb +56 -0
  13. data/lib/seatbelt/core.rb +15 -0
  14. data/lib/seatbelt/core/callee.rb +35 -0
  15. data/lib/seatbelt/core/eigenmethod.rb +150 -0
  16. data/lib/seatbelt/core/eigenmethod_proxy.rb +45 -0
  17. data/lib/seatbelt/core/ext/core_ext.rb +0 -0
  18. data/lib/seatbelt/core/gate.rb +198 -0
  19. data/lib/seatbelt/core/ghost_tunnel.rb +81 -0
  20. data/lib/seatbelt/core/implementation.rb +158 -0
  21. data/lib/seatbelt/core/interface.rb +51 -0
  22. data/lib/seatbelt/core/iterators/method_config.rb +50 -0
  23. data/lib/seatbelt/core/lookup_table.rb +101 -0
  24. data/lib/seatbelt/core/pool.rb +90 -0
  25. data/lib/seatbelt/core/property.rb +161 -0
  26. data/lib/seatbelt/core/proxy.rb +135 -0
  27. data/lib/seatbelt/core/synthesizeable.rb +50 -0
  28. data/lib/seatbelt/core/terminal.rb +59 -0
  29. data/lib/seatbelt/dependencies.rb +5 -0
  30. data/lib/seatbelt/document.rb +175 -0
  31. data/lib/seatbelt/errors.rb +1 -0
  32. data/lib/seatbelt/errors/errors.rb +150 -0
  33. data/lib/seatbelt/gate_config.rb +59 -0
  34. data/lib/seatbelt/ghost.rb +140 -0
  35. data/lib/seatbelt/models.rb +9 -0
  36. data/lib/seatbelt/seatbelt.rb +10 -0
  37. data/lib/seatbelt/synthesizer.rb +3 -0
  38. data/lib/seatbelt/synthesizers/document.rb +16 -0
  39. data/lib/seatbelt/synthesizers/mongoid.rb +16 -0
  40. data/lib/seatbelt/synthesizers/synthesizer.rb +146 -0
  41. data/lib/seatbelt/tape.rb +2 -0
  42. data/lib/seatbelt/tape_deck.rb +71 -0
  43. data/lib/seatbelt/tapes/tape.rb +105 -0
  44. data/lib/seatbelt/tapes/util/delegate.rb +56 -0
  45. data/lib/seatbelt/translator.rb +66 -0
  46. data/lib/seatbelt/version.rb +3 -0
  47. data/seatbelt.gemspec +27 -0
  48. data/spec/lib/seatbelt/core/eigenmethod_spec.rb +102 -0
  49. data/spec/lib/seatbelt/core/gate_spec.rb +521 -0
  50. data/spec/lib/seatbelt/core/ghost_tunnel_spec.rb +21 -0
  51. data/spec/lib/seatbelt/core/lookup_table_spec.rb +234 -0
  52. data/spec/lib/seatbelt/core/pool_spec.rb +270 -0
  53. data/spec/lib/seatbelt/core/proxy_spec.rb +108 -0
  54. data/spec/lib/seatbelt/core/terminal_spec.rb +184 -0
  55. data/spec/lib/seatbelt/document_spec.rb +287 -0
  56. data/spec/lib/seatbelt/gate_config_spec.rb +98 -0
  57. data/spec/lib/seatbelt/ghost_spec.rb +568 -0
  58. data/spec/lib/seatbelt/synthesizers/document_spec.rb +47 -0
  59. data/spec/lib/seatbelt/synthesizers/mongoid_spec.rb +134 -0
  60. data/spec/lib/seatbelt/synthesizers/synthesizer_spec.rb +112 -0
  61. data/spec/lib/seatbelt/tape_deck_spec.rb +180 -0
  62. data/spec/lib/seatbelt/tapes/tape_spec.rb +115 -0
  63. data/spec/lib/seatbelt/translator_spec.rb +108 -0
  64. data/spec/spec_helper.rb +16 -0
  65. data/spec/support/implementations/seatbelt_environment.rb +19 -0
  66. data/spec/support/shared_examples/shared_api_class.rb +7 -0
  67. data/spec/support/shared_examples/shared_collection_child.rb +7 -0
  68. data/spec/support/worlds/eigenmethod_world.rb +7 -0
  69. metadata +205 -0
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe Seatbelt::GateConfig do
4
+
5
+ describe "class methods" do
6
+
7
+ it "provides #method_directive_instance=" do
8
+ expect(Seatbelt::GateConfig).to respond_to(:method_directive_instance=)
9
+ end
10
+
11
+ it "provides #method_directive_instance" do
12
+ expect(Seatbelt::GateConfig).to respond_to(:method_directive_instance)
13
+ end
14
+
15
+ it "provides #method_directive_class" do
16
+ expect(Seatbelt::GateConfig).to respond_to(:method_directive_class)
17
+ end
18
+
19
+ it "provides #method_directive_class=" do
20
+ expect(Seatbelt::GateConfig).to respond_to(:method_directive_class=)
21
+ end
22
+
23
+ it "provides #method_directives" do
24
+ expect(Seatbelt::GateConfig).to respond_to(:method_directives)
25
+ end
26
+
27
+ describe "#method_directives" do
28
+
29
+ before(:all) do
30
+ @directives = Seatbelt::GateConfig.method_directives
31
+ end
32
+
33
+ it "has a :class key and a default value ." do
34
+ expect(@directives).to have_key(:class)
35
+ expect(@directives[:class]).to eq "."
36
+ end
37
+
38
+ it "has a :instance key and a default value #" do
39
+ expect(@directives).to have_key(:instance)
40
+ expect(@directives[:instance]).to eq "#"
41
+ end
42
+
43
+ end
44
+
45
+ describe "#method_directive_instance" do
46
+
47
+ context "default value" do
48
+
49
+ it "is #" do
50
+ expect(Seatbelt::GateConfig.method_directive_instance).to eq "#"
51
+ end
52
+
53
+ end
54
+
55
+ context "custom value" do
56
+
57
+ it "if | set it is |" do
58
+ Seatbelt::GateConfig.method_directive_instance="|"
59
+ expect(Seatbelt::GateConfig.method_directive_instance).to eq "|"
60
+ end
61
+
62
+ it "if :: is set it raises a Seatbelt::Errors::DirectiveNotAllowedError" do
63
+ expect do
64
+ Seatbelt::GateConfig.method_directive_instance="::"
65
+ end.to raise_error(Seatbelt::Errors::DirectiveNotAllowedError)
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
72
+ describe "#method_directive_class" do
73
+
74
+ context "default value" do
75
+
76
+ it "is ." do
77
+ expect(Seatbelt::GateConfig.method_directive_class).to eq "."
78
+ end
79
+
80
+ it "if / set it is /" do
81
+ Seatbelt::GateConfig.method_directive_class="/"
82
+ expect(Seatbelt::GateConfig.method_directive_class).to eq "/"
83
+ end
84
+
85
+ it "if :: is set it raises a Seatbelt::Errors::DirectiveNotAllowedError" do
86
+ expect do
87
+ Seatbelt::GateConfig.method_directive_class="::"
88
+ end.to raise_error(Seatbelt::Errors::DirectiveNotAllowedError)
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+
95
+
96
+ end
97
+
98
+ end
@@ -0,0 +1,568 @@
1
+ require 'spec_helper'
2
+
3
+ describe Seatbelt::Ghost do
4
+
5
+ describe "included in a class" do
6
+
7
+ before(:all) do
8
+ class Sample
9
+ include Seatbelt::Ghost
10
+ end
11
+
12
+ module SampleWithNamespace
13
+ class Sample
14
+ include Seatbelt::Ghost
15
+ end
16
+ end
17
+ end
18
+
19
+ describe "provides class methods" do
20
+ it "#api_method" do
21
+ expect(Sample).to respond_to(:api_method)
22
+ end
23
+
24
+ it "#lookup_tbl" do
25
+ expect(Sample).to respond_to(:lookup_tbl)
26
+ end
27
+
28
+ it "#enable_tunneling!" do
29
+ expect(Sample).to respond_to(:enable_tunneling!)
30
+ end
31
+
32
+ it "#disable_tunneling!" do
33
+ expect(Sample).to respond_to(:disable_tunneling!)
34
+ end
35
+
36
+ it "#interface" do
37
+ expect(Sample).to respond_to(:interface)
38
+ end
39
+
40
+ it "#define" do
41
+ expect(Sample).to respond_to(:define)
42
+ end
43
+
44
+ it "#define_property" do
45
+ expect(Sample).to respond_to(:define_property)
46
+ end
47
+
48
+ it "#define_properties" do
49
+ expect(Sample).to respond_to(:define_properties)
50
+ end
51
+
52
+ it "#accessible_properties" do
53
+ expect(Sample).to respond_to(:accessible_properties)
54
+ end
55
+
56
+ it "#property_accessible" do
57
+ expect(Sample).to respond_to(:property_accessible)
58
+ end
59
+ end
60
+
61
+ describe "provides instance methods" do
62
+
63
+ it "#properties" do
64
+ expect(Sample.new).to respond_to(:properties)
65
+ end
66
+
67
+ it "#properties=" do
68
+ expect(Sample.new).to respond_to("properties=")
69
+ end
70
+
71
+ end
72
+
73
+ describe "calling an instance API method" do
74
+
75
+ before(:all) do
76
+ Seatbelt.configure_gate do |config|
77
+ config.method_directive_class = "."
78
+ config.method_directive_instance = "#"
79
+ end
80
+
81
+ Sample.class_eval do
82
+ api_method :sum_numbers, :args => [:a,:b]
83
+ end
84
+
85
+ class ImplementSample
86
+ include Seatbelt::Gate
87
+
88
+ def sum_numbers_implementation(a,b)
89
+ a+b
90
+ end
91
+ implement :sum_numbers_implementation, :as => "Sample#sum_numbers"
92
+
93
+ end
94
+
95
+ SampleWithNamespace::Sample.class_eval do
96
+ api_method :seat_count, :args => [:flight_number]
97
+ end
98
+
99
+ ImplementSample.class_eval do
100
+ def seats(flight_number)
101
+ 188 if flight_number.eql?("F-1890n")
102
+ end
103
+ implement :seats, :as => "SampleWithNamespace::Sample#seat_count"
104
+ end
105
+ end
106
+
107
+ context "that exists and is implemented" do
108
+
109
+ it "evaluates the implementation method" do
110
+ sample = Sample.new
111
+ next_sample = SampleWithNamespace::Sample.new
112
+ expect(sample.sum_numbers(2,3)).to eq 5
113
+ expect(next_sample.seat_count("F-1890n")).to eq 188
114
+ end
115
+
116
+ context "but isnt a API method" do
117
+ before(:all) do
118
+ Sample.class_eval do
119
+ def multiply(a,b)
120
+ return a*b
121
+ end
122
+ end
123
+ end
124
+
125
+ it "evaluates the method" do
126
+ expect(Sample.new.multiply(2,2)).to eq 4
127
+ end
128
+ end
129
+
130
+ context "but has wrong argument list" do
131
+
132
+ it "raises an ArgumentError" do
133
+ sample = Sample.new
134
+ expect do
135
+ sample.sum_numbers(1)
136
+ end.to raise_error(ArgumentError)
137
+ end
138
+ end
139
+
140
+ context "requires a block that isnt implemented" do
141
+
142
+ before(:all) do
143
+ Sample.class_eval do
144
+ api_method :configure_gateway,
145
+ :block_required => true
146
+ end
147
+ end
148
+
149
+ it "raises Seatbelt::Errors::ApiMethodBlockRequiredError" do
150
+ sample = Sample.new
151
+ expect do
152
+ sample.configure_gateway("hey")
153
+ end.to raise_error(Seatbelt::Errors::ApiMethodBlockRequiredError)
154
+ end
155
+
156
+ end
157
+
158
+
159
+ end
160
+
161
+ context "that isnt defined and didn't exist" do
162
+
163
+ it "raises Seatbelt::Errors::NoMethodError" do
164
+ sample = Sample.new
165
+ expect do
166
+ sample.factorize(6)
167
+ end.to raise_error(Seatbelt::Errors::NoMethodError)
168
+ end
169
+
170
+ end
171
+
172
+ describe "defined with :interface directive" do
173
+ before(:all) do
174
+ class SampleWithInterface
175
+ include Seatbelt::Ghost
176
+ interface :instance do
177
+ define :calc, :args => [:a, :b]
178
+ define :factorize, :args => [:num]
179
+
180
+ define_property :foo
181
+ define_properties :bar,:foobar
182
+ end
183
+
184
+ interface :class do
185
+ define :class_calc, :args => [:a,:b]
186
+ end
187
+ end
188
+
189
+
190
+ class ImplementationSampleWithInterface
191
+ include Seatbelt::Gate
192
+ include Seatbelt::Document
193
+
194
+ def implement_calc(a,b)
195
+ a+b
196
+ end
197
+ implement :implement_calc,
198
+ :as => "SampleWithInterface#calc"
199
+ implement :implement_calc,
200
+ :as => "SampleWithInterface.class_calc"
201
+
202
+ attribute :implement_foo, Integer
203
+
204
+ implement :implement_foo,
205
+ :as => "SampleWithInterface#foo"
206
+ implement :"implement_foo=",
207
+ :as => "SampleWithInterface#foo="
208
+
209
+ attribute :implement_bar, Integer
210
+
211
+ implement :implement_bar,
212
+ :as => "SampleWithInterface#bar"
213
+ implement :"implement_bar=",
214
+ :as => "SampleWithInterface#bar="
215
+
216
+ attribute :implement_foobar, Integer
217
+
218
+ implement :implement_foobar,
219
+ :as => "SampleWithInterface#foobar"
220
+ implement :"implement_foobar=",
221
+ :as => "SampleWithInterface#foobar="
222
+
223
+ end
224
+ end
225
+
226
+ context "instance method" do
227
+ it "evaluates the method" do
228
+ expect(SampleWithInterface.new.calc(5,32)).to eq 37
229
+ end
230
+ end
231
+
232
+ context "class method" do
233
+ it "evaluates the method" do
234
+ expect(SampleWithInterface.class_calc(3,4)).to eq 7
235
+ end
236
+ end
237
+
238
+ context "property" do
239
+
240
+ context "on instance level" do
241
+
242
+ it "evaluates the setter and getter methods" do
243
+ sample_with_interface_instance = SampleWithInterface.new
244
+ sample_with_interface_instance.foo = 12
245
+ sample_with_interface_instance.bar = 10
246
+ sample_with_interface_instance.foobar = 11
247
+ expect(sample_with_interface_instance.foo).to eq 12
248
+ expect(sample_with_interface_instance.bar).to eq 10
249
+ expect(sample_with_interface_instance.foobar).to eq 11
250
+ end
251
+
252
+ end
253
+
254
+ context "accessible properties for mass assignment" do
255
+
256
+ context "when property isnt defined" do
257
+
258
+ it "raises a PropertyNotYetDefinedError error" do
259
+ expect do
260
+ SampleWithInterface.class_eval do
261
+ interface :instance do
262
+ property_accessible :doomed
263
+ end
264
+ end
265
+ end.to raise_error(Seatbelt::Errors::PropertyNotDefinedYetError)
266
+ end
267
+
268
+ end
269
+
270
+ context "when defined as accessible" do
271
+
272
+ before do
273
+ SampleWithInterface.class_eval do
274
+ interface :instance do
275
+
276
+ property_accessible :foo
277
+ end
278
+ end
279
+ end
280
+
281
+ it "is assignable with #properties=" do
282
+ sample = SampleWithInterface.new
283
+ expect(SampleWithInterface.accessible_properties).to include(:foo)
284
+ sample.properties = {:foo => 123}
285
+ expect(sample.foo).to eq 123
286
+ sample.properties = { "foo" => 245 }
287
+ expect(sample.foo).to eq 245
288
+ end
289
+
290
+ it "is included in #properties" do
291
+ expect(SampleWithInterface.new.properties).to have_key(:foo)
292
+ end
293
+
294
+ end
295
+
296
+ context "when not defined as accessible" do
297
+
298
+ before(:all) do
299
+ SampleWithInterface.class_eval do
300
+ interface :instance do
301
+ define_property :doomed
302
+ end
303
+ end
304
+
305
+ ImplementationSampleWithInterface.class_eval do
306
+ attribute :implementation_doomed, Integer
307
+
308
+ implement :implementation_doomed,
309
+ :as => "SampleWithInterface#doomed"
310
+
311
+ implement :"implementation_doomed=",
312
+ :as => "SampleWithInterface#doomed="
313
+
314
+ end
315
+ end
316
+
317
+ it "is not assignable with #properties=" do
318
+ sample = SampleWithInterface.new
319
+ expect(SampleWithInterface.accessible_properties).to_not \
320
+ include(:doomed)
321
+ sample.doomed = 12
322
+ sample.properties = { :doomed => 11 }
323
+ expect(sample.doomed).to_not eq 11
324
+ expect(sample.doomed).to eq 12
325
+ end
326
+
327
+ it "is not included in #properties" do
328
+ sample = SampleWithInterface.new
329
+
330
+ expect(sample.properties).to_not have_key(:doomed)
331
+ end
332
+ end
333
+
334
+ context "an attribute is marked as accessible property" do
335
+
336
+ context "attribute is defined" do
337
+ class AttributeAccessible
338
+ include Seatbelt::Ghost
339
+ include Seatbelt::Document
340
+
341
+ attribute :attribute_a, :Integer
342
+
343
+ interface :instance do
344
+ define_property :kanban
345
+
346
+ property_accessible :attribute_a, :kanban
347
+ end
348
+
349
+ end
350
+
351
+ class ImplementationAttributeAccessible
352
+ include Seatbelt::Gate
353
+ include Seatbelt::Document
354
+ implementation "AttributeAccessible", :instance do
355
+ match_property 'implement_kanban' => 'kanban'
356
+ end
357
+
358
+ attr_accessor :implement_kanban
359
+
360
+ end
361
+
362
+ end
363
+
364
+ it "is assignable with #properties=" do
365
+ sample = AttributeAccessible.new
366
+ expect(AttributeAccessible.accessible_properties).to \
367
+ include(:attribute_a)
368
+ expect(AttributeAccessible.accessible_properties).to \
369
+ include(:kanban)
370
+ sample.properties = { :attribute_a => 900, :kanban => 12 }
371
+ expect(sample.attribute_a).to eq 900
372
+ expect(sample.kanban).to eq 12
373
+ end
374
+
375
+ it "is included in #properties" do
376
+ sample = AttributeAccessible.new
377
+
378
+ expect(sample.properties).to have_key(:attribute_a)
379
+ expect(sample.properties(:all)).to have_key(:attribute_a)
380
+ end
381
+
382
+ end
383
+ end
384
+
385
+ context "on class level" do
386
+
387
+ it "raises an PropertyOnClassLevelDefinedError" do
388
+ expect do
389
+ SampleWithInterface.class_eval do
390
+
391
+ interface :class do
392
+ define_property :class_foo
393
+ end
394
+ end
395
+
396
+ end.to raise_error(Seatbelt::Errors::PropertyOnClassLevelDefinedError)
397
+ end
398
+ end
399
+
400
+ end
401
+
402
+ describe "but not implemented" do
403
+
404
+ it "raises Seatbelt::Errors::NoMethodError" do
405
+ sample = SampleWithInterface.new
406
+ expect do
407
+ sample.factorize(6)
408
+ end.to raise_error(Seatbelt::Errors::MethodNotImplementedError)
409
+ end
410
+
411
+ end
412
+
413
+ end
414
+
415
+ end
416
+
417
+ describe "calling a class API method" do
418
+
419
+ context "that exists and is implemented" do
420
+
421
+ before(:all) do
422
+ class RSpecSampleApiClass
423
+ include Seatbelt::Document
424
+ include Seatbelt::Ghost
425
+
426
+ api_method :find_region_by_code,
427
+ :scope => :class,
428
+ :args => [:code]
429
+ end
430
+
431
+ SampleWithNamespace::Sample.class_eval do
432
+ api_method :book_in_time,
433
+ :scope => :class,
434
+ :args => [:from, :to]
435
+ end
436
+
437
+ class ImplementsSampleClassMethods
438
+ include Seatbelt::Gate
439
+ def region_by_code(code)
440
+ if code.eql?("de")
441
+ "Germany"
442
+ else
443
+ "Great Britain"
444
+ end
445
+ end
446
+ implement :region_by_code, :as => "RSpecSampleApiClass.find_region_by_code"
447
+
448
+ def book_in_time(from, to)
449
+ true
450
+ end
451
+ implement :book_in_time,
452
+ :as => "SampleWithNamespace::Sample.book_in_time"
453
+
454
+ end
455
+ end
456
+
457
+ it "evaluates the implementation method" do
458
+ expect(RSpecSampleApiClass.find_region_by_code("de")).to eq "Germany"
459
+ expect(RSpecSampleApiClass.find_region_by_code("gb")).to eq "Great Britain"
460
+ expect(SampleWithNamespace::Sample.book_in_time("20130208","20130408"))
461
+ .to be true
462
+ end
463
+
464
+ end
465
+
466
+ context "requires a block that isnt implemented" do
467
+
468
+ before(:all) do
469
+ Sample.class_eval do
470
+ api_method :record_giata_multi_codes,
471
+ :scope => :class,
472
+ :block_required => true
473
+ end
474
+ end
475
+
476
+ it "raises Seatbelt::Errors::ApiMethodBlockRequiredError" do
477
+ expect do
478
+ Sample.record_giata_multi_codes
479
+ end.to raise_error(Seatbelt::Errors::ApiMethodBlockRequiredError)
480
+ end
481
+
482
+ end
483
+
484
+ context "that isnt defined and didn't exist" do
485
+
486
+ it "raises Seatbelt::Errors::NoMethodError" do
487
+ expect do
488
+ Sample.find_hotel_next_to(:lat => 50.3, :lng => 37.5)
489
+ end.to raise_error(Seatbelt::Errors::NoMethodError)
490
+ end
491
+
492
+ end
493
+
494
+ end
495
+
496
+ describe "tunneling to an implementation class" do
497
+
498
+ context "tunneling enabled" do
499
+ before(:all) do
500
+ Sample.class_eval do
501
+ enable_tunneling!
502
+
503
+ api_method :call_groupings
504
+ end
505
+ ImplementSample.class_eval do
506
+ include Seatbelt::Document
507
+ attribute :groupings, Integer
508
+
509
+ def get_groupings
510
+ return groupings
511
+ end
512
+ implement :get_groupings, :as => "Sample#call_groupings"
513
+
514
+ def tunnel_with_block(value)
515
+ return value * yield(1)
516
+ end
517
+ end
518
+ end
519
+
520
+ it "provides #tunnel method" do
521
+ sample = Sample.new
522
+ expect(sample).to respond_to(:tunnel)
523
+ end
524
+
525
+ it "tunnels a method call to the implementation class instance" do
526
+ sample = Sample.new
527
+ sample.tunnel(:groupings=, 12)
528
+ expect(sample.call_groupings).to eq 12
529
+
530
+ result = sample.tunnel(:tunnel_with_block, 10) do |maxnum|
531
+ 3*3 - maxnum
532
+ end
533
+ expect(result).to eql 80
534
+ end
535
+ end
536
+
537
+ context "tunneling disabled" do
538
+ before(:all) do
539
+ Sample.class_eval do
540
+ disable_tunneling!
541
+ end
542
+ end
543
+
544
+ it "did not provide #tunnel method" do
545
+ expect(Sample.new).to_not respond_to(:tunnel)
546
+ expect do
547
+ Sample.new.tunnel(:groupings=, 12)
548
+ end.to raise_error(Seatbelt::Errors::NoMethodError)
549
+ end
550
+ end
551
+
552
+ context "tunneling not enabled" do
553
+ before(:all) do
554
+ class TunnelSample
555
+ include Seatbelt::Ghost
556
+ end
557
+ end
558
+
559
+ it "did not provide #tunnel method" do
560
+ expect(TunnelSample.new).to_not respond_to(:tunnel)
561
+ end
562
+
563
+ end
564
+
565
+ end
566
+
567
+ end
568
+ end