Class: Whisper::Handler

Inherits:
Object
  • Object
show all
Includes:
Loggy
Defined in:
lib/whisper/handler.rb

Overview

I borrowed a bit from Rails’s syntax, but the semantics are not the same. Anything with + signs will be treated as a substitutable path component. You can optionally end the path spec with :format or /:page:format.

Constant Summary collapse

DEFAULT_FORMAT =
"html"

Instance Method Summary collapse

Constructor Details

#initialize(request_method, pathspec, &page_creator) ⇒ Handler

Returns a new instance of Handler.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/whisper/handler.rb', line 17

def initialize request_method, pathspec, &page_creator
  @request_method = request_method
  @pathspec = pathspec
  @page_creator = page_creator
  @map = TimedMap.new
  @uses_page = @uses_format = false

  re = @pathspec.gsub(/\+(\w+)/) do
    '([^\.\/][^\/]*?)' # regular path components must start with a non-., non-/, followed by 0 or more non-/es
  end.sub(/\/:page:format$/) do
    @uses_page = @uses_format = true
    '\/?(\d+)?(?:\.([^\/]+))?'
  end.sub(/:format$/) do
    @uses_format = true
    '(?:\.([a-zA-Z]+))?'
  end
  @re = /^#{re}$/
end

Instance Method Details

#contentsObject



68
# File 'lib/whisper/handler.rb', line 68

def contents; @map.values end

#handle(path, params, request_method, route) ⇒ Object



36
37
38
39
40
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
66
# File 'lib/whisper/handler.rb', line 36

def handle path, params, request_method, route
  #debug "comparing #{request_method.inspect} against #{@request_method.inspect}"
  return unless (request_method == @request_method) ||   # special case:
    (request_method == :head && @request_method == :get) # proceed!

  #debug "comparing #{path.inspect} against #{@re} => #{@re.match(path) ? true : false}"
  match = @re.match(path) or return
  #debug "have captures: #{match.captures.inspect}"

  ## assemble the variables to be passed to the caller function
  vars = match.captures
  vars[vars.length - 1] ||= DEFAULT_FORMAT if @uses_format
  vars[vars.length - 2] = (vars[vars.length - 2].to_i || 0) if @uses_page
  vars << params

  ## make a key from the path and the query parameters, if any. the key is basically
  ## a normalized query string.
  key = path + "?" + params.sort_by { |k, v| [k, v] }.map { |k, v| k + "=" + v }.join("&")

  case request_method
  when :post # don't cache
    make route, vars
  else
    @map.prune!
    @map[key] ||= begin
      make(route, vars) || :invalid
    rescue SystemCallError => e
      :invalid
    end
  end
end

#url_for(opts = {}) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/whisper/handler.rb', line 70

def url_for opts={}
  url = @pathspec.gsub(/[:+](\w+)/) do
    spec = $1.intern
    val = opts[spec]
    val = CGI.escape(val.to_s) if val
    case spec
    when :format; val.nil? || (val == DEFAULT_FORMAT) ? "" : ".#{val}"
    when :page; val == "0" ? "" : val
    else
      raise ArgumentError, "missing required path spec #{spec}" unless val
      val
    end
  end
  url += "##{opts[:anchor]}" if opts[:anchor]
  url.gsub!(/\/\.([^\/\.]+)$/, ".\\1")
  url
end