pod4 0.8.0 → 0.8.1
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.
- checksums.yaml +4 -4
- data/.hgtags +1 -0
- data/.ruby-version +1 -1
- data/Gemfile +5 -5
- data/lib/pod4/errors.rb +5 -0
- data/lib/pod4/nebulous_interface.rb +10 -11
- data/lib/pod4/pg_interface.rb +2 -2
- data/lib/pod4/tds_interface.rb +4 -2
- data/lib/pod4/typecasting.rb +1 -1
- data/lib/pod4/version.rb +1 -1
- data/pod4.gemspec +1 -21
- data/spec/common/basic_model_spec.rb +37 -45
- data/spec/common/model_plus_typecasting_spec.rb +16 -16
- data/spec/common/model_spec.rb +96 -103
- data/spec/common/nebulous_interface_spec.rb +78 -74
- data/spec/common/sequel_interface_pg_spec.rb +23 -19
- data/spec/common/sql_helper_spec.rb +24 -14
- data/spec/jruby/sequel_interface_jdbc_ms_spec.rb +24 -17
- data/spec/jruby/sequel_interface_jdbc_pg_spec.rb +30 -4
- data/spec/mri/pg_interface_spec.rb +50 -41
- data/spec/mri/sequel_interface_spec.rb +48 -53
- data/spec/mri/tds_interface_spec.rb +51 -42
- data/tags +186 -47
- metadata +3 -3
data/spec/common/model_spec.rb
CHANGED
@@ -4,57 +4,50 @@ require 'pod4/model'
|
|
4
4
|
require 'pod4/null_interface'
|
5
5
|
|
6
6
|
|
7
|
-
|
8
|
-
# We define a model class to test, since in normal operation we would never use
|
9
|
-
# Model directly, and since it needs an inner Interface.
|
10
|
-
#
|
11
|
-
# We can't use a mock for the interface -- class definitions fall outside the
|
12
|
-
# RSpec DSL as far as I can tell, so I can neither create a mock here or inject
|
13
|
-
# it. Which means we can't mock the interface in the rest of the test either;
|
14
|
-
# any mock we created would not get called.
|
15
|
-
#
|
16
|
-
# But: we want to test that Model calls Interface correctly.
|
17
|
-
#
|
18
|
-
# We do have what appears to be a perfectly sane way of testing. We can define
|
19
|
-
# an inner class based on the genuinely existing, non-mock NullInterface class;
|
20
|
-
# and then define expectations on it. When we do this, Rspec fails to pass the
|
21
|
-
# call on to the object, unless we specifically say `.and_call_original`
|
22
|
-
# instead of `.and_return`.
|
23
|
-
#
|
24
|
-
# This is actually quite nice, but more than a little confusing when you see it
|
25
|
-
# for the first time. Its use isn't spelled out in the RSpec docs AFAICS.
|
26
|
-
#
|
27
|
-
class CustomerModel < Pod4::Model
|
28
|
-
attr_columns :id, :name, :groups
|
29
|
-
attr_columns :price # specifically testing multiple calls to attr_columns
|
30
|
-
set_interface NullInterface.new(:id, :name, :price, :groups, [])
|
31
|
-
|
32
|
-
def map_to_model(ot)
|
33
|
-
super
|
34
|
-
@groups = @groups ? @groups.split(',') : []
|
35
|
-
self
|
36
|
-
end
|
37
|
-
|
38
|
-
def map_to_interface
|
39
|
-
x = super
|
40
|
-
g = (x.>>.groups || []).join(',')
|
41
|
-
x.merge(groups: g)
|
42
|
-
end
|
43
|
-
|
44
|
-
def fake_an_alert(*args)
|
45
|
-
add_alert(*args) #private method
|
46
|
-
end
|
7
|
+
describe 'CustomerModel' do
|
47
8
|
|
48
|
-
|
49
|
-
|
50
|
-
|
9
|
+
##
|
10
|
+
# We define a model class to test, since in normal operation we would never use Model directly,
|
11
|
+
# and since it needs an inner Interface.
|
12
|
+
#
|
13
|
+
# We define an inner class based on the genuinely existing, non-mock NullInterface class; and
|
14
|
+
# then define expectations on it. When we do this, Rspec fails to pass the call on to the object,
|
15
|
+
# unless we specifically say `.and_call_original` instead of `.and_return`.
|
16
|
+
#
|
17
|
+
# This is actually quite nice, but more than a little confusing when you see it for the first
|
18
|
+
# time. Its use isn't spelled out in the RSpec docs AFAICS.
|
19
|
+
#
|
20
|
+
# (Also, we define the class inside an Rspec 'let' so that its scope is limited to this test.)
|
21
|
+
#
|
22
|
+
let(:customer_model_class) do
|
23
|
+
Class.new Pod4::Model do
|
24
|
+
attr_columns :id, :name, :groups
|
25
|
+
attr_columns :price # specifically testing multiple calls to attr_columns
|
26
|
+
set_interface NullInterface.new(:id, :name, :price, :groups, [])
|
27
|
+
|
28
|
+
def map_to_model(ot)
|
29
|
+
super
|
30
|
+
@groups = @groups ? @groups.split(',') : []
|
31
|
+
self
|
32
|
+
end
|
51
33
|
|
52
|
-
|
53
|
-
|
34
|
+
def map_to_interface
|
35
|
+
x = super
|
36
|
+
g = (x.>>.groups || []).join(',')
|
37
|
+
x.merge(groups: g)
|
38
|
+
end
|
54
39
|
|
40
|
+
def fake_an_alert(*args)
|
41
|
+
add_alert(*args) #private method
|
42
|
+
end
|
55
43
|
|
44
|
+
def validate
|
45
|
+
add_alert(:error, "falling over now") if name == "fall over"
|
46
|
+
end
|
56
47
|
|
57
|
-
|
48
|
+
def reset_alerts; @alerts = []; end
|
49
|
+
end
|
50
|
+
end
|
58
51
|
|
59
52
|
let(:records) do
|
60
53
|
[ {id: 10, name: 'Gomez', price: 1.23, groups: 'trains' },
|
@@ -79,17 +72,17 @@ describe 'CustomerModel' do
|
|
79
72
|
# model2 and model3 are in an identical state - they have been filled with a
|
80
73
|
# read(). We have two so that we can RSpec 'allow' on one and not the other.
|
81
74
|
|
82
|
-
let(:model) {
|
75
|
+
let(:model) { customer_model_class.new(20) }
|
83
76
|
|
84
77
|
let(:model2) do
|
85
|
-
m =
|
78
|
+
m = customer_model_class.new(30)
|
86
79
|
|
87
80
|
allow( m.interface ).to receive(:read).and_return( Octothorpe.new(records[2]) )
|
88
81
|
m.read.or_die
|
89
82
|
end
|
90
83
|
|
91
84
|
let(:model3) do
|
92
|
-
m =
|
85
|
+
m = customer_model_class.new(40)
|
93
86
|
|
94
87
|
allow( m.interface ).to receive(:read).and_return( Octothorpe.new(records[3]) )
|
95
88
|
m.read.or_die
|
@@ -99,7 +92,7 @@ describe 'CustomerModel' do
|
|
99
92
|
let(:thing) { Octothorpe.new(id: 'eek', name: 'thing', price: 9.99, groups: 'scuttering') }
|
100
93
|
|
101
94
|
let(:model4) do
|
102
|
-
m =
|
95
|
+
m = customer_model_class.new('eek')
|
103
96
|
|
104
97
|
allow( m.interface ).to receive(:read).and_return(thing)
|
105
98
|
m.read.or_die
|
@@ -111,18 +104,18 @@ describe 'CustomerModel' do
|
|
111
104
|
describe 'Model.attr_columns' do
|
112
105
|
|
113
106
|
it 'requires a list of columns' do
|
114
|
-
expect(
|
107
|
+
expect( customer_model_class ).to respond_to(:attr_columns).with(1).argument
|
115
108
|
end
|
116
109
|
|
117
110
|
it 'exposes the columns just like attr_accessor' do
|
118
|
-
expect(
|
119
|
-
expect(
|
120
|
-
expect(
|
121
|
-
expect(
|
122
|
-
expect(
|
123
|
-
expect(
|
124
|
-
expect(
|
125
|
-
expect(
|
111
|
+
expect( customer_model_class.new ).to respond_to(:id)
|
112
|
+
expect( customer_model_class.new ).to respond_to(:name)
|
113
|
+
expect( customer_model_class.new ).to respond_to(:price)
|
114
|
+
expect( customer_model_class.new ).to respond_to(:groups)
|
115
|
+
expect( customer_model_class.new ).to respond_to(:id=)
|
116
|
+
expect( customer_model_class.new ).to respond_to(:name=)
|
117
|
+
expect( customer_model_class.new ).to respond_to(:price=)
|
118
|
+
expect( customer_model_class.new ).to respond_to(:groups=)
|
126
119
|
end
|
127
120
|
|
128
121
|
# it adds the columns to Model.columns -- covered by the columns test
|
@@ -132,7 +125,7 @@ describe 'CustomerModel' do
|
|
132
125
|
|
133
126
|
describe 'Model.columns' do
|
134
127
|
it 'lists the columns' do
|
135
|
-
expect(
|
128
|
+
expect( customer_model_class.columns ).to match_array( [:id,:name,:price,:groups] )
|
136
129
|
end
|
137
130
|
end
|
138
131
|
##
|
@@ -140,7 +133,7 @@ describe 'CustomerModel' do
|
|
140
133
|
|
141
134
|
describe 'Model.set_interface' do
|
142
135
|
it 'requires an Interface object' do
|
143
|
-
expect(
|
136
|
+
expect( customer_model_class ).to respond_to(:set_interface).with(1).argument
|
144
137
|
end
|
145
138
|
|
146
139
|
# it 'sets interface' - covered by the interface test
|
@@ -150,8 +143,8 @@ describe 'CustomerModel' do
|
|
150
143
|
|
151
144
|
describe 'Model.interface' do
|
152
145
|
it 'is the interface object' do
|
153
|
-
expect(
|
154
|
-
expect(
|
146
|
+
expect( customer_model_class.interface ).to be_a_kind_of NullInterface
|
147
|
+
expect( customer_model_class.interface.id_fld ).to eq :id
|
155
148
|
end
|
156
149
|
end
|
157
150
|
##
|
@@ -159,7 +152,7 @@ describe 'CustomerModel' do
|
|
159
152
|
|
160
153
|
describe 'Model.list' do
|
161
154
|
|
162
|
-
let(:list1) {
|
155
|
+
let(:list1) { customer_model_class.list }
|
163
156
|
|
164
157
|
def arr_without_groups(arr)
|
165
158
|
arr
|
@@ -169,21 +162,21 @@ describe 'CustomerModel' do
|
|
169
162
|
end
|
170
163
|
|
171
164
|
it 'allows an optional selection parameter' do
|
172
|
-
expect{
|
173
|
-
expect{
|
165
|
+
expect{ customer_model_class.list }.not_to raise_exception
|
166
|
+
expect{ customer_model_class.list(name: 'Betty') }.not_to raise_exception
|
174
167
|
end
|
175
168
|
|
176
|
-
it 'returns an array of
|
177
|
-
expect(
|
169
|
+
it 'returns an array of customer_model_class records' do
|
170
|
+
expect( customer_model_class.interface ).
|
178
171
|
to receive(:list).with(nil).
|
179
172
|
and_return( records_as_ot )
|
180
173
|
|
181
174
|
expect( list1 ).to be_a_kind_of Array
|
182
|
-
expect( list1 ).to all(be_a_kind_of
|
175
|
+
expect( list1 ).to all(be_a_kind_of customer_model_class)
|
183
176
|
end
|
184
177
|
|
185
178
|
it 'returns the data from the interface' do
|
186
|
-
expect(
|
179
|
+
expect( customer_model_class.interface ).
|
187
180
|
to receive(:list).with(nil).
|
188
181
|
and_return(records_as_ot)
|
189
182
|
|
@@ -194,11 +187,11 @@ describe 'CustomerModel' do
|
|
194
187
|
it 'honours passed selection criteria' do
|
195
188
|
hash = {price: 2.22}
|
196
189
|
|
197
|
-
expect(
|
190
|
+
expect( customer_model_class.interface ).
|
198
191
|
to receive(:list).with(hash).
|
199
192
|
and_return( [Octothorpe.new(records[1])] )
|
200
193
|
|
201
|
-
list2 =
|
194
|
+
list2 = customer_model_class.list(hash)
|
202
195
|
expect( list2.size ).to eq 1
|
203
196
|
expect( arr_without_groups(list2).first ).to eq( recordsx[1] )
|
204
197
|
end
|
@@ -206,23 +199,23 @@ describe 'CustomerModel' do
|
|
206
199
|
it 'returns an empty array if nothing matches' do
|
207
200
|
hash = {price: 1.23}
|
208
201
|
|
209
|
-
expect(
|
202
|
+
expect( customer_model_class.interface ).
|
210
203
|
to receive(:list).with(hash).
|
211
204
|
and_return([])
|
212
205
|
|
213
|
-
expect(
|
206
|
+
expect( customer_model_class.list(hash) ).to eq []
|
214
207
|
end
|
215
208
|
|
216
209
|
it 'returns an empty array if there are no records' do
|
217
|
-
expect(
|
210
|
+
expect( customer_model_class.list ).to eq []
|
218
211
|
end
|
219
212
|
|
220
213
|
it 'calls map_to_model to set the record data' do
|
221
|
-
allow(
|
214
|
+
allow( customer_model_class.interface ).
|
222
215
|
to receive(:list).
|
223
216
|
and_return(records_as_ot)
|
224
217
|
|
225
|
-
expect(
|
218
|
+
expect( customer_model_class.list.last.groups ).to eq(['trains', 'school'])
|
226
219
|
end
|
227
220
|
|
228
221
|
end
|
@@ -232,25 +225,25 @@ describe 'CustomerModel' do
|
|
232
225
|
describe '#new' do
|
233
226
|
|
234
227
|
it 'takes an optional ID' do
|
235
|
-
expect{
|
236
|
-
expect{
|
228
|
+
expect{ customer_model_class.new }.not_to raise_exception
|
229
|
+
expect{ customer_model_class.new(1) }.not_to raise_exception
|
237
230
|
end
|
238
231
|
|
239
232
|
it 'sets the ID attribute' do
|
240
|
-
expect(
|
233
|
+
expect( customer_model_class.new(23).model_id ).to eq 23
|
241
234
|
end
|
242
235
|
|
243
236
|
it 'sets the status to empty' do
|
244
|
-
expect(
|
237
|
+
expect( customer_model_class.new.model_status ).to eq :empty
|
245
238
|
end
|
246
239
|
|
247
240
|
it 'initializes the alerts attribute' do
|
248
|
-
expect(
|
241
|
+
expect( customer_model_class.new.alerts ).to eq([])
|
249
242
|
end
|
250
243
|
|
251
244
|
it 'doesn''t freak out if the ID is not an integer' do
|
252
|
-
expect{
|
253
|
-
expect(
|
245
|
+
expect{ customer_model_class.new("france") }.not_to raise_exception
|
246
|
+
expect( customer_model_class.new("france").model_id ).to eq "france"
|
254
247
|
end
|
255
248
|
|
256
249
|
end
|
@@ -259,8 +252,8 @@ describe 'CustomerModel' do
|
|
259
252
|
|
260
253
|
describe '#interface' do
|
261
254
|
it 'returns the interface set in the class definition, again' do
|
262
|
-
expect(
|
263
|
-
expect(
|
255
|
+
expect( customer_model_class.new.interface ).to be_a_kind_of NullInterface
|
256
|
+
expect( customer_model_class.new.interface.id_fld ).to eq :id
|
264
257
|
end
|
265
258
|
end
|
266
259
|
##
|
@@ -269,7 +262,7 @@ describe 'CustomerModel' do
|
|
269
262
|
describe '#columns' do
|
270
263
|
it 'returns the attr_columns list from the class definition' do
|
271
264
|
|
272
|
-
expect(
|
265
|
+
expect( customer_model_class.new.columns ).
|
273
266
|
to match_array( [:id,:name,:price,:groups] )
|
274
267
|
|
275
268
|
end
|
@@ -279,7 +272,7 @@ describe 'CustomerModel' do
|
|
279
272
|
|
280
273
|
describe '#alerts' do
|
281
274
|
it 'returns the list of alerts against the model' do
|
282
|
-
cm =
|
275
|
+
cm = customer_model_class.new
|
283
276
|
cm.fake_an_alert(:warning, :foo, 'one')
|
284
277
|
cm.fake_an_alert(:error, :bar, 'two')
|
285
278
|
|
@@ -356,8 +349,8 @@ describe 'CustomerModel' do
|
|
356
349
|
|
357
350
|
describe '#validate' do
|
358
351
|
it 'takes no parameters' do
|
359
|
-
expect{
|
360
|
-
expect{
|
352
|
+
expect{ customer_model_class.new.validate(12) }.to raise_exception ArgumentError
|
353
|
+
expect{ customer_model_class.new.validate }.not_to raise_exception
|
361
354
|
end
|
362
355
|
end
|
363
356
|
##
|
@@ -423,7 +416,7 @@ describe 'CustomerModel' do
|
|
423
416
|
describe '#map_to_model' do
|
424
417
|
|
425
418
|
it 'sets the columns, with groups as an array' do
|
426
|
-
cm =
|
419
|
+
cm = customer_model_class.new
|
427
420
|
cm.map_to_model(records.last)
|
428
421
|
|
429
422
|
expect( cm.groups ).to eq( ['trains','school'] )
|
@@ -436,7 +429,7 @@ describe 'CustomerModel' do
|
|
436
429
|
describe '#map_to_interface' do
|
437
430
|
|
438
431
|
it 'returns the columns, with groups as a list' do
|
439
|
-
cm =
|
432
|
+
cm = customer_model_class.new
|
440
433
|
cm.map_to_model(records.last)
|
441
434
|
|
442
435
|
expect( cm.map_to_interface.>>.groups ).to eq( 'trains,school' )
|
@@ -449,7 +442,7 @@ describe 'CustomerModel' do
|
|
449
442
|
describe '#raise_exceptions' do
|
450
443
|
|
451
444
|
it 'is also known as .or_die' do
|
452
|
-
cm =
|
445
|
+
cm = customer_model_class.new
|
453
446
|
expect( cm.method(:raise_exceptions) ).to eq( cm.method(:or_die) )
|
454
447
|
end
|
455
448
|
|
@@ -477,11 +470,11 @@ describe 'CustomerModel' do
|
|
477
470
|
|
478
471
|
describe '#create' do
|
479
472
|
|
480
|
-
let (:new_model) {
|
473
|
+
let (:new_model) { customer_model_class.new }
|
481
474
|
|
482
475
|
it 'takes no parameters' do
|
483
|
-
expect{
|
484
|
-
expect{
|
476
|
+
expect{ customer_model_class.new.create(12) }.to raise_exception ArgumentError
|
477
|
+
expect{ customer_model_class.new.create }.not_to raise_exception
|
485
478
|
end
|
486
479
|
|
487
480
|
it 'returns self' do
|
@@ -494,8 +487,8 @@ describe 'CustomerModel' do
|
|
494
487
|
end
|
495
488
|
|
496
489
|
it 'calls create on the interface if the record is good' do
|
497
|
-
expect(
|
498
|
-
|
490
|
+
expect( customer_model_class.interface ).to receive(:create)
|
491
|
+
customer_model_class.new.create
|
499
492
|
|
500
493
|
new_model.fake_an_alert(:warning, :name, 'foo')
|
501
494
|
expect( new_model.interface ).to receive(:create)
|
@@ -558,8 +551,8 @@ describe 'CustomerModel' do
|
|
558
551
|
describe '#read' do
|
559
552
|
|
560
553
|
it 'takes no parameters' do
|
561
|
-
expect{
|
562
|
-
expect{
|
554
|
+
expect{ customer_model_class.new.create(12) }.to raise_exception ArgumentError
|
555
|
+
expect{ customer_model_class.new.create }.not_to raise_exception
|
563
556
|
end
|
564
557
|
|
565
558
|
it 'returns self ' do
|
@@ -591,7 +584,7 @@ describe 'CustomerModel' do
|
|
591
584
|
ot = records_as_ot.last
|
592
585
|
allow( model.interface ).to receive(:read).and_return( ot )
|
593
586
|
|
594
|
-
cm =
|
587
|
+
cm = customer_model_class.new(10).read
|
595
588
|
expect( cm.id ).to eq ot.>>.id
|
596
589
|
expect( cm.name ).to eq ot.>>.name
|
597
590
|
expect( cm.price ).to eq ot.>>.price
|
@@ -619,11 +612,11 @@ describe 'CustomerModel' do
|
|
619
612
|
it 'doesn\'t freak out if the model is non-integer' do
|
620
613
|
allow( model.interface ).to receive(:read).and_return( thing )
|
621
614
|
|
622
|
-
expect{
|
615
|
+
expect{ customer_model_class.new('eek').read }.not_to raise_error
|
623
616
|
end
|
624
617
|
|
625
618
|
context 'if the interface.read returns an empty Octothorpe' do
|
626
|
-
let(:missing) {
|
619
|
+
let(:missing) { customer_model_class.new(99) }
|
627
620
|
|
628
621
|
it 'doesn\'t throw an exception' do
|
629
622
|
expect{ missing.read }.not_to raise_exception
|
@@ -1,42 +1,21 @@
|
|
1
1
|
require 'pod4/nebulous_interface'
|
2
2
|
|
3
3
|
require 'nebulous_stomp'
|
4
|
-
require 'nebulous_stomp/
|
4
|
+
require 'nebulous_stomp/stomp_handler_null'
|
5
5
|
|
6
6
|
require_relative 'shared_examples_for_interface'
|
7
7
|
|
8
8
|
|
9
9
|
##
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# subclass NebulousInterface for your model, you don't have to follow that; you
|
13
|
-
# can have a parameter per nebulous parameter, if you want, buy overriding the
|
14
|
-
# CRUDL methods.
|
10
|
+
# This is the class we will pass an instance of to NebulousInterface to use as a cut-out for
|
11
|
+
# creating Nebulous::NebRequest objects.
|
15
12
|
#
|
16
|
-
class
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
set_verb :create, 'custcreate', :name, :price
|
21
|
-
set_verb :read, 'custread', :id
|
22
|
-
set_verb :update, 'custupdate', :id, :name, :price
|
23
|
-
set_verb :delete, 'custdelete', :id
|
24
|
-
set_verb :list, 'custlist', :name
|
25
|
-
end
|
26
|
-
##
|
27
|
-
|
28
|
-
|
29
|
-
##
|
30
|
-
# This is the class we will pass an instance of to NebulousInterface to use as
|
31
|
-
# a cut-out for creating Nebulous::NebRequest objects.
|
32
|
-
#
|
33
|
-
# If we pass an instance of this class to NebulousInterface it will call our
|
34
|
-
# send method instead of creating a NebRequest instance by itself. (It expects
|
35
|
-
# send to return a Nebrequest instance, or something that behaves like one.)
|
13
|
+
# If we pass an instance of this class to NebulousInterface it will call our send method instead of
|
14
|
+
# creating a Request instance by itself. (It expects send to return a Request instance, or
|
15
|
+
# something that behaves like one.)
|
36
16
|
#
|
37
|
-
# This means we can cut Nebulous out of the loop and don't need a real
|
38
|
-
#
|
39
|
-
# RSpec 'inspect' syntax on our cutout object.
|
17
|
+
# This means we can cut Nebulous out of the loop and don't need a real responder. We can also check
|
18
|
+
# the behaviour of NebulousInterface by using RSpec 'inspect' syntax on our cutout object.
|
40
19
|
#
|
41
20
|
# We're basically emulating both a responder and a data source here (!)
|
42
21
|
#
|
@@ -44,68 +23,72 @@ class FakeRequester
|
|
44
23
|
|
45
24
|
def initialize(data={}); @data = data; end
|
46
25
|
|
26
|
+
##
|
27
|
+
# NebulousInterface will call this to return a NebulousStomp::Request object, or something that
|
28
|
+
# behaves like one.
|
29
|
+
#
|
30
|
+
def send(target, requestmsg)
|
31
|
+
hash = response_message_hash(requestmsg)
|
32
|
+
|
33
|
+
stomphandler = NebulousStomp::StompHandlerNull.new
|
34
|
+
|
35
|
+
request = NebulousStomp::Request.new(target, requestmsg)
|
36
|
+
request.stomp_handler = stomphandler
|
37
|
+
|
38
|
+
hash[:inReplyTo] = request.message.reply_id
|
39
|
+
responsemsg = NebulousStomp::Message.new hash
|
40
|
+
stomphandler.insert_fake(responsemsg)
|
41
|
+
|
42
|
+
request
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def create(name, price)
|
48
|
+
id = @data.keys.sort.last.to_i + 1
|
49
|
+
@data[id] = {id: id, name: name, price: price.to_f}
|
50
|
+
id
|
51
|
+
end
|
52
|
+
|
53
|
+
def update(id, name, price)
|
54
|
+
return nil unless @data[id.to_i]
|
55
|
+
@data[id.to_i] = {id: id.to_i, name: name, price: price.to_f}
|
56
|
+
end
|
47
57
|
|
48
|
-
def
|
49
|
-
|
58
|
+
def response_message_hash(requestmsg)
|
59
|
+
hash1 = { contentType: 'application/json' }
|
50
60
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
inReplyTo: nil,
|
59
|
-
contentType: 'application/json' }
|
61
|
+
if requestmsg.params.is_a?(Array)
|
62
|
+
array = requestmsg.params
|
63
|
+
paramstr = array.join(',')
|
64
|
+
else
|
65
|
+
paramstr = requestmsg.params.to_s
|
66
|
+
array = paramstr.split(',')
|
67
|
+
end
|
60
68
|
|
61
|
-
case verb
|
69
|
+
case requestmsg.verb
|
62
70
|
when 'custcreate'
|
63
71
|
id = create(*array)
|
64
72
|
hash2 = {verb: 'success', params: id.to_s}
|
65
73
|
|
66
74
|
when 'custread'
|
67
|
-
record = @data[
|
75
|
+
record = @data[paramstr.to_i]
|
68
76
|
hash2 = { stompBody: (record ? record.to_json : ''.to_json) }
|
69
77
|
|
70
78
|
when 'custupdate'
|
71
79
|
hash2 = update(*array) ? {verb: 'success'} : {verb: 'error' }
|
72
80
|
|
73
81
|
when 'custdelete'
|
74
|
-
hash2 =
|
75
|
-
if @data.delete(paramStr.to_i)
|
76
|
-
{verb: 'success'}
|
77
|
-
else
|
78
|
-
{verb: 'error'}
|
79
|
-
end
|
82
|
+
hash2 = @data.delete(paramstr.to_i) ? {verb: 'success'} : {verb: 'error'}
|
80
83
|
|
81
84
|
when 'custlist'
|
82
85
|
subset = @data.values
|
83
|
-
if
|
84
|
-
subset.select!{|x| x[:name] == array[0] }
|
85
|
-
end
|
86
|
+
subset.select!{|x| x[:name] == array[0] } if (!paramstr.empty? && !array[0].empty?)
|
86
87
|
hash2 = { stompBody: subset.to_json }
|
87
88
|
|
88
89
|
end
|
89
90
|
|
90
|
-
|
91
|
-
hash2[:inReplyTo] = req.replyID
|
92
|
-
|
93
|
-
mess = NebulousStomp::Message.from_cache( hash1.merge(hash2).to_json )
|
94
|
-
req.insert_fake_stomp(mess)
|
95
|
-
req
|
96
|
-
end
|
97
|
-
|
98
|
-
|
99
|
-
def create(name, price)
|
100
|
-
id = @data.keys.sort.last.to_i + 1
|
101
|
-
@data[id] = {id: id, name: name, price: price.to_f}
|
102
|
-
id
|
103
|
-
end
|
104
|
-
|
105
|
-
|
106
|
-
def update(id, name, price)
|
107
|
-
return nil unless @data[id.to_i]
|
108
|
-
@data[id.to_i] = {id: id.to_i, name: name, price: price.to_f}
|
91
|
+
hash1.merge(hash2)
|
109
92
|
end
|
110
93
|
|
111
94
|
end
|
@@ -113,7 +96,28 @@ end
|
|
113
96
|
|
114
97
|
|
115
98
|
|
116
|
-
describe
|
99
|
+
describe "NebulousInterface" do
|
100
|
+
|
101
|
+
##
|
102
|
+
# In order to conform with 'acts_like an interface', our CRUDL routines must
|
103
|
+
# pass a single value as the record, which we are making an array. When you
|
104
|
+
# subclass NebulousInterface for your model, you don't have to follow that; you
|
105
|
+
# can have a parameter per nebulous parameter, if you want, buy overriding the
|
106
|
+
# CRUDL methods.
|
107
|
+
#
|
108
|
+
let(:nebulous_interface_class) do
|
109
|
+
Class.new NebulousInterface do
|
110
|
+
set_target 'faketarget'
|
111
|
+
set_id_fld :id
|
112
|
+
|
113
|
+
set_verb :create, 'custcreate', :name, :price
|
114
|
+
set_verb :read, 'custread', :id
|
115
|
+
set_verb :update, 'custupdate', :id, :name, :price
|
116
|
+
set_verb :delete, 'custdelete', :id
|
117
|
+
set_verb :list, 'custlist', :name
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
117
121
|
|
118
122
|
def init_nebulous
|
119
123
|
stomp_hash = { hosts: [{ login: 'guest',
|
@@ -142,7 +146,7 @@ describe TestNebulousInterface do
|
|
142
146
|
|
143
147
|
let(:interface) do
|
144
148
|
init_nebulous
|
145
|
-
|
149
|
+
nebulous_interface_class.new( FakeRequester.new )
|
146
150
|
end
|
147
151
|
|
148
152
|
end
|
@@ -157,14 +161,14 @@ describe TestNebulousInterface do
|
|
157
161
|
|
158
162
|
let(:interface) do
|
159
163
|
init_nebulous
|
160
|
-
|
164
|
+
nebulous_interface_class.new( FakeRequester.new(data) )
|
161
165
|
end
|
162
166
|
|
163
167
|
|
164
168
|
describe '#new' do
|
165
169
|
|
166
170
|
it 'requires no parameters' do
|
167
|
-
expect{
|
171
|
+
expect{ nebulous_interface_class.new }.not_to raise_exception
|
168
172
|
end
|
169
173
|
|
170
174
|
end
|