lib/angelo/base.rb in angelo-0.4.1 vs lib/angelo/base.rb in angelo-0.5.0
- old
+ new
@@ -1,112 +1,75 @@
module Angelo
class Base
extend Forwardable
include ParamsParser
- include Celluloid::Logger
+ include Celluloid::Internals::Logger
+ include Templates
include Tilt::ERB
include Mustermann
- def_delegators :@responder, :content_type, :headers, :mustermann, :redirect, :request, :transfer_encoding
+ def_delegators :@responder, :content_type, :headers, :mustermann, :redirect, :redirect!, :request, :transfer_encoding
def_delegators :@klass, :public_dir, :report_errors?, :sse_event, :sse_message, :sses, :websockets
attr_accessor :responder
+ attr_writer :request_body
- class << self
-
- attr_accessor :app_file, :server
-
- 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
-
- # 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
-
- class << subclass
-
- def root
- @root ||= File.expand_path '..', app_file
- end
-
- end
-
- end
- end
-
# Methods defined in module DSL will be available in the DSL both
- # in Angelo::Base subclasses and in the top level DSL.
+ # in Angelo::Base subclasses as class methods and, if angelo/main
+ # is required, in the top level DSL by forwarding to an anonymous
+ # Angelo::Base subclass.
module DSL
def addr a = nil
@addr = a if a
@addr
end
+ def port p = nil
+ @port = p if p
+ @port
+ end
+
def log_level ll = nil
@log_level = ll if ll
@log_level
end
def ping_time pt = nil
@ping_time = pt if pt
@ping_time
end
- def port p = nil
- @port = p if p
- @port
- end
-
def views_dir d = nil
@views_dir = d if d
- @views_dir ||= DEFAULT_VIEWS_DIR
File.join root, @views_dir
end
+ def reload_templates!(on = true)
+ @reload_templates = on
+ end
+
def public_dir d = nil
@public_dir = d if d
- @public_dir ||= DEFAULT_PUBLIC_DIR
File.join root, @public_dir
end
def report_errors!
@report_errors = true
end
HTTPABLE.each do |m|
define_method m do |path, opts = {}, &block|
path = ::Mustermann.new path, opts
- routes[m][path] = Responder.new &block
+ routes[m][path] = Responder.new m, &block
end
end
def websocket path, &block
path = ::Mustermann.new path
- routes[:websocket][path] = Responder::Websocket.new &block
+ routes[:websocket][path] = Responder::Websocket.new nil, &block
end
def eventsource path, headers = nil, &block
path = ::Mustermann.new path
routes[:get][path] = Responder::Eventsource.new headers, &block
@@ -123,40 +86,83 @@
def after opts = {}, &block
filter :after, opts, &block
end
def on_pong &block
- Responder::Websocket.on_pong = block
+ @on_pong = block if block
+ @on_pong
end
def content_type type
Responder.content_type type
end
+ def default_headers hs
+ Responder.default_headers = Responder.default_headers.merge hs
+ end
end
- # Make the DSL methods available to subclass-level code.
- # main.rb makes them available to the top level.
+ class << self
+ include DSL
- extend DSL
+ attr_accessor :app_file, :server
- class << self
+ 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
+
+ def root
+ @root ||= File.expand_path '..', app_file
+ end
+
def report_errors?
!!@report_errors
end
def routes
@routes ||= Hash.new{|h,k| h[k] = RouteMap.new}
end
def filters
- @filters ||= {before: {default: []}, after: {default: []}}
+ @filters ||= {
+ before: Hash.new{|h,k| h[k] = []},
+ after: Hash.new{|h,k| h[k] = []},
+ }
end
def filter which, opts = {}, &block
case opts
- when String
+ when String, Regexp
filter_by which, opts, block
when Hash
if opts[:path]
filter_by which, opts[:path], block
else
@@ -165,11 +171,10 @@
end
end
def filter_by which, path, block
pattern = ::Mustermann.new path
- filters[which][pattern] ||= []
filters[which][pattern] << block
end
def websockets reject = true
@websockets ||= Stash::Websocket.new server
@@ -245,16 +250,20 @@
def request_headers
@request_headers ||= Hash.new do |hash, key|
if Symbol === key
k = key.to_s.upcase
k.gsub! UNDERSCORE, DASH
- rhv = request.headers.select {|header_key,v| header_key.upcase == k}
- hash[key] = rhv.values.first
+ _, value = request.headers.find {|header_key,v| header_key.upcase == k}
+ hash[key] = value
end
end
end
+ def request_body
+ @request_body ||= request.body.to_s
+ end
+
task :handle_websocket do |ws|
begin
while !ws.closed? do
ws.read
end
@@ -264,13 +273,11 @@
end
end
task :ping_websockets do
every(@base.ping_time) do
- websockets.all_each do |ws|
- ws.socket << ::WebSocket::Message.ping.to_data
- end
+ websockets.all_each {|ws| ws.ping &@base.on_pong }
end
end
task :handle_event_source do |socket, block|
begin
@@ -351,15 +358,15 @@
self.class.filters[which].each do |pattern, filters|
case pattern
when :default
filters.each {|filter| instance_eval &filter}
when ::Mustermann
- if pattern.match request.path
- @pre_filter_params = params
- @params = @pre_filter_params.merge pattern.params(request.path)
+ 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
+ @params = pre_filter_params
end
end
end
end
@@ -400,14 +407,11 @@
def []= route, responder
@hash[route] = responder
end
def [] route
- responder = nil
- if mustermann = @hash.keys.select {|k| k.match(route)}.first
- responder = @hash.fetch mustermann
- responder.mustermann = mustermann
- end
+ mustermann, responder = @hash.find {|k,v| k.match(route)}
+ responder.mustermann = mustermann if mustermann
responder
end
end