class Angelo::Base
Attributes
app_file[RW]
server[RW]
request_body[W]
responder[RW]
Public Class Methods
filter(which, opts = {})
click to toggle source
# 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)
click to toggle source
# File lib/angelo/base.rb, line 174 def filter_by which, path, block pattern = ::Mustermann.new path filters[which][pattern] << block end
filters()
click to toggle source
# 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)
click to toggle source
# File lib/angelo/base.rb, line 109 def inherited subclass # Set app_file by groveling up the caller stack until we find # the first caller from a directory different from __FILE__. # This allows base.rb to be required from an arbitrarily deep # nesting of require "angelo/<whatever>" and still set # app_file correctly. # subclass.app_file = caller_locations.map(&:absolute_path).find do |f| !f.start_with?(File.dirname(__FILE__) + File::SEPARATOR) end # bring RequestError into this namespace # 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 # Parse command line options if angelo/main has been required. # They could also be parsed in run, but this makes them # available to and overridable by the DSL. # subclass.parse_options(ARGV.dup) if @angelo_main end
local_path(path)
click to toggle source
# 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
new(responder)
click to toggle source
# File lib/angelo/base.rb, line 228 def initialize responder @responder = responder @klass = self.class end
parse_options(argv)
click to toggle source
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.
# 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?()
click to toggle source
# File lib/angelo/base.rb, line 146 def report_errors? !!@report_errors end
root()
click to toggle source
# File lib/angelo/base.rb, line 142 def root @root ||= File.expand_path '..', app_file end
routes()
click to toggle source
# 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 = {})
click to toggle source
# 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 = {})
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# File lib/angelo/base.rb, line 179 def websockets reject = true @websockets ||= Stash::Websocket.new server @websockets.reject! &:closed? if reject @websockets end
Public Instance Methods
async(meth, *args)
click to toggle source
# File lib/angelo/base.rb, line 233 def async meth, *args self.class.server.async.__send__ meth, *args end
chunked_response(&block)
click to toggle source
# File lib/angelo/base.rb, line 352 def chunked_response &block transfer_encoding :chunked ChunkedResponse.new &block end
eventsource(&block)
click to toggle source
# File lib/angelo/base.rb, line 342 def eventsource &block headers SSE_HEADER async :handle_event_source, EventSource.new(responder), block halt 200, :sse end
filter(which)
click to toggle source
# 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)
click to toggle source
# File lib/angelo/base.rb, line 237 def future meth, *args self.class.server.future.__send__ meth, *args end
halt(status = 400, body = '')
click to toggle source
# File lib/angelo/base.rb, line 295 def halt status = 400, body = '' throw :halt, HALT_STRUCT.new(status, body) end
params()
click to toggle source
# File lib/angelo/base.rb, line 241 def params @params ||= case request.method when GET, DELETE, OPTIONS parse_query_string when PATCH, POST, PUT parse_query_string_and_post_body end.merge mustermann.params(request.path) end
request_body()
click to toggle source
# File lib/angelo/base.rb, line 261 def request_body @request_body ||= request.body.to_s end
request_headers()
click to toggle source
# File lib/angelo/base.rb, line 250 def request_headers @request_headers ||= Hash.new do |hash, key| if Symbol === key k = key.to_s.upcase k.gsub! UNDERSCORE, DASH _, value = request.headers.find {|header_key,v| header_key.upcase == k} hash[key] = value end end end
send_data(data, opts = {})
click to toggle source
# File lib/angelo/base.rb, line 322 def send_data data, opts = {} # Content-Type # headers CONTENT_TYPE_HEADER_KEY => (MIME::Types.type_for(File.extname(opts[:filename]))[0].content_type rescue HTML_TYPE) # Content-Disposition # if opts[:disposition] == :attachment headers CONTENT_DISPOSITION_HEADER_KEY => ATTACHMENT_CONTENT_DISPOSITION % opts[:filename] end # Content-Length # headers CONTENT_LENGTH_HEADER_KEY => data.length halt 200, data end
send_file(local_file, opts = {})
click to toggle source
# 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 # headers CONTENT_TYPE_HEADER_KEY => (MIME::Types.type_for(File.extname(lp))[0].content_type rescue HTML_TYPE) # Content-Disposition # if opts[:disposition] == :attachment or opts[:filename] headers CONTENT_DISPOSITION_HEADER_KEY => ATTACHMENT_CONTENT_DISPOSITION % (opts[:filename] or File.basename(lp)) end # Content-Length # headers CONTENT_LENGTH_HEADER_KEY => File.size(lp) halt 200, File.read(lp) end
sleep(time)
click to toggle source
# File lib/angelo/base.rb, line 348 def sleep time Celluloid.sleep time end