praxis 2.0.pre.1 → 2.0.pre.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/.ruby-version +1 -0
- data/.travis.yml +5 -20
- data/CHANGELOG.md +32 -0
- data/Gemfile +1 -1
- data/Guardfile +2 -1
- data/Rakefile +1 -7
- data/TODO.md +28 -0
- data/lib/api_browser/package-lock.json +7110 -0
- data/lib/praxis.rb +7 -4
- data/lib/praxis/action_definition.rb +10 -17
- data/lib/praxis/action_definition/headers_dsl_compiler.rb +1 -1
- data/lib/praxis/api_general_info.rb +21 -0
- data/lib/praxis/application.rb +2 -3
- data/lib/praxis/bootloader_stages/routing.rb +2 -4
- data/lib/praxis/config.rb +1 -1
- data/lib/praxis/docs/generator.rb +11 -6
- data/lib/praxis/docs/open_api_generator.rb +255 -0
- data/lib/praxis/docs/openapi/info_object.rb +31 -0
- data/lib/praxis/docs/openapi/media_type_object.rb +59 -0
- data/lib/praxis/docs/openapi/operation_object.rb +40 -0
- data/lib/praxis/docs/openapi/parameter_object.rb +69 -0
- data/lib/praxis/docs/openapi/paths_object.rb +58 -0
- data/lib/praxis/docs/openapi/request_body_object.rb +51 -0
- data/lib/praxis/docs/openapi/response_object.rb +63 -0
- data/lib/praxis/docs/openapi/responses_object.rb +44 -0
- data/lib/praxis/docs/openapi/schema_object.rb +87 -0
- data/lib/praxis/docs/openapi/server_object.rb +24 -0
- data/lib/praxis/docs/openapi/tag_object.rb +21 -0
- data/lib/praxis/extensions/attribute_filtering.rb +2 -0
- data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +148 -157
- data/lib/praxis/extensions/attribute_filtering/active_record_patches.rb +15 -0
- data/lib/praxis/extensions/attribute_filtering/active_record_patches/5x.rb +90 -0
- data/lib/praxis/extensions/attribute_filtering/active_record_patches/6_0.rb +68 -0
- data/lib/praxis/extensions/attribute_filtering/active_record_patches/6_1_plus.rb +58 -0
- data/lib/praxis/extensions/attribute_filtering/filter_tree_node.rb +35 -0
- data/lib/praxis/extensions/attribute_filtering/filtering_params.rb +13 -12
- data/lib/praxis/extensions/attribute_filtering/sequel_filter_query_builder.rb +3 -2
- data/lib/praxis/extensions/field_selection/active_record_query_selector.rb +24 -30
- data/lib/praxis/extensions/field_selection/field_selector.rb +4 -0
- data/lib/praxis/extensions/field_selection/sequel_query_selector.rb +32 -39
- data/lib/praxis/extensions/pagination.rb +130 -0
- data/lib/praxis/extensions/pagination/active_record_pagination_handler.rb +42 -0
- data/lib/praxis/extensions/pagination/header_generator.rb +70 -0
- data/lib/praxis/extensions/pagination/ordering_params.rb +234 -0
- data/lib/praxis/extensions/pagination/pagination_handler.rb +68 -0
- data/lib/praxis/extensions/pagination/pagination_params.rb +374 -0
- data/lib/praxis/extensions/pagination/sequel_pagination_handler.rb +45 -0
- data/lib/praxis/handlers/json.rb +2 -0
- data/lib/praxis/handlers/www_form.rb +5 -0
- data/lib/praxis/handlers/{xml.rb → xml-sample.rb} +6 -0
- data/lib/praxis/links.rb +4 -0
- data/lib/praxis/mapper/active_model_compat.rb +57 -4
- data/lib/praxis/mapper/resource.rb +18 -11
- data/lib/praxis/mapper/selector_generator.rb +99 -75
- data/lib/praxis/mapper/sequel_compat.rb +43 -3
- data/lib/praxis/media_type.rb +1 -56
- data/lib/praxis/media_type_identifier.rb +2 -1
- data/lib/praxis/multipart/part.rb +5 -2
- data/lib/praxis/notifications.rb +1 -1
- data/lib/praxis/plugins/mapper_plugin.rb +17 -3
- data/lib/praxis/plugins/pagination_plugin.rb +71 -0
- data/lib/praxis/resource_definition.rb +8 -16
- data/lib/praxis/response_definition.rb +1 -1
- data/lib/praxis/route.rb +3 -5
- data/lib/praxis/routing_config.rb +3 -7
- data/lib/praxis/tasks/api_docs.rb +23 -0
- data/lib/praxis/tasks/routes.rb +9 -14
- data/lib/praxis/trait.rb +1 -1
- data/lib/praxis/types/media_type_common.rb +12 -2
- data/lib/praxis/types/multipart.rb +1 -1
- data/lib/praxis/types/multipart_array.rb +64 -2
- data/lib/praxis/types/multipart_array/part_definition.rb +1 -1
- data/lib/praxis/validation_handler.rb +1 -2
- data/lib/praxis/version.rb +1 -1
- data/praxis.gemspec +11 -9
- data/spec/functional_spec.rb +9 -6
- data/spec/praxis/action_definition_spec.rb +4 -16
- data/spec/praxis/api_general_info_spec.rb +6 -6
- data/spec/praxis/application_spec.rb +1 -1
- data/spec/praxis/collection_spec.rb +3 -2
- data/spec/praxis/config_spec.rb +2 -2
- data/spec/praxis/extensions/attribute_filtering/active_record_filter_query_builder_spec.rb +304 -0
- data/spec/praxis/extensions/attribute_filtering/filter_tree_node_spec.rb +39 -0
- data/spec/praxis/extensions/attribute_filtering/filtering_params_spec.rb +34 -0
- data/spec/praxis/extensions/field_expansion_spec.rb +6 -24
- data/spec/praxis/extensions/field_selection/active_record_query_selector_spec.rb +110 -0
- data/spec/praxis/extensions/field_selection/sequel_query_selector_spec.rb +148 -0
- data/spec/praxis/extensions/pagination/active_record_pagination_handler_spec.rb +130 -0
- data/spec/praxis/extensions/support/spec_resources_active_model.rb +173 -0
- data/spec/praxis/extensions/support/spec_resources_sequel.rb +106 -0
- data/spec/praxis/mapper/selector_generator_spec.rb +306 -282
- data/spec/praxis/media_type_spec.rb +5 -139
- data/spec/praxis/middleware_app_spec.rb +1 -1
- data/spec/praxis/request_spec.rb +3 -22
- data/spec/praxis/request_stages/action_spec.rb +8 -1
- data/spec/praxis/resource_definition_spec.rb +1 -1
- data/spec/praxis/response_definition_spec.rb +15 -13
- data/spec/praxis/response_spec.rb +1 -1
- data/spec/praxis/route_spec.rb +2 -9
- data/spec/praxis/router_spec.rb +1 -1
- data/spec/praxis/routing_config_spec.rb +4 -13
- data/spec/praxis/types/multipart_array_spec.rb +4 -21
- data/spec/spec_app/app/controllers/instances.rb +1 -1
- data/spec/spec_app/config/environment.rb +0 -2
- data/spec/spec_app/design/api.rb +7 -1
- data/spec/spec_app/design/media_types/instance.rb +0 -8
- data/spec/spec_app/design/media_types/volume.rb +0 -12
- data/spec/spec_app/design/resources/instances.rb +1 -2
- data/spec/spec_helper.rb +17 -0
- data/spec/support/be_deep_equal_matcher.rb +39 -0
- data/spec/support/spec_media_types.rb +0 -73
- data/spec/support/spec_resources.rb +42 -49
- metadata +91 -56
- data/spec/praxis/handlers/xml_spec.rb +0 -177
- data/spec/praxis/links_spec.rb +0 -68
- data/spec/spec_app/app/models/person.rb +0 -3
data/lib/praxis/media_type.rb
CHANGED
@@ -7,15 +7,12 @@ module Praxis
|
|
7
7
|
# encodings; for example, a controller might respond with an actual Widget object, but a
|
8
8
|
# Content-Type header specifying 'application/vnd.acme.widget+json'; Praxis uses the information
|
9
9
|
# contained in the media-type definition of Widget to transform the object into an equivalent
|
10
|
-
# JSON representation.
|
11
|
-
# registered with the framework, Praxis will respond with an XML representation of the
|
12
|
-
# widget. The use of media types allows your application's models to be decoupled from its
|
10
|
+
# JSON representation. The use of media types allows your application's models to be decoupled from its
|
13
11
|
# HTTP interface specification.
|
14
12
|
#
|
15
13
|
# A media type definition consists of:
|
16
14
|
# - a MIME type identifier
|
17
15
|
# - attributes, each of which has a name and a data type
|
18
|
-
# - named links to other resources
|
19
16
|
# - named views, which expose interesting subsets of attributes
|
20
17
|
#
|
21
18
|
# @example Declare a widget type that's used by my supply-chain management app
|
@@ -37,16 +34,6 @@ module Praxis
|
|
37
34
|
# description: 'The factory in which this widget was produced'
|
38
35
|
# end
|
39
36
|
#
|
40
|
-
# links do
|
41
|
-
# link :factory,
|
42
|
-
# description: 'Link to the factory in which this widget was produced'
|
43
|
-
# end
|
44
|
-
#
|
45
|
-
# # If widgets can be linked-to by other resources, they should have a link view
|
46
|
-
# view :link do
|
47
|
-
# attribute :href
|
48
|
-
# end
|
49
|
-
#
|
50
37
|
# # All resources should have a default view
|
51
38
|
# view :default do
|
52
39
|
# attribute :id
|
@@ -58,32 +45,6 @@ module Praxis
|
|
58
45
|
|
59
46
|
include Types::MediaTypeCommon
|
60
47
|
|
61
|
-
class DSLCompiler < Attributor::HashDSLCompiler
|
62
|
-
def links(&block)
|
63
|
-
attribute :links, Praxis::Links.for(options[:reference]), dsl_compiler: Links::DSLCompiler, &block
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.attributes(opts={}, &block)
|
68
|
-
super(opts.merge(dsl_compiler: MediaType::DSLCompiler), &block)
|
69
|
-
end
|
70
|
-
|
71
|
-
def self._finalize!
|
72
|
-
super
|
73
|
-
|
74
|
-
# Only define our special links accessor if it was setup using the special DSL
|
75
|
-
# (we might have an app defining an attribute called `links` on its own, in which
|
76
|
-
# case we leave it be)
|
77
|
-
if @attribute && self.attributes.key?(:links) && self.attributes[:links].type < Praxis::Links
|
78
|
-
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
79
|
-
def links
|
80
|
-
self.class::Links.new(@object)
|
81
|
-
end
|
82
|
-
RUBY
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
|
87
48
|
class FieldResolver
|
88
49
|
def self.resolve(type,fields)
|
89
50
|
self.new.resolve(type,fields)
|
@@ -118,30 +79,14 @@ module Praxis
|
|
118
79
|
|
119
80
|
|
120
81
|
fields.each do |name, sub_fields|
|
121
|
-
# skip links and do them below
|
122
|
-
next if name == :links && defined?(type::Links)
|
123
82
|
|
124
83
|
new_type = type.attributes[name].type
|
125
84
|
result[name] = resolve(new_type, sub_fields)
|
126
85
|
end
|
127
86
|
|
128
|
-
# now to tackle whatever links there may be
|
129
|
-
if defined?(type::Links) &&(links_fields = fields[:links])
|
130
|
-
resolved_links = resolve_links(type::Links, links_fields)
|
131
|
-
self.deep_merge(result, resolved_links)
|
132
|
-
end
|
133
|
-
|
134
87
|
result
|
135
88
|
end
|
136
89
|
|
137
|
-
def resolve_links(links_type, links)
|
138
|
-
links.each_with_object({}) do |(name, link_fields), hash|
|
139
|
-
using = links_type.links[name]
|
140
|
-
new_type = links_type.attributes[name].type
|
141
|
-
hash[using] = resolve(new_type, link_fields)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
90
|
# perform a deep recursive *in place* merge
|
146
91
|
# form all values in +source+ onto +target+
|
147
92
|
#
|
@@ -146,7 +146,8 @@ module Praxis
|
|
146
146
|
if self.parameters.empty?
|
147
147
|
self
|
148
148
|
else
|
149
|
-
|
149
|
+
val = {type: self.type, subtype: self.subtype, suffix: self.suffix}
|
150
|
+
MediaTypeIdentifier.load(val)
|
150
151
|
end
|
151
152
|
end
|
152
153
|
|
@@ -28,6 +28,10 @@ module Praxis
|
|
28
28
|
self
|
29
29
|
end
|
30
30
|
|
31
|
+
def self.json_schema_type
|
32
|
+
:object
|
33
|
+
end
|
34
|
+
|
31
35
|
def self.example(context=nil, options:{})
|
32
36
|
if (payload_attribute = options[:payload_attribute])
|
33
37
|
payload = payload_attribute.example(context + ['payload'])
|
@@ -52,8 +56,7 @@ module Praxis
|
|
52
56
|
headers_attribute: headers_attribute,
|
53
57
|
filename_attribute: filename_attribute)
|
54
58
|
end
|
55
|
-
|
56
|
-
|
59
|
+
|
57
60
|
def self.describe(shallow=true, example: nil, options:{})
|
58
61
|
hash = super(shallow, example: example)
|
59
62
|
|
data/lib/praxis/notifications.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'singleton'
|
2
|
-
require 'praxis/extensions/attribute_filtering
|
2
|
+
require 'praxis/extensions/attribute_filtering'
|
3
3
|
|
4
4
|
module Praxis
|
5
5
|
module Plugins
|
@@ -8,6 +8,21 @@ module Praxis
|
|
8
8
|
|
9
9
|
class Plugin < Praxis::Plugin
|
10
10
|
include Singleton
|
11
|
+
|
12
|
+
def config_key
|
13
|
+
:mapper
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_config!
|
17
|
+
{} # override the default one, since we don't necessarily want to configure it via a yaml file.
|
18
|
+
end
|
19
|
+
|
20
|
+
def prepare_config!(node)
|
21
|
+
node.attributes do
|
22
|
+
attribute :debug_queries, Attributor::Boolean, default: false,
|
23
|
+
description: 'Weather or not to log debug information about queries executed in the build_query automation module'
|
24
|
+
end
|
25
|
+
end
|
11
26
|
end
|
12
27
|
|
13
28
|
module Controller
|
@@ -32,8 +47,7 @@ module Praxis
|
|
32
47
|
filters = request.params.filters if request.params&.respond_to?(:filters)
|
33
48
|
base_query = domain_model.craft_filter_query( base_query , filters: filters )
|
34
49
|
|
35
|
-
|
36
|
-
base_query = domain_model.craft_field_selection_query(base_query, selectors: selector_generator.selectors, resolved: resolved)
|
50
|
+
base_query = domain_model.craft_field_selection_query(base_query, selectors: selector_generator.selectors)
|
37
51
|
|
38
52
|
# TODO: handle pagination and ordering
|
39
53
|
base_query
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'praxis/extensions/pagination'
|
3
|
+
|
4
|
+
# Simple plugin concept
|
5
|
+
# Example configuration for this plugin
|
6
|
+
# Praxis::Application.configure do |application|
|
7
|
+
# application.bootloader.use Praxis::Plugins::PaginationPlugin, {
|
8
|
+
# max_items: 500, # Unlimited by default,
|
9
|
+
# default_page_size: 100,
|
10
|
+
# disallow_paging_by_default: false,
|
11
|
+
# # See all available options below
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# This would be applied to all controllers etc...so if one does not that
|
16
|
+
# It can easily add the `include Praxis::Extensions::Pagination` for every controller
|
17
|
+
# and use the class `Praxis::Types::PaginationParams.xxx yyy` stanzas to configure defaults
|
18
|
+
|
19
|
+
module Praxis
|
20
|
+
module Plugins
|
21
|
+
module PaginationPlugin
|
22
|
+
include Praxis::PluginConcern
|
23
|
+
|
24
|
+
class Plugin < Praxis::Plugin
|
25
|
+
include Singleton
|
26
|
+
|
27
|
+
def config_key
|
28
|
+
:pagination
|
29
|
+
end
|
30
|
+
|
31
|
+
def load_config!
|
32
|
+
@options || {}
|
33
|
+
end
|
34
|
+
|
35
|
+
def prepare_config!(node)
|
36
|
+
node.attributes do
|
37
|
+
attribute :max_items, Integer # Defaults to unlimited
|
38
|
+
attribute :default_page_size, Integer, default: Praxis::Types::PaginationParams.default_page_size
|
39
|
+
attribute :paging_default_mode, Hash, default: Praxis::Types::PaginationParams.paging_default_mode
|
40
|
+
attribute :disallow_paging_by_default, Attributor::Boolean, default: Praxis::Types::PaginationParams.disallow_paging_by_default
|
41
|
+
attribute :disallow_cursor_by_default, Attributor::Boolean, default: Praxis::Types::PaginationParams.disallow_cursor_by_default
|
42
|
+
attribute :disallow_cursor_by_default, Attributor::Boolean, default: Praxis::Types::PaginationParams.disallow_cursor_by_default
|
43
|
+
attribute :sorting do
|
44
|
+
attribute :enforce_all_fields, Attributor::Boolean, default: Praxis::Types::OrderingParams.enforce_all_fields
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def setup!
|
50
|
+
self.config.each do |name, val|
|
51
|
+
if name == :sorting
|
52
|
+
val.each do |ordername, orderval|
|
53
|
+
Praxis::Types::OrderingParams.send(ordername, orderval)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
Praxis::Types::PaginationParams.send(name, val)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module Controller
|
63
|
+
extend ActiveSupport::Concern
|
64
|
+
|
65
|
+
included do
|
66
|
+
include Praxis::Extensions::Pagination
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -49,7 +49,7 @@ module Praxis
|
|
49
49
|
unless base_attributes.empty?
|
50
50
|
params do
|
51
51
|
base_attributes.each do |base_name, base_attribute|
|
52
|
-
attribute base_name, base_attribute.type, base_attribute.options
|
52
|
+
attribute base_name, base_attribute.type, **base_attribute.options
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
@@ -87,22 +87,14 @@ module Praxis
|
|
87
87
|
@display_name = string
|
88
88
|
end
|
89
89
|
|
90
|
-
def on_finalize
|
90
|
+
def on_finalize(&block)
|
91
91
|
if block_given?
|
92
|
-
@on_finalize <<
|
92
|
+
@on_finalize << proc(&block)
|
93
93
|
end
|
94
94
|
|
95
95
|
@on_finalize
|
96
96
|
end
|
97
97
|
|
98
|
-
# FIXME: this is inconsistent with the rest of the magic DSL convention.
|
99
|
-
def routing(&block)
|
100
|
-
warn "DEPRECATED: ResourceDefinition.routing is deprecated use prefix directly instead."
|
101
|
-
|
102
|
-
# eval this assuming it will only call #prefix
|
103
|
-
self.instance_eval(&block)
|
104
|
-
end
|
105
|
-
|
106
98
|
def prefix(prefix=nil)
|
107
99
|
return @prefix if prefix.nil?
|
108
100
|
@routing_prefix = nil # reset routing_prefix
|
@@ -125,7 +117,7 @@ module Praxis
|
|
125
117
|
@routing_prefix = nil # reset routing_prefix
|
126
118
|
|
127
119
|
parent_action = parent.canonical_path
|
128
|
-
parent_route = parent_action.
|
120
|
+
parent_route = parent_action.route.path
|
129
121
|
|
130
122
|
# if a mapping is passed, it *must* resolve any param name conflicts
|
131
123
|
unless mapping.any?
|
@@ -146,7 +138,7 @@ module Praxis
|
|
146
138
|
if mapping.key?(name)
|
147
139
|
param = mapping[name]
|
148
140
|
# FIXME: this won't handle URI Template type paths, ie '/{parent_id}'
|
149
|
-
prefixed_path = parent_action.
|
141
|
+
prefixed_path = parent_action.route.prefixed_path
|
150
142
|
@parent_prefix = prefixed_path.gsub(/(:)(#{name})(\W+|$)/, "\\1#{param.to_s}\\3")
|
151
143
|
else
|
152
144
|
mapping[name] = name
|
@@ -168,7 +160,7 @@ module Praxis
|
|
168
160
|
|
169
161
|
parent_attribute = parent_action.params.attributes[parent_name]
|
170
162
|
|
171
|
-
attribute name, parent_attribute.type, parent_attribute.options
|
163
|
+
attribute name, parent_attribute.type, **parent_attribute.options
|
172
164
|
end
|
173
165
|
end
|
174
166
|
end
|
@@ -221,14 +213,14 @@ module Praxis
|
|
221
213
|
end
|
222
214
|
|
223
215
|
def to_href( params )
|
224
|
-
canonical_path.
|
216
|
+
canonical_path.route.path.expand(params)
|
225
217
|
end
|
226
218
|
|
227
219
|
def parse_href(path)
|
228
220
|
if path.kind_of?(::URI::Generic)
|
229
221
|
path = path.path
|
230
222
|
end
|
231
|
-
param_values = canonical_path.
|
223
|
+
param_values = canonical_path.route.path.params(path)
|
232
224
|
attrs = canonical_path.params.attributes
|
233
225
|
param_values.each_with_object({}) do |(key,value),hash|
|
234
226
|
hash[key.to_sym] = attrs[key.to_sym].load(value,[key])
|
data/lib/praxis/route.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module Praxis
|
2
2
|
|
3
3
|
class Route
|
4
|
-
attr_accessor :verb, :path, :version, :
|
4
|
+
attr_accessor :verb, :path, :version, :prefixed_path, :options
|
5
5
|
|
6
|
-
def initialize(verb, path, version='n/a',
|
6
|
+
def initialize(verb, path, version='n/a', prefixed_path:nil, **options)
|
7
7
|
@verb = verb
|
8
8
|
@path = path
|
9
9
|
@version = version
|
10
|
-
@name = name
|
11
10
|
@options = options
|
12
11
|
@prefixed_path = prefixed_path
|
13
12
|
end
|
@@ -24,7 +23,7 @@ module Praxis
|
|
24
23
|
path_params = example_hash.select{|k,v| path_param_keys.include? k }
|
25
24
|
# Let's generate the example only using required params, to avoid mixing incompatible parameters
|
26
25
|
query_params = example_hash.select{|k,v| required_query_param_keys.include? k }
|
27
|
-
example = { verb: self.verb, url: self.path.expand(path_params), query_params: query_params }
|
26
|
+
example = { verb: self.verb, url: self.path.expand(path_params.transform_values(&:to_s)), query_params: query_params }
|
28
27
|
|
29
28
|
end
|
30
29
|
|
@@ -34,7 +33,6 @@ module Praxis
|
|
34
33
|
path: path.to_s,
|
35
34
|
version: version
|
36
35
|
}
|
37
|
-
result[:name] = name unless name.nil?
|
38
36
|
result[:options] = options if options.any?
|
39
37
|
result
|
40
38
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Praxis
|
2
2
|
class RoutingConfig
|
3
3
|
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :route
|
5
5
|
attr_reader :version
|
6
6
|
attr_reader :base
|
7
7
|
|
@@ -10,7 +10,7 @@ module Praxis
|
|
10
10
|
@base = base
|
11
11
|
@prefix_segments = Array(prefix)
|
12
12
|
|
13
|
-
@
|
13
|
+
@route = nil
|
14
14
|
|
15
15
|
if block_given?
|
16
16
|
instance_eval(&block)
|
@@ -53,12 +53,8 @@ module Praxis
|
|
53
53
|
end
|
54
54
|
prefixed_path = path.gsub('//','/')
|
55
55
|
path = (base + path).gsub('//','/')
|
56
|
-
# Reject our own options
|
57
|
-
route_name = options.delete(:name);
|
58
56
|
pattern = Mustermann.new(path, {ignore_unknown_options: true}.merge( options ))
|
59
|
-
route = Route.new(verb, pattern, version,
|
60
|
-
@routes << route
|
61
|
-
route
|
57
|
+
@route = Route.new(verb, pattern, version, prefixed_path: prefixed_path, **options)
|
62
58
|
end
|
63
59
|
|
64
60
|
end
|
@@ -62,5 +62,28 @@ namespace :praxis do
|
|
62
62
|
generator.save!
|
63
63
|
end
|
64
64
|
|
65
|
+
desc "Generate OpenAPI 3 docs for a Praxis App"
|
66
|
+
task :openapi => [:environment] do |t, args|
|
67
|
+
require 'fileutils'
|
68
|
+
|
69
|
+
Praxis::Blueprint.caching_enabled = false
|
70
|
+
generator = Praxis::Docs::OpenApiGenerator.new(Dir.pwd)
|
71
|
+
generator.save!
|
72
|
+
end
|
73
|
+
|
74
|
+
desc "Preview (and Generate) OpenAPI 3 docs for a Praxis App"
|
75
|
+
task :openapipreview => [:openapi] do |t, args|
|
76
|
+
require 'webrick'
|
77
|
+
docs_port = 9090
|
78
|
+
root = Dir.pwd + '/docs/openapi/'
|
79
|
+
wb = Thread.new do
|
80
|
+
s = WEBrick::HTTPServer.new(:Port => docs_port, :DocumentRoot => root)
|
81
|
+
trap('INT') { s.shutdown }
|
82
|
+
s.start
|
83
|
+
end
|
84
|
+
`open http://localhost:#{docs_port}/`
|
85
|
+
wb.join
|
86
|
+
end
|
87
|
+
|
65
88
|
end
|
66
89
|
end
|
data/lib/praxis/tasks/routes.rb
CHANGED
@@ -7,7 +7,7 @@ namespace :praxis do
|
|
7
7
|
table = Terminal::Table.new title: "Routes",
|
8
8
|
headings: [
|
9
9
|
"Version", "Path", "Verb",
|
10
|
-
"Resource", "Action", "Implementation", "
|
10
|
+
"Resource", "Action", "Implementation", "Options"
|
11
11
|
]
|
12
12
|
|
13
13
|
rows = []
|
@@ -31,20 +31,16 @@ namespace :praxis do
|
|
31
31
|
warn "Warning: No routes defined for #{resource_definition.name}##{name}."
|
32
32
|
rows << row
|
33
33
|
else
|
34
|
-
action.
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
options: route.options
|
42
|
-
})
|
34
|
+
route = action.route
|
35
|
+
rows << row.merge({
|
36
|
+
version: route.version,
|
37
|
+
verb: route.verb,
|
38
|
+
path: route.path,
|
39
|
+
options: route.options
|
40
|
+
})
|
43
41
|
end
|
44
42
|
end
|
45
43
|
end
|
46
|
-
end
|
47
|
-
|
48
44
|
case args[:format] || "table"
|
49
45
|
when "json"
|
50
46
|
puts JSON.pretty_generate(rows)
|
@@ -52,7 +48,7 @@ namespace :praxis do
|
|
52
48
|
rows.each do |row|
|
53
49
|
formatted_options = row[:options].map{|(k,v)| "#{k}:#{v.to_s}"}.join("\n")
|
54
50
|
row_data = row.values_at(:version, :path, :verb, :resource,
|
55
|
-
:action, :implementation
|
51
|
+
:action, :implementation)
|
56
52
|
row_data << formatted_options
|
57
53
|
table.add_row(row_data)
|
58
54
|
end
|
@@ -60,6 +56,5 @@ namespace :praxis do
|
|
60
56
|
else
|
61
57
|
raise "unknown output format: #{args[:format]}"
|
62
58
|
end
|
63
|
-
|
64
59
|
end
|
65
60
|
end
|