Class: Rack::Routes

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/routes.rb

Defined Under Namespace

Classes: LocDirectiveError

Constant Summary collapse

VERSION =
'0.1.0'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app = nil) ⇒ Routes

rack app



120
121
122
123
# File 'lib/rack/routes.rb', line 120

def initialize app = nil
  self.class.compile!
  @app = app
end

Class Method Details

.call(env) ⇒ Object

convience rack interface Enables the use of either: use Rack::Routes or run Rack::Routes



17
18
19
20
# File 'lib/rack/routes.rb', line 17

def call env
  @app ||= new
  @app.call env
end

.compile!Object

location directives should be run in a certain order. This is needed to establish that order.



25
26
27
28
29
30
# File 'lib/rack/routes.rb', line 25

def compile!
  # longest first
  [:exact, :string, :string_break].each do |type|
    locations[type].sort_by!{|path, _| -path.length}
  end
end

.location(path, opts = {}, &blk) ⇒ Object

Description

Main interface method. Reimplementation of nginx location directive.

Args

path

The path to match on. Can be String or Regexp.

opts

Hash of options. see below.

opts keys:

:exact

Type of string matching. default false Also can be :prefix (for making ‘^~’ make sense)

:method

HTTP Request Method matching. defaults nil (all)

:type

Explicetly set the type of match.

exact values can be:

false

prefix match

true

literal match

=

literal match

^~

skip regex matching

yields env

Examples

# config.ru

# matches everything # but longer matches will get applied first Rack::Routes.location ‘/’ do

[200, {}, ['hi']]

end

# matches everything beginning with /asdf Rack::Routes.location ‘/asdf’ do

[200, {}, ['hi asdf']]

end

# matches /foo and not /foobar nor /foo/baz etc. Rack::Routes.location ‘/foo’, :exact => true do

[200, {}, ['hi foo']]

end

# matches anything beginning with /bar # path can be any ruby regex # matchdata is stored in env Rack::Routes.location //bar(.*)/ do |env|

m = env['routes.location.matchdata']
[200, {}, ["hi #{m[1]}"]]

end

# matches beginning of path but stops if match is found. Does not evaluate regexen Rack::Routes.location ‘/baz’, :prefix => ‘^~’ do

[200, {}, ['hi baz']]

end

run Rack::Routes

Raises:



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/rack/routes.rb', line 92

def location path, opts = {}, &blk
  type = opts.fetch(:type, nil)
  type = :regex if Regexp === path
  type ||= case opts.fetch(:exact, opts.fetch(:prefix, false))
           when FalseClass
             :string
           when TrueClass, '='
             :exact
           when '^~'
             :string_break
           end

  raise LocDirectiveError, "unknown type `#{type}'" unless
    [:regex, :string, :exact, :string_break].include? type

  app = blk

  locations[type] << [path, app, opts]
end

.locationsObject

accessor for @locations hash



113
114
115
# File 'lib/rack/routes.rb', line 113

def locations
  @locations ||= Hash.new{|h,k| h[k] = []}
end

Instance Method Details

#call(env) ⇒ Object

rack interface



126
127
128
# File 'lib/rack/routes.rb', line 126

def call env
  dup.call! env
end

#call!(env) ⇒ Object



130
131
132
133
134
135
# File 'lib/rack/routes.rb', line 130

def call! env
  @env  = env
  @path = URI.decode @env['PATH_INFO']

  (matching_app || @app).call(env)
end

#find_exactObject



145
146
147
# File 'lib/rack/routes.rb', line 145

def find_exact
  find_type(:exact){|pth| pth == @path}
end

#find_regexObject



157
158
159
160
# File 'lib/rack/routes.rb', line 157

def find_regex
  find_type(:regex){|pth| pth === @path and
    @env['routes.location.matchdata'] = Regexp.last_match }
end

#find_stringObject



149
150
151
# File 'lib/rack/routes.rb', line 149

def find_string
  find_type(:string){|pth| @path[0, pth.length] == pth}
end

#find_string_breakObject



153
154
155
# File 'lib/rack/routes.rb', line 153

def find_string_break
  find_type(:string_break){|pth| @path[0, pth.length] == pth}
end

#find_type(type) ⇒ Object



137
138
139
140
141
142
143
# File 'lib/rack/routes.rb', line 137

def find_type type
  _, app = locations[type].find do |path, _, opts|
    next if opts[:method] and opts[:method] != @env['REQUEST_METHOD']
    yield path
  end
  app
end

#locationsObject



162
163
164
# File 'lib/rack/routes.rb', line 162

def locations
  self.class.locations
end

#matching_appObject

search exact matches first then ^~ strings (not sure what else to call them) then regex then all the other strings

NOTE the docs say to run strings before regex but I don’t see why it matters as the return logic is the same.



174
175
176
177
178
179
# File 'lib/rack/routes.rb', line 174

def matching_app
  find_exact          ||
    find_string_break ||
    find_regex        ||
    find_string
end