shamu 0.0.9 → 0.0.11

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/Gemfile +5 -3
  4. data/bin/rake +17 -0
  5. data/bin/rspec +17 -0
  6. data/lib/shamu/attributes.rb +3 -1
  7. data/lib/shamu/events/active_record/migration.rb +6 -6
  8. data/lib/shamu/json_api/builder_methods/identifier.rb +18 -4
  9. data/lib/shamu/json_api/context.rb +3 -1
  10. data/lib/shamu/json_api/error.rb +7 -1
  11. data/lib/shamu/json_api/presenter.rb +23 -1
  12. data/lib/shamu/json_api/rails/controller.rb +195 -62
  13. data/lib/shamu/locale/en.yml +3 -1
  14. data/lib/shamu/rails/controller.rb +5 -2
  15. data/lib/shamu/rails/entity.rb +29 -15
  16. data/lib/shamu/rails/railtie.rb +12 -7
  17. data/lib/shamu/services/active_record.rb +2 -2
  18. data/lib/shamu/services/active_record_crud.rb +36 -38
  19. data/lib/shamu/services/error.rb +11 -1
  20. data/lib/shamu/services/lazy_transform.rb +9 -4
  21. data/lib/shamu/services/request_support.rb +5 -2
  22. data/lib/shamu/services/result.rb +40 -7
  23. data/lib/shamu/services/service.rb +17 -8
  24. data/lib/shamu/services/service_call_failed_error.rb +4 -0
  25. data/lib/shamu/version.rb +2 -2
  26. data/shamu.gemspec +4 -4
  27. data/spec/lib/shamu/json_api/builder_methods/identifier_spec.rb +45 -0
  28. data/spec/lib/shamu/json_api/rails/controller_spec.rb +141 -7
  29. data/spec/lib/shamu/json_api/rails/responder_spec.rb +9 -9
  30. data/spec/lib/shamu/rails/controller_spec.rb +4 -4
  31. data/spec/lib/shamu/rails/entity_spec.rb +34 -16
  32. data/spec/lib/shamu/rails/features_spec.rb +6 -6
  33. data/spec/lib/shamu/services/active_record_crud_spec.rb +12 -7
  34. data/spec/lib/shamu/services/lazy_transform_spec.rb +23 -14
  35. data/spec/lib/shamu/services/request_support_spec.rb +15 -1
  36. data/spec/lib/shamu/services/result_spec.rb +37 -1
  37. data/spec/lib/shamu/services/service_spec.rb +25 -14
  38. data/spec/spec_helper.rb +1 -1
  39. metadata +23 -17
@@ -16,6 +16,8 @@ module JsonApiControllerSpec
16
16
  def present
17
17
  builder.identifier :resource, resource.id
18
18
  builder.attribute name: resource.name
19
+
20
+ builder.link :self, "somewhere"
19
21
  end
20
22
  end
21
23
  end
@@ -25,12 +27,38 @@ end
25
27
  describe JsonApiControllerSpec::ResourcesController, type: :controller do
26
28
  controller JsonApiControllerSpec::ResourcesController do
27
29
  def show
28
- resource = resources.first
29
- render json: json_resource( resource )
30
+ render_resource resources.first
30
31
  end
31
32
 
32
33
  def index
33
- render json: json_collection( resources )
34
+ render_collection resources
35
+ end
36
+
37
+ def create
38
+ result = Shamu::Services::Result.new resources.first
39
+ render_result result
40
+ end
41
+
42
+ def update
43
+ result = Shamu::Services::Result.new resources.first
44
+ render_result result
45
+ end
46
+
47
+ def destroy
48
+ result = Shamu::Services::Result.new resources.first
49
+ render_result result
50
+ end
51
+
52
+ def invalid
53
+ result = Shamu::Services::Result.new
54
+ result.errors.add :base, "nope"
55
+
56
+ render_result result
57
+ end
58
+
59
+ def no_entity
60
+ result = Shamu::Services::Result.new
61
+ render_result result
34
62
  end
35
63
 
36
64
  def nope
@@ -51,7 +79,7 @@ describe JsonApiControllerSpec::ResourcesController, type: :controller do
51
79
 
52
80
  describe "#json_resource" do
53
81
  subject do
54
- get :show, id: 1, format: :json
82
+ get :show, params: { id: 1, format: :json }
55
83
  JSON.parse( response.body )
56
84
  end
57
85
 
@@ -59,19 +87,70 @@ describe JsonApiControllerSpec::ResourcesController, type: :controller do
59
87
  it { is_expected.to include "data" => hash_including( "attributes" => kind_of( Hash ) ) }
60
88
 
61
89
  it "reflects fields param to meta" do
62
- get :show, id: 1, fields: { people: "id,name" }
90
+ get :show, params: { id: 1, fields: { people: "id,name" } }
63
91
  json = JSON.parse( response.body )
64
92
  expect( json ).to include "meta" => hash_including( "fields" )
65
93
  end
66
94
 
67
95
  it "fails when 'include' paramter is given" do
68
- get :show, id: 1, include: :contact
96
+ get :show, params: { id: 1, include: :contact }
69
97
 
70
98
  expect( response.code ).to eq "400"
71
99
  expect( response.body ).to include "include"
72
100
  end
73
101
  end
74
102
 
103
+ describe "#render_resource" do
104
+ it "adds Location header" do
105
+ get :show, params: { id: 1 }
106
+ expect( response.headers ).to include 'Location'
107
+ end
108
+ end
109
+
110
+ describe "#render_result" do
111
+ it "returns status created on #create" do
112
+ post :create, params: { name: 'example' }
113
+ expect( response.status ).to eq 201
114
+ expect( response.body ).to include "data"
115
+ end
116
+
117
+ it "returns status ok on #update" do
118
+ put :update, params: { id: 1 }
119
+
120
+ expect( response.status ).to eq 200
121
+ expect( response.body ).to include "data"
122
+ end
123
+
124
+ it "returns status no_content on delete" do
125
+ delete :destroy, params: { id: 1 }
126
+
127
+ expect( response.status ).to eq 204
128
+ end
129
+
130
+ it "returns status bad_request on error" do
131
+ routes.draw do
132
+ post "invalid" => "json_api_controller_spec/resources#invalid"
133
+ end
134
+
135
+ post :invalid
136
+
137
+ expect( response.status ).to be 422
138
+ expect( response.body ).to include "errors"
139
+ end
140
+
141
+ it "returns status no_content on success without entity" do
142
+ routes.draw do
143
+ post "no_entity" => "json_api_controller_spec/resources#no_entity"
144
+ end
145
+
146
+ post :no_entity
147
+
148
+ expect( response.status ).to eq 204
149
+ expect( response.body ).to be_blank
150
+ end
151
+
152
+ end
153
+
75
154
  describe "#json_collection" do
76
155
  before( :each ) do
77
156
  allow( controller.resources ).to receive( :current_page ).and_return 1
@@ -115,4 +194,59 @@ describe JsonApiControllerSpec::ResourcesController, type: :controller do
115
194
  end
116
195
  end
117
196
 
118
- end
197
+ describe "#request_params" do
198
+ let( :body ) do
199
+ {
200
+ data: {
201
+ attributes: {
202
+ name: "Example"
203
+ },
204
+ relationships: {
205
+ book: {
206
+ data: { type: "book", id: "5", attributes: { title: "Bibliography" } }
207
+ },
208
+ stores: {
209
+ data: [
210
+ { "type": "store", id: "56", attributes: { title: "First Street" } }
211
+ ]
212
+ }
213
+ }
214
+ }
215
+ }
216
+ end
217
+
218
+ before( :each ) do
219
+ expect( request ).to receive( :body ) { StringIO.new( body.to_json ) }
220
+ end
221
+
222
+ it "maps data attributes" do
223
+ expect( controller.send( :request_params, :example ) ).to include name: "Example"
224
+ end
225
+
226
+ it "maps relationship ids to root attributes" do
227
+ expect( controller.send( :request_params, :example ) ).to include book_id: "5"
228
+ expect( controller.send( :request_params, :example ) ).to include store_ids: [ "56" ]
229
+ end
230
+
231
+ it "maps relationship data to root attributes" do
232
+ expect( controller.send( :request_params, :example ) ).to include book: { id: "5", title: "Bibliography" }
233
+ expect( controller.send( :request_params, :example ) ).to include stores: [ { id: "56", title: "First Street" } ]
234
+ end
235
+
236
+ it "maps data id if available" do
237
+ body[ :data ][ :id ] = "73"
238
+
239
+ expect( controller.send( :request_params, :example ) ).to include id: "73"
240
+ end
241
+
242
+ it "maps id request params if available" do
243
+ allow( controller.request ).to receive( :params ).and_return( { id: "90" }.with_indifferent_access )
244
+
245
+ expect( controller.send( :request_params, :example ) ).to include id: "90"
246
+ end
247
+
248
+ it "returns relationship directly if matching param key" do
249
+ expect( controller.send( :request_params, :book ) ).to include id: "5", title: "Bibliography"
250
+ end
251
+ end
252
+ end
@@ -60,7 +60,7 @@ describe JsonApiResponderSpec::ResourcesController, type: :controller do
60
60
 
61
61
  let( :resource ) { JsonApiResponderSpec::Resource.new( id: 562, name: "Example" ) }
62
62
  let( :resources ) { [ resource ] }
63
- let( :body ) { JSON.load( response.body, nil, symbolize_names: true ) }
63
+ let( :body ) { JSON.parse( response.body, symbolize_names: true ) }
64
64
 
65
65
  before( :each ) do
66
66
  allow( controller ).to receive( :_routes ).and_return @routes
@@ -69,12 +69,12 @@ describe JsonApiResponderSpec::ResourcesController, type: :controller do
69
69
 
70
70
  describe "#show" do
71
71
  it "has JSON content_type" do
72
- get :show, id: 1
72
+ get :show, params: { id: 1 }
73
73
  expect( response.content_type ).to eq Shamu::JsonApi::MIME_TYPE
74
74
  end
75
75
 
76
76
  it "renders JSON API response" do
77
- get :show, id: 1
77
+ get :show, params: { id: 1 }
78
78
  expect( body ).to include data: hash_including( id: resource.id.to_s )
79
79
  end
80
80
 
@@ -84,7 +84,7 @@ describe JsonApiResponderSpec::ResourcesController, type: :controller do
84
84
  allow( resource ).to receive( :errors ).and_return errors
85
85
  allow( resource ).to receive( :valid? ).and_return false
86
86
 
87
- get :show, id: 1
87
+ get :show, params: { id: 1 }
88
88
  expect( body ).to include :errors
89
89
  end
90
90
  end
@@ -113,22 +113,22 @@ describe JsonApiResponderSpec::ResourcesController, type: :controller do
113
113
 
114
114
  describe "#update" do
115
115
  it "has JSON content_type" do
116
- put :update, id: 1
116
+ put :update, params: { id: 1 }
117
117
  expect( response.content_type ).to eq Shamu::JsonApi::MIME_TYPE
118
118
  end
119
119
 
120
120
  it "includes location header" do
121
- post :update, id: 1
121
+ post :update, params: { id: 1 }
122
122
  expect( response.location ).to be_present
123
123
  end
124
124
 
125
125
  it "returns 200 status code" do
126
- put :update, id: 1
126
+ put :update, params: { id: 1 }
127
127
  expect( response.status ).to eq 200
128
128
  end
129
129
 
130
130
  it "includes the json entity" do
131
- put :update, id: 1
131
+ put :update, params: { id: 1 }
132
132
  expect( body ).to include data: hash_including( id: resource.id.to_s )
133
133
  end
134
134
  end
@@ -150,4 +150,4 @@ describe JsonApiResponderSpec::ResourcesController, type: :controller do
150
150
  end
151
151
  end
152
152
 
153
- end
153
+ end
@@ -18,7 +18,7 @@ describe Shamu::Rails::Controller, type: :controller do
18
18
  public :services, :secure_services, :permit?
19
19
 
20
20
  def show
21
- render text: ""
21
+ render plain: ""
22
22
  end
23
23
  end
24
24
 
@@ -47,10 +47,10 @@ describe Shamu::Rails::Controller, type: :controller do
47
47
 
48
48
  expect( controller ).to receive( :show ) do
49
49
  expect( scorpion.fetch( Shamu::Security::Principal ).user_id ).to eq 945
50
- controller.render( text: "" )
50
+ controller.render( plain: "" )
51
51
  end
52
52
 
53
- get :show, id: 5
53
+ get :show, params: { id: 5 }
54
54
  end
55
55
  end
56
56
 
@@ -71,4 +71,4 @@ describe Shamu::Rails::Controller, type: :controller do
71
71
  expect( controller ).not_to be_permitted_to :read, :something
72
72
  end
73
73
  end
74
- end
74
+ end
@@ -15,8 +15,6 @@ module LoadEntitySpec
15
15
 
16
16
  def authorize!( * )
17
17
  end
18
-
19
-
20
18
  end
21
19
 
22
20
  class ExampleEntity < Shamu::Entities::Entity
@@ -34,20 +32,24 @@ describe Shamu::Rails::Entity, type: :controller do
34
32
  hunt( :example_service, LoadEntitySpec::Service ) { scorpion.new LoadEntitySpec::Service }
35
33
 
36
34
  controller ActionController::Base do
37
- service :example_service, LoadEntitySpec::Service
35
+ service :examples_service, LoadEntitySpec::Service
38
36
  entity LoadEntitySpec::ExampleEntity
39
37
 
40
38
  def show
41
- render text: ""
39
+ render plain: ""
42
40
  end
43
41
 
44
42
  def index
45
- render text: ""
43
+ render plain: ""
46
44
  end
47
45
 
48
46
  def new
47
+ render plan: ""
48
+ end
49
+
50
+ def create
49
51
  example_request
50
- render text: ""
52
+ render plain: ""
51
53
  end
52
54
 
53
55
  end
@@ -62,6 +64,7 @@ describe Shamu::Rails::Entity, type: :controller do
62
64
 
63
65
  it "loads the entity from the service" do
64
66
  expect( example_service ).to receive( :find )
67
+ controller.params[:id] = 1
65
68
  controller.send :example
66
69
  end
67
70
 
@@ -83,7 +86,7 @@ describe Shamu::Rails::Entity, type: :controller do
83
86
 
84
87
  it "loads the entity before the request" do
85
88
  expect( controller ).to receive( :example ).and_call_original
86
- get :show, id: 1
89
+ get :show, params: { id: 1 }
87
90
  end
88
91
 
89
92
  it "invokes list for index types" do
@@ -94,7 +97,13 @@ describe Shamu::Rails::Entity, type: :controller do
94
97
  it "authorizes action for entity request" do
95
98
  expect( example_service ).to receive( :authorize! )
96
99
 
97
- get :new
100
+ post :create
101
+ end
102
+
103
+ it "doesn't load entity on create actions" do
104
+ expect( controller ).not_to receive( :example )
105
+
106
+ post :create
98
107
  end
99
108
 
100
109
  context "only some actions" do
@@ -103,21 +112,26 @@ describe Shamu::Rails::Entity, type: :controller do
103
112
  entity LoadEntitySpec::ExampleEntity, only: :show
104
113
 
105
114
  def show
106
- render text: ""
115
+ render plain: ""
107
116
  end
108
117
 
109
118
  def new
110
- render text: ""
119
+ render plain: ""
120
+ end
121
+
122
+ def create
123
+ render plain: ""
111
124
  end
112
125
  end
113
126
 
114
127
  it "loads on show" do
115
128
  expect( controller ).to receive( :example )
116
- get :show, id: 1
129
+ get :show, params: { id: 1 }
117
130
  end
118
131
 
119
132
  it "doesn't load on new" do
120
133
  expect( controller ).not_to receive( :example )
134
+ post :create
121
135
  get :new
122
136
  end
123
137
  end
@@ -128,23 +142,27 @@ describe Shamu::Rails::Entity, type: :controller do
128
142
  entity LoadEntitySpec::ExampleEntity, except: :show
129
143
 
130
144
  def show
131
- render text: ""
145
+ render plain: ""
132
146
  end
133
147
 
134
148
  def new
135
- render text: ""
149
+ render plain: ""
150
+ end
151
+
152
+ def create
153
+ render plain: ""
136
154
  end
137
155
  end
138
156
 
139
157
  it "loads on show" do
140
158
  expect( controller ).not_to receive( :example )
141
- get :show, id: 1
159
+ get :show, params: { id: 1 }
142
160
  end
143
161
 
144
162
  it "doesn't load on new" do
145
- expect( controller ).to receive( :example )
163
+ expect( controller ).not_to receive( :example )
146
164
  get :new
147
165
  end
148
166
  end
149
167
 
150
- end
168
+ end
@@ -6,7 +6,7 @@ describe Shamu::Rails::Features, type: :controller do
6
6
  public :feature_enabled?
7
7
 
8
8
  def show
9
- render text: ""
9
+ render plain: ""
10
10
  end
11
11
  end
12
12
 
@@ -22,10 +22,10 @@ describe Shamu::Rails::Features, type: :controller do
22
22
 
23
23
  expect( controller ).to receive( :show ) do
24
24
  expect( controller.feature_enabled?( "shopping/nux" ) ).to be_truthy
25
- controller.render text: ""
25
+ controller.render plain: ""
26
26
  end
27
27
 
28
- get :show, id: 1
28
+ get :show, params: { id: 1 }
29
29
  end
30
30
 
31
31
  it "allows toggles to be overridden by query param" do
@@ -36,10 +36,10 @@ describe Shamu::Rails::Features, type: :controller do
36
36
 
37
37
  expect( controller ).to receive( :show ) do
38
38
  expect( controller.feature_enabled?( "shopping/discounts" ) ).to be_truthy
39
- controller.render text: ""
39
+ controller.render plain: ""
40
40
  end
41
41
 
42
- get :show, id: 1, Shamu::Features::EnvStore::RACK_PARAMS_KEY => override
42
+ get :show, params: { id: 1, Shamu::Features::EnvStore::RACK_PARAMS_KEY => override }
43
43
  end
44
44
 
45
- end
45
+ end
@@ -65,8 +65,8 @@ describe Shamu::Services::ActiveRecordCrud do
65
65
  expect( klass.model_class ).to eq ActiveRecordSpec::Favorite
66
66
  end
67
67
 
68
- it "defines a build_entity method" do
69
- expect( klass.new.respond_to?( :build_entity, true ) ).to be_truthy
68
+ it "defines a build_entities method" do
69
+ expect( klass.new.respond_to?( :build_entities, true ) ).to be_truthy
70
70
  end
71
71
 
72
72
  Shamu::Services::ActiveRecordCrud::DSL_METHODS.each do |method|
@@ -76,7 +76,7 @@ describe Shamu::Services::ActiveRecordCrud do
76
76
  end
77
77
  end
78
78
 
79
- it "takes a block defining #build_entity" do
79
+ it "takes a block defining #build_entities" do
80
80
  expect do |b|
81
81
  yield_klass = Class.new( klass ) do
82
82
  resource( ActiveRecordCrudSpec::FavoriteEntity, ActiveRecordSpec::Favorite, &b )
@@ -223,6 +223,8 @@ describe Shamu::Services::ActiveRecordCrud do
223
223
  end
224
224
 
225
225
  it "calls #authorize!" do
226
+ entity
227
+
226
228
  expect( service ).to receive( :authorize! ).with(
227
229
  :update,
228
230
  kind_of( ActiveRecordCrudSpec::FavoriteEntity ),
@@ -434,7 +436,7 @@ describe Shamu::Services::ActiveRecordCrud do
434
436
  end
435
437
  end
436
438
 
437
- describe ".build_entity" do
439
+ describe ".build_entities" do
438
440
  let!( :entity ) { service.create( name: "Example", label: "Books" ).entity }
439
441
  let( :entity_class ) do
440
442
  Class.new( Shamu::Entities::Entity ) do
@@ -444,9 +446,12 @@ describe Shamu::Services::ActiveRecordCrud do
444
446
  let( :klass ) do
445
447
  ec = entity_class
446
448
  Class.new( super() ) do
447
- build_entity do |record, _ = nil|
448
- scorpion.fetch ec, { record: record }, {}
449
+ build_entities do |records|
450
+ records.map do |record|
451
+ scorpion.fetch ec, { record: record }, {}
452
+ end
449
453
  end
454
+ public :build_entities
450
455
  public :build_entity
451
456
  end
452
457
  end
@@ -457,4 +462,4 @@ describe Shamu::Services::ActiveRecordCrud do
457
462
  end
458
463
 
459
464
  end
460
- end
465
+ end
@@ -3,77 +3,86 @@ require "spec_helper"
3
3
  describe Shamu::Services::LazyTransform do
4
4
  let( :source ) { [ 1, 2, 3 ] }
5
5
 
6
+ def transformer( &block )
7
+ ->( records ) {
8
+ records.map do |r|
9
+ yield
10
+ r
11
+ end
12
+ }
13
+ end
14
+
6
15
  it "short-circuits count" do
7
16
  expect do |block|
8
- transformed = Shamu::Services::LazyTransform.new( source, &block )
17
+ transformed = Shamu::Services::LazyTransform.new( source, &transformer( &block ) )
9
18
  expect( transformed.count ).to eq source.count
10
19
  end.not_to yield_control
11
20
  end
12
21
 
13
22
  it "delegates when count has an arg" do
14
23
  expect do |block|
15
- transformed = Shamu::Services::LazyTransform.new( source, &block )
24
+ transformed = Shamu::Services::LazyTransform.new( source, &transformer( &block ) )
16
25
  expect( transformed.count( 1000 ) ).to eq 0
17
26
  end.to yield_control
18
27
  end
19
28
 
20
29
  it "delegates when count has a block given" do
21
30
  expect do |block|
22
- transformed = Shamu::Services::LazyTransform.new( source, &block )
31
+ transformed = Shamu::Services::LazyTransform.new( source, &transformer( &block ) )
23
32
  expect( transformed.count { true } ).to eq source.count
24
33
  end.to yield_control
25
34
  end
26
35
 
27
36
  it "short-circuits first" do
28
37
  expect do |block|
29
- transformed = Shamu::Services::LazyTransform.new( source, &block )
38
+ transformed = Shamu::Services::LazyTransform.new( source, &transformer( &block ) )
30
39
  transformed.first
31
40
  end.to yield_control.once
32
41
  end
33
42
 
34
43
  it "doesn't short-circuit first(n)" do
35
44
  expect do |block|
36
- transformed = Shamu::Services::LazyTransform.new( source, &block )
45
+ transformed = Shamu::Services::LazyTransform.new( source, &transformer( &block ) )
37
46
  transformed.first( 2 )
38
47
  end.to yield_control.exactly(3)
39
48
  end
40
49
 
41
50
  it "short-circuits empty?" do
42
51
  expect do |block|
43
- transformed = Shamu::Services::LazyTransform.new( source, &block )
52
+ transformed = Shamu::Services::LazyTransform.new( source, &transformer( &block ) )
44
53
  expect( transformed ).not_to be_empty
45
54
  end.not_to yield_control
46
55
  end
47
56
 
48
57
  it "short-circuits present?" do
49
58
  expect do |block|
50
- transformed = Shamu::Services::LazyTransform.new( source, &block )
59
+ transformed = Shamu::Services::LazyTransform.new( source, &transformer( &block ) )
51
60
  transformed.present?
52
61
  end.not_to yield_control
53
62
  end
54
63
 
55
64
  it "transforms when enumerated" do
56
65
  expect do |block|
57
- transformed = Shamu::Services::LazyTransform.new( source, &block )
66
+ transformed = Shamu::Services::LazyTransform.new( source, &transformer( &block ) )
58
67
  transformed.to_a
59
68
  end.to yield_control.exactly( 3 )
60
69
  end
61
70
 
62
71
  it "yields transformed values" do
63
- transformed = Shamu::Services::LazyTransform.new( source ) { |v| v * v }
72
+ transformed = Shamu::Services::LazyTransform.new( source ) { |vs| vs.map { |v| v * v } }
64
73
  expect( transformed.to_a ).to eq [ 1, 4, 9 ]
65
74
  end
66
75
 
67
76
  it "short-circuits drop" do
68
77
  expect do |block|
69
- transformed = Shamu::Services::LazyTransform.new( source, &block )
78
+ transformed = Shamu::Services::LazyTransform.new( source, &transformer( &block ) )
70
79
  transformed.drop( 2 ).to_a
71
80
  end.to yield_control.exactly( 1 )
72
81
  end
73
82
 
74
83
  it "uses existing transformed on drop if avaialable" do
75
84
  expect do |block|
76
- transformed = Shamu::Services::LazyTransform.new( source, &block )
85
+ transformed = Shamu::Services::LazyTransform.new( source, &transformer( &block ) )
77
86
  transformed.to_a
78
87
  transformed.drop( 2 ).to_a
79
88
  end.to yield_control.exactly( 3 )
@@ -81,16 +90,16 @@ describe Shamu::Services::LazyTransform do
81
90
 
82
91
  it "short-circuits take" do
83
92
  expect do |block|
84
- transformed = Shamu::Services::LazyTransform.new( source, &block )
93
+ transformed = Shamu::Services::LazyTransform.new( source, &transformer( &block ) )
85
94
  transformed.take( 2 ).to_a
86
95
  end.to yield_control.exactly( 2 )
87
96
  end
88
97
 
89
98
  it "users existing transformed on take if avaialable" do
90
99
  expect do |block|
91
- transformed = Shamu::Services::LazyTransform.new( source, &block )
100
+ transformed = Shamu::Services::LazyTransform.new( source, &transformer( &block ) )
92
101
  transformed.to_a
93
102
  transformed.take( 2 ).to_a
94
103
  end.to yield_control.exactly( 3 )
95
104
  end
96
- end
105
+ end
@@ -49,6 +49,15 @@ module RequestSupportSpec
49
49
  attribute :level, on: :record
50
50
  attribute :amount, on: :record
51
51
  end
52
+
53
+ class UsersService < Shamu::Services::Service
54
+ include Shamu::Services::RequestSupport
55
+ end
56
+
57
+ module UserRequest
58
+ class Change < Shamu::Services::Request
59
+ end
60
+ end
52
61
  end
53
62
 
54
63
  describe Shamu::Services::RequestSupport do
@@ -72,6 +81,11 @@ describe Shamu::Services::RequestSupport do
72
81
  end.request_class( :change )
73
82
  end.to raise_error Shamu::Services::IncompleteSetupError, /Request/
74
83
  end
84
+
85
+ it "singularizes service namespace" do
86
+ service = scorpion.new RequestSupportSpec::UsersService
87
+ expect( service.request_class( :change ) ).to be RequestSupportSpec::UserRequest::Change
88
+ end
75
89
 
76
90
  it "uses common alias fallback new -> create" do
77
91
  expect( service.request_class( :new ) ).to be RequestSupportSpec::Request::Create
@@ -150,4 +164,4 @@ describe Shamu::Services::RequestSupport do
150
164
  expect( request ).to be_a Shamu::Services::Request
151
165
  end
152
166
  end
153
- end
167
+ end