Class: Angelo::Base
Defined Under Namespace
Modules: DSL
Classes: ChunkedResponse, EventSource, RouteMap
Constant Summary
Constants included
from Tilt::ERB
Tilt::ERB::ACCEPT_ALL, Tilt::ERB::DEFAULT_LAYOUT, Tilt::ERB::DEFAULT_TYPE, Tilt::ERB::LAYOUTS_DIR
Constants included
from Templates
Templates::Tilt
ParamsParser::EMPTY_JSON
Class Attribute Summary collapse
Instance Attribute Summary collapse
Class Method Summary
collapse
-
.filter(which, opts = {}, &block) ⇒ Object
-
.filter_by(which, path, block) ⇒ Object
-
.filters ⇒ Object
-
.inherited(subclass) ⇒ Object
-
.local_path(path) ⇒ Object
-
.parse_options(argv) ⇒ Object
It seems more sensible to put this in main.rb since it’s used only if angelo/main is required, but it’s here so it can be tested, since requiring angelo/main doesn’t play well with the test code.
-
.report_errors? ⇒ Boolean
-
.root ⇒ Object
-
.routes ⇒ Object
-
.run(_addr = addr, _port = port, options = {}, blocking = false) ⇒ Object
-
.run!(_addr = addr, _port = port, options = {}) ⇒ Object
-
.sse_event(event_name, data) ⇒ Object
-
.sse_message(data) ⇒ Object
-
.sses(reject = true) ⇒ Object
-
.websockets(reject = true) ⇒ Object
Instance Method Summary
collapse
Methods included from DSL
addr, after, before, content_type, default_headers, helpers, log_level, on_pong, ping_time, port, public_dir, reload_templates!, report_errors!, task, views_dir, websocket
Methods included from Tilt::ERB
#erb, #template_type
Methods included from Templates
#_erb
#content_type?, #form_encoded?, #json?, #parse_formencoded, #parse_post_body, #parse_query_string, #parse_query_string_and_post_body
Constructor Details
#initialize(responder) ⇒ Base
228
229
230
231
|
# File 'lib/angelo/base.rb', line 228
def initialize responder
@responder = responder
@klass = self.class
end
|
Class Attribute Details
.app_file ⇒ Object
Returns the value of attribute app_file.
107
108
109
|
# File 'lib/angelo/base.rb', line 107
def app_file
@app_file
end
|
.server ⇒ Object
Returns the value of attribute server.
107
108
109
|
# File 'lib/angelo/base.rb', line 107
def server
@server
end
|
Instance Attribute Details
#request_body ⇒ Object
261
262
263
|
# File 'lib/angelo/base.rb', line 261
def request_body
@request_body ||= request.body.to_s
end
|
#responder ⇒ Object
Returns the value of attribute responder.
14
15
16
|
# File 'lib/angelo/base.rb', line 14
def responder
@responder
end
|
Class Method Details
.filter(which, opts = {}, &block) ⇒ Object
161
162
163
164
165
166
167
168
169
170
171
172
|
# File 'lib/angelo/base.rb', line 161
def filter which, opts = {}, &block
case opts
when String, Regexp
filter_by which, opts, block
when Hash
if opts[:path]
filter_by which, opts[:path], block
else
filters[which][:default] << block
end
end
end
|
.filter_by(which, path, block) ⇒ Object
174
175
176
177
|
# File 'lib/angelo/base.rb', line 174
def filter_by which, path, block
pattern = ::Mustermann.new path
filters[which][pattern] << block
end
|
.filters ⇒ Object
154
155
156
157
158
159
|
# File 'lib/angelo/base.rb', line 154
def filters
@filters ||= {
before: Hash.new{|h,k| h[k] = []},
after: Hash.new{|h,k| h[k] = []},
}
end
|
.inherited(subclass) ⇒ Object
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
# File 'lib/angelo/base.rb', line 109
def inherited subclass
subclass.app_file = caller_locations.map(&:absolute_path).find do |f|
!f.start_with?(File.dirname(__FILE__) + File::SEPARATOR)
end
subclass.class_eval 'class RequestError < Angelo::RequestError; end'
subclass.addr DEFAULT_ADDR
subclass.port DEFAULT_PORT
subclass.ping_time DEFAULT_PING_TIME
subclass.log_level DEFAULT_LOG_LEVEL
subclass.views_dir DEFAULT_VIEWS_DIR
subclass.public_dir DEFAULT_PUBLIC_DIR
subclass.parse_options(ARGV.dup) if @angelo_main
end
|
.local_path(path) ⇒ Object
209
210
211
212
213
214
|
# File 'lib/angelo/base.rb', line 209
def local_path path
if public_dir
lp = File.join(public_dir, path)
File.file?(lp) ? lp : nil
end
end
|
.parse_options(argv) ⇒ Object
It seems more sensible to put this in main.rb since it’s used only if angelo/main is required, but it’s here so it can be tested, since requiring angelo/main doesn’t play well with the test code.
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
|
# File 'lib/angelo/base.rb', line 378
def self.parse_options(argv)
require "optparse"
optparse = OptionParser.new do |op|
op.banner = "Usage: #{$0} [options]"
op.on('-p port', OptionParser::DecimalInteger, "set the port (default is #{port})") {|val| port val}
op.on('-o addr', "set the host (default is #{addr})") {|val| addr val}
op.on('-h', '--help', "Show this help") do
puts op
exit
end
end
begin
optparse.parse(argv)
rescue OptionParser::ParseError => ex
$stderr.puts ex
$stderr.puts optparse
exit 1
end
end
|
.report_errors? ⇒ Boolean
146
147
148
|
# File 'lib/angelo/base.rb', line 146
def report_errors?
!!@report_errors
end
|
.root ⇒ Object
142
143
144
|
# File 'lib/angelo/base.rb', line 142
def root
@root ||= File.expand_path '..', app_file
end
|
.routes ⇒ Object
150
151
152
|
# File 'lib/angelo/base.rb', line 150
def routes
@routes ||= Hash.new{|h,k| h[k] = RouteMap.new}
end
|
.run(_addr = addr, _port = port, options = {}, blocking = false) ⇒ Object
195
196
197
198
199
200
201
202
203
204
205
206
207
|
# File 'lib/angelo/base.rb', line 195
def run _addr = addr, _port = port, options = {}, blocking = false
Celluloid.logger.level = log_level
@server = Angelo::Server.new self, _addr, _port, options
@server.async.ping_websockets
if blocking
trap "INT" do
@server.terminate if @server and @server.alive?
exit
end
sleep
end
@server
end
|
.run!(_addr = addr, _port = port, options = {}) ⇒ Object
191
192
193
|
# File 'lib/angelo/base.rb', line 191
def run! _addr = addr, _port = port, options = {}
run _addr, _port, options, true
end
|
.sse_event(event_name, data) ⇒ Object
216
217
218
219
|
# File 'lib/angelo/base.rb', line 216
def sse_event event_name, data
data = data.to_json if Hash === data
SSE_EVENT_TEMPLATE % [event_name.to_s, data]
end
|
.sse_message(data) ⇒ Object
221
222
223
224
|
# File 'lib/angelo/base.rb', line 221
def sse_message data
data = data.to_json if Hash === data
SSE_DATA_TEMPLATE % data
end
|
.sses(reject = true) ⇒ Object
185
186
187
188
189
|
# File 'lib/angelo/base.rb', line 185
def sses reject = true
@sses ||= Stash::SSE.new server
@sses.reject! &:closed? if reject
@sses
end
|
.websockets(reject = true) ⇒ Object
179
180
181
182
183
|
# File 'lib/angelo/base.rb', line 179
def websockets reject = true
@websockets ||= Stash::Websocket.new server
@websockets.reject! &:closed? if reject
@websockets
end
|
Instance Method Details
#async(meth, *args) ⇒ Object
233
234
235
|
# File 'lib/angelo/base.rb', line 233
def async meth, *args
self.class.server.async.__send__ meth, *args
end
|
#chunked_response(&block) ⇒ Object
352
353
354
355
|
# File 'lib/angelo/base.rb', line 352
def chunked_response &block
transfer_encoding :chunked
ChunkedResponse.new &block
end
|
#eventsource(&block) ⇒ Object
342
343
344
345
346
|
# File 'lib/angelo/base.rb', line 342
def eventsource &block
SSE_HEADER
async :handle_event_source, EventSource.new(responder), block
halt 200, :sse
end
|
#filter(which) ⇒ Object
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
|
# File 'lib/angelo/base.rb', line 357
def filter which
self.class.filters[which].each do |pattern, filters|
case pattern
when :default
filters.each {|filter| instance_eval &filter}
when ::Mustermann
if mustermann_params = pattern.params(request.path)
pre_filter_params = params
@params = pre_filter_params.merge mustermann_params
filters.each {|filter| instance_eval &filter}
@params = pre_filter_params
end
end
end
end
|
#future(meth, *args) ⇒ Object
237
238
239
|
# File 'lib/angelo/base.rb', line 237
def future meth, *args
self.class.server.future.__send__ meth, *args
end
|
#halt(status = 400, body = '') ⇒ Object
295
296
297
|
# File 'lib/angelo/base.rb', line 295
def halt status = 400, body = ''
throw :halt, HALT_STRUCT.new(status, body)
end
|
#params ⇒ Object
241
242
243
244
245
246
247
248
|
# File 'lib/angelo/base.rb', line 241
def params
@params ||= case request.method
when GET, DELETE, OPTIONS
parse_query_string
when POST, PUT
parse_query_string_and_post_body
end.merge mustermann.params(request.path)
end
|
250
251
252
253
254
255
256
257
258
259
|
# File 'lib/angelo/base.rb', line 250
def
@request_headers ||= Hash.new do |hash, key|
if Symbol === key
k = key.to_s.upcase
k.gsub! UNDERSCORE, DASH
_, value = request..find {|,v| .upcase == k}
hash[key] = value
end
end
end
|
#send_data(data, opts = {}) ⇒ Object
#send_file(local_file, opts = {}) ⇒ Object
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
|
# File 'lib/angelo/base.rb', line 299
def send_file local_file, opts = {}
lp = local_file[0] == File::SEPARATOR ? local_file : File.expand_path(File.join(self.class.root, local_file))
halt 404 unless File.exist? lp
CONTENT_TYPE_HEADER_KEY =>
(MIME::Types.type_for(File.extname(lp))[0].content_type rescue HTML_TYPE)
if opts[:disposition] == :attachment or opts[:filename]
CONTENT_DISPOSITION_HEADER_KEY =>
ATTACHMENT_CONTENT_DISPOSITION % (opts[:filename] or File.basename(lp))
end
CONTENT_LENGTH_HEADER_KEY => File.size(lp)
halt 200, File.read(lp)
end
|
#sleep(time) ⇒ Object
348
349
350
|
# File 'lib/angelo/base.rb', line 348
def sleep time
Celluloid.sleep time
end
|