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

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 (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,7 +1,8 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
1
+ # frozen_string_literal: true
2
2
 
3
- describe Praxis::Trait do
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
4
4
 
5
+ describe Praxis::Trait do
5
6
  subject(:trait) do
6
7
  Praxis::Trait.new do
7
8
  description 'my awesome trait'
@@ -19,14 +20,13 @@ describe Praxis::Trait do
19
20
  end
20
21
  params do
21
22
  attribute :order, String,
22
- description: "Field to sort by."
23
+ description: 'Field to sort by.'
23
24
  end
24
25
 
25
26
  headers do
26
- header "Authorization"
27
- key "Header2", String, required: true
27
+ header 'Authorization'
28
+ key 'Header2', String, required: true, null: false
28
29
  end
29
-
30
30
  end
31
31
  end
32
32
 
@@ -35,24 +35,24 @@ describe Praxis::Trait do
35
35
 
36
36
  its([:description]) { should eq('my awesome trait') }
37
37
 
38
- its([:responses, :something]) { should eq Hash.new }
39
- its([:responses, :nothing]) { should eq Hash.new }
38
+ its(%i[responses something]) { should eq({}) }
39
+ its(%i[responses nothing]) { should eq({}) }
40
40
 
41
- its([:params, :app_name, :type, :name]) { should eq 'String' }
42
- its([:params, :order, :type, :name]) { should eq 'String' }
43
- its([:routing, :prefix]) { should eq '/:app_name'}
41
+ its(%i[params app_name type name]) { should eq 'String' }
42
+ its(%i[params order type name]) { should eq 'String' }
43
+ its(%i[routing prefix]) { should eq '/:app_name' }
44
44
 
45
- its([:headers, "Header2"]) { should include({required: true}) }
45
+ its([:headers, 'Header2']) { should include({ required: true, null: false }) }
46
46
  context 'using the special DSL syntax for headers' do
47
- subject(:dsl_header) { describe[:headers]["Authorization"] }
48
- its([:required]){ should be(true) }
49
- its([:type]){ should eq( { :id=>"Attributor-String", :name=>"String", :family=>"string"} )}
47
+ subject(:dsl_header) { describe[:headers]['Authorization'] }
48
+ its([:required]) { should be(true) }
49
+ its([:null]) { should be_nil }
50
+ its([:type]) { should eq({ id: 'Attributor-String', name: 'String', family: 'string' }) }
50
51
  end
51
-
52
52
  end
53
53
 
54
54
  context 'apply!' do
55
- let(:target) { double("Target") }
55
+ let(:target) { double('Target') }
56
56
  it 'does' do
57
57
  expect(target).to receive(:routing).once
58
58
  expect(target).to receive(:response).twice
@@ -1,20 +1,22 @@
1
- require "spec_helper"
1
+ # frozen_string_literal: true
2
2
 
3
- describe Praxis::Types::FuzzyHash do
3
+ require 'spec_helper'
4
4
 
5
- let(:initial_value) {{
6
- 'key' => 'value',
7
- /bob/ => 'rob',
8
- /\d+/ => 'one'
9
- }}
5
+ describe Praxis::Types::FuzzyHash do
6
+ let(:initial_value) do
7
+ {
8
+ 'key' => 'value',
9
+ /bob/ => 'rob',
10
+ /\d+/ => 'one'
11
+ }
12
+ end
10
13
 
11
14
  subject(:hash) { Praxis::Types::FuzzyHash.new(initial_value) }
12
15
 
13
16
  its(['key']) { should eq 'value' }
14
17
  its([/bob/]) { should eq 'rob' }
15
18
  its(['bobby']) { should eq 'rob' }
16
-
19
+
17
20
  its([1]) { should eq 'one' }
18
21
  its(['1']) { should eq 'one' }
19
22
  end
20
-
@@ -1,5 +1,6 @@
1
- require "spec_helper"
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
2
4
 
3
5
  describe Praxis::Types::MultipartArray::PartDefinition do
4
6
  end
5
-
@@ -1,15 +1,16 @@
1
- require "spec_helper"
1
+ # frozen_string_literal: true
2
2
 
3
- describe Praxis::Types::MultipartArray do
3
+ require 'spec_helper'
4
4
 
5
+ describe Praxis::Types::MultipartArray do
5
6
  let(:type) do
6
7
  Class.new(Praxis::Types::MultipartArray) do
7
- self.options[:case_insensitive_load] = true
8
+ options[:case_insensitive_load] = true
8
9
 
9
10
  part 'title', String, required: true
10
11
  part(/nam/, String, regexp: /Bob/i)
11
12
 
12
- part /stuff/ do
13
+ part(/stuff/) do
13
14
  payload Hash
14
15
  end
15
16
 
@@ -22,33 +23,31 @@ describe Praxis::Types::MultipartArray do
22
23
  file 'thumbnail', Attributor::Tempfile
23
24
 
24
25
  part 'image', Attributor::Tempfile, filename: true
25
-
26
26
  end
27
27
  end
28
28
 
29
-
30
29
  let(:form) do
31
30
  form_data = MIME::Multipart::FormData.new
32
31
  entity = MIME::Text.new('Bob')
33
- form_data.add entity,'name'
32
+ form_data.add entity, 'name'
34
33
 
35
34
  entity = MIME::Text.new('Captain')
36
- form_data.add entity,'title'
35
+ form_data.add entity, 'title'
37
36
 
38
37
  entity = MIME::Application.new('file1')
39
- form_data.add entity,'files', 'file1'
38
+ form_data.add entity, 'files', 'file1'
40
39
 
41
40
  entity = MIME::Application.new('file2')
42
- form_data.add entity,'files', 'file2'
41
+ form_data.add entity, 'files', 'file2'
43
42
 
44
43
  entity = MIME::Application.new('{"first_name": "Frank"}', 'json')
45
- form_data.add entity,'stuff2'
44
+ form_data.add entity, 'stuff2'
46
45
 
47
46
  entity = MIME::Application.new('SOMEBINARYDATA', 'jpg')
48
- form_data.add entity,'thumbnail', 'thumb.jpg'
47
+ form_data.add entity, 'thumbnail', 'thumb.jpg'
49
48
 
50
49
  entity = MIME::Application.new('', 'jpg')
51
- form_data.add entity,'image', 'image.jpg'
50
+ form_data.add entity, 'image', 'image.jpg'
52
51
 
53
52
  form_data
54
53
  end
@@ -59,7 +58,6 @@ describe Praxis::Types::MultipartArray do
59
58
  subject(:payload) { type.load(body, content_type: content_type) }
60
59
 
61
60
  it 'validates' do
62
- part = payload.part('files').first
63
61
  expect(payload.validate).to be_empty
64
62
  end
65
63
 
@@ -94,9 +92,9 @@ describe Praxis::Types::MultipartArray do
94
92
  end
95
93
  end
96
94
 
97
- let(:json_payload) { {sub_hash: {key:'value'}}.to_json }
95
+ let(:json_payload) { { sub_hash: { key: 'value' } }.to_json }
98
96
  let(:body) { StringIO.new("--boundary\r\nContent-Disposition: form-data; name=blah\r\n\r\n#{json_payload}\r\n--boundary--") }
99
- let(:content_type) { "multipart/form-data; boundary=boundary" }
97
+ let(:content_type) { 'multipart/form-data; boundary=boundary' }
100
98
 
101
99
  it do
102
100
  expect(payload.part('blah').payload['sub_hash']).to eq('key' => 'value')
@@ -117,9 +115,9 @@ describe Praxis::Types::MultipartArray do
117
115
  end
118
116
  end
119
117
 
120
- let(:json_payload) { {attr: 'value'}.to_json }
118
+ let(:json_payload) { { attr: 'value' }.to_json }
121
119
  let(:body) { StringIO.new("--boundary\r\nContent-Disposition: form-data; name=blah\r\n\r\n#{json_payload}\r\n--boundary--") }
122
- let(:content_type) { "multipart/form-data; boundary=boundary" }
120
+ let(:content_type) { 'multipart/form-data; boundary=boundary' }
123
121
 
124
122
  it do
125
123
  expect(payload.part('blah').payload.class.ancestors).to include(Attributor::Struct)
@@ -142,7 +140,7 @@ describe Praxis::Types::MultipartArray do
142
140
 
143
141
  context 'attributes' do
144
142
  subject(:attributes) { description[:attributes] }
145
- its(:keys) { should match_array ['title', 'files', 'thumbnail', 'image']}
143
+ its(:keys) { should match_array %w[title files thumbnail image] }
146
144
 
147
145
  context 'the "title" part' do
148
146
  subject(:title_description) { attributes['title'] }
@@ -172,14 +170,12 @@ describe Praxis::Types::MultipartArray do
172
170
  expect(filename[:options]).to eq(regexp: /file/)
173
171
  expect(filename[:type]).to eq Attributor::String.describe
174
172
  end
175
-
176
173
  end
177
-
178
174
  end
179
175
 
180
176
  context 'pattern attributes' do
181
177
  subject(:pattern_attributes) { description[:pattern_attributes] }
182
- its(:keys) { should match_array ['nam', 'stuff']}
178
+ its(:keys) { should match_array %w[nam stuff] }
183
179
  end
184
180
 
185
181
  context 'with no parts defined' do
@@ -226,17 +222,16 @@ describe Praxis::Types::MultipartArray do
226
222
  subject(:dumped) { payload.dump }
227
223
 
228
224
  it 'dumps' do
229
- loaded = type.load(dumped, content_type: payload.content_type)
225
+ type.load(dumped, content_type: payload.content_type)
230
226
  end
231
227
  context 'an example' do
232
228
  let(:payload) { type.example }
233
229
 
234
230
  it 'dumps' do
235
- loaded = type.load(dumped, content_type: payload.content_type)
231
+ type.load(dumped, content_type: payload.content_type)
236
232
  end
237
233
  end
238
234
 
239
-
240
235
  context 'with default_format' do
241
236
  let(:type) do
242
237
  Class.new(Praxis::Types::MultipartArray) do
@@ -267,7 +262,7 @@ describe Praxis::Types::MultipartArray do
267
262
 
268
263
  let(:output) { example.dump(default_format: default_format) }
269
264
 
270
- let(:parts) { Praxis::MultipartParser.parse({'Content-Type'=>example.content_type}, output).last }
265
+ let(:parts) { Praxis::MultipartParser.parse({ 'Content-Type' => example.content_type }, output).last }
271
266
 
272
267
  it 'dumps the parts with the proper handler' do
273
268
  json_handler = Praxis::Application.instance.handlers['json']
@@ -290,9 +285,7 @@ describe Praxis::Types::MultipartArray do
290
285
  expect(instance.payload).to eq json_handler.generate(example.part('instances')[i].payload.dump)
291
286
  end
292
287
  end
293
-
294
288
  end
295
-
296
289
  end
297
290
 
298
291
  context 'with errors' do
@@ -300,11 +293,10 @@ describe Praxis::Types::MultipartArray do
300
293
  form_data = MIME::Multipart::FormData.new
301
294
 
302
295
  entity = MIME::Text.new('James')
303
- form_data.add entity,'name'
304
-
296
+ form_data.add entity, 'name'
305
297
 
306
298
  entity = MIME::Text.new('file1')
307
- form_data.add entity,'files', 'file1'
299
+ form_data.add entity, 'files', 'file1'
308
300
 
309
301
  form_data
310
302
  end
@@ -314,10 +306,10 @@ describe Praxis::Types::MultipartArray do
314
306
  it 'validates part headers' do
315
307
  expect(errors).to have(3).items
316
308
  expect(errors).to match_array([
317
- %r|\.name\.payload value .* does not match regexp|,
318
- %r|\.files\.headers.* is not within the allowed values|,
319
- %r|\.title is required|
320
- ])
309
+ /\.name\.payload value .* does not match regexp/,
310
+ /\.files\.headers.* is not within the allowed values/,
311
+ /\.title is required/
312
+ ])
321
313
  end
322
314
  end
323
315
 
@@ -327,14 +319,14 @@ describe Praxis::Types::MultipartArray do
327
319
  it 'generates parts' do
328
320
  title = payload.part('title')
329
321
  expect(title).to_not be_nil
330
- expect(title.payload).to match /\w+/
322
+ expect(title.payload).to match(/\w+/)
331
323
 
332
324
  files = payload.part('files')
333
325
  expect(files).to have(2).items
334
326
 
335
327
  files.each do |file|
336
328
  expect(file.payload).to be_kind_of(Tempfile)
337
- expect(file.filename).to match /\w+/
329
+ expect(file.filename).to match(/\w+/)
338
330
 
339
331
  expect(file.headers['Content-Type']).to eq 'application/octet-stream'
340
332
  end
@@ -343,15 +335,14 @@ describe Praxis::Types::MultipartArray do
343
335
  it 'is valid' do
344
336
  expect(payload.validate).to have(0).items
345
337
  end
346
-
347
338
  end
348
339
 
349
340
  context 'with a hackish default part definition' do
350
341
  let(:type) do
351
342
  Class.new(Praxis::Types::MultipartArray) do
352
- self.options[:case_insensitive_load] = true
343
+ options[:case_insensitive_load] = true
353
344
 
354
- part /\d+/, Instance
345
+ part(/\d+/, Instance)
355
346
  end
356
347
  end
357
348
 
@@ -362,7 +353,7 @@ describe Praxis::Types::MultipartArray do
362
353
  instance = Instance.example("instance-#{i}")
363
354
  body = JSON.pretty_generate(instance.render)
364
355
  entity = MIME::Text.new(body)
365
- form_data.add entity,i.to_s
356
+ form_data.add entity, i.to_s
366
357
  end
367
358
 
368
359
  form_data
@@ -373,10 +364,8 @@ describe Praxis::Types::MultipartArray do
373
364
  expect(part.payload).to be_kind_of(Instance)
374
365
  end
375
366
  end
376
-
377
367
  end
378
368
 
379
-
380
369
  context 'anonymous generation' do
381
370
  let(:definition_block) do
382
371
  proc do
@@ -396,7 +385,7 @@ describe Praxis::Types::MultipartArray do
396
385
  instance = Instance.example("instance-#{i}")
397
386
  body = JSON.pretty_generate(instance.render)
398
387
  entity = MIME::Text.new(body)
399
- form_data.add entity,i.to_s
388
+ form_data.add entity, i.to_s
400
389
  end
401
390
 
402
391
  form_data
@@ -411,9 +400,5 @@ describe Praxis::Types::MultipartArray do
411
400
  expect(part.payload).to be_kind_of(Instance)
412
401
  end
413
402
  end
414
-
415
-
416
403
  end
417
-
418
-
419
404
  end
@@ -1,15 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Concerns
2
4
  module Authenticated
3
5
  extend ActiveSupport::Concern
4
6
  include Praxis::Callbacks
5
-
7
+
6
8
  included do
7
9
  before :action do |controller|
8
10
  auth_data = controller.request.headers['Authorization']
9
- if auth_data && auth_data !~ /secret/
10
- Praxis::Responses::Unauthorized.new(body: 'Authentication info is invalid')
11
- end
11
+ Praxis::Responses::Unauthorized.new(body: 'Authentication info is invalid') if auth_data && auth_data !~ /secret/
12
12
  end
13
13
  end
14
14
  end
15
- end
15
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'authenticated'
2
4
  require_relative 'log_wrapper'
3
5
 
@@ -9,4 +11,4 @@ module Concerns
9
11
  include Concerns::Authenticated
10
12
  include Concerns::LogWrapper
11
13
  end
12
- end
14
+ end
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Concerns
2
4
  module LogWrapper
3
5
  extend ActiveSupport::Concern
4
6
  include Praxis::Callbacks
5
-
7
+
6
8
  included do
7
- before :around do |controller, callee|
9
+ before :around do |_controller, callee|
8
10
  # Log something at the beginning
9
11
  callee.call
10
12
  # Log something at the end
11
13
  end
12
14
  end
13
15
  end
14
- end
16
+ end
@@ -1,14 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class BaseClass
2
4
  # Do NOT use a controller inherited base class to add concerns!
3
5
  # If you do that, you'd be sharing state (i.e. overriding/adding) from concerns across controllers
4
6
  # which will probably lead to sharing issues you didn't expect.
5
7
  # For example: any controller adding after/before/around filters will be visible
6
8
  # to any other controllers sharing the concern.
7
- # Include a concern to all of them instead
8
-
9
+ # Include a concern to all of them instead
10
+
9
11
  # Inheritance of classes should be independent from the concerns.
10
12
  # I.e., you can use class inheritance in cases where it makes sense from an OO point of view
11
13
  # but for the most part, you can probably share code through modules/concerns too.
12
- def this_is_shared
13
- end
14
- end
14
+ def this_is_shared; end
15
+ end
@@ -1,59 +1,57 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Instances < BaseClass
2
4
  include Praxis::Controller
3
5
 
4
6
  implements ApiResources::Instances
5
7
  include Concerns::BasicApi
6
8
 
7
- before :validate, actions: [:index] do |controller|
8
- #p [:before, :validate, :params_and_headers, controller.request.action.name]
9
+ before :validate, actions: [:index] do |controller|
10
+ # p [:before, :validate, :params_and_headers, controller.request.action.name]
9
11
  end
10
12
 
11
13
  before actions: [:show] do |controller|
12
- #puts "before action"
13
- if controller.request.params.fail_filter
14
- Praxis::Responses::Unauthorized.new
15
- end
14
+ # puts "before action"
15
+ Praxis::Responses::Unauthorized.new if controller.request.params.fail_filter
16
16
  end
17
17
 
18
- around :validate, actions: [:show] do |controller, blk|
19
- #puts "Before validate decorator (for show)"
18
+ around :validate, actions: [:show] do |_controller, blk|
19
+ # puts "Before validate decorator (for show)"
20
20
  blk.call
21
- #puts "After validate decorator"
21
+ # puts "After validate decorator"
22
22
  end
23
23
 
24
- around :action do |controller, blk|
25
- #puts "Decorator one (all actions) start"
24
+ around :action do |_controller, blk|
25
+ # puts "Decorator one (all actions) start"
26
26
  blk.call
27
- #puts "Decorator one end"
27
+ # puts "Decorator one end"
28
28
  end
29
29
 
30
- around :action, actions: [:show] do |controller, blk|
31
- #puts "Decorator two (show action) start"
30
+ around :action, actions: [:show] do |_controller, blk|
31
+ # puts "Decorator two (show action) start"
32
32
  blk.call
33
- #puts "Decorator two end"
33
+ # puts "Decorator two end"
34
34
  end
35
35
 
36
- around :action, actions: [:index] do |controller, blk|
37
- #puts "Decorator three (index action) start"
36
+ around :action, actions: [:index] do |_controller, blk|
37
+ # puts "Decorator three (index action) start"
38
38
  blk.call
39
- #puts "Decorator three end"
39
+ # puts "Decorator three end"
40
40
  end
41
41
 
42
- def index(cloud_id:, response_content_type: 'application/vnd.acme.instance;type=collection', **params)
42
+ def index(response_content_type: 'application/vnd.acme.instance;type=collection', **_params)
43
43
  instances = Instance::Collection.example
44
- response.body = JSON.pretty_generate(instances.collect { |i| i.render })
45
- response.headers['Content-Type'] = response_content_type #'application/vnd.acme.instance;type=collection'
44
+ response.body = JSON.pretty_generate(instances.collect(&:render))
45
+ response.headers['Content-Type'] = response_content_type # 'application/vnd.acme.instance;type=collection'
46
46
  response
47
47
  end
48
48
 
49
49
  def show(cloud_id:, id:, junk:, create_identity_map:, **other_params)
50
- if create_identity_map
51
- request.identity_map
52
- end
50
+ request.identity_map if create_identity_map
53
51
 
54
52
  payload = request.payload
55
53
 
56
- response.body = {cloud_id: cloud_id, id: id, junk: junk, other_params: other_params, payload: payload && payload.dump}
54
+ response.body = { cloud_id: cloud_id, id: id, junk: junk, other_params: other_params, payload: payload && payload.dump }
57
55
  response.headers['Content-Type'] = 'application/json'
58
56
  response
59
57
  end
@@ -68,12 +66,12 @@ class Instances < BaseClass
68
66
 
69
67
  part_body = {
70
68
  key: instance_id,
71
- value: instance.render(fields: {id: true, name: true})
69
+ value: instance.render(fields: { id: true, name: true })
72
70
  }
73
71
 
74
72
  headers = {
75
73
  'Status' => '201',
76
- 'Content-Type' => (Instance.identifier + '+json').to_s,
74
+ 'Content-Type' => "#{Instance.identifier}+json".to_s,
77
75
  'Location' => definition.to_href(cloud_id: cloud_id, id: instance.id)
78
76
  }
79
77
 
@@ -84,14 +82,13 @@ class Instances < BaseClass
84
82
  response
85
83
  end
86
84
 
87
-
88
- def attach_file(id:, cloud_id:)
85
+ def attach_file(*)
89
86
  response.headers['Content-Type'] = 'application/json'
90
87
 
91
88
  destination_path = request.payload.part('destination_path').payload
92
89
  file = request.payload.part('file')
93
90
  file.payload.rewind # Ensure contents is at the beggining.
94
- extra_part_names = request.payload.map(&:name) - ['destination_path', 'file']
91
+ extra_part_names = request.payload.map(&:name) - %w[destination_path file]
95
92
  extra_parts = extra_part_names.each_with_object({}) do |pname, hash|
96
93
  hash[pname] = request.payload.part(pname).body
97
94
  end
@@ -109,23 +106,23 @@ class Instances < BaseClass
109
106
  response
110
107
  end
111
108
 
112
- def terminate(id:, cloud_id:)
109
+ def terminate(*)
113
110
  response.headers['Content-Type'] = 'application/json'
114
111
  response
115
112
  end
116
113
 
117
- def stop(id:, cloud_id:)
114
+ def stop(*)
118
115
  response.headers['Content-Type'] = 'application/json'
119
116
  response
120
117
  end
121
118
 
122
- def update(id:, cloud_id:)
119
+ def update(*)
123
120
  response.body = JSON.pretty_generate(request.payload.dump)
124
121
  response.headers['Content-Type'] = 'application/vnd.acme.instance'
125
122
  response
126
123
  end
127
124
 
128
- def exceptional(cloud_id:, splat:)
125
+ def exceptional(*)
129
126
  response.headers['Content-Type'] = 'application/json'
130
127
  response
131
128
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Volumes < BaseClass
2
4
  include Praxis::Controller
3
5
 
@@ -5,22 +7,20 @@ class Volumes < BaseClass
5
7
  include Concerns::BasicApi
6
8
 
7
9
  before actions: [:show] do |controller|
8
- #puts "before action for volumes"
10
+ # puts "before action for volumes"
9
11
  end
10
12
 
11
13
  def index
12
14
  volumes = Volume::Collection.example
13
-
14
- response.body = volumes.collect { |v| v.render }
15
+
16
+ response.body = volumes.collect(&:render)
15
17
  response.headers['Content-Type'] = 'application/vnd.acme.volumes'
16
18
  response
17
19
  end
18
20
 
19
- def show(id:, **other_params)
21
+ def show(*)
20
22
  response.body = JSON.pretty_generate(Volume.example.render)
21
23
  response.headers['Content-Type'] = 'application/vnd.acme.volume'
22
24
  response
23
25
  end
24
-
25
-
26
26
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  class MultipartResponse < Praxis::Response
3
4
  self.response_name = :multipart
@@ -5,6 +6,4 @@ class MultipartResponse < Praxis::Response
5
6
  def handle
6
7
  @status = 200
7
8
  end
8
-
9
9
  end
10
-
@@ -1,6 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class OtherResponse < Praxis::Response
2
4
  self.response_name = :other_response
3
5
  self.status = 200
4
-
5
6
  end
6
-