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,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe Seatbelt::Synthesizers::Document do
4
+ describe "#synthesize" do
5
+
6
+ before(:all) do
7
+ class ApiDocumentSynthesize
8
+ include Seatbelt::Document
9
+ include Seatbelt::Ghost
10
+
11
+ attribute :name, String
12
+ attribute :age, Integer
13
+
14
+ api_method :lolspeak_my_name
15
+ end
16
+
17
+ class ImplementationApiDocumentSynthesize
18
+ include Seatbelt::Document
19
+ include Seatbelt::Gate
20
+
21
+ #field :name, :type => String
22
+ attribute :name, String
23
+
24
+ synthesize :from => "ApiDocumentSynthesize"
25
+
26
+ def implement_lolspeak_my_name
27
+ return self
28
+ end
29
+ implement :implement_lolspeak_my_name,
30
+ :as => "ApiDocumentSynthesize#lolspeak_my_name"
31
+ end
32
+ end
33
+
34
+ it "synchrones the implementation object with the proxy object" do
35
+ api = ApiDocumentSynthesize.new(:name => "Hendrik")
36
+
37
+ impl_name = api.lolspeak_my_name
38
+
39
+ expect(impl_name.name).to eq api.name
40
+ api.name="Jan"
41
+ expect(impl_name.name).to eq api.name
42
+ impl_name.name = "Gerno"
43
+ expect(api.name).to eq impl_name.name
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,134 @@
1
+ require 'spec_helper'
2
+
3
+ describe Seatbelt::Synthesizers::Mongoid do
4
+ describe "#synthesize" do
5
+
6
+ before(:all) do
7
+ class ApiMongoidSynthesize
8
+ include Seatbelt::Document
9
+ include Seatbelt::Ghost
10
+
11
+ attribute :name, String
12
+ attribute :age, Integer
13
+
14
+ api_method :lolspeak_my_name
15
+ end
16
+
17
+ class ApiMongoidSynthesize2
18
+ include Seatbelt::Document
19
+ include Seatbelt::Ghost
20
+
21
+ attribute :name, String
22
+ attribute :lastname, String
23
+
24
+ api_method :lolspeak_lastname
25
+ api_method :change_my_name
26
+ end
27
+
28
+ class ImplementationApiMongoidSynthesize
29
+ include ::Mongoid::Document
30
+ include Seatbelt::Gate
31
+
32
+ field :name, :type => String
33
+ field :age, :type => String
34
+ field :lastname, :type => String
35
+
36
+ synthesize :from => "ApiMongoidSynthesize",
37
+ :adapter => "Seatbelt::Synthesizers::Mongoid"
38
+
39
+ def implement_lolspeak_my_name
40
+ return self
41
+ end
42
+ implement :implement_lolspeak_my_name,
43
+ :as => "ApiMongoidSynthesize#lolspeak_my_name"
44
+
45
+ def implement_lolspeak_lastname
46
+ return self
47
+ end
48
+ implement :implement_lolspeak_lastname,
49
+ :as => "ApiMongoidSynthesize2#lolspeak_lastname"
50
+
51
+ def implement_change_my_name(name_value)
52
+ @proxy.name = name_value
53
+ return self
54
+ end
55
+ implement :implement_change_my_name,
56
+ :as => "ApiMongoidSynthesize2#change_my_name"
57
+ end
58
+ end
59
+
60
+ it "synchrones the implementation object with the proxy object" do
61
+ api = ApiMongoidSynthesize.new(:name => "Hendrik")
62
+
63
+ impl_name = api.lolspeak_my_name
64
+
65
+ expect(impl_name.name).to eq api.name
66
+ api.name="Jan"
67
+ expect(impl_name.name).to eq api.name
68
+ impl_name.name = "Gerno"
69
+ expect(api.name).to eq impl_name.name
70
+
71
+ api2 = ApiMongoidSynthesize.new(:name => "Jon")
72
+
73
+ impl2_name = api2.lolspeak_my_name
74
+ expect(impl2_name.name).to eq api2.name
75
+ end
76
+
77
+ describe "different attributes than API class" do
78
+ before(:all) do
79
+ class ApiMongoid
80
+ include Seatbelt::Document
81
+ include Seatbelt::Ghost
82
+
83
+ attribute :name, String
84
+ attribute :age, Integer
85
+
86
+ api_method :my_name
87
+ end
88
+ class ImplementationApiMongoidSynthesizeDifferentAttrs
89
+ include ::Mongoid::Document
90
+ include Seatbelt::Gate
91
+
92
+ field :prx_identifier, :type => String
93
+ field :n_age, :type => Integer
94
+
95
+ synthesize :from => "ApiMongoid",
96
+ :adapter => "Seatbelt::Synthesizers::Mongoid"
97
+
98
+ synthesize_map :name => :prx_identifier,:age => :n_age
99
+
100
+ def implement_speak_my_name
101
+ return self
102
+ end
103
+ implement :implement_speak_my_name,
104
+ :as => "ApiMongoid#my_name"
105
+ end
106
+ end
107
+ it "synchrones the implementation object with the proxy object" do
108
+ api = ApiMongoid.new(:name => "John")
109
+
110
+ impl_name = api.my_name
111
+ expect(impl_name.prx_identifier).to eq api.name
112
+
113
+ api.name="Jan"
114
+ expect(impl_name.prx_identifier).to eq api.name
115
+ impl_name.prx_identifier = "Gerno"
116
+ expect(api.name).to eq impl_name.prx_identifier
117
+
118
+ api.age = 29
119
+ expect(impl_name.n_age).to eq api.age
120
+
121
+ impl_name.n_age = 44
122
+ expect(api.age).to eq impl_name.n_age
123
+
124
+ api2 = ApiMongoid.new(:name => "George",:age => 65)
125
+
126
+ impl2_name = api2.my_name
127
+ expect(impl2_name.prx_identifier).to eq api2.name
128
+ expect(impl2_name.n_age).to eq api2.age
129
+
130
+ end
131
+ end
132
+
133
+ end
134
+ end
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+
3
+ describe Seatbelt::Synthesizer do
4
+ before(:all) do
5
+ class ApiFromSynthesize
6
+ include Seatbelt::Document
7
+ include Seatbelt::Ghost
8
+
9
+ attribute :age, Integer
10
+ attribute :name, String
11
+ end
12
+
13
+ class ImplementationSynthesize
14
+ include Mongoid::Document
15
+
16
+ field :age, :type => Integer
17
+ end
18
+
19
+ class SynthesizeWrapper
20
+ include Seatbelt::Synthesizer
21
+
22
+ def synthesizable_attributes
23
+ [:age]
24
+ end
25
+ end
26
+ end
27
+
28
+ describe "#instance_methods" do
29
+ let(:implementation) { ImplementationSynthesize.new }
30
+ let(:instance) do
31
+ SynthesizeWrapper.new(ApiFromSynthesize, implementation)
32
+ end
33
+
34
+ it "provides #synthesize" do
35
+ expect(instance).to respond_to(:synthesize)
36
+ end
37
+
38
+ it "expects a #synthesizable_attributes method" do
39
+ class InvalidSynthesizer
40
+ include Seatbelt::Synthesizer
41
+ end
42
+
43
+ synthesizer = InvalidSynthesizer.new(ApiFromSynthesize, implementation)
44
+
45
+ expect do
46
+ synthesizer.synthesize
47
+ end.to \
48
+ raise_error(Seatbelt::Errors::SynthesizeableAttributesNotImplementedError,
49
+ "Your synthesizer has to implement #synthesizable_attributes.")
50
+
51
+ end
52
+
53
+ describe "#synthesize" do
54
+
55
+ it "sets the attributes of the proxy object and vice versa" do
56
+ implementation.stub(:proxy).and_return(ApiFromSynthesize.new)
57
+ implementation.class.stub(:get_synthesize_map).and_return({})
58
+ instance.synthesize
59
+
60
+ implementation.proxy.age = 12
61
+ expect(implementation.age).to eq implementation.proxy.age
62
+
63
+ implementation.age = 44
64
+ expect(implementation.proxy.age).to eq implementation.age
65
+ end
66
+
67
+ describe "and a #synthesize_map" do
68
+ before(:all) do
69
+
70
+ class ImplementationSynthesizeWithDifferentAttributes
71
+ include Mongoid::Document
72
+
73
+ field :lc_age, :type => Integer
74
+ field :prx_identifier, :type => String
75
+
76
+ def self.synthesize_map
77
+ {
78
+ :age => :lc_age,
79
+ :name => :prx_identifier
80
+ }
81
+ end
82
+
83
+ SynthesizeWrapper.class_eval do
84
+ def synthesizable_attributes
85
+ [:lc_age, :prx_identifier]
86
+ end
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+ it "sets the attributes of the proxy object and vice versa" do
93
+ implementation2 = ImplementationSynthesizeWithDifferentAttributes.new
94
+ instance = SynthesizeWrapper.new(ApiFromSynthesize, implementation2)
95
+ implementation2.stub(:proxy).and_return(ApiFromSynthesize.new)
96
+
97
+ instance.synthesize
98
+ implementation2.proxy.age = 12
99
+ implementation2.proxy.name = "Kafka"
100
+ expect(implementation2.lc_age).to eq implementation2.proxy.age
101
+ expect(implementation2.prx_identifier).to eq implementation2.proxy.name
102
+
103
+ implementation2.lc_age = 44
104
+ expect(implementation2.proxy.age).to eq implementation2.lc_age
105
+ implementation2.prx_identifier = "Roberts"
106
+ expect(implementation2.proxy.name).to eq implementation2.prx_identifier
107
+ end
108
+ end
109
+ end
110
+
111
+ end
112
+ end
@@ -0,0 +1,180 @@
1
+ require 'spec_helper'
2
+
3
+ describe Seatbelt::TapeDeck do
4
+
5
+ describe "#class_methods" do
6
+
7
+ before(:all) do
8
+ class Sample
9
+ include Seatbelt::TapeDeck
10
+ end
11
+ end
12
+
13
+ it "provides #tapes" do
14
+ expect(Sample).to respond_to(:tapes)
15
+ end
16
+
17
+ it "provides #use_tape" do
18
+ expect(Sample).to respond_to(:use_tape)
19
+ end
20
+
21
+ it "provides #use_tapes" do
22
+ expect(Sample).to respond_to(:use_tapes)
23
+ end
24
+
25
+ it "provides #add_tape" do
26
+ expect(Sample).to respond_to(:add_tape)
27
+ end
28
+
29
+ it "provides #respond" do
30
+ expect(Sample).to respond_to(:respond)
31
+ end
32
+
33
+ describe "#tapes" do
34
+
35
+ let(:mock_tape){ double("ATape") }
36
+
37
+ it "is a store to hold tapes for the class" do
38
+ expect do
39
+ Sample.tapes << mock_tape
40
+ end.to change { Sample.tapes.size }.by(1)
41
+ end
42
+
43
+ end
44
+
45
+ describe "#use_tape" do
46
+
47
+ let(:sample_tape){ double("SampleTape") }
48
+
49
+ it "adds a tape to the tape store for this class" do
50
+ sample_tape.stub(:tape_deck=)
51
+ sample_tape.stub(:tape_deck).and_return(nil)
52
+ expect do
53
+ Sample.use_tape sample_tape
54
+ end.to change { Sample.tapes.size }.by(1)
55
+
56
+ end
57
+
58
+ it "a tape is not useable in multiple tapedecks" do
59
+ sample_tape.stub(:tape_deck).and_return(Sample)
60
+ class Sample2
61
+ include Seatbelt::TapeDeck
62
+ end
63
+ expect do
64
+ Sample2.use_tape sample_tape
65
+ end.to raise_error(Seatbelt::Errors::MultipleTapeUsageDetectedError)
66
+ end
67
+
68
+ context "the tape is already in the tape store for this class" do
69
+
70
+ before(:all) do
71
+ class SampleTape < Seatbelt::Tape
72
+ end
73
+ Sample.instance_eval do
74
+ self.instance_variable_set(:@tapes, [])
75
+ end
76
+ Sample.use_tape SampleTape
77
+ end
78
+
79
+ it "then it didn't add the tape again" do
80
+ expect do
81
+ Sample.use_tape SampleTape
82
+ end.to change{ Sample.tapes.size }.by(0)
83
+ end
84
+ end
85
+
86
+ end
87
+
88
+ describe "#use_tapes" do
89
+
90
+ before(:all) do
91
+ class RegionTape < Seatbelt::Tape;end
92
+ class HotelTape < Seatbelt::Tape;end
93
+ end
94
+
95
+ it "adds a bunch of tapes to the tape store for this class" do
96
+ expect do
97
+ Sample.use_tapes RegionTape, HotelTape
98
+ end.to change{ Sample.tapes.size }.by(2)
99
+ end
100
+
101
+ end
102
+
103
+ describe "#respond" do
104
+
105
+ before(:all) do
106
+ Sample.instance_eval do
107
+ self.instance_variable_set(:@tapes, [])
108
+ end
109
+
110
+ class TestTape < Seatbelt::Tape
111
+ end
112
+
113
+ Sample.class_eval do
114
+ use_tape TestTape
115
+ end
116
+ end
117
+
118
+ it "finds an answer on the tapes for the class that matches a query" do
119
+ TestTape.class_eval do
120
+ translate /Call me (\w+) !/ do |sentence, name|
121
+ name
122
+ end
123
+ end
124
+
125
+ query = "Call me Harry !"
126
+ expect(Sample.respond(query)).to eq "Harry"
127
+ end
128
+
129
+ it "passes the original query as first param to the block" do
130
+ TestTape.class_eval do
131
+ translate /Super summer party at (\d+)/ do |sentence, data|
132
+ sentence
133
+ end
134
+ end
135
+ query2 = "Super summer party at 12.08.2014"
136
+ expect(Sample.respond(query2)).to eq query2
137
+ end
138
+
139
+ it "passes the matched data as second param list to the block" do
140
+ TestTape.class_eval do
141
+ translate /Add (\d+) to (\d+) and divide it by (\d+)/ do |sentence,
142
+ sum1,
143
+ sum2,
144
+ divider|
145
+ result = sum1.to_i + sum2.to_i
146
+ result/divider.to_i
147
+ end
148
+ end
149
+ query = "Add 5 to 11 and divide it by 2"
150
+ result = Sample.respond(query)
151
+ expect(result).to be_instance_of Fixnum
152
+ expect(result).to eq 8
153
+ end
154
+
155
+ it "raises an error if no answer is found for the query" do
156
+ expect do
157
+ Sample.respond(%Q{Show me 2 hotels nearby London})
158
+ end.to raise_error(Seatbelt::Errors::NoTapeFoundForQueryError)
159
+ end
160
+
161
+ context "translate block takes just one argument" do
162
+
163
+ it "then the argument is not the query sentence" do
164
+ TestTape.class_eval do
165
+ translate /Finde für mich (\d+) Hotels nahe meiner aktuellen Position/ do |count|
166
+ count.to_i
167
+ end
168
+ end
169
+
170
+ query = "Finde für mich 5 Hotels nahe meiner aktuellen Position"
171
+ result = Sample.answer(query)
172
+ expect(result).to_not eq query
173
+ expect(result).to eq 5
174
+ end
175
+ end
176
+
177
+ end
178
+ end
179
+
180
+ end