praxis 2.0.pre.17 → 2.0.pre.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (235) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +54 -0
  3. data/.simplecov +3 -1
  4. data/.travis.yml +2 -1
  5. data/CHANGELOG.md +19 -0
  6. data/CONTRIBUTING.md +2 -79
  7. data/Gemfile +5 -1
  8. data/Guardfile +6 -4
  9. data/LICENSE +0 -2
  10. data/MAINTAINERS.md +1 -0
  11. data/README.md +15 -22
  12. data/Rakefile +4 -2
  13. data/bin/praxis +55 -58
  14. data/lib/praxis/action_definition/headers_dsl_compiler.rb +5 -6
  15. data/lib/praxis/action_definition.rb +65 -95
  16. data/lib/praxis/api_definition.rb +21 -29
  17. data/lib/praxis/api_general_info.rb +55 -66
  18. data/lib/praxis/application.rb +15 -32
  19. data/lib/praxis/blueprint.rb +80 -73
  20. data/lib/praxis/bootloader.rb +24 -33
  21. data/lib/praxis/bootloader_stages/environment.rb +5 -10
  22. data/lib/praxis/bootloader_stages/file_loader.rb +3 -6
  23. data/lib/praxis/bootloader_stages/plugin_config_load.rb +4 -6
  24. data/lib/praxis/bootloader_stages/plugin_config_prepare.rb +2 -2
  25. data/lib/praxis/bootloader_stages/plugin_loader.rb +3 -7
  26. data/lib/praxis/bootloader_stages/plugin_setup.rb +3 -3
  27. data/lib/praxis/bootloader_stages/routing.rb +5 -8
  28. data/lib/praxis/bootloader_stages/subgroup_loader.rb +2 -10
  29. data/lib/praxis/bootloader_stages/warn_unloaded_files.rb +15 -19
  30. data/lib/praxis/callbacks.rb +12 -11
  31. data/lib/praxis/collection.rb +11 -14
  32. data/lib/praxis/config.rb +17 -28
  33. data/lib/praxis/config_hash.rb +2 -1
  34. data/lib/praxis/controller.rb +7 -6
  35. data/lib/praxis/dispatcher.rb +34 -42
  36. data/lib/praxis/docs/open_api/info_object.rb +11 -8
  37. data/lib/praxis/docs/open_api/media_type_object.rb +18 -17
  38. data/lib/praxis/docs/open_api/operation_object.rb +7 -4
  39. data/lib/praxis/docs/open_api/parameter_object.rb +17 -14
  40. data/lib/praxis/docs/open_api/paths_object.rb +11 -9
  41. data/lib/praxis/docs/open_api/request_body_object.rb +14 -13
  42. data/lib/praxis/docs/open_api/response_object.rb +24 -18
  43. data/lib/praxis/docs/open_api/responses_object.rb +3 -1
  44. data/lib/praxis/docs/open_api/schema_object.rb +61 -29
  45. data/lib/praxis/docs/open_api/server_object.rb +5 -2
  46. data/lib/praxis/docs/open_api/tag_object.rb +9 -6
  47. data/lib/praxis/docs/open_api_generator.rb +114 -150
  48. data/lib/praxis/endpoint_definition.rb +60 -77
  49. data/lib/praxis/error_handler.rb +2 -2
  50. data/lib/praxis/exception.rb +2 -0
  51. data/lib/praxis/exceptions/config.rb +3 -1
  52. data/lib/praxis/exceptions/config_load.rb +2 -0
  53. data/lib/praxis/exceptions/config_validation.rb +3 -1
  54. data/lib/praxis/exceptions/invalid_configuration.rb +3 -1
  55. data/lib/praxis/exceptions/invalid_response.rb +3 -1
  56. data/lib/praxis/exceptions/invalid_trait.rb +3 -1
  57. data/lib/praxis/exceptions/stage_not_found.rb +3 -1
  58. data/lib/praxis/exceptions/validation.rb +4 -3
  59. data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +163 -149
  60. data/lib/praxis/extensions/attribute_filtering/active_record_patches/5x.rb +18 -13
  61. data/lib/praxis/extensions/attribute_filtering/active_record_patches/6_0.rb +13 -9
  62. data/lib/praxis/extensions/attribute_filtering/active_record_patches/6_1_plus.rb +14 -11
  63. data/lib/praxis/extensions/attribute_filtering/active_record_patches.rb +12 -9
  64. data/lib/praxis/extensions/attribute_filtering/filter_tree_node.rb +8 -5
  65. data/lib/praxis/extensions/attribute_filtering/filtering_params.rb +89 -65
  66. data/lib/praxis/extensions/attribute_filtering/filters_parser.rb +68 -62
  67. data/lib/praxis/extensions/attribute_filtering.rb +3 -1
  68. data/lib/praxis/extensions/field_expansion.rb +6 -4
  69. data/lib/praxis/extensions/field_selection/active_record_query_selector.rb +10 -8
  70. data/lib/praxis/extensions/field_selection/field_selector.rb +91 -92
  71. data/lib/praxis/extensions/field_selection/sequel_query_selector.rb +12 -12
  72. data/lib/praxis/extensions/field_selection.rb +3 -1
  73. data/lib/praxis/extensions/pagination/active_record_pagination_handler.rb +6 -4
  74. data/lib/praxis/extensions/pagination/header_generator.rb +16 -11
  75. data/lib/praxis/extensions/pagination/ordering_params.rb +29 -28
  76. data/lib/praxis/extensions/pagination/pagination_handler.rb +44 -42
  77. data/lib/praxis/extensions/pagination/pagination_params.rb +29 -48
  78. data/lib/praxis/extensions/pagination/sequel_pagination_handler.rb +8 -7
  79. data/lib/praxis/extensions/pagination.rb +10 -15
  80. data/lib/praxis/extensions/rails_compat/request_methods.rb +3 -4
  81. data/lib/praxis/extensions/rails_compat.rb +2 -0
  82. data/lib/praxis/extensions/rendering.rb +12 -12
  83. data/lib/praxis/field_expander.rb +8 -9
  84. data/lib/praxis/file_group.rb +8 -12
  85. data/lib/praxis/finalizable.rb +1 -0
  86. data/lib/praxis/handlers/json.rb +5 -2
  87. data/lib/praxis/handlers/plain.rb +2 -1
  88. data/lib/praxis/handlers/www_form.rb +6 -3
  89. data/lib/praxis/handlers/{xml-sample.rb → xml_sample.rb} +26 -22
  90. data/lib/praxis/mapper/active_model_compat.rb +13 -10
  91. data/lib/praxis/mapper/resource.rb +196 -181
  92. data/lib/praxis/mapper/selector_generator.rb +106 -112
  93. data/lib/praxis/mapper/sequel_compat.rb +70 -67
  94. data/lib/praxis/media_type.rb +2 -2
  95. data/lib/praxis/media_type_identifier.rb +26 -22
  96. data/lib/praxis/middleware_app.rb +18 -15
  97. data/lib/praxis/multipart/parser.rb +46 -51
  98. data/lib/praxis/multipart/part.rb +78 -110
  99. data/lib/praxis/notifications.rb +2 -4
  100. data/lib/praxis/plugin.rb +11 -18
  101. data/lib/praxis/plugin_concern.rb +12 -15
  102. data/lib/praxis/plugins/mapper_plugin.rb +15 -13
  103. data/lib/praxis/plugins/pagination_plugin.rb +8 -6
  104. data/lib/praxis/plugins/rails_plugin.rb +33 -28
  105. data/lib/praxis/renderer.rb +11 -15
  106. data/lib/praxis/request.rb +48 -44
  107. data/lib/praxis/request_stages/action.rb +4 -6
  108. data/lib/praxis/request_stages/load_request.rb +2 -4
  109. data/lib/praxis/request_stages/request_stage.rb +19 -23
  110. data/lib/praxis/request_stages/response.rb +4 -6
  111. data/lib/praxis/request_stages/validate.rb +3 -5
  112. data/lib/praxis/request_stages/validate_params_and_headers.rb +15 -22
  113. data/lib/praxis/request_stages/validate_payload.rb +25 -28
  114. data/lib/praxis/request_superclassing.rb +3 -3
  115. data/lib/praxis/resource_definition.rb +1 -0
  116. data/lib/praxis/response.rb +24 -26
  117. data/lib/praxis/response_definition.rb +77 -122
  118. data/lib/praxis/response_template.rb +11 -15
  119. data/lib/praxis/responses/http.rb +23 -44
  120. data/lib/praxis/responses/internal_server_error.rb +18 -21
  121. data/lib/praxis/responses/multipart_ok.rb +4 -9
  122. data/lib/praxis/responses/validation_error.rb +8 -15
  123. data/lib/praxis/route.rb +8 -10
  124. data/lib/praxis/router/rack.rb +13 -7
  125. data/lib/praxis/router/simple.rb +10 -5
  126. data/lib/praxis/router.rb +27 -34
  127. data/lib/praxis/routing_config.rb +52 -29
  128. data/lib/praxis/simple_media_type.rb +5 -8
  129. data/lib/praxis/stage.rb +17 -25
  130. data/lib/praxis/tasks/api_docs.rb +17 -16
  131. data/lib/praxis/tasks/console.rb +3 -1
  132. data/lib/praxis/tasks/environment.rb +2 -0
  133. data/lib/praxis/tasks/routes.rb +26 -24
  134. data/lib/praxis/tasks.rb +3 -1
  135. data/lib/praxis/trait.rb +37 -46
  136. data/lib/praxis/types/fuzzy_hash.rb +13 -14
  137. data/lib/praxis/types/media_type_common.rb +11 -10
  138. data/lib/praxis/types/multipart_array/part_definition.rb +14 -17
  139. data/lib/praxis/types/multipart_array.rb +100 -115
  140. data/lib/praxis/validation_handler.rb +5 -3
  141. data/lib/praxis/version.rb +3 -1
  142. data/lib/praxis.rb +4 -5
  143. data/praxis.gemspec +22 -21
  144. data/spec/functional_spec.rb +44 -56
  145. data/spec/praxis/action_definition_spec.rb +39 -48
  146. data/spec/praxis/api_definition_spec.rb +45 -47
  147. data/spec/praxis/api_general_info_spec.rb +28 -29
  148. data/spec/praxis/application_spec.rb +18 -14
  149. data/spec/praxis/blueprint_spec.rb +33 -34
  150. data/spec/praxis/bootloader_spec.rb +32 -30
  151. data/spec/praxis/callbacks_spec.rb +37 -37
  152. data/spec/praxis/collection_spec.rb +18 -25
  153. data/spec/praxis/config_hash_spec.rb +5 -4
  154. data/spec/praxis/config_spec.rb +27 -26
  155. data/spec/praxis/controller_spec.rb +8 -9
  156. data/spec/praxis/endpoint_definition_spec.rb +25 -32
  157. data/spec/praxis/extensions/attribute_filtering/active_record_filter_query_builder_spec.rb +171 -114
  158. data/spec/praxis/extensions/attribute_filtering/filter_tree_node_spec.rb +22 -21
  159. data/spec/praxis/extensions/attribute_filtering/filtering_params_spec.rb +112 -60
  160. data/spec/praxis/extensions/attribute_filtering/filters_parser_spec.rb +37 -38
  161. data/spec/praxis/extensions/field_expansion_spec.rb +8 -10
  162. data/spec/praxis/extensions/field_selection/active_record_query_selector_spec.rb +14 -13
  163. data/spec/praxis/extensions/field_selection/field_selector_spec.rb +9 -16
  164. data/spec/praxis/extensions/field_selection/sequel_query_selector_spec.rb +50 -49
  165. data/spec/praxis/extensions/pagination/active_record_pagination_handler_spec.rb +32 -31
  166. data/spec/praxis/extensions/rendering_spec.rb +9 -9
  167. data/spec/praxis/extensions/support/spec_resources_active_model.rb +32 -49
  168. data/spec/praxis/extensions/support/spec_resources_sequel.rb +48 -48
  169. data/spec/praxis/field_expander_spec.rb +6 -5
  170. data/spec/praxis/file_group_spec.rb +3 -1
  171. data/spec/praxis/handlers/json_spec.rb +6 -5
  172. data/spec/praxis/mapper/resource_spec.rb +39 -29
  173. data/spec/praxis/mapper/selector_generator_spec.rb +80 -46
  174. data/spec/praxis/media_type_identifier_spec.rb +13 -10
  175. data/spec/praxis/media_type_spec.rb +12 -12
  176. data/spec/praxis/middleware_app_spec.rb +23 -22
  177. data/spec/praxis/multipart/parser_spec.rb +7 -9
  178. data/spec/praxis/notifications_spec.rb +4 -4
  179. data/spec/praxis/plugin_concern_spec.rb +5 -6
  180. data/spec/praxis/renderer_spec.rb +10 -9
  181. data/spec/praxis/request_spec.rb +38 -41
  182. data/spec/praxis/request_stages/action_spec.rb +14 -15
  183. data/spec/praxis/request_stages/request_stage_spec.rb +30 -41
  184. data/spec/praxis/request_stages/validate_spec.rb +3 -1
  185. data/spec/praxis/response_definition_spec.rb +79 -92
  186. data/spec/praxis/response_spec.rb +35 -40
  187. data/spec/praxis/responses/internal_server_error_spec.rb +6 -9
  188. data/spec/praxis/responses/validation_error_spec.rb +17 -18
  189. data/spec/praxis/route_spec.rb +4 -7
  190. data/spec/praxis/router_spec.rb +69 -79
  191. data/spec/praxis/routing_config_spec.rb +15 -14
  192. data/spec/praxis/stage_spec.rb +56 -53
  193. data/spec/praxis/trait_spec.rb +17 -17
  194. data/spec/praxis/types/fuzzy_hash_spec.rb +11 -9
  195. data/spec/praxis/types/multipart_array/part_definition_spec.rb +3 -2
  196. data/spec/praxis/types/multipart_array_spec.rb +33 -48
  197. data/spec/spec_app/app/concerns/authenticated.rb +5 -5
  198. data/spec/spec_app/app/concerns/basic_api.rb +3 -1
  199. data/spec/spec_app/app/concerns/log_wrapper.rb +5 -3
  200. data/spec/spec_app/app/controllers/base_class.rb +6 -5
  201. data/spec/spec_app/app/controllers/instances.rb +31 -34
  202. data/spec/spec_app/app/controllers/volumes.rb +6 -6
  203. data/spec/spec_app/app/responses/multipart.rb +1 -2
  204. data/spec/spec_app/app/responses/other_response.rb +2 -2
  205. data/spec/spec_app/config/environment.rb +19 -6
  206. data/spec/spec_app/config.ru +4 -3
  207. data/spec/spec_app/design/api.rb +13 -15
  208. data/spec/spec_app/design/media_types/instance.rb +6 -6
  209. data/spec/spec_app/design/media_types/volume.rb +2 -1
  210. data/spec/spec_app/design/media_types/volume_snapshot.rb +2 -1
  211. data/spec/spec_app/design/resources/instances.rb +11 -17
  212. data/spec/spec_app/design/resources/volume_snapshots.rb +4 -5
  213. data/spec/spec_app/design/resources/volumes.rb +4 -5
  214. data/spec/spec_helper.rb +11 -13
  215. data/spec/support/be_deep_equal_matcher.rb +5 -0
  216. data/spec/support/spec_authorization_plugin.rb +7 -12
  217. data/spec/support/spec_blueprints.rb +5 -4
  218. data/spec/support/spec_complex_authentication_plugin.rb +17 -34
  219. data/spec/support/spec_endpoint_definitions.rb +2 -3
  220. data/spec/support/spec_media_types.rb +28 -35
  221. data/spec/support/spec_resources.rb +22 -16
  222. data/spec/support/spec_simple_authentication_plugin.rb +5 -9
  223. data/tasks/loader.thor +4 -2
  224. data/tasks/thor/app.rb +7 -5
  225. data/tasks/thor/example.rb +23 -22
  226. data/tasks/thor/model.rb +7 -7
  227. data/tasks/thor/scaffold.rb +23 -23
  228. data/tasks/thor/templates/generator/example_app/app/v1/resources/user.rb +0 -8
  229. data/tasks/thor/templates/generator/scaffold/implementation/resources/item.rb +1 -2
  230. metadata +72 -84
  231. data/MAINTAINERS +0 -2
  232. data/TODO.md +0 -25
  233. data/spec/praxis/api_resource_spec.rb +0 -0
  234. data/spec/praxis/dispatcher_spec.rb +0 -0
  235. data/spec/spec_app/app/responses/bulk_response.rb +0 -0
@@ -1,15 +1,17 @@
1
- require "spec_helper"
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
2
4
 
3
5
  describe Praxis::ResponseDefinition do
4
6
  subject(:response_definition) { Praxis::ResponseDefinition.new(name, &block) }
5
7
  let(:name) { 'response_name' }
6
8
 
7
9
  let(:block) do
8
- Proc.new do
10
+ proc do
9
11
  status 200
10
12
  description 'test description'
11
- header( "X-Header", "value", description: 'Very nais header')
12
- header( "Content-Type", "application/some-type" )
13
+ header('X-Header', 'value', description: 'Very nais header')
14
+ header('Content-Type', 'application/some-type')
13
15
  end
14
16
  end
15
17
 
@@ -17,11 +19,10 @@ describe Praxis::ResponseDefinition do
17
19
  its(:description) { should == 'test description' }
18
20
  its(:parts) { should be(nil) }
19
21
  let(:response_status) { 200 }
20
- let(:response_content_type) { "application/some-type" }
21
- let(:response_headers) { { "X-Header" => "value", "Content-Type" => response_content_type, "Location" => '/somewhere/over/the/rainbow'} }
22
-
23
- let(:response) { instance_double("Praxis::Response", status: response_status , headers: response_headers, content_type: response_content_type ) }
22
+ let(:response_content_type) { 'application/some-type' }
23
+ let(:response_headers) { { 'X-Header' => 'value', 'Content-Type' => response_content_type, 'Location' => '/somewhere/over/the/rainbow' } }
24
24
 
25
+ let(:response) { instance_double('Praxis::Response', status: response_status, headers: response_headers, content_type: response_content_type) }
25
26
 
26
27
  context '#media_type' do
27
28
  it 'accepts a MediaType object and returns the media_type that was set' do
@@ -42,11 +43,11 @@ describe Praxis::ResponseDefinition do
42
43
  end
43
44
 
44
45
  it 'should return an error when media_type is not a String or a MediaType' do
45
- expect{ response_definition.media_type Object.new }.to raise_error(Praxis::Exceptions::InvalidConfiguration)
46
+ expect { response_definition.media_type Object.new }.to raise_error(Praxis::Exceptions::InvalidConfiguration)
46
47
  end
47
48
 
48
49
  it 'should return an error when media_type is a Symbol other than :controller_defined' do
49
- expect{ response_definition.media_type :symbol }.to raise_error(Praxis::Exceptions::InvalidConfiguration)
50
+ expect { response_definition.media_type :symbol }.to raise_error(Praxis::Exceptions::InvalidConfiguration)
50
51
  end
51
52
  end
52
53
 
@@ -73,7 +74,7 @@ describe Praxis::ResponseDefinition do
73
74
  end
74
75
 
75
76
  # TODO: Complete/correct the "example" generation when it is done in the ResponseDefinition class
76
- #context 'with media_type set to a MediaType' do
77
+ # context 'with media_type set to a MediaType' do
77
78
  # let(:media_type) { Person }
78
79
  #
79
80
  # let(:expected_context) { "Person-#{name}" }
@@ -87,17 +88,17 @@ describe Praxis::ResponseDefinition do
87
88
  # it 'is rendered in the describe output' do
88
89
  # expect(response_definition.describe[:example]).to eq(example.render)
89
90
  # end
90
- #end
91
+ # end
91
92
  end
92
93
 
93
94
  context '#location' do
94
95
  it 'accepts a String' do
95
- response_definition.location "string_location"
96
- expect(response_definition.location).to eq("string_location")
96
+ response_definition.location 'string_location'
97
+ expect(response_definition.location).to eq('string_location')
97
98
  end
98
99
 
99
100
  it 'accepts a Regex' do
100
- response_definition.location /regex_location/
101
+ response_definition.location(/regex_location/)
101
102
  expect(response_definition.location).to eq(/regex_location/)
102
103
  end
103
104
 
@@ -114,31 +115,30 @@ describe Praxis::ResponseDefinition do
114
115
 
115
116
  subject(:parts) { response_definition.parts }
116
117
 
117
- it{ should be_kind_of(Praxis::ResponseDefinition) }
118
- its('media_type.identifier'){ should == 'application/special' }
119
- its(:name){ should be(:ok) }
120
- its(:status){ should be( 200 ) }
121
-
118
+ it { should be_kind_of(Praxis::ResponseDefinition) }
119
+ its('media_type.identifier') { should == 'application/special' }
120
+ its(:name) { should be(:ok) }
121
+ its(:status) { should be(200) }
122
122
  end
123
123
  context 'without a :like argument, and without a block' do
124
124
  it 'complains' do
125
- expect{
125
+ expect do
126
126
  response_definition.parts media_type: 'application/special'
127
- }.to raise_error(ArgumentError, /needs a :like argument or a block/)
127
+ end.to raise_error(ArgumentError, /needs a :like argument or a block/)
128
128
  end
129
129
  end
130
130
  context 'with a :like argument, and a block' do
131
131
  it 'complains' do
132
- expect{
132
+ expect do
133
133
  response_definition.parts like: :something, media_type: 'application/special' do
134
134
  end
135
- }.to raise_error(ArgumentError, /does not allow :like and a block simultaneously/)
135
+ end.to raise_error(ArgumentError, /does not allow :like and a block simultaneously/)
136
136
  end
137
137
  end
138
138
 
139
139
  context 'with a proc' do
140
140
  let(:the_proc) do
141
- Proc.new do
141
+ proc do
142
142
  status 201
143
143
  media_type 'from_proc'
144
144
  end
@@ -150,10 +150,9 @@ describe Praxis::ResponseDefinition do
150
150
 
151
151
  subject(:parts) { response_definition.parts }
152
152
 
153
- it{ should be_kind_of(Praxis::ResponseDefinition) }
154
- its('media_type.identifier'){ should == 'from_proc' }
155
- its(:status){ should be( 201 ) }
156
-
153
+ it { should be_kind_of(Praxis::ResponseDefinition) }
154
+ its('media_type.identifier') { should == 'from_proc' }
155
+ its(:status) { should be(201) }
157
156
  end
158
157
 
159
158
  context 'with a block' do
@@ -166,10 +165,9 @@ describe Praxis::ResponseDefinition do
166
165
 
167
166
  subject(:parts) { response_definition.parts }
168
167
 
169
- it{ should be_kind_of(Praxis::ResponseDefinition) }
170
- its('media_type.identifier'){ should == 'from_proc' }
171
- its(:status){ should be( 201 ) }
172
-
168
+ it { should be_kind_of(Praxis::ResponseDefinition) }
169
+ its('media_type.identifier') { should == 'from_proc' }
170
+ its(:status) { should be(201) }
173
171
  end
174
172
  end
175
173
  # context '#multipart' do
@@ -217,8 +215,7 @@ describe Praxis::ResponseDefinition do
217
215
 
218
216
  context '#validate' do
219
217
  context 'functional test' do
220
-
221
- it "calls all the validation sub-functions" do
218
+ it 'calls all the validation sub-functions' do
222
219
  expect(response_definition).to receive(:validate_status!).once
223
220
  expect(response_definition).to receive(:validate_headers!).once
224
221
  expect(response_definition).to receive(:validate_content_type!).once
@@ -227,68 +224,64 @@ describe Praxis::ResponseDefinition do
227
224
  end
228
225
 
229
226
  describe 'custom validate_xxx! methods' do
230
-
231
- describe "#validate_status!" do
227
+ describe '#validate_status!' do
232
228
  context 'that is completely valid' do
233
229
  it 'should succeed' do
234
- expect {
230
+ expect do
235
231
  response_definition.validate_status!(response)
236
- }.to_not raise_error
232
+ end.to_not raise_error
237
233
  end
238
234
  end
239
235
 
240
-
241
236
  context 'with internal error' do
242
237
  let(:response_status) { 500 }
243
238
  it 'should raise an error that later gets swallowed' do
244
- expect {
239
+ expect do
245
240
  response_definition.validate_status!(response)
246
- }.to raise_error(Praxis::Exceptions::Validation)
241
+ end.to raise_error(Praxis::Exceptions::Validation)
247
242
  end
248
243
  end
249
-
250
244
  end
251
245
 
252
- describe "#validate_headers!" do
246
+ describe '#validate_headers!' do
253
247
  context 'when there are missing headers' do
254
248
  it 'should raise error' do
255
249
  response_definition.header('X-Unknown', 'test')
256
- expect {
250
+ expect do
257
251
  response_definition.validate_headers!(response)
258
- }.to raise_error(Praxis::Exceptions::Validation)
252
+ end.to raise_error(Praxis::Exceptions::Validation)
259
253
  end
260
254
  end
261
255
  context 'when headers with same names are returned' do
262
256
  it 'a simply required header should not raise error just by being there' do
263
257
  response_definition.header('X-Header', nil)
264
- expect {
258
+ expect do
265
259
  response_definition.validate_headers!(response)
266
- }.to_not raise_error
260
+ end.to_not raise_error
267
261
  end
268
262
  it 'an exact string header should not raise error if it fully matches' do
269
263
  response_definition.header('X-Header', 'value')
270
- expect {
264
+ expect do
271
265
  response_definition.validate_headers!(response)
272
- }.to_not raise_error
266
+ end.to_not raise_error
273
267
  end
274
268
  it 'a regexp header should not raise error if it matches the regexp' do
275
269
  response_definition.header('X-Header', /value/)
276
- expect {
270
+ expect do
277
271
  response_definition.validate_headers!(response)
278
- }.to_not raise_error
272
+ end.to_not raise_error
279
273
  end
280
274
  it 'a regexp header should raise error if it does not match the regexp' do
281
275
  response_definition.header('X-Header', /anotherthing/)
282
- expect {
276
+ expect do
283
277
  response_definition.validate_headers!(response)
284
- }.to raise_error(Praxis::Exceptions::Validation)
278
+ end.to raise_error(Praxis::Exceptions::Validation)
285
279
  end
286
280
  end
287
281
  end
288
282
 
289
- describe "#validate_content_type!" do
290
-
291
- let(:response_headers) { {'Content-Type' => content_type } }
283
+ describe '#validate_content_type!' do
284
+ let(:response_headers) { { 'Content-Type' => content_type } }
292
285
  let(:content_type) { 'application/none' }
293
286
 
294
287
  let(:media_type) do
@@ -299,9 +292,9 @@ describe Praxis::ResponseDefinition do
299
292
 
300
293
  context 'for definition without media_type defined' do
301
294
  it 'should not check that it matches the content type' do
302
- expect {
295
+ expect do
303
296
  response_definition.validate_content_type!(response)
304
- }.to_not raise_error
297
+ end.to_not raise_error
305
298
  end
306
299
  end
307
300
 
@@ -312,60 +305,58 @@ describe Praxis::ResponseDefinition do
312
305
  let(:response_content_type) { content_type }
313
306
 
314
307
  it 'validates successfully' do
315
- expect {
308
+ expect do
316
309
  response_definition.validate_content_type!(response)
317
- }.to_not raise_error
310
+ end.to_not raise_error
318
311
  end
319
312
  end
320
313
 
321
314
  context 'when content type includes a parameter' do
322
315
  let(:response_content_type) { "#{content_type}; collection=true" }
323
316
  it 'validates successfully' do
324
- expect {
317
+ expect do
325
318
  response_definition.validate_content_type!(response)
326
- }.to_not raise_error
319
+ end.to_not raise_error
327
320
  end
328
321
  end
329
322
 
330
323
  context 'when content type does not match' do
331
- let(:response_content_type) { "application/will_never_match" }
324
+ let(:response_content_type) { 'application/will_never_match' }
332
325
 
333
326
  it 'should raise error telling you so' do
334
- expect {
327
+ expect do
335
328
  response_definition.validate_content_type!(response)
336
- }.to raise_error(Praxis::Exceptions::Validation)
329
+ end.to raise_error(Praxis::Exceptions::Validation)
337
330
  end
338
331
  end
339
332
 
340
333
  context 'when content type is not set' do
341
334
  let(:response_headers) { {} }
342
335
  it 'should still raise an error' do
343
- expect {
336
+ expect do
344
337
  response_definition.validate_content_type!(response)
345
- }.to raise_error(Praxis::Exceptions::Validation)
338
+ end.to raise_error(Praxis::Exceptions::Validation)
346
339
  end
347
340
  end
348
341
  end
349
342
  end
350
343
  end
351
-
352
344
  end
353
345
 
354
-
355
346
  context 'with invalid definitions' do
356
347
  it 'raises an error if status code is not part of the definition' do
357
348
  expect do
358
349
  Praxis::ResponseDefinition.new('response name') do
359
- description "testing"
350
+ description 'testing'
360
351
  end
361
352
  end.to raise_error(Praxis::Exceptions::InvalidConfiguration)
362
353
  end
363
354
  end
364
355
 
365
356
  context '.describe' do
366
- let(:description) { "A description" }
357
+ let(:description) { 'A description' }
367
358
  let(:location) { %r{/my/url/} }
368
- let(:headers) { {'Header1' => 'Value1'} }
359
+ let(:headers) { { 'Header1' => 'Value1' } }
369
360
  let(:parts) { nil }
370
361
  let(:parts_block) { nil }
371
362
 
@@ -380,7 +371,7 @@ describe Praxis::ResponseDefinition do
380
371
  response.description(description) if description
381
372
  response.location(location) if location
382
373
  if parts || parts_block
383
- parts ? response.parts(nil, **parts, &parts_block) : response.parts(nil, &parts_block)
374
+ parts ? response.parts(nil, **parts, &parts_block) : response.parts(nil, &parts_block)
384
375
  end
385
376
 
386
377
  headers&.each do |(name, value)|
@@ -403,7 +394,6 @@ describe Praxis::ResponseDefinition do
403
394
  it 'properly encodes the example bodies' do
404
395
  expect(JSON.parse(examples['json'][:body])).to be_kind_of(Hash)
405
396
  end
406
-
407
397
  end
408
398
 
409
399
  context 'which does not have a identifier' do
@@ -416,51 +406,48 @@ describe Praxis::ResponseDefinition do
416
406
  expect(subject['json'][:content_type]).to eq('application/json')
417
407
  end
418
408
  end
419
-
420
-
421
409
  end
422
410
 
423
-
424
411
  context 'for a definition without parts' do
425
- it{ should be_kind_of(::Hash) }
426
- its([:description]){ should be(description) }
427
- its([:location]){ should == {value: location.inspect ,type: :regexp} }
412
+ it { should be_kind_of(::Hash) }
413
+ its([:description]) { should be(description) }
414
+ its([:location]) { should == { value: location.inspect, type: :regexp } }
428
415
 
429
416
  it 'should have a header defined with value and type keys' do
430
- expect( output[:headers] ).to have(2).keys
431
- expect( output[:headers]['Header1'] ).to eq({value: 'Value1' ,type: :string })
432
- expect( output[:headers]['Location'] ).to eq({value: "/\\/my\\/url\\//" ,type: :regexp })
417
+ expect(output[:headers]).to have(2).keys
418
+ expect(output[:headers]['Header1']).to eq({ value: 'Value1', type: :string })
419
+ expect(output[:headers]['Location']).to eq({ value: '/\\/my\\/url\\//', type: :regexp })
433
420
  end
434
421
  end
435
422
 
436
423
  context 'for a definition with (homogeneous) parts' do
437
- subject(:described_parts){ output[:parts_like] }
424
+ subject(:described_parts) { output[:parts_like] }
438
425
  context 'using :like' do
439
- let(:parts) { {like: :ok, media_type: 'foobar'} }
426
+ let(:parts) { { like: :ok, media_type: 'foobar' } }
440
427
 
441
428
  it 'should contain a parts_like key with a hash' do
442
- expect( output ).to have_key(:parts_like)
429
+ expect(output).to have_key(:parts_like)
443
430
  end
444
431
 
445
- it{ should be_kind_of(::Hash) }
432
+ it { should be_kind_of(::Hash) }
446
433
  it 'has the right type info' do
447
434
  expect(subject[:payload][:type]).to match(id: 'Praxis-SimpleMediaType', name: 'Praxis::SimpleMediaType', family: 'string', identifier: 'foobar')
448
435
  end
449
- its([:status]){ should == 200 }
436
+ its([:status]) { should == 200 }
450
437
  end
451
438
  context 'using a full response definition block' do
452
439
  let(:parts_block) do
453
- Proc.new do
440
+ proc do
454
441
  status 234
455
442
  media_type 'custom_media'
456
443
  end
457
444
  end
458
445
 
459
446
  it 'should contain a parts_like key with a hash' do
460
- expect( output ).to have_key(:parts_like)
447
+ expect(output).to have_key(:parts_like)
461
448
  end
462
449
 
463
- it{ should be_kind_of(::Hash) }
450
+ it { should be_kind_of(::Hash) }
464
451
  it 'has the right type info' do
465
452
  expect(subject[:payload][:type]).to match(id: 'Praxis-SimpleMediaType', name: 'Praxis::SimpleMediaType', family: 'string', identifier: 'custom_media')
466
453
  end
@@ -1,11 +1,12 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
+ require 'spec_helper'
3
4
 
4
5
  describe Praxis::Response do
5
6
  let(:spec_status) { 200 }
6
7
  let(:spec_location) { /resources/ }
7
8
  let(:spec_headers) { { 'X-Header' => 'Foobar' } }
8
- let(:spec_mime_type) { "application/vnd.resource" }
9
+ let(:spec_mime_type) { 'application/vnd.resource' }
9
10
 
10
11
  let(:application_vnd_resource_media_type) do
11
12
  Class.new(Praxis::MediaType) do
@@ -18,33 +19,33 @@ describe Praxis::Response do
18
19
  let(:response_spec) do
19
20
  instance_double(
20
21
  Praxis::ResponseDefinition,
21
- :status => spec_status,
22
- :location => spec_location,
23
- :headers => spec_headers,
24
- :media_type => spec_media_type,
25
- :name => :ok
22
+ status: spec_status,
23
+ location: spec_location,
24
+ headers: spec_headers,
25
+ media_type: spec_media_type,
26
+ name: :ok
26
27
  )
27
28
  end
28
29
 
29
30
  let(:action) do
30
31
  instance_double(
31
32
  Praxis::ActionDefinition,
32
- :endpoint_definition => config_class
33
+ endpoint_definition: config_class
33
34
  )
34
35
  end
35
36
 
36
37
  let(:response_status) { 200 }
37
- let(:response_headers) {
38
+ let(:response_headers) do
38
39
  { 'Content-Type' => 'application/vnd.resource+json;type=collection',
39
- 'X-Header' => 'Foobar',
40
- 'Location' => '/api/resources/123' }
41
- }
40
+ 'X-Header' => 'Foobar',
41
+ 'Location' => '/api/resources/123' }
42
+ end
42
43
 
43
44
  let(:config_media_type) { nil }
44
45
  let(:config_class) do
45
46
  instance_double(
46
47
  Praxis::ResponseDefinition,
47
- :media_type => config_media_type
48
+ media_type: config_media_type
48
49
  )
49
50
  end
50
51
 
@@ -52,7 +53,7 @@ describe Praxis::Response do
52
53
 
53
54
  describe '#validate' do
54
55
  before do
55
- allow(action).to receive(:responses).and_return({response_spec.name => response_spec })
56
+ allow(action).to receive(:responses).and_return({ response_spec.name => response_spec })
56
57
  end
57
58
  context 'response spec is not defined' do
58
59
  before :each do
@@ -60,26 +61,29 @@ describe Praxis::Response do
60
61
  end
61
62
 
62
63
  it 'should raise an error' do
63
- expect {
64
- response.validate(action)
65
- }.to raise_error(Praxis::Exceptions::Validation, /response definition with that name can be found/)
64
+ resp = nil
65
+ expect do
66
+ resp = response.validate(action)
67
+ end.to_not raise_error
68
+
69
+ expect(resp.status).to eq(500)
70
+ expect(resp.body[:name]).to eq('ValidationError')
71
+ expect(resp.body[:summary]).to eq('Error validating response')
72
+ expect(resp.body[:errors]).to include(/response definition with that name can be found/)
66
73
  end
67
74
  end
68
75
 
69
76
  context 'with an existing response spec in the action' do
70
-
71
77
  it 'should use the spec to validate the response' do
72
78
  expect(response_spec).to receive(:validate).and_return(nil)
73
79
 
74
80
  response.validate(action)
75
81
  end
76
82
  end
77
-
78
-
79
83
  end
80
84
 
81
85
  describe '#encode!' do
82
- let(:response_body_structured_data) { [{"moo" => "bah"}] }
86
+ let(:response_body_structured_data) { [{ 'moo' => 'bah' }] }
83
87
  let(:response_body_entity) { '[{"moo": "bah"}]' }
84
88
 
85
89
  context 'given a String body' do
@@ -96,31 +100,28 @@ describe Praxis::Response do
96
100
 
97
101
  it 'encodes using a suitable handler' do
98
102
  response.encode!
99
- expect(JSON.load(response.body)).to eq(response_body_structured_data)
103
+ expect(JSON.parse(response.body)).to eq(response_body_structured_data)
100
104
  end
101
105
  end
102
106
 
103
107
  context 'when no Content-Type is defined' do
104
108
  before { response.body = response_body_structured_data }
105
109
 
106
- let(:response_headers) {
107
- { 'X-Header' => 'Foobar',
108
- 'Location' => '/api/resources/123' }
109
- }
110
+ let(:response_headers) do
111
+ { 'X-Header' => 'Foobar',
112
+ 'Location' => '/api/resources/123' }
113
+ end
110
114
  it 'still defaults to the default handler' do
111
115
  response.encode!
112
- expect(JSON.load(response.body)).to eq(response_body_structured_data)
116
+ expect(JSON.parse(response.body)).to eq(response_body_structured_data)
113
117
  end
114
118
  end
115
-
116
-
117
119
  end
118
120
 
119
121
  context 'multipart responses' do
120
- let(:part) { Praxis::MultipartPart.new('not so ok', {'Status' => 400, "Location" => "somewhere"}) }
122
+ let(:part) { Praxis::MultipartPart.new('not so ok', { 'Status' => 400, 'Location' => 'somewhere' }) }
121
123
 
122
124
  context '#add_part' do
123
-
124
125
  context 'without a name' do
125
126
  before do
126
127
  response.add_part(part)
@@ -140,18 +141,16 @@ describe Praxis::Response do
140
141
  context 'with a name' do
141
142
  let(:part_name) { 'a-part' }
142
143
  before do
143
- response.add_part(part_name, part)
144
+ response.add_part(part, part_name)
144
145
  end
145
146
 
146
147
  it 'adds the part' do
147
148
  expect(response.parts[part_name]).to be(part)
148
149
  end
149
150
  end
150
-
151
151
  end
152
152
 
153
153
  context '#finish for a multipart response' do
154
-
155
154
  before do
156
155
  response.add_part(part)
157
156
  response.body = 'a preamble'
@@ -172,7 +171,7 @@ describe Praxis::Response do
172
171
  end
173
172
 
174
173
  it 'sets the headers' do
175
- expect(response.headers['Content-Type']).to match(/multipart\/form-data/)
174
+ expect(response.headers['Content-Type']).to match(%r{multipart/form-data})
176
175
  expect(response.headers['Location']).to eq('/api/resources/123')
177
176
  end
178
177
 
@@ -180,7 +179,7 @@ describe Praxis::Response do
180
179
  parser = Praxis::MultipartParser.new(response.headers, response.body)
181
180
  preamble, parts = parser.parse
182
181
 
183
- expect(preamble).to eq("a preamble")
182
+ expect(preamble).to eq('a preamble')
184
183
  expect(parts).to have(1).item
185
184
 
186
185
  part_response = parts.first
@@ -189,9 +188,5 @@ describe Praxis::Response do
189
188
  expect(part_response.body).to eq('not so ok')
190
189
  end
191
190
  end
192
-
193
191
  end
194
-
195
-
196
-
197
192
  end
@@ -1,8 +1,8 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
+ require 'spec_helper'
3
4
 
4
5
  describe Praxis::Responses::InternalServerError do
5
-
6
6
  context 'a basic response' do
7
7
  subject(:response) { Praxis::Responses::InternalServerError.new }
8
8
  it 'always sets the json content type' do
@@ -15,12 +15,11 @@ describe Praxis::Responses::InternalServerError do
15
15
  end
16
16
  end
17
17
 
18
-
19
18
  context '.format!' do
20
19
  let(:error) { double('error', message: 'error message', backtrace: [1, 2], cause: cause) }
21
20
 
22
21
  let(:show_exceptions) { true }
23
- let(:config) { double("config", show_exceptions: show_exceptions) }
22
+ let(:config) { double('config', show_exceptions: show_exceptions) }
24
23
 
25
24
  before do
26
25
  allow(Praxis::Application.instance.config).to receive(:praxis).and_return(config)
@@ -30,18 +29,17 @@ describe Praxis::Responses::InternalServerError do
30
29
  end
31
30
 
32
31
  context 'with show_exceptions true' do
33
-
34
32
  context 'without a cause' do
35
33
  let(:cause) { nil }
36
34
  it 'it fills message and backtrace' do
37
- expect(response.body).to eq({name: error.class.name, message: error.message, backtrace: error.backtrace})
35
+ expect(response.body).to eq({ name: error.class.name, message: error.message, backtrace: error.backtrace })
38
36
  end
39
37
  end
40
38
 
41
39
  context 'with a cause' do
42
40
  let(:cause) { Exception.new('cause message') }
43
41
  it 'it fills message, backtrace and cause' do
44
- expect(response.body.keys).to eq([:name, :message, :backtrace, :cause])
42
+ expect(response.body.keys).to eq(%i[name message backtrace cause])
45
43
  expect(response.body[:name]).to eq(error.class.name)
46
44
  expect(response.body[:message]).to eq(error.message)
47
45
  expect(response.body[:backtrace]).to eq(error.backtrace)
@@ -55,11 +53,10 @@ describe Praxis::Responses::InternalServerError do
55
53
  expect(response.body).to be_nil
56
54
  response.format!
57
55
  end
58
-
59
56
  end
60
57
 
61
58
  context 'its response template' do
62
- let(:template){ Praxis::ApiDefinition.instance.responses[:internal_server_error] }
59
+ let(:template) { Praxis::ApiDefinition.instance.responses[:internal_server_error] }
63
60
  it 'is registered with the ApiDefinition' do
64
61
  expect(template).to be_kind_of(Praxis::ResponseTemplate)
65
62
  end