praxis 0.10.1 → 0.11pre
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/.gitignore +0 -1
- data/CHANGELOG.md +47 -10
- data/Gemfile +1 -1
- data/Guardfile +1 -0
- data/bin/praxis +33 -4
- data/lib/api_browser/app/css/main.css +0 -3
- data/lib/praxis.rb +16 -0
- data/lib/praxis/action_definition.rb +16 -18
- data/lib/praxis/application.rb +31 -2
- data/lib/praxis/bootloader.rb +37 -4
- data/lib/praxis/bootloader_stages/environment.rb +3 -7
- data/lib/praxis/bootloader_stages/plugin_config_load.rb +20 -0
- data/lib/praxis/bootloader_stages/plugin_config_prepare.rb +18 -0
- data/lib/praxis/bootloader_stages/plugin_loader.rb +19 -0
- data/lib/praxis/bootloader_stages/plugin_setup.rb +13 -0
- data/lib/praxis/bootloader_stages/routing.rb +16 -6
- data/lib/praxis/callbacks.rb +0 -2
- data/lib/praxis/config.rb +3 -2
- data/lib/praxis/dispatcher.rb +25 -13
- data/lib/praxis/error_handler.rb +16 -0
- data/lib/praxis/links.rb +9 -4
- data/lib/praxis/media_type_collection.rb +2 -3
- data/lib/praxis/notifications.rb +41 -0
- data/lib/praxis/plugin.rb +18 -8
- data/lib/praxis/plugin_concern.rb +40 -0
- data/lib/praxis/request.rb +27 -7
- data/lib/praxis/request_stages/action.rb +7 -2
- data/lib/praxis/request_stages/response.rb +7 -3
- data/lib/praxis/request_stages/validate_payload.rb +7 -1
- data/lib/praxis/resource_definition.rb +37 -16
- data/lib/praxis/response.rb +1 -0
- data/lib/praxis/responses/internal_server_error.rb +13 -8
- data/lib/praxis/responses/validation_error.rb +10 -7
- data/lib/praxis/restful_doc_generator.rb +312 -0
- data/lib/praxis/router.rb +7 -5
- data/lib/praxis/skeletor/restful_routing_config.rb +12 -5
- data/lib/praxis/stage.rb +5 -1
- data/lib/praxis/stats.rb +106 -0
- data/lib/praxis/tasks/api_docs.rb +8 -314
- data/lib/praxis/version.rb +1 -1
- data/praxis.gemspec +4 -1
- data/spec/functional_spec.rb +87 -32
- data/spec/praxis/action_definition_spec.rb +13 -12
- data/spec/praxis/bootloader_spec.rb +12 -5
- data/spec/praxis/notifications_spec.rb +23 -0
- data/spec/praxis/plugin_concern_spec.rb +21 -0
- data/spec/praxis/request_spec.rb +56 -1
- data/spec/praxis/request_stages_validate_spec.rb +3 -3
- data/spec/praxis/resource_definition_spec.rb +44 -60
- data/spec/praxis/responses/internal_server_error_spec.rb +32 -16
- data/spec/praxis/restful_routing_config_spec.rb +15 -2
- data/spec/praxis/router_spec.rb +5 -3
- data/spec/praxis/stats_spec.rb +9 -0
- data/spec/praxis_mapper_plugin_spec.rb +71 -0
- data/spec/spec_app/app/controllers/instances.rb +12 -0
- data/spec/spec_app/app/controllers/volumes.rb +5 -0
- data/spec/spec_app/app/models/person.rb +3 -0
- data/spec/spec_app/config/active_record.yml +2 -0
- data/spec/spec_app/config/authentication.yml +3 -0
- data/spec/spec_app/config/authorization.yml +4 -0
- data/spec/spec_app/config/environment.rb +28 -1
- data/spec/spec_app/config/praxis_mapper.yml +6 -0
- data/spec/spec_app/config/sequel_model.yml +2 -0
- data/spec/spec_app/config/stats.yml +8 -0
- data/spec/spec_app/config/stats.yml.dis +8 -0
- data/spec/spec_app/design/resources/instances.rb +53 -16
- data/spec/spec_app/design/resources/volumes.rb +13 -2
- data/spec/spec_helper.rb +14 -0
- data/spec/support/spec_authentication_plugin.rb +126 -0
- data/spec/support/spec_authorization_plugin.rb +95 -0
- data/spec/support/spec_praxis_mapper_plugin.rb +157 -0
- data/tasks/loader.thor +6 -0
- data/tasks/thor/app.rb +48 -0
- data/tasks/thor/example.rb +283 -0
- data/tasks/thor/templates/generator/empty_app/.gitignore +3 -0
- data/tasks/thor/templates/generator/empty_app/.rspec +1 -0
- data/tasks/thor/templates/generator/empty_app/Gemfile +29 -0
- data/tasks/thor/templates/generator/empty_app/Guardfile +3 -0
- data/tasks/thor/templates/generator/empty_app/README.md +4 -0
- data/tasks/thor/templates/generator/empty_app/Rakefile +25 -0
- data/tasks/thor/templates/generator/empty_app/app/models/.empty_directory +0 -0
- data/tasks/thor/templates/generator/empty_app/app/models/.gitkeep +0 -0
- data/tasks/thor/templates/generator/empty_app/app/responses/.empty_directory +0 -0
- data/tasks/thor/templates/generator/empty_app/app/responses/.gitkeep +0 -0
- data/tasks/thor/templates/generator/empty_app/app/v1/controllers/.empty_directory +0 -0
- data/tasks/thor/templates/generator/empty_app/app/v1/controllers/.gitkeep +0 -0
- data/tasks/thor/templates/generator/empty_app/config.ru +7 -0
- data/tasks/thor/templates/generator/empty_app/config/environment.rb +17 -0
- data/tasks/thor/templates/generator/empty_app/config/rainbows.rb +57 -0
- data/tasks/thor/templates/generator/empty_app/design/api.rb +0 -0
- data/tasks/thor/templates/generator/empty_app/design/response_templates/.empty_directory +0 -0
- data/tasks/thor/templates/generator/empty_app/design/response_templates/.gitkeep +0 -0
- data/tasks/thor/templates/generator/empty_app/design/v1/media_types/.empty_directory +0 -0
- data/tasks/thor/templates/generator/empty_app/design/v1/media_types/.gitkeep +0 -0
- data/tasks/thor/templates/generator/empty_app/design/v1/resources/.empty_directory +0 -0
- data/tasks/thor/templates/generator/empty_app/design/v1/resources/.gitkeep +0 -0
- data/tasks/thor/templates/generator/empty_app/spec/spec_helper.rb +18 -0
- metadata +97 -6
- data/tasks/praxis_app_generator.thor +0 -307
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5925b03e5020e28fc79530a6991c3f030897996d
|
|
4
|
+
data.tar.gz: f301a81c0628df629ae32e805debbb653b0c2477
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f573ece40063959ee3df1a11db4a36563acd44c68bc7ad70192f90bb8268501b4c128e504ba8080406037303a6fa5dbbf4a854d741843c80aae559df6b2a0f63
|
|
7
|
+
data.tar.gz: 3adb04192e7414e607482a44f2a8f9f83618dee6b0202094ee77c77d4d46ae0dd63e5579dd55e87ed76aa6212a0a294229108d8c5bd8d8bd841de417cf73fb63
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,49 @@
|
|
|
1
1
|
# praxis changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 0.11
|
|
4
4
|
|
|
5
|
-
*
|
|
5
|
+
* `MediaTypeCollection`:
|
|
6
|
+
* Added support for loading `decorate`ed `Resource` associations.
|
|
7
|
+
* Refined and enhanced support for API versioning:
|
|
8
|
+
* version DSL now can take a `using` option which specifies and array of the methods are allowed: `:header`,`:params`,`:path`(new)
|
|
9
|
+
* if not specified, it will default to `using: [:header, :params]` (so that the version can be passed to the header OR the params)
|
|
10
|
+
* the new `:path` option will build the action routes by prefixing the version given a common pattern (i.e., "/v1.0/...")
|
|
11
|
+
* The effects of path versioning will be visible through `rake praxis:routes`
|
|
12
|
+
* the default api prefix pattern is ("/v(version)/") but can changed by either
|
|
13
|
+
* overriding ``Praxis::Request.path_version_prefix` and return the appropriate string prefix (i.e., by default this returns "/v")
|
|
14
|
+
* or overriding `Praxis::Request.path_version_matcher` and providing the fully custom matching regexp. This regexp must have a capture (named `version`) that would return matched version value.
|
|
15
|
+
* Enhanced praxis generator:
|
|
16
|
+
* Added a new generator (available through `praxis new app_name`) which creates a blank new app, with enough basic structure and setup to start building an API.
|
|
17
|
+
* Changed the example hello world generation command. Instead of `praxis generate app_name`, it is now available through `praxis example app_name`
|
|
18
|
+
* Changed the path lookup for the praxis directory (to not use installed gems, which could be multiple). [Issue #67]
|
|
19
|
+
* `ResourceDefinition`:
|
|
20
|
+
* Added: `action_defaults` method, to define default options for actions. May be called more than once.
|
|
21
|
+
* Removed: `params`, `payload`, `headers`, and `response`. Specify these inside `action_defaults` instead.
|
|
22
|
+
* `Application`:
|
|
23
|
+
* Added `middleware` method to use Rack middleware.
|
|
24
|
+
* `ErrorHandler`
|
|
25
|
+
* It is now possible to register the error handler class to be invoked when an uncaught exception is thrown by setting `Application#error_handler`.
|
|
26
|
+
* The default error handler writes the error and backtrace into the Praxis logger, and returns an `InternalServerError` response
|
|
27
|
+
* Added `Praxis::Notifications` framework backed by ActiveSupport::Notifications
|
|
28
|
+
* Its interface is the same as AS::Notifications (.publish, .instrument, .subscribe, and etc.)
|
|
29
|
+
* Each incoming rack request is instrumented as `rack.request.all`, with a payload of `{response: response}`, where `response` is the `Response` object that will be returned to the client. Internally, Praxis subscribes to this to generate timing statistics with `Praxis::Stats`.
|
|
30
|
+
* Additionally, each request that is dispatched to an action is instrumented as `praxis.request.all`, with a payload of `{request: request, response: response}`, where `response` is as above, and `request` is the `Request` object for the request.
|
|
31
|
+
* Added `Praxis::Stats` framework backed by `Harness` (i.e. a statsd interface)
|
|
32
|
+
* Can be configured with a collector type (fake, Statsd) and an asynchronous queue + thread
|
|
33
|
+
* Wraps the statsd interface: count, increment, decrement, time ...
|
|
34
|
+
* Added a new `decorate_docs` method to enhance generated JSON docs for actions in `ResourceDefinitions`
|
|
35
|
+
* Using this hook, anybody can register a block that can change/enhance the JSON structure of generated documents for any given action
|
|
36
|
+
* Added a brand new Plugins architecture
|
|
37
|
+
* Plugins can easily inject code in the Request, Controller, ResourceDefinition or ActionDefinition
|
|
38
|
+
* Can be instances or singletons (and will be initialized correspondingly)
|
|
39
|
+
* Plugins can be easily configured under a unique "config key" in the Praxis config
|
|
40
|
+
* See the [Plugins](http://praxis-framework.io/reference/plugins/) section in the documentation for more information.
|
|
41
|
+
* Added a Plugin for using the Praxis::Mapper gem
|
|
42
|
+
* Configurable through a simple `praxis_mapper.yml` file
|
|
43
|
+
* Its supports several repositories (by name)
|
|
44
|
+
* Each repository can be of a different type (default is sequel)
|
|
45
|
+
* `praxis:doc_browser` rake task now takes a port argument for specifying the port to run on, e.g. `rake praxis:doc_browser[9000]` to run on port 9000.
|
|
46
|
+
* Added `show_exceptions` configuration option to to control default ErrorHandler behavior.
|
|
6
47
|
|
|
7
48
|
## 0.10.0
|
|
8
49
|
|
|
@@ -22,7 +63,7 @@
|
|
|
22
63
|
* Fixes [Issue #21](https://github.com/rightscale/praxis/issues/21)
|
|
23
64
|
* Introduced `around` filters using blocks:
|
|
24
65
|
* Around filters can be set wrapping any of the request stages (load, validate, action...) and might apply to only certain actions (i.e. exactly the same as the before/after filters)
|
|
25
|
-
* Therefore they supports the same attributes as `before` and `after` filters. The only difference is that an around filter block will get an extra parameter with the block to call to continue the chain.
|
|
66
|
+
* Therefore they supports the same attributes as `before` and `after` filters. The only difference is that an around filter block will get an extra parameter with the block to call to continue the chain.
|
|
26
67
|
* See the [Instances](https://github.com/rightscale/praxis/blob/master/spec/spec_app/app/controllers/instances.rb) controller for examples.
|
|
27
68
|
* Fix: Change :created response template to take an optiona ‘location’ parameter (instead of a media_type one, since it doesn’t make sense for a 201 type response) [Issue #26](https://github.com/rightscale/praxis/issues/23)
|
|
28
69
|
* Make the system be more robust in error reporting when controllers do not return a String or a Response
|
|
@@ -41,11 +82,7 @@
|
|
|
41
82
|
* `MediaTypeCollection`. See [volume_snapshot](spec/spec_app/design/media_types/volume_snapshot.rb) in the specs for an example.
|
|
42
83
|
* Added `member_view` DSL to define a view that renders the collection's members with the given view.
|
|
43
84
|
* Change: Now requires all views to be explicitly defined (and will not automatically use the underlying member view if it exists). To define a view for member element (wrapping it in a collection) one can use the new member_view.
|
|
44
|
-
*
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
** Header keys are case sensitive now (although Praxis gracefully allows loading the uppercased RACK names )
|
|
48
|
-
* Added tests for using `Attributor::Hash` attributes that can accept "extra" keys:
|
|
49
|
-
** See the `bulk_create` action for an example applied to `Praxis::Multipart` (which derives from `Attributor::Hash`) payload [here](https://github.com/rightscale/praxis/blob/master/spec/spec_app/design/resources/instances.rb).
|
|
50
|
-
|
|
85
|
+
*
|
|
86
|
+
|
|
87
|
+
|
|
51
88
|
## 0.9 Initial release
|
data/Gemfile
CHANGED
data/Guardfile
CHANGED
data/bin/praxis
CHANGED
|
@@ -2,9 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
require 'bundler'
|
|
4
4
|
|
|
5
|
-
path_to_praxis
|
|
6
|
-
|
|
5
|
+
path_to_praxis = File.expand_path(File.dirname(File.dirname(__FILE__)))
|
|
6
|
+
path_to_loader = '%s/tasks/loader.thor' % path_to_praxis
|
|
7
7
|
|
|
8
|
-
load
|
|
8
|
+
load path_to_loader
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
class PraxisGenerator < Thor
|
|
11
|
+
|
|
12
|
+
# Simple helper to go get the existing description for the real action
|
|
13
|
+
# Usage must still be provided rather than retrieved (since it is not a
|
|
14
|
+
# straight "usage" from the remote action when arguments are defined )
|
|
15
|
+
def self.desc_for( usage_string, klass, action_name, description_prefix="")
|
|
16
|
+
action_name = action_name.to_s
|
|
17
|
+
cmd = klass.commands[action_name]
|
|
18
|
+
raise "Error, could not find description for #{klass.name}##{action_name}" if cmd.nil?
|
|
19
|
+
desc usage_string, "#{description_prefix}#{cmd.description}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
desc_for "new APP_NAME", ::PraxisGen::App, :new
|
|
23
|
+
def new(app_name)
|
|
24
|
+
::PraxisGen::App.start(['new' , app_name])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
desc_for "example APP_NAME", ::PraxisGen::Example, :new
|
|
28
|
+
def example(app_name)
|
|
29
|
+
::PraxisGen::Example.start(['new', app_name])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
desc_for "generate APP_NAME", ::PraxisGen::Example, :new, "DEPRECATED!: "
|
|
33
|
+
def generate(app_name)
|
|
34
|
+
warn "This is a deprecated method.\nTo generate a hello world example, please use:\n praxis example #{app_name} "
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
PraxisGenerator.start(ARGV)
|
data/lib/praxis.rb
CHANGED
|
@@ -3,6 +3,8 @@ require 'attributor'
|
|
|
3
3
|
require 'praxis-mapper'
|
|
4
4
|
require 'praxis-blueprints'
|
|
5
5
|
|
|
6
|
+
require 'active_support/concern'
|
|
7
|
+
|
|
6
8
|
$:.unshift File.dirname(__FILE__)
|
|
7
9
|
|
|
8
10
|
module Attributor
|
|
@@ -24,6 +26,7 @@ module MIME
|
|
|
24
26
|
end
|
|
25
27
|
|
|
26
28
|
module Praxis
|
|
29
|
+
|
|
27
30
|
autoload :ActionDefinition, 'praxis/action_definition'
|
|
28
31
|
autoload :ApiDefinition, 'praxis/api_definition'
|
|
29
32
|
autoload :Application, 'praxis/application'
|
|
@@ -32,9 +35,11 @@ module Praxis
|
|
|
32
35
|
autoload :Controller, 'praxis/controller'
|
|
33
36
|
autoload :Callbacks, 'praxis/callbacks'
|
|
34
37
|
autoload :Dispatcher, 'praxis/dispatcher'
|
|
38
|
+
autoload :ErrorHandler, 'praxis/error_handler'
|
|
35
39
|
autoload :Exception, 'praxis/exception'
|
|
36
40
|
autoload :FileGroup,'praxis/file_group'
|
|
37
41
|
autoload :Plugin, 'praxis/plugin'
|
|
42
|
+
autoload :PluginConcern, 'praxis/plugin_concern'
|
|
38
43
|
autoload :Request, 'praxis/request'
|
|
39
44
|
autoload :ResourceDefinition, 'praxis/resource_definition'
|
|
40
45
|
autoload :Response, 'praxis/response'
|
|
@@ -46,6 +51,11 @@ module Praxis
|
|
|
46
51
|
autoload :Stage, 'praxis/stage'
|
|
47
52
|
autoload :ContentTypeParser, 'praxis/content_type_parser'
|
|
48
53
|
|
|
54
|
+
autoload :Stats, 'praxis/stats'
|
|
55
|
+
autoload :Notifications, 'praxis/notifications'
|
|
56
|
+
|
|
57
|
+
autoload :RestfulDocGenerator, 'praxis/restful_doc_generator'
|
|
58
|
+
|
|
49
59
|
# types
|
|
50
60
|
autoload :Links, 'praxis/links'
|
|
51
61
|
autoload :MediaType, 'praxis/media_type'
|
|
@@ -79,6 +89,12 @@ module Praxis
|
|
|
79
89
|
module BootloaderStages
|
|
80
90
|
autoload :FileLoader, 'praxis/bootloader_stages/file_loader'
|
|
81
91
|
autoload :Environment, 'praxis/bootloader_stages/environment'
|
|
92
|
+
|
|
93
|
+
autoload :PluginLoader, 'praxis/bootloader_stages/plugin_loader'
|
|
94
|
+
autoload :PluginConfigPrepare, 'praxis/bootloader_stages/plugin_config_prepare'
|
|
95
|
+
autoload :PluginConfigLoad, 'praxis/bootloader_stages/plugin_config_load'
|
|
96
|
+
autoload :PluginSetup, 'praxis/bootloader_stages/plugin_setup'
|
|
97
|
+
|
|
82
98
|
autoload :SubgroupLoader, 'praxis/bootloader_stages/subgroup_loader'
|
|
83
99
|
autoload :WarnUnloadedFiles, 'praxis/bootloader_stages/warn_unloaded_files'
|
|
84
100
|
autoload :Routing, 'praxis/bootloader_stages/routing'
|
|
@@ -16,6 +16,16 @@ module Praxis
|
|
|
16
16
|
attr_reader :named_routes
|
|
17
17
|
attr_reader :responses
|
|
18
18
|
|
|
19
|
+
class << self
|
|
20
|
+
attr_accessor :doc_decorations
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
@doc_decorations = []
|
|
24
|
+
|
|
25
|
+
def self.decorate_docs(&callback)
|
|
26
|
+
self.doc_decorations << callback
|
|
27
|
+
end
|
|
28
|
+
|
|
19
29
|
def initialize(name, resource_definition, **opts, &block)
|
|
20
30
|
@name = name
|
|
21
31
|
@resource_definition = resource_definition
|
|
@@ -27,23 +37,8 @@ module Praxis
|
|
|
27
37
|
end
|
|
28
38
|
end
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
params(saved_type, saved_opts, &saved_block)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
if resource_definition.payload
|
|
36
|
-
saved_type, saved_opts, saved_block = resource_definition.payload
|
|
37
|
-
payload(saved_type, saved_opts, &saved_block)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
if resource_definition.headers
|
|
41
|
-
saved_opts, saved_block = resource_definition.headers
|
|
42
|
-
headers(saved_opts, &saved_block)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
resource_definition.responses.each do |name, args|
|
|
46
|
-
response(name, args)
|
|
40
|
+
resource_definition.action_defaults.each do |defaults|
|
|
41
|
+
self.instance_eval(&defaults)
|
|
47
42
|
end
|
|
48
43
|
|
|
49
44
|
self.instance_eval(&block) if block_given?
|
|
@@ -141,13 +136,13 @@ module Praxis
|
|
|
141
136
|
end
|
|
142
137
|
end
|
|
143
138
|
|
|
139
|
+
|
|
144
140
|
def description(text = nil)
|
|
145
141
|
@description = text if text
|
|
146
142
|
@description
|
|
147
143
|
end
|
|
148
144
|
|
|
149
145
|
|
|
150
|
-
|
|
151
146
|
def describe
|
|
152
147
|
{}.tap do |hash|
|
|
153
148
|
hash[:description] = description
|
|
@@ -161,6 +156,9 @@ module Praxis
|
|
|
161
156
|
memo[response.name] = response.describe
|
|
162
157
|
memo
|
|
163
158
|
end
|
|
159
|
+
self.class.doc_decorations.each do |callback|
|
|
160
|
+
callback.call(self, hash)
|
|
161
|
+
end
|
|
164
162
|
end
|
|
165
163
|
end
|
|
166
164
|
|
data/lib/praxis/application.rb
CHANGED
|
@@ -9,6 +9,8 @@ module Praxis
|
|
|
9
9
|
attr_reader :router
|
|
10
10
|
attr_reader :controllers
|
|
11
11
|
attr_reader :resource_definitions
|
|
12
|
+
attr_reader :app
|
|
13
|
+
attr_reader :builder
|
|
12
14
|
|
|
13
15
|
attr_accessor :bootloader
|
|
14
16
|
attr_accessor :file_layout
|
|
@@ -16,6 +18,8 @@ module Praxis
|
|
|
16
18
|
attr_accessor :logger
|
|
17
19
|
attr_accessor :plugins
|
|
18
20
|
attr_accessor :root
|
|
21
|
+
attr_accessor :error_handler
|
|
22
|
+
|
|
19
23
|
|
|
20
24
|
def self.configure
|
|
21
25
|
yield(self.instance)
|
|
@@ -25,11 +29,16 @@ module Praxis
|
|
|
25
29
|
@controllers = Set.new
|
|
26
30
|
@resource_definitions = Set.new
|
|
27
31
|
|
|
32
|
+
@error_handler = ErrorHandler.new
|
|
33
|
+
|
|
28
34
|
@router = Router.new(self)
|
|
29
35
|
|
|
36
|
+
@builder = Rack::Builder.new
|
|
37
|
+
@app = nil
|
|
38
|
+
|
|
30
39
|
@bootloader = Bootloader.new(self)
|
|
31
40
|
@file_layout = nil
|
|
32
|
-
@plugins =
|
|
41
|
+
@plugins = Hash.new
|
|
33
42
|
@loaded_files = Set.new
|
|
34
43
|
@config = Config.new
|
|
35
44
|
@root = nil
|
|
@@ -40,11 +49,30 @@ module Praxis
|
|
|
40
49
|
@root = Pathname.new(root).expand_path
|
|
41
50
|
|
|
42
51
|
@bootloader.setup!
|
|
52
|
+
|
|
53
|
+
@builder.run(@router)
|
|
54
|
+
@app = @builder.to_app
|
|
55
|
+
|
|
56
|
+
Notifications.subscribe 'rack.request.all'.freeze do |name, start, finish, _id, payload|
|
|
57
|
+
duration = (finish - start) * 1000
|
|
58
|
+
Stats.timing(name, duration)
|
|
59
|
+
|
|
60
|
+
status, _, _ = payload[:response]
|
|
61
|
+
Stats.increment "rack.request.#{status}"
|
|
62
|
+
end
|
|
63
|
+
|
|
43
64
|
self
|
|
44
65
|
end
|
|
45
66
|
|
|
67
|
+
def middleware(middleware, *args, &block)
|
|
68
|
+
@builder.use(middleware, *args, &block)
|
|
69
|
+
end
|
|
70
|
+
|
|
46
71
|
def call(env)
|
|
47
|
-
|
|
72
|
+
response = []
|
|
73
|
+
Notifications.instrument 'rack.request.all'.freeze, response: response do
|
|
74
|
+
response.push(*@app.call(env))
|
|
75
|
+
end
|
|
48
76
|
end
|
|
49
77
|
|
|
50
78
|
def layout(&block)
|
|
@@ -62,5 +90,6 @@ module Praxis
|
|
|
62
90
|
def config=(config)
|
|
63
91
|
@config.set(config)
|
|
64
92
|
end
|
|
93
|
+
|
|
65
94
|
end
|
|
66
95
|
end
|
data/lib/praxis/bootloader.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
module Praxis
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
class Bootloader
|
|
5
4
|
|
|
6
|
-
attr_reader :application
|
|
5
|
+
attr_reader :application
|
|
6
|
+
attr_reader :stages
|
|
7
7
|
|
|
8
8
|
def initialize(application)
|
|
9
9
|
@application = application
|
|
@@ -24,6 +24,9 @@ module Praxis
|
|
|
24
24
|
# Require environment first. they define constants and environment specific settings
|
|
25
25
|
stages << BootloaderStages::Environment.new(:environment, application)
|
|
26
26
|
|
|
27
|
+
# then setup plugins
|
|
28
|
+
stages << BootloaderStages::PluginLoader.new(:plugins, application)
|
|
29
|
+
|
|
27
30
|
# then the initializers. as it is their job to ensure monkey patches and other
|
|
28
31
|
# config is in place first.
|
|
29
32
|
stages << BootloaderStages::FileLoader.new(:initializers, application)
|
|
@@ -71,11 +74,41 @@ module Praxis
|
|
|
71
74
|
stages.find { |stage| stage.name == stage_name }.after(*stage_path, &block)
|
|
72
75
|
end
|
|
73
76
|
|
|
74
|
-
def use(plugin
|
|
75
|
-
|
|
77
|
+
def use(plugin,**options, &block)
|
|
78
|
+
if plugin.ancestors.include?(PluginConcern)
|
|
79
|
+
plugin.setup!
|
|
80
|
+
plugin = plugin::Plugin
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
instance = if plugin.ancestors.include?(Singleton)
|
|
84
|
+
plugin.instance
|
|
85
|
+
elsif plugin.kind_of?(Class)
|
|
86
|
+
plugin.new
|
|
87
|
+
else
|
|
88
|
+
plugin
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
instance.application = application
|
|
92
|
+
instance.options.merge!(options)
|
|
93
|
+
instance.block = block if block_given?
|
|
94
|
+
|
|
95
|
+
if application.plugins.key?(instance.config_key)
|
|
96
|
+
raise "Can not use plugin: #{plugin}, another plugin is already registered with key: #{instance.config_key}"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
if instance.config_key.nil?
|
|
100
|
+
raise "Error initializing plugin: #{plugin}, config_key may not be nil."
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
application.plugins[instance.config_key] = instance
|
|
104
|
+
instance
|
|
76
105
|
end
|
|
77
106
|
|
|
78
107
|
def setup!
|
|
108
|
+
# use the Stats and Notifications plugins by default
|
|
109
|
+
use Praxis::Stats
|
|
110
|
+
use Praxis::Notifications
|
|
111
|
+
|
|
79
112
|
run
|
|
80
113
|
end
|
|
81
114
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
module Praxis
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
module BootloaderStages
|
|
5
4
|
|
|
6
5
|
class Environment < Stage
|
|
@@ -9,18 +8,14 @@ module Praxis
|
|
|
9
8
|
# 1) the environment.rb file - generic stuff for all environments
|
|
10
9
|
# 2) "Deployer.environment".rb - environment specific stuff
|
|
11
10
|
def execute
|
|
11
|
+
setup_initial_config!
|
|
12
|
+
|
|
12
13
|
env_file = application.root + "config/environment.rb"
|
|
13
14
|
require env_file if File.exists? env_file
|
|
14
15
|
|
|
15
|
-
application.plugins.each do |plugin|
|
|
16
|
-
plugin.setup!
|
|
17
|
-
end
|
|
18
|
-
|
|
19
16
|
unless application.file_layout
|
|
20
17
|
setup_default_layout!
|
|
21
18
|
end
|
|
22
|
-
|
|
23
|
-
setup_initial_config!
|
|
24
19
|
end
|
|
25
20
|
|
|
26
21
|
def setup_default_layout!
|
|
@@ -47,6 +42,7 @@ module Praxis
|
|
|
47
42
|
application.config do
|
|
48
43
|
attribute :praxis do
|
|
49
44
|
attribute :validate_responses, Attributor::Boolean, default: false
|
|
45
|
+
attribute :show_exceptions, Attributor::Boolean, default: false
|
|
50
46
|
end
|
|
51
47
|
end
|
|
52
48
|
end
|