praxis 0.22.pre.2 → 2.0.pre.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +323 -324
- data/lib/praxis/action_definition.rb +7 -9
- data/lib/praxis/api_definition.rb +27 -44
- data/lib/praxis/api_general_info.rb +2 -3
- data/lib/praxis/application.rb +14 -141
- data/lib/praxis/bootloader.rb +1 -2
- data/lib/praxis/bootloader_stages/environment.rb +13 -0
- data/lib/praxis/controller.rb +0 -2
- data/lib/praxis/dispatcher.rb +4 -6
- data/lib/praxis/docs/generator.rb +8 -18
- data/lib/praxis/docs/link_builder.rb +1 -1
- data/lib/praxis/error_handler.rb +5 -5
- data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +1 -1
- data/lib/praxis/extensions/attribute_filtering/sequel_filter_query_builder.rb +125 -0
- data/lib/praxis/extensions/field_selection/active_record_query_selector.rb +16 -18
- data/lib/praxis/extensions/field_selection/sequel_query_selector.rb +5 -5
- data/lib/praxis/extensions/field_selection.rb +1 -12
- data/lib/praxis/extensions/rendering.rb +1 -1
- data/lib/praxis/file_group.rb +1 -1
- data/lib/praxis/handlers/xml.rb +1 -1
- data/lib/praxis/mapper/active_model_compat.rb +63 -0
- data/lib/praxis/mapper/resource.rb +242 -0
- data/lib/praxis/mapper/selector_generator.rb +126 -0
- data/lib/praxis/mapper/sequel_compat.rb +37 -0
- data/lib/praxis/middleware_app.rb +13 -15
- data/lib/praxis/multipart/part.rb +3 -5
- data/lib/praxis/plugins/mapper_plugin.rb +50 -0
- data/lib/praxis/request.rb +14 -7
- data/lib/praxis/request_stages/response.rb +2 -3
- data/lib/praxis/resource_definition.rb +10 -14
- data/lib/praxis/response.rb +6 -5
- data/lib/praxis/response_definition.rb +5 -7
- data/lib/praxis/response_template.rb +3 -4
- data/lib/praxis/responses/http.rb +36 -0
- data/lib/praxis/responses/internal_server_error.rb +12 -3
- data/lib/praxis/responses/multipart_ok.rb +11 -4
- data/lib/praxis/responses/validation_error.rb +10 -1
- data/lib/praxis/router.rb +3 -3
- data/lib/praxis/tasks/api_docs.rb +2 -10
- data/lib/praxis/tasks/routes.rb +0 -1
- data/lib/praxis/version.rb +1 -1
- data/lib/praxis.rb +13 -9
- data/praxis.gemspec +2 -3
- data/spec/functional_spec.rb +0 -1
- data/spec/praxis/action_definition_spec.rb +15 -26
- data/spec/praxis/api_definition_spec.rb +8 -13
- data/spec/praxis/api_general_info_spec.rb +8 -3
- data/spec/praxis/application_spec.rb +7 -13
- data/spec/praxis/handlers/xml_spec.rb +2 -2
- data/spec/praxis/mapper/resource_spec.rb +169 -0
- data/spec/praxis/mapper/selector_generator_spec.rb +301 -0
- data/spec/praxis/middleware_app_spec.rb +15 -9
- data/spec/praxis/request_spec.rb +7 -17
- data/spec/praxis/request_stages/validate_spec.rb +1 -1
- data/spec/praxis/resource_definition_spec.rb +10 -12
- data/spec/praxis/response_definition_spec.rb +5 -22
- data/spec/praxis/response_spec.rb +5 -12
- data/spec/praxis/responses/internal_server_error_spec.rb +5 -2
- data/spec/praxis/router_spec.rb +4 -8
- data/spec/spec_app/app/models/person.rb +3 -3
- data/spec/spec_app/config/environment.rb +3 -21
- data/spec/spec_app/config.ru +6 -1
- data/spec/spec_helper.rb +2 -17
- data/spec/support/spec_resources.rb +131 -0
- metadata +19 -31
- data/lib/praxis/extensions/attribute_filtering/query_builder.rb +0 -39
- data/lib/praxis/extensions/attribute_filtering.rb +0 -28
- data/lib/praxis/extensions/mapper_selectors.rb +0 -16
- data/lib/praxis/media_type_collection.rb +0 -127
- data/lib/praxis/plugins/praxis_mapper_plugin.rb +0 -246
- data/spec/praxis/media_type_collection_spec.rb +0 -157
- data/spec/praxis/plugins/praxis_mapper_plugin_spec.rb +0 -142
@@ -12,7 +12,6 @@ module Praxis
|
|
12
12
|
|
13
13
|
attr_reader :name
|
14
14
|
attr_reader :resource_definition
|
15
|
-
attr_reader :api_definition
|
16
15
|
attr_reader :routes
|
17
16
|
attr_reader :primary_route
|
18
17
|
attr_reader :named_routes
|
@@ -40,7 +39,6 @@ module Praxis
|
|
40
39
|
@metadata = Hash.new
|
41
40
|
@routes = []
|
42
41
|
@traits = []
|
43
|
-
@api_definition = resource_definition.application.api_definition
|
44
42
|
|
45
43
|
if (media_type = resource_definition.media_type)
|
46
44
|
if media_type.kind_of?(Class) && media_type < Praxis::Types::MediaTypeCommon
|
@@ -49,7 +47,7 @@ module Praxis
|
|
49
47
|
end
|
50
48
|
|
51
49
|
version = resource_definition.version
|
52
|
-
api_info =
|
50
|
+
api_info = ApiDefinition.instance.info(resource_definition.version)
|
53
51
|
|
54
52
|
route_base = "#{api_info.base_path}#{resource_definition.version_prefix}"
|
55
53
|
prefix = Array(resource_definition.routing_prefix)
|
@@ -66,11 +64,11 @@ module Praxis
|
|
66
64
|
end
|
67
65
|
|
68
66
|
def trait(trait_name)
|
69
|
-
unless
|
67
|
+
unless ApiDefinition.instance.traits.has_key? trait_name
|
70
68
|
raise Exceptions::InvalidTrait.new("Trait #{trait_name} not found in the system")
|
71
69
|
end
|
72
70
|
|
73
|
-
trait =
|
71
|
+
trait = ApiDefinition.instance.traits.fetch(trait_name)
|
74
72
|
trait.apply!(self)
|
75
73
|
traits << trait_name
|
76
74
|
end
|
@@ -92,7 +90,7 @@ module Praxis
|
|
92
90
|
args[:media_type] = type
|
93
91
|
end
|
94
92
|
|
95
|
-
template =
|
93
|
+
template = ApiDefinition.instance.response(name)
|
96
94
|
@responses[name] = template.compile(self, **args)
|
97
95
|
end
|
98
96
|
|
@@ -305,7 +303,7 @@ module Praxis
|
|
305
303
|
|
306
304
|
# and return that one if it already corresponds to a registered handler
|
307
305
|
# otherwise, add the encoding
|
308
|
-
if
|
306
|
+
if Praxis::Application.instance.handlers.include?(pick.handler_name)
|
309
307
|
return pick
|
310
308
|
else
|
311
309
|
return pick + handler_name
|
@@ -322,13 +320,13 @@ module Praxis
|
|
322
320
|
|
323
321
|
hash[:examples] = {}
|
324
322
|
|
325
|
-
default_handlers =
|
323
|
+
default_handlers = ApiDefinition.instance.info.consumes
|
326
324
|
|
327
325
|
default_handlers.each do |default_handler|
|
328
326
|
dumped_payload = payload.dump(example, default_format: default_handler)
|
329
327
|
|
330
328
|
content_type = derive_content_type(example, default_handler)
|
331
|
-
handler =
|
329
|
+
handler = Praxis::Application.instance.handlers[content_type.handler_name]
|
332
330
|
|
333
331
|
# in case handler is nil, use dumped_payload as-is.
|
334
332
|
generated_payload = if handler.nil?
|
@@ -1,57 +1,41 @@
|
|
1
|
+
require 'singleton'
|
1
2
|
require 'forwardable'
|
2
3
|
|
3
4
|
module Praxis
|
4
5
|
|
5
6
|
class ApiDefinition
|
7
|
+
include Singleton
|
6
8
|
extend Forwardable
|
7
9
|
|
8
10
|
attr_reader :traits
|
9
11
|
attr_reader :responses
|
10
12
|
attr_reader :infos
|
11
13
|
attr_reader :global_info
|
12
|
-
attr_reader :application
|
13
14
|
|
14
15
|
attr_accessor :versioning_scheme
|
15
16
|
|
16
|
-
def self.instance
|
17
|
-
i = Thread.current[:praxis_instance] || $praxis_initializing_instance
|
18
|
-
raise "Trying to use Praxis::ApiDefinition outside the context of a Praxis::Application" unless i
|
19
|
-
i.api_definition
|
20
|
-
end
|
21
|
-
|
22
17
|
def self.define(&block)
|
23
|
-
|
24
|
-
definition = Praxis::Application.current_instance.api_definition
|
25
|
-
if block.arity == 0
|
26
|
-
definition.instance_eval(&block)
|
27
|
-
else
|
28
|
-
yield(definition)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def define(&block)
|
33
18
|
if block.arity == 0
|
34
|
-
self.instance_eval(&block)
|
19
|
+
self.instance.instance_eval(&block)
|
35
20
|
else
|
36
|
-
yield(self)
|
21
|
+
yield(self.instance)
|
37
22
|
end
|
38
23
|
end
|
39
24
|
|
40
|
-
def initialize
|
41
|
-
@application = application
|
25
|
+
def initialize
|
42
26
|
@responses = Hash.new
|
43
27
|
@traits = Hash.new
|
44
28
|
@base_path = ''
|
45
29
|
|
46
|
-
@global_info = ApiGeneralInfo.new
|
30
|
+
@global_info = ApiGeneralInfo.new
|
47
31
|
|
48
32
|
@infos = Hash.new do |hash, version|
|
49
|
-
hash[version] = ApiGeneralInfo.new(@global_info,
|
33
|
+
hash[version] = ApiGeneralInfo.new(@global_info, version: version)
|
50
34
|
end
|
51
35
|
end
|
52
36
|
|
53
37
|
def response_template(name, &block)
|
54
|
-
@responses[name] = Praxis::ResponseTemplate.new(name,
|
38
|
+
@responses[name] = Praxis::ResponseTemplate.new(name, &block)
|
55
39
|
end
|
56
40
|
|
57
41
|
def response(name)
|
@@ -107,26 +91,25 @@ module Praxis
|
|
107
91
|
data
|
108
92
|
end
|
109
93
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
# end
|
94
|
+
define do |api|
|
95
|
+
api.response_template :ok do |media_type: , location: nil, headers: nil, description: nil |
|
96
|
+
status 200
|
97
|
+
description( description || 'Standard response for successful HTTP requests.' )
|
98
|
+
|
99
|
+
media_type media_type
|
100
|
+
location location
|
101
|
+
headers headers if headers
|
102
|
+
end
|
103
|
+
|
104
|
+
api.response_template :created do |media_type: nil, location: nil, headers: nil, description: nil|
|
105
|
+
status 201
|
106
|
+
description( description || 'The request has been fulfilled and resulted in a new resource being created.' )
|
107
|
+
|
108
|
+
media_type media_type if media_type
|
109
|
+
location location
|
110
|
+
headers headers if headers
|
111
|
+
end
|
112
|
+
end
|
130
113
|
|
131
114
|
end
|
132
115
|
|
@@ -3,11 +3,10 @@ module Praxis
|
|
3
3
|
|
4
4
|
attr_reader :version
|
5
5
|
|
6
|
-
def initialize(global_info=nil,
|
6
|
+
def initialize(global_info=nil, version: nil)
|
7
7
|
@data = Hash.new
|
8
8
|
@global_info = global_info
|
9
9
|
@version = version
|
10
|
-
@application = application
|
11
10
|
|
12
11
|
if @global_info.nil? # this *is* the global info
|
13
12
|
version_with [:header, :params]
|
@@ -55,7 +54,7 @@ module Praxis
|
|
55
54
|
get(:version_with)
|
56
55
|
else
|
57
56
|
if @global_info.nil? # this *is* the global info
|
58
|
-
|
57
|
+
Application.instance.versioning_scheme = val
|
59
58
|
set(:version_with, val)
|
60
59
|
else
|
61
60
|
raise "Use of version_with is only allowed in the global part of " \
|
data/lib/praxis/application.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
+
require 'singleton'
|
1
2
|
require 'mustermann'
|
2
3
|
require 'logger'
|
3
4
|
|
4
5
|
module Praxis
|
5
6
|
class Application
|
7
|
+
include Singleton
|
6
8
|
|
7
9
|
attr_reader :router
|
8
10
|
attr_reader :controllers
|
9
11
|
attr_reader :resource_definitions
|
10
12
|
attr_reader :app
|
11
13
|
attr_reader :builder
|
12
|
-
attr_reader :api_definition
|
13
14
|
|
14
15
|
attr_accessor :bootloader
|
15
16
|
attr_accessor :file_layout
|
@@ -24,30 +25,12 @@ module Praxis
|
|
24
25
|
|
25
26
|
attr_accessor :versioning_scheme
|
26
27
|
|
27
|
-
@@registered_apps = {}
|
28
28
|
|
29
|
-
def self.registered_apps
|
30
|
-
@@registered_apps
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.instance
|
34
|
-
i = current_instance
|
35
|
-
return i if i
|
36
|
-
$praxis_initializing_instance = self.new
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.current_instance
|
40
|
-
Thread.current[:praxis_instance] || $praxis_initializing_instance
|
41
|
-
end
|
42
|
-
|
43
29
|
def self.configure
|
44
|
-
|
45
|
-
yield(current_instance)
|
30
|
+
yield(self.instance)
|
46
31
|
end
|
47
32
|
|
48
|
-
def initialize
|
49
|
-
old = $praxis_initializing_instance
|
50
|
-
$praxis_initializing_instance = self # ApiDefinition.new needs to get the instance...
|
33
|
+
def initialize
|
51
34
|
@controllers = Set.new
|
52
35
|
@resource_definitions = Set.new
|
53
36
|
|
@@ -68,135 +51,29 @@ module Praxis
|
|
68
51
|
@config = Config.new
|
69
52
|
@root = nil
|
70
53
|
@logger = Logger.new(STDOUT)
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
media_type media_type
|
79
|
-
location location
|
80
|
-
headers headers if headers
|
81
|
-
end
|
82
|
-
|
83
|
-
api.response_template :created do |media_type: nil, location: nil, headers: nil, description: nil|
|
84
|
-
status 201
|
85
|
-
description( description || 'The request has been fulfilled and resulted in a new resource being created.' )
|
86
|
-
|
87
|
-
media_type media_type if media_type
|
88
|
-
location location
|
89
|
-
headers headers if headers
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
require 'praxis/responses/http'
|
94
|
-
self.api_definition.define do |api|
|
95
|
-
[
|
96
|
-
[ :accepted, 202, "The request has been accepted for processing, but the processing has not been completed." ],
|
97
|
-
[ :no_content, 204,"The server successfully processed the request, but is not returning any content."],
|
98
|
-
[ :multiple_choices, 300,"Indicates multiple options for the resource that the client may follow."],
|
99
|
-
[ :moved_permanently, 301,"This and all future requests should be directed to the given URI."],
|
100
|
-
[ :found, 302,"The requested resource resides temporarily under a different URI."],
|
101
|
-
[ :see_other, 303,"The response to the request can be found under another URI using a GET method"],
|
102
|
-
[ :not_modified, 304,"Indicates that the resource has not been modified since the version specified by the request headers If-Modified-Since or If-Match."],
|
103
|
-
[ :temporary_redirect, 307,"In this case, the request should be repeated with another URI; however, future requests should still use the original URI."],
|
104
|
-
[ :bad_request, 400,"The request cannot be fulfilled due to bad syntax."],
|
105
|
-
[ :unauthorized, 401,"Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided."],
|
106
|
-
[ :forbidden, 403,"The request was a valid request, but the server is refusing to respond to it."],
|
107
|
-
[ :not_found, 404,"The requested resource could not be found but may be available again in the future."],
|
108
|
-
[ :method_not_allowed, 405,"A request was made of a resource using a request method not supported by that resource."],
|
109
|
-
[ :not_acceptable, 406,"The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request."],
|
110
|
-
[ :request_timeout, 408,"The server timed out waiting for the request."],
|
111
|
-
[ :conflict, 409, "Indicates that the request could not be processed because of conflict in the request, such as an edit conflict in the case of multiple updates."],
|
112
|
-
[ :precondition_failed, 412,"The server does not meet one of the preconditions that the requester put on the request."],
|
113
|
-
[ :unprocessable_entity, 422,"The request was well-formed but was unable to be followed due to semantic errors."],
|
114
|
-
].each do |name, code, base_description|
|
115
|
-
api.response_template name do |media_type: nil, location: nil, headers: nil, description: nil|
|
116
|
-
status code
|
117
|
-
description( description || base_description ) # description can "potentially" be overriden in an individual action.
|
118
|
-
|
119
|
-
media_type media_type if media_type
|
120
|
-
location location if location
|
121
|
-
headers headers if headers
|
122
|
-
end
|
123
|
-
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def setup(root: '.')
|
58
|
+
return self unless @app.nil?
|
59
|
+
|
60
|
+
@root = Pathname.new(root).expand_path
|
124
61
|
|
125
|
-
end
|
126
|
-
|
127
|
-
require 'praxis/responses/internal_server_error'
|
128
|
-
self.api_definition.define do |api|
|
129
|
-
api.response_template :internal_server_error do
|
130
|
-
description "A generic error message, given when an unexpected condition was encountered and no more specific message is suitable."
|
131
|
-
status 500
|
132
|
-
media_type "application/json"
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
require 'praxis/responses/validation_error'
|
137
|
-
self.api_definition.define do |api|
|
138
|
-
api.response_template :validation_error do
|
139
|
-
description "An error message indicating that one or more elements of the request did not match the API specification for the action"
|
140
|
-
status 400
|
141
|
-
media_type "application/json"
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
|
146
|
-
require 'praxis/responses/multipart_ok'
|
147
|
-
self.api_definition.define do |api|
|
148
|
-
api.response_template :multipart_ok do |media_type: Praxis::Types::MultipartArray|
|
149
|
-
status 200
|
150
|
-
media_type media_type
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
62
|
builtin_handlers = {
|
155
63
|
'plain' => Praxis::Handlers::Plain,
|
156
64
|
'json' => Praxis::Handlers::JSON,
|
157
65
|
'x-www-form-urlencoded' => Praxis::Handlers::WWWForm
|
158
66
|
}
|
159
|
-
|
160
67
|
# Register built-in handlers unless the app already provided its own
|
161
68
|
builtin_handlers.each_pair do |name, handler|
|
162
69
|
self.handler(name, handler) unless handlers.key?(name)
|
163
70
|
end
|
164
|
-
|
165
|
-
setup_initial_config!
|
166
|
-
|
167
|
-
unless skip_registration
|
168
|
-
if self.class.registered_apps[name]
|
169
|
-
raise "A Praxis instance named #{name} has already been registered, please use the :name parameter to initialize them"
|
170
|
-
end
|
171
|
-
self.class.registered_apps[name] = self
|
172
|
-
end
|
173
|
-
$praxis_initializing_instance = old
|
174
|
-
end
|
175
|
-
|
176
|
-
def setup_initial_config!
|
177
|
-
self.config do
|
178
|
-
attribute :praxis do
|
179
|
-
attribute :validate_responses, Attributor::Boolean, default: false
|
180
|
-
attribute :validate_response_bodies, Attributor::Boolean, default: false
|
181
|
-
|
182
|
-
attribute :show_exceptions, Attributor::Boolean, default: false
|
183
|
-
attribute :x_cascade, Attributor::Boolean, default: true
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
71
|
|
189
|
-
|
190
|
-
return self unless @app.nil?
|
191
|
-
saved_value = $praxis_initializing_instance
|
192
|
-
$praxis_initializing_instance = self
|
193
|
-
@root = Pathname.new(root).expand_path
|
72
|
+
@bootloader.setup!
|
194
73
|
|
195
|
-
|
196
|
-
builder.
|
197
|
-
@app = builder.to_app
|
74
|
+
@builder.run(@router)
|
75
|
+
@app = @builder.to_app
|
198
76
|
|
199
|
-
$praxis_initializing_instance = saved_value
|
200
77
|
self
|
201
78
|
end
|
202
79
|
|
@@ -226,13 +103,9 @@ module Praxis
|
|
226
103
|
|
227
104
|
def call(env)
|
228
105
|
response = []
|
229
|
-
old = Thread.current[:praxis_instance]
|
230
|
-
Thread.current[:praxis_instance] = self
|
231
106
|
Notifications.instrument 'rack.request.all'.freeze, response: response do
|
232
107
|
response.push(*@app.call(env))
|
233
108
|
end
|
234
|
-
ensure
|
235
|
-
Thread.current[:praxis_instance] = old
|
236
109
|
end
|
237
110
|
|
238
111
|
def layout(&block)
|
data/lib/praxis/bootloader.rb
CHANGED
@@ -47,9 +47,8 @@ module Praxis
|
|
47
47
|
stages << BootloaderStages::WarnUnloadedFiles.new(:warn_unloaded_files, application)
|
48
48
|
|
49
49
|
after(:app) do
|
50
|
-
Praxis::Mapper.finalize!
|
51
50
|
Praxis::Blueprint.finalize!
|
52
|
-
Praxis::ResourceDefinition.finalize!
|
51
|
+
Praxis::ResourceDefinition.finalize!
|
53
52
|
end
|
54
53
|
|
55
54
|
end
|
@@ -8,6 +8,7 @@ module Praxis
|
|
8
8
|
# 1) the environment.rb file - generic stuff for all environments
|
9
9
|
# 2) "Deployer.environment".rb - environment specific stuff
|
10
10
|
def execute
|
11
|
+
setup_initial_config!
|
11
12
|
|
12
13
|
env_file = application.root + "config/environment.rb"
|
13
14
|
require env_file if File.exists? env_file
|
@@ -36,6 +37,18 @@ module Praxis
|
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
40
|
+
# TODO: not really sure I like this here... but where else is better?
|
41
|
+
def setup_initial_config!
|
42
|
+
application.config do
|
43
|
+
attribute :praxis do
|
44
|
+
attribute :validate_responses, Attributor::Boolean, default: false
|
45
|
+
attribute :validate_response_bodies, Attributor::Boolean, default: false
|
46
|
+
|
47
|
+
attribute :show_exceptions, Attributor::Boolean, default: false
|
48
|
+
attribute :x_cascade, Attributor::Boolean, default: true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
39
52
|
|
40
53
|
end
|
41
54
|
|
data/lib/praxis/controller.rb
CHANGED
@@ -20,8 +20,6 @@ module Praxis
|
|
20
20
|
end
|
21
21
|
|
22
22
|
definition.controller = self
|
23
|
-
# `implements` should only be processed while the application initializes/setup
|
24
|
-
# So we will use the `.instance` function to get the "current" application instance
|
25
23
|
Application.instance.controllers << self
|
26
24
|
end
|
27
25
|
|
data/lib/praxis/dispatcher.rb
CHANGED
@@ -28,13 +28,11 @@ module Praxis
|
|
28
28
|
@deferred_callbacks[:after] << [conditions, block]
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
# But we'll leave the application param as optional if we know there is a dispatcher in the thread
|
33
|
-
def self.current(thread: Thread.current, application: nil)
|
31
|
+
def self.current(thread: Thread.current, application: Application.instance)
|
34
32
|
thread[:praxis_dispatcher] ||= self.new(application: application)
|
35
33
|
end
|
36
34
|
|
37
|
-
def initialize(application:)
|
35
|
+
def initialize(application: Application.instance)
|
38
36
|
@stages = []
|
39
37
|
@application = application
|
40
38
|
setup_stages!
|
@@ -106,9 +104,9 @@ module Praxis
|
|
106
104
|
response_stage.run
|
107
105
|
|
108
106
|
payload[:response] = controller.response
|
109
|
-
controller.response.finish
|
107
|
+
controller.response.finish
|
110
108
|
rescue => e
|
111
|
-
@application.error_handler.handle!(request, e
|
109
|
+
@application.error_handler.handle!(request, e)
|
112
110
|
end
|
113
111
|
end
|
114
112
|
end
|
@@ -5,8 +5,7 @@ module Praxis
|
|
5
5
|
require 'active_support/core_ext/enumerable' # For index_by
|
6
6
|
|
7
7
|
API_DOCS_DIRNAME = 'docs/api'
|
8
|
-
|
9
|
-
attr_reader :app_instance
|
8
|
+
|
10
9
|
attr_reader :resources_by_version, :types_by_id, :infos_by_version
|
11
10
|
attr_reader :doc_root_dir
|
12
11
|
|
@@ -25,21 +24,13 @@ module Praxis
|
|
25
24
|
Attributor::URI,
|
26
25
|
]).freeze
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
Thread.current[:praxis_instance] = instance
|
31
|
-
self.new(root, instance: instance, name: name, skip_sub_directory: skip_sub_directory).save!
|
32
|
-
Thread.current[:praxis_instance] = nil
|
33
|
-
end
|
34
|
-
|
35
|
-
def initialize(root, instance:, name:, skip_sub_directory:)
|
27
|
+
|
28
|
+
def initialize(root)
|
36
29
|
require 'yaml'
|
37
30
|
@resources_by_version = Hash.new do |h,k|
|
38
31
|
h[k] = Set.new
|
39
32
|
end
|
40
|
-
|
41
|
-
subdir = skip_sub_directory ? nil : name
|
42
|
-
initialize_directories(root, subdir: subdir )
|
33
|
+
initialize_directories(root)
|
43
34
|
|
44
35
|
Attributor::AttributeResolver.current = Attributor::AttributeResolver.new
|
45
36
|
collect_infos
|
@@ -57,10 +48,9 @@ module Praxis
|
|
57
48
|
|
58
49
|
private
|
59
50
|
|
60
|
-
def initialize_directories(root
|
51
|
+
def initialize_directories(root)
|
61
52
|
@doc_root_dir = File.join(root, API_DOCS_DIRNAME)
|
62
|
-
|
63
|
-
|
53
|
+
|
64
54
|
# remove previous data (and reset the directory)
|
65
55
|
FileUtils.rm_rf @doc_root_dir if File.exists?(@doc_root_dir)
|
66
56
|
FileUtils.mkdir_p @doc_root_dir unless File.exists? @doc_root_dir
|
@@ -68,7 +58,7 @@ module Praxis
|
|
68
58
|
|
69
59
|
def collect_resources
|
70
60
|
# load all resource definitions registered with Praxis
|
71
|
-
|
61
|
+
Praxis::Application.instance.resource_definitions.map do |resource|
|
72
62
|
# skip resources with doc_visibility of :none
|
73
63
|
next if resource.metadata[:doc_visibility] == :none
|
74
64
|
version = resource.version
|
@@ -86,7 +76,7 @@ module Praxis
|
|
86
76
|
|
87
77
|
def collect_infos
|
88
78
|
# All infos. Including keys for `:global`, "n/a", and any string version
|
89
|
-
@infos_by_version =
|
79
|
+
@infos_by_version = ApiDefinition.instance.describe
|
90
80
|
end
|
91
81
|
|
92
82
|
|
@@ -20,7 +20,7 @@ module Praxis
|
|
20
20
|
|
21
21
|
def endpoint
|
22
22
|
@endpoint ||= begin
|
23
|
-
endpoint =
|
23
|
+
endpoint = ApiDefinition.instance.global_info.documentation_url
|
24
24
|
endpoint.gsub(/\/index\.html$/i, '/') if endpoint
|
25
25
|
end
|
26
26
|
end
|
data/lib/praxis/error_handler.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
module Praxis
|
2
2
|
class ErrorHandler
|
3
|
-
|
4
|
-
def handle!(request, error
|
5
|
-
|
3
|
+
|
4
|
+
def handle!(request, error)
|
5
|
+
Application.instance.logger.error error.inspect
|
6
6
|
error.backtrace.each do |line|
|
7
|
-
|
7
|
+
Application.instance.logger.error line
|
8
8
|
end
|
9
9
|
|
10
10
|
response = Responses::InternalServerError.new(error: error)
|
11
11
|
response.request = request
|
12
|
-
response.finish
|
12
|
+
response.finish
|
13
13
|
end
|
14
14
|
|
15
15
|
end
|