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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'spec_media_types'
2
4
 
3
5
  Praxis::ApiDefinition.define do
@@ -37,10 +39,8 @@ class PeopleResource
37
39
  attribute :id, Integer, required: true
38
40
  end
39
41
  end
40
-
41
42
  end
42
43
 
43
-
44
44
  class AddressResource
45
45
  include Praxis::EndpointDefinition
46
46
 
@@ -68,5 +68,4 @@ class AddressResource
68
68
  attribute :id, Integer, required: true
69
69
  end
70
70
  end
71
-
72
71
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'praxis/extensions/field_selection'
2
4
  class Person < Praxis::MediaType
3
- identifier "application/vnd.acme.person"
5
+ identifier 'application/vnd.acme.person'
4
6
 
5
7
  attributes do
6
8
  attribute :id, Integer
@@ -13,7 +15,6 @@ class Person < Praxis::MediaType
13
15
  attribute :name
14
16
  end
15
17
 
16
-
17
18
  class CollectionSummary < Praxis::MediaType
18
19
  attributes do
19
20
  attribute :href, String
@@ -23,11 +24,9 @@ class Person < Praxis::MediaType
23
24
  default_fieldset do
24
25
  attribute :href
25
26
  end
26
-
27
27
  end
28
28
  end
29
29
 
30
-
31
30
  class Address < Praxis::MediaType
32
31
  identifier 'application/json'
33
32
 
@@ -55,26 +54,23 @@ class Address < Praxis::MediaType
55
54
  end
56
55
  end
57
56
 
58
-
59
-
60
-
61
57
  class Blog < Praxis::MediaType
62
58
  identifier 'application/vnd.bloggy.blog'
63
- description "A Bloggy Blog"
59
+ description 'A Bloggy Blog'
64
60
 
65
61
  attributes do
66
62
  attribute :id, Integer,
67
- description: 'Unique identifier'
63
+ description: 'Unique identifier'
68
64
  attribute :name, String,
69
- description: 'Short name'
65
+ description: 'Short name'
70
66
  attribute :href, String,
71
- example: proc {|o,ctx| "/api/v1.0/blogs/#{o.id}"},
72
- description: 'Href for use with this API'
67
+ example: proc { |o, _ctx| "/api/v1.0/blogs/#{o.id}" },
68
+ description: 'Href for use with this API'
73
69
  attribute :description, String,
74
- description: 'Longer description'
70
+ description: 'Longer description'
75
71
  attribute :url, String,
76
- example: proc {|o,ctx| "example.com/blogs/#{o.id}"},
77
- description: 'URL for a web browser'
72
+ example: proc { |o, _ctx| "example.com/blogs/#{o.id}" },
73
+ description: 'URL for a web browser'
78
74
 
79
75
  attribute :timestamps do
80
76
  attribute :created_at, DateTime
@@ -82,17 +78,16 @@ class Blog < Praxis::MediaType
82
78
  end
83
79
 
84
80
  attribute :tags, Attributor::Collection.of(String),
85
- description: 'Array of tags'
81
+ description: 'Array of tags'
86
82
 
87
83
  attribute :recent_posts, Praxis::Collection.of(Post),
88
- description: 'Array of recent related Post resources'
84
+ description: 'Array of recent related Post resources'
89
85
  attribute :owner, User,
90
- description: 'Related User resource'
86
+ description: 'Related User resource'
91
87
 
92
88
  attribute :posts_summary, Post::CollectionSummary,
93
- example: proc { |blog,ctx| Post::CollectionSummary.example(ctx, href: "#{blog.href}/posts") },
94
- description: "Summary of information from related Post resources"
95
-
89
+ example: proc { |blog, ctx| Post::CollectionSummary.example(ctx, href: "#{blog.href}/posts") },
90
+ description: 'Summary of information from related Post resources'
96
91
  end
97
92
 
98
93
  default_fieldset do
@@ -107,7 +102,6 @@ class Blog < Praxis::MediaType
107
102
  end
108
103
  end
109
104
 
110
-
111
105
  class Post < Praxis::MediaType
112
106
  identifier 'application/vnd.bloggy.post'
113
107
 
@@ -115,23 +109,23 @@ class Post < Praxis::MediaType
115
109
 
116
110
  attributes do
117
111
  attribute :id, Integer,
118
- description: 'Unique identifier'
112
+ description: 'Unique identifier'
119
113
  attribute :href, String,
120
- example: proc {|o,ctx| "/api/v1.0/posts/#{o.id}"},
121
- description: 'Href for use with this API'
114
+ example: proc { |o, _ctx| "/api/v1.0/posts/#{o.id}" },
115
+ description: 'Href for use with this API'
122
116
 
123
117
  attribute :title, String,
124
- example: /\w+/
118
+ example: /\w+/
125
119
  attribute :content, String,
126
- example: /[:sentence:]{4,5}/
120
+ example: /[:sentence:]{4,5}/
127
121
  attribute :url, String,
128
- description: 'URL for a web browser',
129
- example: proc {|o,ctx| "example.com/posts/#{o.id}"}
122
+ description: 'URL for a web browser',
123
+ example: proc { |o, _ctx| "example.com/posts/#{o.id}" }
130
124
 
131
125
  attribute :author, User,
132
- description: 'Related User resource'
126
+ description: 'Related User resource'
133
127
  attribute :blog, Blog,
134
- description: 'Related Blog resource'
128
+ description: 'Related Blog resource'
135
129
 
136
130
  attribute :followup_posts, Attributor::Collection.of(Post)
137
131
 
@@ -161,21 +155,20 @@ class Post < Praxis::MediaType
161
155
  end
162
156
  end
163
157
 
164
-
165
158
  class User < Praxis::MediaType
166
159
  identifier 'application/vnd.bloggy.user'
167
160
 
168
161
  attributes do
169
162
  attribute :id, Integer
170
163
  attribute :href, String,
171
- example: proc {|o,ctx| "/api/v1.0/users/#{o.id}"}
164
+ example: proc { |o, _ctx| "/api/v1.0/users/#{o.id}" }
172
165
 
173
166
  attribute :first, String, example: /[:first_name:]/
174
167
  attribute :last, String, example: /[:last_name:]/
175
168
  attribute :posts, Attributor::Collection.of(Post)
176
169
 
177
170
  attribute :post_matrix, Attributor::Collection.of(Attributor::Collection.of(Post)),
178
- description: 'matrix of posts with some row and some column axes that make sense'
171
+ description: 'matrix of posts with some row and some column axes that make sense'
179
172
  attribute :daily_posts, Attributor::Collection.of(Attributor::Struct) do
180
173
  attribute :day, String
181
174
  attribute :posts, Attributor::Collection.of(Post)
@@ -189,7 +182,7 @@ class User < Praxis::MediaType
189
182
  end
190
183
 
191
184
  attribute :posts_summary, Post::CollectionSummary,
192
- example: proc { |user,ctx| Post::CollectionSummary.example(ctx, href: "#{user.href}/posts") }
185
+ example: proc { |user, ctx| Post::CollectionSummary.example(ctx, href: "#{user.href}/posts") }
193
186
  end
194
187
 
195
188
  default_fieldset do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ostruct'
2
4
 
3
5
  require 'praxis/mapper/active_model_compat'
@@ -63,15 +65,15 @@ end
63
65
  class YamlArrayModel < OpenStruct
64
66
  include Praxis::Mapper::ActiveModelCompat
65
67
  def self._praxis_associations
66
- {
67
- parents: {
68
- model: ParentModel,
69
- primary_key: :id,
70
- type: :one_to_many,
71
- local_key_columns: [:id],
72
- remote_key_columns: [:parent_id]
68
+ {
69
+ parents: {
70
+ model: ParentModel,
71
+ primary_key: :id,
72
+ type: :one_to_many,
73
+ local_key_columns: [:id],
74
+ remote_key_columns: [:parent_id]
75
+ }
73
76
  }
74
- }
75
77
  end
76
78
  end
77
79
 
@@ -79,7 +81,7 @@ end
79
81
  class BaseResource < Praxis::Mapper::Resource
80
82
  def href
81
83
  base_href = '' # "/api"
82
- base_href + "/#{self.class.collection_name}/#{self.id}"
84
+ base_href + "/#{self.class.collection_name}/#{id}"
83
85
  end
84
86
 
85
87
  property :href, dependencies: [:id]
@@ -93,30 +95,34 @@ end
93
95
 
94
96
  class ParentResource < BaseResource
95
97
  model ParentModel
98
+
99
+ property :display_name, dependencies: %i[simple_name id other_attribute]
96
100
  end
97
101
 
98
102
  class SimpleResource < BaseResource
99
103
  model SimpleModel
100
104
 
101
- resource_delegate :other_model => [:other_attribute]
105
+ resource_delegate other_model: [:other_attribute]
102
106
 
103
107
  def other_resource
104
- self.other_model
108
+ other_model
105
109
  end
106
110
 
107
- property :aliased_method, dependencies: [:column1, :other_model]
111
+ property :aliased_method, dependencies: %i[column1 other_model]
108
112
  property :other_resource, dependencies: [:other_model]
109
113
 
110
- property :parent, dependencies: [:parent, :added_column]
114
+ property :parent, dependencies: %i[parent added_column]
111
115
 
112
116
  property :name, dependencies: [:simple_name]
113
- property :direct_other_name, dependencies: [ 'other_model.name' ]
114
- property :aliased_other_name, dependencies: [ 'other_model.display_name' ]
117
+ property :direct_other_name, dependencies: ['other_model.name']
118
+ property :aliased_other_name, dependencies: ['other_model.display_name']
115
119
 
116
120
  property :everything, dependencies: [:*]
117
121
  property :everything_from_parent, dependencies: ['parent.*']
118
- property :circular_dep, dependencies: [ :circular_dep, :column1 ]
122
+ property :circular_dep, dependencies: %i[circular_dep column1]
119
123
  property :no_deps, dependencies: []
124
+
125
+ property :deep_nested_deps, dependencies: ['parent.simple_children.other_model.parent.display_name']
120
126
  end
121
127
 
122
128
  class YamlArrayResource < BaseResource
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'singleton'
2
4
 
3
5
  module SimpleAuthenticationPlugin
@@ -7,7 +9,8 @@ module SimpleAuthenticationPlugin
7
9
  include Singleton
8
10
 
9
11
  def initialize
10
- @options = {config_file: 'config/authentication.yml'}
12
+ @options = { config_file: 'config/authentication.yml' }
13
+ super
11
14
  end
12
15
 
13
16
  def config_key
@@ -23,10 +26,8 @@ module SimpleAuthenticationPlugin
23
26
  def self.authenticate(request)
24
27
  request.current_user == 'guest'
25
28
  end
26
-
27
29
  end
28
30
 
29
-
30
31
  module Request
31
32
  def current_user
32
33
  'guest'
@@ -39,15 +40,11 @@ module SimpleAuthenticationPlugin
39
40
  included do
40
41
  before :action do |controller|
41
42
  action = controller.request.action
42
- if action.authentication_required
43
- Plugin.authenticate(controller.request)
44
- end
43
+ Plugin.authenticate(controller.request) if action.authentication_required
45
44
  end
46
45
  end
47
-
48
46
  end
49
47
 
50
-
51
48
  module ActionDefinition
52
49
  extend ActiveSupport::Concern
53
50
 
@@ -64,6 +61,5 @@ module SimpleAuthenticationPlugin
64
61
  def authentication_required
65
62
  @authentication_required ||= false
66
63
  end
67
-
68
64
  end
69
65
  end
data/tasks/loader.thor CHANGED
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thor'
2
4
 
3
- files = Dir[File.join(File.dirname(__FILE__), "thor/*.rb")]
5
+ files = Dir[File.join(File.dirname(__FILE__), 'thor/*.rb')]
4
6
  files.each do |f|
5
- require File.expand_path(f)
7
+ require File.expand_path(f)
6
8
  end
data/tasks/thor/app.rb CHANGED
@@ -1,24 +1,26 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module PraxisGen
2
4
  class App < Thor
3
5
  include Thor::Actions
4
6
 
5
- namespace "praxis:app"
7
+ namespace 'praxis:app'
6
8
  def self.source_root
7
- File.dirname(__FILE__) + "/templates/generator/empty_app"
9
+ "#{File.dirname(__FILE__)}/templates/generator/empty_app"
8
10
  end
9
11
 
10
12
  argument :app_name, required: true
11
- desc "new", "Generates a blank new app under <app_name> (with a full skeleton ready to start coding)"
13
+ desc 'new', 'Generates a blank new app under <app_name> (with a full skeleton ready to start coding)'
12
14
 
13
15
  # Generator for a blank new app (with a full skeleton ready to get you going)
14
16
  def new
15
17
  puts "Creating new blank Praxis app under #{app_name}"
16
18
  # Copy example files
17
- ['config.ru','Gemfile','Rakefile','README.md'].each do |file|
19
+ ['config.ru', 'Gemfile', 'Rakefile', 'README.md'].each do |file|
18
20
  copy_file file, verbose: true
19
21
  end
20
22
  # Copy example directories
21
- root_dirs = ['config','app','design','spec','docs']
23
+ root_dirs = %w[config app design spec docs]
22
24
  root_dirs.each do |dir|
23
25
  directory dir, recursive: true
24
26
  end
@@ -1,55 +1,56 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  module PraxisGen
3
4
  class Example < Thor
4
5
  include Thor::Actions
5
6
 
6
- namespace "praxis:example"
7
+ namespace 'praxis:example'
7
8
 
8
9
  def self.source_root
9
- File.dirname(__FILE__) + "/templates/generator/example_app"
10
+ "#{File.dirname(__FILE__)}/templates/generator/example_app"
10
11
  end
11
12
 
12
13
  argument :app_name, required: true
13
- desc "example", "Generates a new example application under an <app_name> directory to showcase some features"
14
+ desc 'example', 'Generates a new example application under an <app_name> directory to showcase some features'
14
15
 
15
16
  def example
16
17
  sanitized = app_name.downcase.gsub(/[^a-z0-9_\-.]/, '')
17
18
  puts "APP_NAME: #{app_name}"
18
- raise "Please use only letters, numbers, underscores, dashes or periods for the app name" unless sanitized == app_name
19
+ raise 'Please use only letters, numbers, underscores, dashes or periods for the app name' unless sanitized == app_name
19
20
 
20
21
  # Copy example files
21
- root_files = ['Gemfile','config.ru','Rakefile']
22
+ root_files = ['Gemfile', 'config.ru', 'Rakefile']
22
23
  root_files.each do |file|
23
24
  copy_file file, verbose: true
24
25
  end
25
26
  # Copy example directories
26
- root_dirs = ['app','config','design','db','spec']
27
+ root_dirs = %w[app config design db spec]
27
28
  root_dirs.each do |dir|
28
29
  directory dir, recursive: true
29
30
  end
30
31
 
31
32
  puts
32
- puts "To run the example application:"
33
+ puts 'To run the example application:'
33
34
  puts
34
35
  puts " cd #{app_name}"
35
- puts " bundle"
36
- puts " bundle exec rake db:recreate # To create/migrate/seed the dev DB"
37
- puts " bundle exec rackup # To start the web server"
38
- puts
39
- puts "From another terminal/app, use curl (or your favorite HTTP client) to retrieve data from the API"
40
- puts " For example: "
41
- puts " Get all users without filters or limit, and display only id, and first_name fields"
36
+ puts ' bundle'
37
+ puts ' bundle exec rake db:recreate # To create/migrate/seed the dev DB'
38
+ puts ' bundle exec rackup # To start the web server'
39
+ puts
40
+ puts 'From another terminal/app, use curl (or your favorite HTTP client) to retrieve data from the API'
41
+ puts ' For example: '
42
+ puts ' Get all users without filters or limit, and display only id, and first_name fields'
42
43
  puts " curl -G -H 'X-Api-Version: 1' http://localhost:9292/users \\"
43
- puts " --data-urlencode \"fields=id,first_name\""
44
+ puts ' --data-urlencode "fields=id,first_name"'
44
45
  puts
45
- puts " Get the last 5 users, with last_names starting with \"L\" ordered by first_name (descending)"
46
- puts " and display only id, first_name, last_name, and email fields"
46
+ puts ' Get the last 5 users, with last_names starting with "L" ordered by first_name (descending)'
47
+ puts ' and display only id, first_name, last_name, and email fields'
47
48
  puts " curl -G -H 'X-Api-Version: 1' http://localhost:9292/users \\"
48
- puts " --data-urlencode \"filters=last_name=L*\" \\"
49
- puts " --data-urlencode \"pagination=by=first_name,items=5\" \\"
50
- puts " --data-urlencode \"order=-first_name\" \\"
51
- puts " --data-urlencode \"fields=id,first_name,last_name,email\""
52
- puts " (Note: To list all routes use: bundle exec rake praxis:routes)"
49
+ puts ' --data-urlencode "filters=last_name=L*" \\'
50
+ puts ' --data-urlencode "pagination=by=first_name,items=5" \\'
51
+ puts ' --data-urlencode "order=-first_name" \\'
52
+ puts ' --data-urlencode "fields=id,first_name,last_name,email"'
53
+ puts ' (Note: To list all routes use: bundle exec rake praxis:routes)'
53
54
  puts
54
55
  nil
55
56
  end
data/tasks/thor/model.rb CHANGED
@@ -4,23 +4,23 @@ module PraxisGen
4
4
  class Model < Thor
5
5
  require 'active_support/inflector'
6
6
  include Thor::Actions
7
-
7
+
8
8
  def self.source_root
9
- File.dirname(__FILE__) + "/templates/generator/scaffold"
9
+ "#{File.dirname(__FILE__)}/templates/generator/scaffold"
10
10
  end
11
11
 
12
- desc "gmodel", "Generates a skeleton model file under app/models for ActiveRecord or Sequel."
12
+ desc 'gmodel', 'Generates a skeleton model file under app/models for ActiveRecord or Sequel.'
13
13
  argument :model_name, required: true
14
- option :orm, required: false, default: 'activerecord', enum: ['activerecord','sequel']
14
+ option :orm, required: false, default: 'activerecord', enum: %w[activerecord sequel]
15
15
  def g
16
- #self.class.check_name(model_name)
16
+ # self.class.check_name(model_name)
17
17
  template_file = \
18
18
  if options[:orm] == 'activerecord'
19
19
  'models/active_record.rb'
20
20
  else
21
21
  'models/sequel.rb'
22
22
  end
23
- puts "Generating Model for #{model_name}"
23
+ puts "Generating Model for #{model_name}"
24
24
  template template_file, "app/models/#{model_name}.rb"
25
25
  nil
26
26
  end
@@ -34,7 +34,7 @@ module PraxisGen
34
34
  # TODO: do we want the argument to be camelcase? or snake case?
35
35
  def self.check_name(name)
36
36
  sanitized = name.downcase.gsub(/[^a-z0-9_]/, '')
37
- raise "Please use only downcase letters, numbers and underscores for the model" unless sanitized == name
37
+ raise 'Please use only downcase letters, numbers and underscores for the model' unless sanitized == name
38
38
  end
39
39
  end
40
40
  end
@@ -4,32 +4,32 @@ module PraxisGen
4
4
  class Scaffold < Thor
5
5
  require 'active_support/inflector'
6
6
  include Thor::Actions
7
-
7
+
8
8
  attr_reader :actions_hash
9
9
 
10
10
  def self.source_root
11
- File.dirname(__FILE__) + "/templates/generator/scaffold"
11
+ "#{File.dirname(__FILE__)}/templates/generator/scaffold"
12
12
  end
13
13
 
14
- desc "g","Generates an API design and implementation scaffold for managing a collection of <collection_name>"
14
+ desc 'g', 'Generates an API design and implementation scaffold for managing a collection of <collection_name>'
15
15
  argument :collection_name, required: true
16
16
  option :version, required: false, default: '1',
17
- desc: 'Version string for the API endpoint. This also dictates the directory structure (i.e., v1/endpoints/...))'
17
+ desc: 'Version string for the API endpoint. This also dictates the directory structure (i.e., v1/endpoints/...))'
18
18
  option :design, type: :boolean, default: true,
19
- desc: 'Include the Endpoint and MediaType files for the collection'
19
+ desc: 'Include the Endpoint and MediaType files for the collection'
20
20
  option :implementation, type: :boolean, default: true,
21
- desc: 'Include the Controller and (possibly the) Resource files for the collection (see --no-resource)'
21
+ desc: 'Include the Controller and (possibly the) Resource files for the collection (see --no-resource)'
22
22
  option :resource, type: :boolean, default: true,
23
- desc: 'Disable (or enable) the creation of the Resource files when generating implementation'
24
- option :model, type: :string, enum: ['activerecord','sequel'],
25
- desc: 'It also generates a model for the given ORM. An empty --model flag will default to activerecord'
26
- option :actions, type: :string, default: 'crud', enum: ['cr','cru','crud','u','ud','d'],
27
- desc: 'Specifies the actions to generate for the API. cr=create, u=update, d=delete. Index and show actions are always generated'
23
+ desc: 'Disable (or enable) the creation of the Resource files when generating implementation'
24
+ option :model, type: :string, enum: %w[activerecord sequel],
25
+ desc: 'It also generates a model for the given ORM. An empty --model flag will default to activerecord'
26
+ option :actions, type: :string, default: 'crud', enum: %w[cr cru crud u ud d],
27
+ desc: 'Specifies the actions to generate for the API. cr=create, u=update, d=delete. Index and show actions are always generated'
28
28
  def g
29
29
  self.class.check_name(collection_name)
30
30
  @actions_hash = self.class.compose_actions_hash(options[:actions])
31
- env_rb = Pathname.new(destination_root)+Pathname.new("config/environment.rb")
32
- @pagination_plugin_found = File.open(env_rb).grep(/Praxis::Plugins::PaginationPlugin.*/).reject{|l| l.strip[0] == '#'}.present?
31
+ env_rb = Pathname.new(destination_root) + Pathname.new('config/environment.rb')
32
+ @pagination_plugin_found = File.open(env_rb).grep(/Praxis::Plugins::PaginationPlugin.*/).reject { |l| l.strip[0] == '#' }.present?
33
33
  if options[:design]
34
34
  say_status 'Design', "Generating scaffold for #{plural_class}", :blue
35
35
  template 'design/media_types/item.rb', "design/#{version_dir}/media_types/#{collection_name.singularize}.rb"
@@ -38,14 +38,14 @@ module PraxisGen
38
38
  if options[:implementation]
39
39
  say_status 'Implement', "Generating scaffold for #{plural_class}", :blue
40
40
  if options[:resource]
41
- base_resource = Pathname.new(destination_root)+Pathname.new("app/#{version_dir}/resources/base.rb")
41
+ base_resource = Pathname.new(destination_root) + Pathname.new("app/#{version_dir}/resources/base.rb")
42
42
  unless base_resource.exist?
43
43
  # Copy an appropriate base resource for the version (resources within same version must share same base)
44
- say_status "NOTE:",
45
- "Creating a base resource file for resources to inherit from (at 'app/#{version_dir}/resources/base.rb')",
46
- :yellow
47
- say_status "",
48
- "If you had already other resources in the app, change them to derive from this Base"
44
+ say_status 'NOTE:',
45
+ "Creating a base resource file for resources to inherit from (at 'app/#{version_dir}/resources/base.rb')",
46
+ :yellow
47
+ say_status '',
48
+ 'If you had already other resources in the app, change them to derive from this Base'
49
49
  template 'implementation/resources/base.rb', "app/#{version_dir}/resources/base.rb"
50
50
  end
51
51
  template 'implementation/resources/item.rb', "app/#{version_dir}/resources/#{collection_name.singularize}.rb"
@@ -60,11 +60,11 @@ module PraxisGen
60
60
  def plural_class
61
61
  collection_name.camelize
62
62
  end
63
-
63
+
64
64
  def singular_class
65
65
  collection_name.singularize.camelize
66
66
  end
67
-
67
+
68
68
  def version
69
69
  options[:version]
70
70
  end
@@ -72,7 +72,7 @@ module PraxisGen
72
72
  def version_module
73
73
  "V#{version}"
74
74
  end
75
-
75
+
76
76
  def version_dir
77
77
  version_module.camelize(:lower)
78
78
  end
@@ -111,7 +111,7 @@ module PraxisGen
111
111
  def self.check_name(name)
112
112
  sanitized = name.downcase.gsub(/[^a-z0-9_]/, '')
113
113
  # TODO: bail or support CamelCase collections (for now only snake case)
114
- raise "Please use only downcase letters, numbers and underscores for the collection" unless sanitized == name
114
+ raise 'Please use only downcase letters, numbers and underscores for the collection' unless sanitized == name
115
115
  end
116
116
  end
117
117
  end
@@ -5,14 +5,6 @@ module V1
5
5
  class User < Base
6
6
  model ::User
7
7
 
8
- # Mappings for the allowed filters
9
- filters_mapping(
10
- 'uuid': 'uuid',
11
- 'first_name': 'first_name',
12
- 'last_name': 'last_name',
13
- 'email': 'email'
14
- )
15
-
16
8
  # To compute the full_name (method below) we need to load first and last names from the DB
17
9
  property :full_name, dependencies: %i[first_name last_name]
18
10
 
@@ -6,9 +6,8 @@ module <%= version_module %>
6
6
  model ::<%= singular_class %> # Change it if it maps to a different DB model class
7
7
 
8
8
  # Define the name mapping from API filter params, to model attribute/associations
9
- # when they aren't 1:1
9
+ # when they aren't 1:1 the same
10
10
  # filters_mapping(
11
- # 'name': 'name',
12
11
  # 'label': 'association.label_name'
13
12
  # )
14
13