deas 0.36.0 → 0.37.0
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.
- data/lib/deas/error_handler.rb +46 -15
- data/lib/deas/handler_proxy.rb +22 -14
- data/lib/deas/logging.rb +2 -2
- data/lib/deas/route.rb +4 -3
- data/lib/deas/server.rb +182 -166
- data/lib/deas/server_data.rb +22 -0
- data/lib/deas/sinatra_app.rb +40 -19
- data/lib/deas/version.rb +1 -1
- data/test/support/factory.rb +25 -0
- data/test/support/fake_sinatra_call.rb +3 -8
- data/test/support/routes.rb +3 -3
- data/test/unit/error_handler_tests.rb +112 -63
- data/test/unit/handler_proxy_tests.rb +32 -29
- data/test/unit/logging_tests.rb +1 -3
- data/test/unit/route_tests.rb +9 -7
- data/test/unit/server_data_tests.rb +43 -0
- data/test/unit/server_tests.rb +144 -0
- data/test/unit/sinatra_app_tests.rb +19 -13
- data/test/unit/sinatra_runner_tests.rb +1 -2
- metadata +114 -88
- checksums.yaml +0 -7
- data/test/unit/server_configuration_tests.rb +0 -154
data/lib/deas/error_handler.rb
CHANGED
@@ -6,28 +6,59 @@ module Deas
|
|
6
6
|
self.new(*args).run
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
@exception = exception
|
11
|
-
@sinatra_call = sinatra_call
|
9
|
+
attr_reader :exception, :context, :error_procs
|
12
10
|
|
13
|
-
|
11
|
+
def initialize(exception, context_hash)
|
12
|
+
@exception = exception
|
13
|
+
@context = Context.new(context_hash)
|
14
|
+
@error_procs = context_hash[:server_data].error_procs.reverse
|
14
15
|
end
|
15
16
|
|
17
|
+
# The exception that we are generating a response for can change in the case
|
18
|
+
# that the configured error proc raises an exception. If this occurs, a
|
19
|
+
# response will be generated for that exception, instead of the original
|
20
|
+
# one. This is designed to avoid "hidden" errors happening, this way the
|
21
|
+
# server will respond and log based on the last exception that occurred.
|
22
|
+
|
16
23
|
def run
|
17
|
-
response
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
response = result if result
|
22
|
-
rescue Exception => proc_exception
|
24
|
+
@error_procs.inject(nil) do |response, error_proc|
|
25
|
+
result = begin
|
26
|
+
error_proc.call(@exception, @context)
|
27
|
+
rescue StandardError => proc_exception
|
23
28
|
@exception = proc_exception
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
29
|
+
response = nil # reset response
|
30
|
+
end
|
31
|
+
response || result
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Context
|
36
|
+
|
37
|
+
attr_reader :server_data
|
38
|
+
attr_reader :request, :response, :handler_class, :handler, :params
|
39
|
+
|
40
|
+
def initialize(args)
|
41
|
+
@server_data = args[:server_data]
|
42
|
+
@request = args[:request]
|
43
|
+
@response = args[:response]
|
44
|
+
@handler_class = args[:handler_class]
|
45
|
+
@handler = args[:handler]
|
46
|
+
@params = args[:params]
|
47
|
+
end
|
48
|
+
|
49
|
+
def ==(other)
|
50
|
+
if other.kind_of?(self.class)
|
51
|
+
self.server_data == other.server_data &&
|
52
|
+
self.handler_class == other.handler_class &&
|
53
|
+
self.request == other.request &&
|
54
|
+
self.response == other.response &&
|
55
|
+
self.handler == other.handler &&
|
56
|
+
self.params == other.params
|
57
|
+
else
|
58
|
+
super
|
28
59
|
end
|
29
60
|
end
|
30
|
-
|
61
|
+
|
31
62
|
end
|
32
63
|
|
33
64
|
end
|
data/lib/deas/handler_proxy.rb
CHANGED
@@ -15,24 +15,32 @@ module Deas
|
|
15
15
|
raise NotImplementedError
|
16
16
|
end
|
17
17
|
|
18
|
-
def run(sinatra_call)
|
18
|
+
def run(server_data, sinatra_call)
|
19
19
|
runner = SinatraRunner.new(self.handler_class, {
|
20
|
-
:sinatra_call
|
21
|
-
:request
|
22
|
-
:response
|
23
|
-
:session
|
24
|
-
:params
|
25
|
-
:logger
|
26
|
-
:router
|
27
|
-
:template_source =>
|
20
|
+
:sinatra_call => sinatra_call,
|
21
|
+
:request => sinatra_call.request,
|
22
|
+
:response => sinatra_call.response,
|
23
|
+
:session => sinatra_call.session,
|
24
|
+
:params => sinatra_call.params,
|
25
|
+
:logger => server_data.logger,
|
26
|
+
:router => server_data.router,
|
27
|
+
:template_source => server_data.template_source
|
28
28
|
})
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
30
|
+
runner.request.env.tap do |env|
|
31
|
+
# make runner data available to Rack (ie middlewares)
|
32
|
+
# this is specifically needed by the Logging middleware
|
33
|
+
# this is also needed by the Sinatra error handlers so they can provide
|
34
|
+
# error context. This may change when we eventually remove Sinatra.
|
35
|
+
env['deas.handler_class'] = self.handler_class
|
36
|
+
env['deas.handler'] = runner.handler
|
37
|
+
env['deas.params'] = runner.params
|
38
|
+
|
39
|
+
# this handles the verbose logging (it is a no-op if summary logging)
|
40
|
+
env['deas.logging'].call " Handler: #{self.handler_class.name}"
|
41
|
+
env['deas.logging'].call " Params: #{runner.params.inspect}"
|
35
42
|
end
|
43
|
+
|
36
44
|
runner.run
|
37
45
|
end
|
38
46
|
|
data/lib/deas/logging.rb
CHANGED
@@ -13,7 +13,7 @@ module Deas
|
|
13
13
|
|
14
14
|
def initialize(app)
|
15
15
|
@app = app
|
16
|
-
@logger = @app.settings.logger
|
16
|
+
@logger = @app.settings.deas_server_data.logger
|
17
17
|
end
|
18
18
|
|
19
19
|
# The Rack call interface. The receiver acts as a prototype and runs
|
@@ -101,7 +101,7 @@ module Deas
|
|
101
101
|
line_attrs = {
|
102
102
|
'method' => request.request_method,
|
103
103
|
'path' => request.path,
|
104
|
-
'handler' => env['deas.
|
104
|
+
'handler' => env['deas.handler_class'].name,
|
105
105
|
'params' => env['deas.params'],
|
106
106
|
'time' => env['deas.time_taken'],
|
107
107
|
'status' => status
|
data/lib/deas/route.rb
CHANGED
@@ -16,14 +16,15 @@ module Deas
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def run(sinatra_call)
|
20
|
-
type =
|
19
|
+
def run(server_data, sinatra_call)
|
20
|
+
type = server_data.router.request_type_name(sinatra_call.request)
|
21
21
|
proxy = begin
|
22
22
|
@handler_proxies[type]
|
23
23
|
rescue HandlerProxyNotFound
|
24
24
|
sinatra_call.halt(404)
|
25
25
|
end
|
26
|
-
|
26
|
+
# TODO: eventually stop sending sinatra call (part of phasing out Sinatra)
|
27
|
+
proxy.run(server_data, sinatra_call)
|
27
28
|
end
|
28
29
|
|
29
30
|
end
|
data/lib/deas/server.rb
CHANGED
@@ -9,220 +9,236 @@ require 'deas/show_exceptions'
|
|
9
9
|
require 'deas/sinatra_app'
|
10
10
|
require 'deas/template_source'
|
11
11
|
|
12
|
-
module Deas
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
option :root, Pathname, :required => true
|
23
|
-
option :public_root, Pathname
|
24
|
-
option :views_root, Pathname
|
25
|
-
|
26
|
-
option :dump_errors, NsOptions::Boolean, :default => false
|
27
|
-
option :method_override, NsOptions::Boolean, :default => true
|
28
|
-
option :sessions, NsOptions::Boolean, :default => false
|
29
|
-
option :show_exceptions, NsOptions::Boolean, :default => false
|
30
|
-
option :static_files, NsOptions::Boolean, :default => true
|
31
|
-
option :reload_templates, NsOptions::Boolean, :default => false
|
32
|
-
option :default_encoding, String, :default => 'utf-8'
|
33
|
-
|
34
|
-
# server handling options
|
35
|
-
|
36
|
-
option :verbose_logging, NsOptions::Boolean, :default => true
|
37
|
-
option :logger, :default => proc{ Deas::NullLogger.new }
|
38
|
-
option :template_source, :default => proc{ Deas::NullTemplateSource.new }
|
39
|
-
|
40
|
-
attr_accessor :settings, :error_procs, :init_procs, :template_helpers
|
41
|
-
attr_accessor :middlewares, :router
|
42
|
-
|
43
|
-
def initialize(values = nil)
|
44
|
-
# these are defaulted here because we want to use the Configuration
|
45
|
-
# instance `root`. If we define a proc above, we will be using the
|
46
|
-
# Configuration class `root`, which will not update these options as
|
47
|
-
# expected.
|
48
|
-
super((values || {}).merge({
|
49
|
-
:public_root => proc{ self.root.join('public') },
|
50
|
-
:views_root => proc{ self.root.join('views') }
|
51
|
-
}))
|
52
|
-
@settings = {}
|
53
|
-
@error_procs, @init_procs, @template_helpers, @middlewares = [], [], [], []
|
54
|
-
@router = Deas::Router.new
|
55
|
-
@valid = nil
|
12
|
+
module Deas
|
13
|
+
|
14
|
+
module Server
|
15
|
+
|
16
|
+
def self.included(receiver)
|
17
|
+
receiver.class_eval do
|
18
|
+
extend ClassMethods
|
19
|
+
include InstanceMethods
|
20
|
+
end
|
56
21
|
end
|
57
22
|
|
58
|
-
|
59
|
-
|
23
|
+
module InstanceMethods
|
24
|
+
# TODO: once Deas is no longer powered by Sinatra, this should define an
|
25
|
+
# `initialize` method that builds a server instance. Right now there is
|
26
|
+
# a `new` class method that builds a SinatraApp which does this init
|
27
|
+
# behavior
|
60
28
|
end
|
61
29
|
|
62
|
-
|
63
|
-
# key here is that this only needs to be done _once_ for each config.
|
30
|
+
module ClassMethods
|
64
31
|
|
65
|
-
|
66
|
-
|
32
|
+
# TODO: needed while Deas is powered by Sinatra
|
33
|
+
# eventually do an initialize method more like Sanford does
|
34
|
+
def new
|
35
|
+
Deas::SinatraApp.new(self.configuration)
|
36
|
+
end
|
67
37
|
|
68
|
-
|
69
|
-
|
70
|
-
|
38
|
+
def configuration
|
39
|
+
@configuration ||= Configuration.new
|
40
|
+
end
|
71
41
|
|
72
|
-
#
|
73
|
-
self.routes.each(&:validate!)
|
42
|
+
# sinatra settings DSL
|
74
43
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
self.settings[:erb] ||= {}
|
79
|
-
self.settings[:erb][:outvar] ||= '@_out_buf'
|
44
|
+
def env(*args)
|
45
|
+
self.configuration.env *args
|
46
|
+
end
|
80
47
|
|
81
|
-
|
82
|
-
|
83
|
-
# the request and just after the app sends a response.
|
84
|
-
self.middlewares << [Deas::ShowExceptions] if self.show_exceptions
|
85
|
-
[*Deas::Logging.middleware(self.verbose_logging)].tap do |mw_args|
|
86
|
-
self.middlewares << mw_args
|
48
|
+
def root(*args)
|
49
|
+
self.configuration.root *args
|
87
50
|
end
|
88
51
|
|
89
|
-
|
90
|
-
|
52
|
+
def public_root(*args)
|
53
|
+
self.configuration.public_root *args
|
54
|
+
end
|
91
55
|
|
92
|
-
|
93
|
-
|
94
|
-
|
56
|
+
def views_root(*args)
|
57
|
+
self.configuration.views_root *args
|
58
|
+
end
|
95
59
|
|
96
|
-
|
97
|
-
|
98
|
-
|
60
|
+
def dump_errors(*args)
|
61
|
+
self.configuration.dump_errors *args
|
62
|
+
end
|
99
63
|
|
100
|
-
|
64
|
+
def method_override(*args)
|
65
|
+
self.configuration.method_override *args
|
66
|
+
end
|
101
67
|
|
102
|
-
|
103
|
-
|
104
|
-
|
68
|
+
def sessions(*args)
|
69
|
+
self.configuration.sessions *args
|
70
|
+
end
|
105
71
|
|
106
|
-
|
72
|
+
def show_exceptions(*args)
|
73
|
+
self.configuration.show_exceptions *args
|
74
|
+
end
|
107
75
|
|
108
|
-
|
109
|
-
|
110
|
-
|
76
|
+
def static_files(*args)
|
77
|
+
self.configuration.static_files *args
|
78
|
+
end
|
111
79
|
|
112
|
-
|
113
|
-
|
114
|
-
|
80
|
+
def reload_templates(*args)
|
81
|
+
self.configuration.reload_templates *args
|
82
|
+
end
|
115
83
|
|
116
|
-
|
84
|
+
# Server handling DSL
|
117
85
|
|
118
|
-
|
119
|
-
|
120
|
-
|
86
|
+
def init(&block)
|
87
|
+
self.configuration.init_procs << block
|
88
|
+
end
|
121
89
|
|
122
|
-
|
123
|
-
|
124
|
-
|
90
|
+
def error(&block)
|
91
|
+
self.configuration.error_procs << block
|
92
|
+
end
|
125
93
|
|
126
|
-
|
127
|
-
|
128
|
-
|
94
|
+
def template_helpers(*helper_modules)
|
95
|
+
helper_modules.each{ |m| self.configuration.template_helpers << m }
|
96
|
+
self.configuration.template_helpers
|
97
|
+
end
|
129
98
|
|
130
|
-
|
131
|
-
|
132
|
-
|
99
|
+
def template_helper?(helper_module)
|
100
|
+
self.configuration.template_helpers.include?(helper_module)
|
101
|
+
end
|
133
102
|
|
134
|
-
|
135
|
-
|
136
|
-
|
103
|
+
def use(*args)
|
104
|
+
self.configuration.middlewares << args
|
105
|
+
end
|
137
106
|
|
138
|
-
|
139
|
-
|
140
|
-
|
107
|
+
def set(name, value)
|
108
|
+
self.configuration.settings[name.to_sym] = value
|
109
|
+
end
|
141
110
|
|
142
|
-
|
143
|
-
|
144
|
-
|
111
|
+
def verbose_logging(*args)
|
112
|
+
self.configuration.verbose_logging *args
|
113
|
+
end
|
145
114
|
|
146
|
-
|
147
|
-
|
148
|
-
|
115
|
+
def logger(*args)
|
116
|
+
self.configuration.logger *args
|
117
|
+
end
|
149
118
|
|
150
|
-
|
151
|
-
|
152
|
-
|
119
|
+
def default_encoding(*args)
|
120
|
+
self.configuration.default_encoding *args
|
121
|
+
end
|
153
122
|
|
154
|
-
|
155
|
-
|
156
|
-
|
123
|
+
def template_source(*args)
|
124
|
+
self.configuration.template_source *args
|
125
|
+
end
|
157
126
|
|
158
|
-
|
127
|
+
# router handling
|
159
128
|
|
160
|
-
|
161
|
-
|
162
|
-
|
129
|
+
def router(value = nil)
|
130
|
+
self.configuration.router = value if !value.nil?
|
131
|
+
self.configuration.router
|
132
|
+
end
|
163
133
|
|
164
|
-
|
165
|
-
self.
|
166
|
-
end
|
134
|
+
def view_handler_ns(*args); self.router.view_handler_ns(*args); end
|
135
|
+
def base_url(*args); self.router.base_url(*args); end
|
167
136
|
|
168
|
-
|
169
|
-
|
170
|
-
self.configuration.template_helpers
|
171
|
-
end
|
137
|
+
def url(*args, &block); self.router.url(*args, &block); end
|
138
|
+
def url_for(*args, &block); self.router.url_for(*args, &block); end
|
172
139
|
|
173
|
-
|
174
|
-
self.
|
175
|
-
|
140
|
+
def default_request_type_name(*args); self.router.default_request_type_name(*args); end
|
141
|
+
def add_request_type(*args, &block); self.router.add_request_type(*args, &block); end
|
142
|
+
def request_type_name(*args); self.router.request_type_name(*args); end
|
176
143
|
|
177
|
-
|
178
|
-
self.
|
179
|
-
end
|
144
|
+
def get(*args, &block); self.router.get(*args, &block); end
|
145
|
+
def post(*args, &block); self.router.post(*args, &block); end
|
146
|
+
def put(*args, &block); self.router.put(*args, &block); end
|
147
|
+
def patch(*args, &block); self.router.patch(*args, &block); end
|
148
|
+
def delete(*args, &block); self.router.delete(*args, &block); end
|
180
149
|
|
181
|
-
|
182
|
-
self.
|
183
|
-
end
|
150
|
+
def route(*args, &block); self.router.route(*args, &block); end
|
151
|
+
def redirect(*args, &block); self.router.redirect(*args, &block); end
|
184
152
|
|
185
|
-
def verbose_logging(*args)
|
186
|
-
self.configuration.verbose_logging *args
|
187
153
|
end
|
188
154
|
|
189
|
-
|
190
|
-
|
191
|
-
end
|
155
|
+
class Configuration
|
156
|
+
include NsOptions::Proxy
|
192
157
|
|
193
|
-
|
194
|
-
self.configuration.default_encoding *args
|
195
|
-
end
|
158
|
+
# Sinatra-based options
|
196
159
|
|
197
|
-
|
198
|
-
self.configuration.template_source *args
|
199
|
-
end
|
160
|
+
option :env, String, :default => 'development'
|
200
161
|
|
201
|
-
|
162
|
+
option :root, Pathname, :required => true
|
163
|
+
option :public_root, Pathname
|
164
|
+
option :views_root, Pathname
|
202
165
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
166
|
+
option :dump_errors, NsOptions::Boolean, :default => false
|
167
|
+
option :method_override, NsOptions::Boolean, :default => true
|
168
|
+
option :sessions, NsOptions::Boolean, :default => false
|
169
|
+
option :show_exceptions, NsOptions::Boolean, :default => false
|
170
|
+
option :static_files, NsOptions::Boolean, :default => true
|
171
|
+
option :reload_templates, NsOptions::Boolean, :default => false
|
172
|
+
option :default_encoding, String, :default => 'utf-8'
|
207
173
|
|
208
|
-
|
209
|
-
def base_url(*args); self.router.base_url(*args); end
|
174
|
+
# server handling options
|
210
175
|
|
211
|
-
|
212
|
-
|
176
|
+
option :verbose_logging, NsOptions::Boolean, :default => true
|
177
|
+
option :logger, :default => proc{ Deas::NullLogger.new }
|
178
|
+
option :template_source, :default => proc{ Deas::NullTemplateSource.new }
|
213
179
|
|
214
|
-
|
215
|
-
|
216
|
-
def request_type_name(*args); self.router.request_type_name(*args); end
|
180
|
+
attr_accessor :settings, :init_procs, :error_procs, :template_helpers
|
181
|
+
attr_accessor :middlewares, :router
|
217
182
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
183
|
+
def initialize(values = nil)
|
184
|
+
# these are defaulted here because we want to use the Configuration
|
185
|
+
# instance `root`. If we define a proc above, we will be using the
|
186
|
+
# Configuration class `root`, which will not update these options as
|
187
|
+
# expected.
|
188
|
+
super((values || {}).merge({
|
189
|
+
:public_root => proc{ self.root.join('public') },
|
190
|
+
:views_root => proc{ self.root.join('views') }
|
191
|
+
}))
|
192
|
+
@settings = {}
|
193
|
+
@init_procs, @error_procs, @template_helpers, @middlewares = [], [], [], []
|
194
|
+
@router = Deas::Router.new
|
195
|
+
@valid = nil
|
196
|
+
end
|
197
|
+
|
198
|
+
def urls
|
199
|
+
self.router.urls
|
200
|
+
end
|
201
|
+
|
202
|
+
def routes
|
203
|
+
self.router.routes
|
204
|
+
end
|
205
|
+
|
206
|
+
def to_hash
|
207
|
+
super.merge({
|
208
|
+
:error_procs => self.error_procs,
|
209
|
+
:router => self.router
|
210
|
+
})
|
211
|
+
end
|
212
|
+
|
213
|
+
def valid?
|
214
|
+
!!@valid
|
215
|
+
end
|
223
216
|
|
224
|
-
|
225
|
-
|
217
|
+
# for the config to be considered "valid", a few things need to happen. The
|
218
|
+
# key here is that this only needs to be done _once_ for each config.
|
219
|
+
|
220
|
+
def validate!
|
221
|
+
return @valid if !@valid.nil? # only need to run this once per config
|
222
|
+
|
223
|
+
# ensure all user and plugin configs/settings are applied
|
224
|
+
self.init_procs.each{ |p| p.call }
|
225
|
+
raise Deas::ServerRootError if self.root.nil?
|
226
|
+
|
227
|
+
# validate the routes
|
228
|
+
self.routes.each(&:validate!)
|
229
|
+
|
230
|
+
# append the show exceptions and logging middlewares last. This ensures
|
231
|
+
# that the logging and exception showing happens just before the app gets
|
232
|
+
# the request and just after the app sends a response.
|
233
|
+
self.middlewares << [Deas::ShowExceptions] if self.show_exceptions
|
234
|
+
[*Deas::Logging.middleware(self.verbose_logging)].tap do |mw_args|
|
235
|
+
self.middlewares << mw_args
|
236
|
+
end
|
237
|
+
|
238
|
+
@valid = true # if it made it this far, its valid!
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
226
242
|
|
227
243
|
end
|
228
244
|
|