Module: Sansomable

Defined in:
lib/sansom/sansomable.rb

Constant Summary collapse

RouteError =
Class.new StandardError
ResponseError =
Class.new StandardError
HTTP_VERBS =
[:get,:head, :post, :put, :delete, :patch, :options, :link, :unlink, :trace].freeze
ACTION_VERBS =
[:mount].freeze
VALID_VERBS =
(HTTP_VERBS+ACTION_VERBS).freeze
RACK_HANDLERS =
["puma", "unicorn", "thin", "webrick"].freeze
NOT_FOUND_RESP =
[404, {}, ["Not found."]].freeze

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &block) ⇒ Object



80
81
82
83
84
85
86
# File 'lib/sansom/sansomable.rb', line 80

def method_missing meth, *args, &block
  path, item = *args.dup.push(block)
  return super unless path && item && item != self
  return super unless VALID_VERBS.include? meth
  return super unless item.respond_to? :call
  _pine.map_path path, item, meth
end

Instance Method Details

#_call_handler(handler, *args) ⇒ Object

Raises:



24
25
26
27
28
29
30
# File 'lib/sansom/sansomable.rb', line 24

def _call_handler handler, *args
  res = handler.call *args
  res = res.finish if res.is_a? Rack::Response
  raise ResponseError, "Response must either be a rack response, string, or object" unless Rack::Lint.fastlint res
  res = [200, {}, [res.to_str]] if res.respond_to? :to_str
  res
end

#_pineObject



16
17
18
19
20
21
22
# File 'lib/sansom/sansomable.rb', line 16

def _pine
  if @_pine.nil?
    @_pine = Pine.new
    routes if respond_to? :routes
  end
  @_pine
end

#after(&block) ⇒ Object

2 args



77
# File 'lib/sansom/sansomable.rb', line 77

def after █ @_after = block; end

#before(&block) ⇒ Object

1 arg



76
# File 'lib/sansom/sansomable.rb', line 76

def before █ @_before = block; end

#call(env) ⇒ Object

Raises:



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/sansom/sansomable.rb', line 32

def call env
  raise RouteError, "No routes." if _pine.empty?
  
  handler, remaining_path, _, route_params = _pine.match env["PATH_INFO"], env["REQUEST_METHOD"]
  return NOT_FOUND_RESP if handler.nil?
  
  r = Rack::Request.new env
  
  begin
    r.path_info = remaining_path unless Proc === handler
    
    unless route_params.empty?
      r.env["rack.request.query_string"] = r.query_string # now Rack::Request#GET will return r.env["rack.request.query_hash"]
      r.env["rack.request.query_hash"] = Rack::Utils.parse_nested_query(r.query_string).merge(route_params) # add route params r.env["rack.request.query_hash"]
      r.instance_variable_set "@params", nil # tell Rack::Request to recalc Rack::Request#params
    end
    
    res   = _call_handler    @_before, r                               if @_before       # call before block
    res ||= _call_handler     handler, (Proc === handler ? r : r.env)                    # call route handler block
    res ||= _call_handler     @_after, r, res                          if @_after && res # call after block
    res ||= _call_handler @_not_found, r                               if @_not_found    # call error block
    res ||= NOT_FOUND_RESP # fallback error message
    res
  rescue => e
    _call_handler @_error_blocks[e.class], e, r rescue raise e
  end
end

#error(error_class = :default, &block) ⇒ Object

Raises:

  • (ArgumentError)


71
72
73
74
# File 'lib/sansom/sansomable.rb', line 71

def error error_class=:default, &block
  raise ArgumentError, "Invalid error: #{error_class}" unless Class === error_class || error_class == :default
  (@_error_blocks ||= Hash.new { |h| h[:default] })[error_class] = block
end

#not_found(&block) ⇒ Object

1 arg



78
# File 'lib/sansom/sansomable.rb', line 78

def not_found █ @_not_found = block; end

#start(port = 3001, handler = "") ⇒ Object

Raises:



60
61
62
63
64
65
66
67
68
69
# File 'lib/sansom/sansomable.rb', line 60

def start port=3001, handler=""
  raise RouteError, "No routes." if _pine.empty?
  begin
    h = Rack::Handler.get handler.to_s
  rescue LoadError, NameError
    h = Rack::Handler.pick(RACK_HANDLERS)
  ensure
    h.run self, :Port => port
  end
end