Class: HttpRouter::Route

Inherits:
Object
  • Object
show all
Defined in:
lib/http_router/route.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(router, path) ⇒ Route

Returns a new instance of Route.



8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/http_router/route.rb', line 8

def initialize(router, path)
  @router = router
  path[0,0] = '/' unless path[0] == ?/
  @path = path
  @original_path = path.dup
  @partially_match = extract_partial_match(path)
  @trailing_slash_ignore = extract_trailing_slash(path)
  @matches_with = {}
  @arbitrary = []
  @conditions =  {}
  @default_values = {}
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

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



21
22
23
24
25
26
27
# File 'lib/http_router/route.rb', line 21

def method_missing(method, *args, &block)
  if RequestNode::RequestMethods.include?(method)
    condition(method => args)
  else
    super
  end
end

Instance Attribute Details

#default_valuesObject

Returns the value of attribute default_values.



6
7
8
# File 'lib/http_router/route.rb', line 6

def default_values
  @default_values
end

#destObject (readonly)

Returns the value of attribute dest.



5
6
7
# File 'lib/http_router/route.rb', line 5

def dest
  @dest
end

#matches_withObject (readonly)

Returns the value of attribute matches_with.



5
6
7
# File 'lib/http_router/route.rb', line 5

def matches_with
  @matches_with
end

#original_pathObject (readonly)

Returns the value of attribute original_path.



5
6
7
# File 'lib/http_router/route.rb', line 5

def original_path
  @original_path
end

#partially_matchObject

Returns the value of attribute partially_match.



6
7
8
# File 'lib/http_router/route.rb', line 6

def partially_match
  @partially_match
end

#pathObject (readonly)

Returns the value of attribute path.



5
6
7
# File 'lib/http_router/route.rb', line 5

def path
  @path
end

#pathsObject (readonly)

Returns the value of attribute paths.



5
6
7
# File 'lib/http_router/route.rb', line 5

def paths
  @paths
end

#trailing_slash_ignoreObject

Returns the value of attribute trailing_slash_ignore.



6
7
8
# File 'lib/http_router/route.rb', line 6

def trailing_slash_ignore
  @trailing_slash_ignore
end

Instance Method Details

#arbitrary(proc = nil, &block) ⇒ Object

Adds an arbitrary proc matcher to a Route. Receives either a block, or a proc. The proc will receive a Rack::Request object, a Hash of the params, and the destination for this route. The proc must return true if the Route is matched. Returns self.



181
182
183
184
185
# File 'lib/http_router/route.rb', line 181

def arbitrary(proc = nil, &block)
  guard_compiled
  @arbitrary << (proc || block)
  self
end

#as_optionsObject

Returns the options used to create this route.



34
35
36
# File 'lib/http_router/route.rb', line 34

def as_options
  {:matching => @matches_with, :conditions => @conditions, :default_values => @default_values, :name => @name, :partial => @partially_match, :arbitrary => @arbitrary}
end

#clone(new_router) ⇒ Object

Creates a deep uncompiled copy of this route.



39
40
41
# File 'lib/http_router/route.rb', line 39

def clone(new_router)
  Route.new(new_router, @original_path.dup).with_options(as_options)
end

#compileObject

Compiles the route and inserts it into the tree. This is called automatically when you add a destination via #to to the route. Until a route is compiled, it will not be recognized.



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/http_router/route.rb', line 194

def compile
  if @paths.nil?
    router.named_routes[@name] = self if @name
    @paths = compile_paths
    @paths.each_with_index do |p1, i|
      @paths[i+1, @paths.size].each do |p2|
        raise AmbiguousRouteException if p1 === p2
      end
    end
    @paths.each do |path|
      current_node = router.root.add_path(path)
      working_set = current_node.add_request_methods(@conditions)
      working_set.map!{|node| node.add_arbitrary(@arbitrary)}
      working_set.each do |current_node|
        case current_node.value
        when nil
          current_node.value = [path]
        else
          current_node.value << path
        end
      end
      path.variable_names.each{|vn| router.variable_names << vn} unless path.static?
    end
  end
  self
end

#compiled?Boolean

Compile state for route. Returns true or false.

Returns:

  • (Boolean)


188
189
190
# File 'lib/http_router/route.rb', line 188

def compiled?
  !@paths.nil?
end

#condition(conditions) ⇒ Object Also known as: conditions

Sets a request condition for the route Returns self.

Example

router = HttpRouter.new
router.add("/:test").condition(:host => 'www.example.org').name(:test).compile


116
117
118
119
120
121
122
123
124
125
# File 'lib/http_router/route.rb', line 116

def condition(conditions)
  guard_compiled
  conditions.each do |k,v|
    @conditions.key?(k) ?
      @conditions[k] << v :
      @conditions[k] = Array(v)
    @conditions[k].flatten!
  end
  self
end

#default(v) ⇒ Object

Sets a default value for the route Returns self.

Example

router = HttpRouter.new
router.add("/:test").default(:test => 'foo').name(:test).compile
router.url(:test)
# ==> "/foo"
router.url(:test, 'override')
# ==> "/override"


80
81
82
83
# File 'lib/http_router/route.rb', line 80

def default(v)
  @default_values.merge!(v)
  self
end

#deleteObject

Causes this route to recognize the DELETE request method. Returns self.



106
107
108
# File 'lib/http_router/route.rb', line 106

def delete
  request_method('DELETE')
end

#getObject

Causes this route to recognize the GET request method. Returns self.



86
87
88
# File 'lib/http_router/route.rb', line 86

def get
  request_method('GET')
end

#headObject

Causes this route to recognize the HEAD request method. Returns self.



96
97
98
# File 'lib/http_router/route.rb', line 96

def head
  request_method('HEAD')
end

#match_path(matcher) ⇒ Object

Convenient regexp matching on an entire path. Returns self



176
177
178
# File 'lib/http_router/route.rb', line 176

def match_path(matcher)
  arbitrary{|env, params, dest| match = matcher.match(env.path_info); !match.nil? and match.begin(0) == 0 and match[0].size == env.path_info.size}
end

#matching(match) ⇒ Object

Sets a regex matcher for a variable Returns self.

Example

router = HttpRouter.new
router.add("/:test").matching(:test => /\d+/).name(:test).compile


134
135
136
137
138
139
140
141
142
143
# File 'lib/http_router/route.rb', line 134

def matching(match)
  guard_compiled
  match.each do |var_name, matchers|
    matchers = Array(matchers)
    matchers.each do |m|
      @matches_with.key?(var_name) ? raise : @matches_with[var_name] = m
    end
  end
  self
end

#matching_path(params, other_hash = nil) ⇒ Object



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/http_router/route.rb', line 278

def matching_path(params, other_hash = nil)
  if @paths.size == 1
    @paths.first
  else
    if params.is_a?(Array)
      significant_keys = other_hash && significant_variable_names & other_hash.keys
      @paths.find { |path|
        var_count = significant_keys ? params.size + significant_keys.size : params.size
        path.variables.size == var_count
      }
    else
      @paths.reverse_each do |path|
        if params && !params.empty?
          return path if (path.variable_names & params.keys).size == path.variable_names.size
        elsif path.variable_names.empty?
          return path
        end
      end
      nil
    end
  end
end

#name(name) ⇒ Object

Sets the name of the route Returns self.



64
65
66
67
68
# File 'lib/http_router/route.rb', line 64

def name(name)
  @name = name
  router.named_routes[@name] = self if @name && compiled?
  self
end

#namedObject

Returns the current route’s name.



146
147
148
# File 'lib/http_router/route.rb', line 146

def named
  @name
end

#partial(match = true) ⇒ Object

Sets partial matching on this route. Defaults to true. Returns self.



170
171
172
173
# File 'lib/http_router/route.rb', line 170

def partial(match = true)
  @partially_match = match
  self
end

#partially_match?Boolean

The current state of partial matching on this route. Returns true or false.

Returns:

  • (Boolean)


249
250
251
# File 'lib/http_router/route.rb', line 249

def partially_match?
  @partially_match
end

#postObject

Causes this route to recognize the POST request method. Returns self.



91
92
93
# File 'lib/http_router/route.rb', line 91

def post
  request_method('POST')
end

#putObject

Causes this route to recognize the PUT request method. Returns self.



101
102
103
# File 'lib/http_router/route.rb', line 101

def put
  request_method('PUT')
end

#redirect(path, status = 302) ⇒ Object

Sets the destination of this route to redirect to an arbitrary URL.

Raises:

  • (ArgumentError)


222
223
224
225
226
227
228
229
230
231
# File 'lib/http_router/route.rb', line 222

def redirect(path, status = 302)
  raise ArgumentError, "Status has to be an integer between 300 and 399" unless (300..399).include?(status)
  to { |env|
    params = env['router.params']
    response = ::Rack::Response.new
    response.redirect(eval(%|"#{path}"|), status)
    response.finish
  }
  self
end

#significant_variable_namesObject



274
275
276
# File 'lib/http_router/route.rb', line 274

def significant_variable_names
  @significant_variable_names ||= @path.scan(/(^|[^\\])[:\*]([a-zA-Z0-9_]+)/).map{|p| p.last.to_sym}
end

#static(root) ⇒ Object

Sets the destination of this route to serve static files from either a directory or a single file.



234
235
236
237
238
239
240
241
# File 'lib/http_router/route.rb', line 234

def static(root)
  if File.directory?(root)
    partial.to ::Rack::File.new(root)
  else
    to proc{|env| env['PATH_INFO'] = File.basename(root); ::Rack::File.new(File.dirname(root)).call(env)}
  end
  self
end

#to(dest = nil, &block) ⇒ Object

Sets the destination of the route. Receives either a block, or a proc. Returns self.

Example

router = HttpRouter.new
router.add("/:test").matching(:test => /\d+/).name(:test).to(proc{ |env| Rack::Response.new("hi there").finish })

Or

router.add("/:test").matching(:test => /\d+/).name(:test).to { |env| Rack::Response.new("hi there").finish }


158
159
160
161
162
163
164
165
166
167
# File 'lib/http_router/route.rb', line 158

def to(dest = nil, &block)
  compile
  @dest = dest || block
  if @dest.respond_to?(:url_mount=)
    urlmount = UrlMount.new(@original_path, @default_values)
    urlmount.url_mount = router.url_mount if router.url_mount
    @dest.url_mount = urlmount
  end
  self
end

#to_sObject



29
30
31
# File 'lib/http_router/route.rb', line 29

def to_s
  "#{@original_path} conditions: #{@conditions.inspect} default_values: #{@default_values.inspect} name: #{named.inspect}"
end

#trailing_slash_ignore?Boolean

The current state of trailing / ignoring on this route. Returns true or false.

Returns:

  • (Boolean)


244
245
246
# File 'lib/http_router/route.rb', line 244

def trailing_slash_ignore?
  @trailing_slash_ignore
end

#url(*args) ⇒ Object

Generates a URL for this route. See HttpRouter#url for how the arguments for this are structured.



254
255
256
257
# File 'lib/http_router/route.rb', line 254

def url(*args)
  result, extra_params = url_with_params(*args)
  router.append_querystring(result, extra_params)
end

#url_with_params(*args) ⇒ Object



259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/http_router/route.rb', line 259

def url_with_params(*args)
  options = args.last.is_a?(Hash) ? args.pop : nil
  options = options.nil? ? default_values.dup : default_values.merge(options) if default_values
  options.delete_if{ |k,v| v.nil? } if options
  path = if args.empty?
    matching_path(options)
  else
    matching_path(args, options)
  end
  raise UngeneratableRouteException unless path
  result, params = path.url(args, options)
  mount_point = router.url_mount && router.url_mount.url(options)
  mount_point ? [File.join(mount_point, result), params] : [result, params]
end

#with_options(options) ⇒ Object

Uses an option hash to apply conditions to a Route. The following keys are supported. *name – Maps to #name method. *matching – Maps to #matching method. *conditions – Maps to #conditions method. *default_value – Maps to #default_value method.



49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/http_router/route.rb', line 49

def with_options(options)
  if options
    name(options.delete(:name))                               if options[:name]
    matching(options.delete(:matching))                       if options[:matching]
    condition(options.delete(:conditions))                    if options[:conditions]
    default(options.delete(:default_values))                  if options[:default_values]
    partial(options.delete(:partial))                         if options[:partial]
    Array(options.delete(:arbitrary)).each{|a| arbitrary(&a)} if options[:arbitrary]
    matching(options)
  end
  self
end