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,49 +1,50 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
+ require 'spec_helper'
3
4
 
4
5
  describe Praxis::Mapper::SelectorGenerator do
5
6
  let(:resource) { SimpleResource }
6
- subject(:generator) {described_class.new }
7
+ subject(:generator) { described_class.new }
7
8
 
8
9
  context '#add' do
9
10
  let(:resource) { SimpleResource }
10
11
  shared_examples 'a proper selector' do
11
12
  it { expect(generator.add(resource, fields).selectors.dump).to be_deep_equal selectors }
12
13
  end
13
-
14
+
14
15
  context 'basic combos' do
15
16
  context 'direct column fields' do
16
- let(:fields) { {id: true, foobar: true} }
17
- let(:selectors) do
17
+ let(:fields) { { id: true, foobar: true } }
18
+ let(:selectors) do
18
19
  {
19
20
  model: SimpleModel,
20
- columns: [:id, :foobar]
21
- }
21
+ columns: %i[id foobar]
22
+ }
22
23
  end
23
24
  it_behaves_like 'a proper selector'
24
25
  end
25
26
 
26
27
  context 'aliased column fields' do
27
- let(:fields) { {id: true, name: true} }
28
+ let(:fields) { { id: true, name: true } }
28
29
  let(:selectors) do
29
30
  {
30
31
  model: SimpleModel,
31
- columns: [:id, :simple_name]
32
+ columns: %i[id simple_name]
32
33
  }
33
34
  end
34
35
  it_behaves_like 'a proper selector'
35
36
  end
36
37
 
37
38
  context 'pure associations without recursion' do
38
- let(:fields) { {other_model: true} }
39
+ let(:fields) { { other_model: true } }
39
40
  let(:selectors) do
40
41
  {
41
42
  model: SimpleModel,
42
43
  columns: [:other_model_id], # FK of the other_model association
43
44
  tracks: {
44
- other_model: {
45
+ other_model: {
45
46
  columns: [:id], # joining key for the association
46
- model: OtherModel
47
+ model: OtherModel
47
48
  }
48
49
  }
49
50
  }
@@ -52,15 +53,15 @@ describe Praxis::Mapper::SelectorGenerator do
52
53
  end
53
54
 
54
55
  context 'aliased associations without recursion' do
55
- let(:fields) { {other_resource: true} }
56
+ let(:fields) { { other_resource: true } }
56
57
  let(:selectors) do
57
58
  {
58
59
  model: SimpleModel,
59
60
  columns: [:other_model_id], # FK of the other_model association
60
61
  tracks: {
61
- other_model: {
62
+ other_model: {
62
63
  columns: [:id], # joining key for the association
63
- model: OtherModel
64
+ model: OtherModel
64
65
  }
65
66
  }
66
67
  }
@@ -68,15 +69,15 @@ describe Praxis::Mapper::SelectorGenerator do
68
69
  it_behaves_like 'a proper selector'
69
70
  end
70
71
  context 'aliased associations without recursion (that map to columns and other associations)' do
71
- let(:fields) { {aliased_method: true} }
72
+ let(:fields) { { aliased_method: true } }
72
73
  let(:selectors) do
73
74
  {
74
75
  model: SimpleModel,
75
- columns: [:column1, :other_model_id], # other_model_id => because of the association
76
+ columns: %i[column1 other_model_id], # other_model_id => because of the association
76
77
  tracks: {
77
- other_model: {
78
+ other_model: {
78
79
  columns: [:id], # joining key for the association
79
- model: OtherModel
80
+ model: OtherModel
80
81
  }
81
82
  }
82
83
  }
@@ -85,13 +86,13 @@ describe Praxis::Mapper::SelectorGenerator do
85
86
  end
86
87
 
87
88
  context 'redefined associations that add some extra columns (would need both the underlying association AND the columns in place)' do
88
- let(:fields) { {parent: true} }
89
+ let(:fields) { { parent: true } }
89
90
  let(:selectors) do
90
91
  {
91
92
  model: SimpleModel,
92
- columns: [:parent_id, :added_column],
93
+ columns: %i[parent_id added_column],
93
94
  tracks: {
94
- parent: {
95
+ parent: {
95
96
  columns: [:id],
96
97
  model: ParentModel
97
98
  }
@@ -102,29 +103,29 @@ describe Praxis::Mapper::SelectorGenerator do
102
103
  end
103
104
 
104
105
  context 'a simple property that requires all fields' do
105
- let(:fields) { {everything: true} }
106
+ let(:fields) { { everything: true } }
106
107
  let(:selectors) do
107
108
  {
108
109
  model: SimpleModel,
109
- columns: [:*],
110
+ columns: [:*]
110
111
  }
111
112
  end
112
113
  it_behaves_like 'a proper selector'
113
114
  end
114
115
 
115
116
  context 'a simple property that requires itself' do
116
- let(:fields) { {circular_dep: true} }
117
+ let(:fields) { { circular_dep: true } }
117
118
  let(:selectors) do
118
119
  {
119
120
  model: SimpleModel,
120
- columns: [:circular_dep, :column1], #allows to "expand" the dependency into itself + others
121
+ columns: %i[circular_dep column1] # allows to "expand" the dependency into itself + others
121
122
  }
122
123
  end
123
124
  it_behaves_like 'a proper selector'
124
125
  end
125
126
 
126
127
  context 'a simple property without dependencies' do
127
- let(:fields) { {no_deps: true} }
128
+ let(:fields) { { no_deps: true } }
128
129
  let(:selectors) do
129
130
  {
130
131
  model: SimpleModel
@@ -132,13 +133,12 @@ describe Praxis::Mapper::SelectorGenerator do
132
133
  end
133
134
  it_behaves_like 'a proper selector'
134
135
  end
135
-
136
136
  end
137
137
 
138
138
  context 'nested tracking' do
139
139
  context 'pure associations follow the nested fields' do
140
140
  let(:fields) do
141
- {
141
+ {
142
142
  other_model: {
143
143
  id: true
144
144
  }
@@ -196,7 +196,7 @@ describe Praxis::Mapper::SelectorGenerator do
196
196
  let(:selectors) do
197
197
  {
198
198
  model: SimpleModel,
199
- columns: [:parent_id, :added_column],
199
+ columns: %i[parent_id added_column],
200
200
  tracks: {
201
201
  parent: {
202
202
  model: ParentModel,
@@ -225,7 +225,7 @@ describe Praxis::Mapper::SelectorGenerator do
225
225
  tracks: {
226
226
  other_model: {
227
227
  model: OtherModel,
228
- columns: [:id, :name]
228
+ columns: %i[id name]
229
229
  }
230
230
  }
231
231
  }
@@ -242,7 +242,7 @@ describe Praxis::Mapper::SelectorGenerator do
242
242
  tracks: {
243
243
  other_model: {
244
244
  model: OtherModel,
245
- columns: [:id, :name]
245
+ columns: %i[id name]
246
246
  }
247
247
  }
248
248
  }
@@ -251,13 +251,13 @@ describe Praxis::Mapper::SelectorGenerator do
251
251
  end
252
252
 
253
253
  context 'for a property that requires all fields from an association' do
254
- let(:fields) { {everything_from_parent: true} }
254
+ let(:fields) { { everything_from_parent: true } }
255
255
  let(:selectors) do
256
256
  {
257
257
  model: SimpleModel,
258
258
  columns: [:parent_id],
259
259
  tracks: {
260
- parent: {
260
+ parent: {
261
261
  model: ParentModel,
262
262
  columns: [:*]
263
263
  }
@@ -270,15 +270,15 @@ describe Praxis::Mapper::SelectorGenerator do
270
270
 
271
271
  context 'required extra select fields due to associations' do
272
272
  context 'many_to_one' do
273
- let(:fields) { {other_model: true} }
273
+ let(:fields) { { other_model: true } }
274
274
  let(:selectors) do
275
275
  {
276
276
  model: SimpleModel,
277
277
  columns: [:other_model_id], # FK of the other_model association
278
278
  tracks: {
279
- other_model: {
279
+ other_model: {
280
280
  columns: [:id],
281
- model: OtherModel
281
+ model: OtherModel
282
282
  }
283
283
  }
284
284
  }
@@ -287,39 +287,73 @@ describe Praxis::Mapper::SelectorGenerator do
287
287
  end
288
288
  context 'one_to_many' do
289
289
  let(:resource) { ParentResource }
290
- let(:fields) { {simple_children: true} }
290
+ let(:fields) { { simple_children: true } }
291
291
  let(:selectors) do
292
292
  {
293
293
  model: ParentModel,
294
294
  columns: [:id], # No FKs in the source model for one_to_many
295
295
  tracks: {
296
- simple_children: {
296
+ simple_children: {
297
297
  columns: [:parent_id],
298
- model: SimpleModel
298
+ model: SimpleModel
299
299
  }
300
300
  }
301
301
  }
302
302
  end
303
303
  it_behaves_like 'a proper selector'
304
- end
304
+ end
305
305
  context 'many_to_many' do
306
306
  let(:resource) { OtherResource }
307
- let(:fields) { {simple_models: true} }
307
+ let(:fields) { { simple_models: true } }
308
308
  let(:selectors) do
309
309
  {
310
310
  model: OtherModel,
311
- columns: [:id], #join key in the source model for many_to_many (where the middle table points to)
311
+ columns: [:id], # join key in the source model for many_to_many (where the middle table points to)
312
312
  tracks: {
313
- simple_models: {
314
- columns: [:id], #join key in the target model for many_to_many (where the middle table points to)
313
+ simple_models: {
314
+ columns: [:id], # join key in the target model for many_to_many (where the middle table points to)
315
315
  model: SimpleModel
316
316
  }
317
317
  }
318
318
  }
319
319
  end
320
320
  it_behaves_like 'a proper selector'
321
- end
321
+ end
322
322
 
323
+ context 'that are several attriutes deep' do
324
+ let(:fields) { { deep_nested_deps: true } }
325
+ let(:selectors) do
326
+ {
327
+ model: SimpleModel,
328
+ columns: [:parent_id],
329
+ tracks: {
330
+ parent: {
331
+ model: ParentModel,
332
+ columns: [:id], # No FKs in the source model for one_to_many
333
+ tracks: {
334
+ simple_children: {
335
+ columns: %i[parent_id other_model_id],
336
+ model: SimpleModel,
337
+ tracks: {
338
+ other_model: {
339
+ model: OtherModel,
340
+ columns: %i[id parent_id],
341
+ tracks: {
342
+ parent: {
343
+ model: ParentModel,
344
+ columns: %i[id simple_name other_attribute]
345
+ }
346
+ }
347
+ }
348
+ }
349
+ }
350
+ }
351
+ }
352
+ }
353
+ }
354
+ end
355
+ it_behaves_like 'a proper selector'
356
+ end
323
357
  end
324
358
  end
325
359
  end
@@ -1,4 +1,8 @@
1
- require "spec_helper"
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Style/StringConcatenation
4
+
5
+ require 'spec_helper'
2
6
 
3
7
  describe Praxis::MediaTypeIdentifier do
4
8
  let(:example) { 'application/ice-cream+sundae; nuts="true"; fudge="true"' }
@@ -14,7 +18,7 @@ describe Praxis::MediaTypeIdentifier do
14
18
  end
15
19
 
16
20
  context 'of empty string values' do
17
- let(:example) { "" }
21
+ let(:example) { '' }
18
22
  it 'returns nil' do
19
23
  expect(subject).to be(nil)
20
24
  end
@@ -47,8 +51,6 @@ describe Praxis::MediaTypeIdentifier do
47
51
  # pending("need to stop using a regexp to do a context-free parser's job")
48
52
  # expect(described_class.new(tricky_example).parameters['sauce']).to eq('yes; absolutely')
49
53
  # end
50
-
51
-
52
54
  end
53
55
 
54
56
  context 'given a malformed type' do
@@ -164,7 +166,7 @@ describe Praxis::MediaTypeIdentifier do
164
166
 
165
167
  let(:with_suffix) { 'application/vnd.widget+xml' }
166
168
  let(:with_subtype) { 'text/xml' }
167
- let(:with_both) { 'text/json+xml' } #nonsensical but valid!
169
+ let(:with_both) { 'text/json+xml' } # nonsensical but valid!
168
170
 
169
171
  it 'uses the suffix' do
170
172
  expect(subject.new(with_suffix).handler_name).to eq('xml')
@@ -192,15 +194,15 @@ describe Praxis::MediaTypeIdentifier do
192
194
 
193
195
  it 'adds parameters' do
194
196
  expect(simple_subject + 'nuts=true').to \
195
- eq(described_class.new('application/vnd.icecream; nuts=true'))
197
+ eq(described_class.new('application/vnd.icecream; nuts=true'))
196
198
 
197
199
  expect(simple_subject + '; nuts=true').to \
198
- eq(described_class.new('application/vnd.icecream; nuts=true'))
200
+ eq(described_class.new('application/vnd.icecream; nuts=true'))
199
201
  end
200
202
 
201
203
  it 'adds suffix and parameters' do
202
204
  expect(simple_subject + 'xml; nuts=true').to \
203
- eq(described_class.new('application/vnd.icecream+xml; nuts=true'))
205
+ eq(described_class.new('application/vnd.icecream+xml; nuts=true'))
204
206
  end
205
207
 
206
208
  it 'replaces the suffix' do
@@ -210,7 +212,7 @@ describe Praxis::MediaTypeIdentifier do
210
212
 
211
213
  it 'replaces existing parameters and adds new ones' do
212
214
  expect(complex_subject + 'nuts=false; cherry=true').to \
213
- eq(described_class.new('application/vnd.icecream+json; cherry=true; nuts=false'))
215
+ eq(described_class.new('application/vnd.icecream+json; cherry=true; nuts=false'))
214
216
 
215
217
  expect(complex_subject + '; nuts=false; cherry=true').to \
216
218
  eq(described_class.new('application/vnd.icecream+json; cherry=true; nuts=false'))
@@ -235,4 +237,5 @@ describe Praxis::MediaTypeIdentifier do
235
237
  end
236
238
  end
237
239
  end
238
- end
240
+ end
241
+ # rubocop:enable Style/StringConcatenation
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Praxis::MediaType do
@@ -5,19 +7,18 @@ describe Praxis::MediaType do
5
7
  let(:manager_resource) { instance_double(Person, id: 101, name: /[:name:]/.gen, href: '/') }
6
8
  let(:custodian_resource) { instance_double(Person, id: 102, name: /[:name:]/.gen, href: '/') }
7
9
  let(:residents_summary_resource) do
8
- instance_double(Person::CollectionSummary, href: "/people", size: 2)
10
+ instance_double(Person::CollectionSummary, href: '/people', size: 2)
9
11
  end
10
12
 
11
13
  let(:resource) do
12
14
  double('address',
13
- id: 1,
14
- name: 'Home',
15
- owner: owner_resource,
16
- manager: manager_resource,
17
- custodian: custodian_resource,
18
- residents_summary: residents_summary_resource,
19
- fields: {id: true, name: true}
20
- )
15
+ id: 1,
16
+ name: 'Home',
17
+ owner: owner_resource,
18
+ manager: manager_resource,
19
+ custodian: custodian_resource,
20
+ residents_summary: residents_summary_resource,
21
+ fields: { id: true, name: true })
21
22
  end
22
23
 
23
24
  subject(:address) { Address.new(resource) }
@@ -28,7 +29,6 @@ describe Praxis::MediaType do
28
29
  its(:owner) { should be_instance_of(Person) }
29
30
  end
30
31
 
31
-
32
32
  context 'accessor methods' do
33
33
  subject(:address_klass) { address.class }
34
34
 
@@ -41,12 +41,12 @@ describe Praxis::MediaType do
41
41
  its(:description) { should be_kind_of(String) }
42
42
  end
43
43
 
44
- context "rendering" do
44
+ context 'rendering' do
45
45
  subject(:output) { address.render }
46
46
 
47
47
  its([:id]) { should eq(address.id) }
48
48
  its([:name]) { should eq(address.name) }
49
49
  its([:owner]) { should eq(Person.dump(owner_resource)) }
50
- its([:fields]) { should eq(address.fields.dump ) }
50
+ its([:fields]) { should eq(address.fields.dump) }
51
51
  end
52
52
  end
@@ -1,73 +1,74 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Praxis::MiddlewareApp do
4
-
5
- let(:init_args){ { root: 'here'} }
6
- let(:middleware) { Praxis::MiddlewareApp.for( **init_args ) }
7
- let(:instance){ middleware.new(target)}
6
+ let(:init_args) { { root: 'here' } }
7
+ let(:middleware) { Praxis::MiddlewareApp.for(**init_args) }
8
+ let(:instance) { middleware.new(target) }
8
9
 
9
10
  context '.for' do
10
11
  it 'does not initialize the Application instance yet' do
11
- expect( Praxis::Application.instance ).to_not receive(:setup)
12
+ expect(Praxis::Application.instance).to_not receive(:setup)
12
13
  middleware
13
14
  end
14
15
  it 'returns its class' do
15
- expect( middleware ).to be < Praxis::MiddlewareApp
16
+ expect(middleware).to be < Praxis::MiddlewareApp
16
17
  end
17
18
  end
18
19
 
19
20
  context 'instantiated' do
20
- subject{ instance }
21
- let(:target_response){ [201,{}] }
22
- let(:target){ double("target app", call: target_response) }
21
+ subject { instance }
22
+ let(:target_response) { [201, {}] }
23
+ let(:target) { double('target app', call: target_response) }
23
24
  it 'saves the target app' do
24
25
  expect(subject.target).to be(target)
25
26
  end
26
27
  it 'does not initialize the Application instance yet' do
27
- expect( Praxis::Application.instance ).to_not receive(:setup)
28
+ expect(Praxis::Application.instance).to_not receive(:setup)
28
29
  subject
29
30
  end
30
-
31
+
31
32
  context '.call' do
32
- let(:env){ {} }
33
- let(:praxis_response){ [200,{}] }
34
- subject(:response){ instance.call(env) }
33
+ let(:env) { {} }
34
+ let(:praxis_response) { [200, {}] }
35
+ subject(:response) { instance.call(env) }
35
36
  before do
36
37
  # always invokes the praxis app
37
- expect( Praxis::Application.instance ).to receive(:call).with( env ).once.and_return(praxis_response)
38
+ expect(Praxis::Application.instance).to receive(:call).with(env).once.and_return(praxis_response)
38
39
  end
39
40
 
40
41
  context 'when it has not been setup yet' do
41
42
  it 'initializes the application singleton with the passed parameters' do
42
- expect( Praxis::Application.instance ).to receive(:setup).with( init_args ).once
43
+ expect(Praxis::Application.instance).to receive(:setup).with(init_args).once
43
44
  subject
44
45
  end
45
46
  end
46
47
  context 'when it has already been setup' do
47
48
  it 'does NOT call instance setup' do
48
49
  middleware.setup
49
- expect( Praxis::Application.instance ).to_not receive(:setup)
50
+ expect(Praxis::Application.instance).to_not receive(:setup)
50
51
  subject
51
52
  end
52
53
  end
53
54
 
54
55
  context 'properly handled (non-404 and 405) responses from praxis' do
55
56
  it 'are returned straight through' do
56
- expect( response ).to be(praxis_response)
57
+ expect(response).to be(praxis_response)
57
58
  end
58
59
  end
59
60
 
60
61
  context '404/405 responses with X-Cascade = pass' do
61
- let(:praxis_response){ [404, {'X-Cascade' => 'pass'}]}
62
+ let(:praxis_response) { [404, { 'X-Cascade' => 'pass' }] }
62
63
  it 'are forwarded to the target app' do
63
- expect( response ).to be(target_response)
64
+ expect(response).to be(target_response)
64
65
  end
65
66
  end
66
67
 
67
68
  context '404/405 responses without X-Cascade = pass' do
68
- let(:praxis_response){ [404, {}]}
69
+ let(:praxis_response) { [404, {}] }
69
70
  it 'returned straight through' do
70
- expect( response ).to be(praxis_response)
71
+ expect(response).to be(praxis_response)
71
72
  end
72
73
  end
73
74
  end
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Praxis::MultipartParser do
4
-
5
6
  let(:form) do
6
7
  form_data = MIME::Multipart::FormData.new
7
8
 
@@ -36,17 +37,16 @@ describe Praxis::MultipartParser do
36
37
  form.add text, 'file', 'docker'
37
38
  end
38
39
 
39
- subject(:part) { parts.find { |p| p.name == 'file'} }
40
- #subject(:part_body) { part.body }
41
-
40
+ subject(:part) { parts.find { |p| p.name == 'file' } }
41
+ # subject(:part_body) { part.body }
42
42
 
43
43
  its(:payload) { should be_kind_of(Tempfile) }
44
- its(:filename) { should eq("docker") }
45
- its(:name) { should eq("file") }
44
+ its(:filename) { should eq('docker') }
45
+ its(:name) { should eq('file') }
46
46
 
47
47
  context 'headers' do
48
48
  subject(:part_headers) { part.headers }
49
- its(['Content-Type']) { should eq("text/plain") }
49
+ its(['Content-Type']) { should eq('text/plain') }
50
50
  its(['Content-Disposition']) { should match(/filename=docker/) }
51
51
  end
52
52
 
@@ -56,7 +56,5 @@ describe Praxis::MultipartParser do
56
56
  part.payload.rewind
57
57
  expect(part.payload.read).to eq('DOCKER_HOST=tcp://127.0.0.1:2375')
58
58
  end
59
-
60
59
  end
61
-
62
60
  end
@@ -1,11 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Praxis::Notifications do
4
-
5
6
  let(:events) { [] }
6
7
 
7
8
  before do
8
- Praxis::Notifications.subscribe('render') do |name, start, finish, id, payload|
9
+ Praxis::Notifications.subscribe('render') do |_name, _start, _finish, _id, payload|
9
10
  events << payload
10
11
  end
11
12
 
@@ -17,7 +18,6 @@ describe Praxis::Notifications do
17
18
 
18
19
  it 'works' do
19
20
  expect(events).to have(2).items
20
- expect(events).to match [{extra: :information}, {extra: :single}]
21
+ expect(events).to match [{ extra: :information }, { extra: :single }]
21
22
  end
22
-
23
23
  end
@@ -1,21 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Praxis::PluginConcern do
4
-
5
6
  it 'works' do
6
7
  expect(Praxis::Request.instance_methods).to include(:user_abilities)
7
8
  end
8
9
 
9
10
  context 'ActionDefinition' do
10
11
  subject(:action) { ApiResources::Instances.actions[:terminate] }
11
- its(:required_abilities) { should match_array [:terminate, :read] }
12
+ its(:required_abilities) { should match_array %i[terminate read] }
12
13
 
13
14
  context '#describe' do
14
15
  subject(:describe) { action.describe }
15
- it { should have_key :required_abilities}
16
- its([:required_abilities]) { should match_array action.required_abilities}
16
+ it { should have_key :required_abilities }
17
+ its([:required_abilities]) { should match_array action.required_abilities }
17
18
  end
18
-
19
19
  end
20
-
21
20
  end