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 =
[:map].freeze
VALID_VERBS =
(HTTP_VERBS+ACTION_VERBS).freeze
RACK_HANDLERS =
["puma", "unicorn", "thin", "webrick"].freeze
NOTFOUND_TEXT =
"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



97
98
99
100
101
102
103
# File 'lib/sansom/sansomable.rb', line 97

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:

  • (ArgumentError)


25
26
27
28
29
30
31
32
33
34
# File 'lib/sansom/sansomable.rb', line 25

def _call_handler handler, *args
  raise ArgumentError, "Handler must not be nil." if handler.nil?
  raise ArgumentError, "Handler must be a valid rack app." unless handler.respond_to? :call
  raise ArgumentError, "Handler cannot take all passed args." if handler.respond_to?(:arity) && args.count != handler.arity
  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 # custom method
  res = [200, {}, [res.to_str]] if res.respond_to? :to_str
  res
end

#_not_foundObject



36
37
38
39
# File 'lib/sansom/sansomable.rb', line 36

def _not_found
  return _call_route @_not_found, r unless @_not_found.nil?
  [404, {}, [NOTFOUND_TEXT]]
end

#_pineObject



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

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

#after(&block) ⇒ Object

Raises:

  • (ArgumentError)


87
88
89
90
# File 'lib/sansom/sansomable.rb', line 87

def after &block
  raise ArgumentError, "After filter blocks must take two arguments." if block && block.arity != 2
  @_after = block
end

#before(&block) ⇒ Object

Raises:

  • (ArgumentError)


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

def before &block
  raise ArgumentError, "Before filter blocks must take one argument." if block && block.arity != 1
  @_before = block
end

#call(env) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/sansom/sansomable.rb', line 41

def call env
  return _not_found if _pine.empty? # no routes
  m = _pine.match env["PATH_INFO"], env["REQUEST_METHOD"]
  return _not_found if m.nil?
  
  r = Rack::Request.new env
  
  begin
    r.path_info = m.remaining_path unless Proc === m.handler
    
    unless m.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"] ||= {}).merge! m.params # update the necessary field in the 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 m.handler, (Proc === m.handler ? r : r.env) # call route handler block
    res ||= _call_handler @_after, r, res if @_after # call after block
    res ||= _not_found
    res
  rescue => e
    _call_handler @_error_blocks[e.class], e, r rescue raise e
  end
end

#error(error_key = nil, &block) ⇒ Object



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

def error error_key=nil, &block
  (@_error_blocks ||= Hash.new { |h| h[:default] })[error_key || :default] = block
end

#not_found(&block) ⇒ Object

Raises:

  • (ArgumentError)


92
93
94
95
# File 'lib/sansom/sansomable.rb', line 92

def not_found &block
  raise ArgumentError, "Not found blocks must take one argument." if block && block.arity != 1
  @_not_found = block
end

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

Raises:



67
68
69
70
71
72
73
74
75
76
# File 'lib/sansom/sansomable.rb', line 67

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