http_router 0.8.11 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,8 @@ class HttpRouter
3
3
  def initialize(router, path, opts = {})
4
4
  @router, @original_path, @opts = router, path, opts
5
5
  @param_names = @original_path.respond_to?(:names) ? @original_path.names.map(&:to_sym) : []
6
+ @path_validation_regex = original_path
7
+ Util.add_path_generation(self, self, opts.delete(:path_for_generation), @original_path) if opts.key?(:path_for_generation)
6
8
  process_opts
7
9
  end
8
10
 
@@ -22,5 +24,16 @@ class HttpRouter
22
24
  def regex?
23
25
  true
24
26
  end
27
+
28
+ def generate_from?(params)
29
+ false
30
+ end
31
+
32
+ def url_with_params(*a)
33
+ url_args_processing(a) do |args, options|
34
+ respond_to?(:raw_url) or raise InvalidRouteException
35
+ raw_url(args, options)
36
+ end
37
+ end
25
38
  end
26
39
  end
@@ -1,16 +1,16 @@
1
1
  class HttpRouter
2
2
  class Route
3
- DoubleCompileError = Class.new(RuntimeError)
4
-
5
3
  attr_reader :default_values, :router, :path, :conditions, :original_path, :match_partially, :dest, :regex, :named, :matches_with
6
4
  alias_method :match_partially?, :match_partially
7
5
  alias_method :regex?, :regex
8
6
 
9
7
  def initialize(router, path, opts = {})
10
8
  @router, @original_path, @opts = router, path, opts
11
- if @original_path[-1] == ?*
9
+ if @original_path
10
+ @match_partially = true and path.slice!(-1) if @original_path[/[^\\]\*$/]
11
+ @original_path[0, 0] = '/' if @original_path[0] != ?/
12
+ else
12
13
  @match_partially = true
13
- path.slice!(-1)
14
14
  end
15
15
  process_opts
16
16
  end
@@ -26,6 +26,7 @@ class HttpRouter
26
26
  @match_partially = @opts[:__partial__] if @match_partially.nil? && !@opts[:__partial__].nil?
27
27
  @match_partially = @opts[:partial] if @match_partially.nil? && !@opts[:partial].nil?
28
28
  name(@opts[:__name__] || @opts[:name]) if @opts.key?(:__name__) || @opts.key?(:name)
29
+ @needed_keys = significant_variable_names - @default_values.keys
29
30
  end
30
31
 
31
32
  def as_options
@@ -49,24 +50,30 @@ class HttpRouter
49
50
 
50
51
  def name(n)
51
52
  @named = n
52
- @router.named_routes[n] = self
53
+ @router.named_routes[n] << self
54
+ @router.named_routes[n].sort!{|r1, r2| r2.significant_variable_names.size <=> r1.significant_variable_names.size }
53
55
  self
54
56
  end
55
57
 
56
- def request_method(m)
57
- ((@conditions ||= {})[:request_method] ||= []) << m; self
58
+ def request_method(*method)
59
+ add_to_contitions(:request_method, method)
60
+ end
61
+
62
+ def host(*host)
63
+ add_to_contitions(:host, host)
58
64
  end
59
65
 
60
- def host(host)
61
- ((@conditions ||= {})[:host] ||= []) << host; self
66
+ def scheme(*scheme)
67
+ add_to_contitions(:scheme, scheme)
62
68
  end
63
69
 
64
- def scheme(scheme)
65
- ((@conditions ||= {})[:scheme] ||= []) << scheme; self
70
+ def user_agent(*user_agent)
71
+ add_to_contitions(:user_agent, user_agent)
66
72
  end
67
73
 
68
- def user_agent(user_agent)
69
- ((@conditions ||= {})[:user_agent] ||= []) << user_agent; self
74
+ def add_to_contitions(name, *vals)
75
+ ((@conditions ||= {})[name] ||= []).concat(vals.flatten)
76
+ self
70
77
  end
71
78
 
72
79
  def matching(matchers)
@@ -101,13 +108,15 @@ class HttpRouter
101
108
  self
102
109
  end
103
110
 
104
- def post; request_method('POST'); end
105
- def get; request_method('GET'); end
106
- def put; request_method('PUT'); end
107
- def delete; request_method('DELETE'); end
108
- def head; request_method('HEAD'); end
109
- def options; request_method('OPTIONS'); end
110
- def patch; request_method('PATCH'); end
111
+ def post; request_method('POST'); end
112
+ def get; request_method('GET'); end
113
+ def put; request_method('PUT'); end
114
+ def delete; request_method('DELETE'); end
115
+ def head; request_method('HEAD'); end
116
+ def options; request_method('OPTIONS'); end
117
+ def patch; request_method('PATCH'); end
118
+ def trace; request_method('TRACE'); end
119
+ def conenct; request_method('CONNECT'); end
111
120
 
112
121
  def arbitrary(blk = nil, &blk2)
113
122
  arbitrary_with_continue { |req, params|
@@ -129,19 +138,25 @@ class HttpRouter
129
138
  Route.new(new_router, @original_path.dup, as_options)
130
139
  end
131
140
 
132
- def url_with_params(*args)
141
+ def url_with_params(*a)
142
+ url_args_processing(a) do |args, options|
143
+ path = args.empty? ? matching_path(options) : matching_path(args, options)
144
+ raise InvalidRouteException unless path
145
+ path.url(args, options)
146
+ end
147
+ end
148
+
149
+ def url_args_processing(args)
133
150
  options = args.last.is_a?(Hash) ? args.pop : nil
134
151
  options = options.nil? ? default_values.dup : default_values.merge(options) if default_values
135
152
  options.delete_if{ |k,v| v.nil? } if options
136
- path = args.empty? ? matching_path(options) : matching_path(args, options)
137
- raise InvalidRouteException unless path
138
- result, params = path.url(args, options)
153
+ result, params = yield args, options
139
154
  mount_point = router.url_mount && router.url_mount.url(options)
140
155
  mount_point ? [File.join(mount_point, result), params] : [result, params]
141
156
  end
142
157
 
143
158
  def significant_variable_names
144
- @significant_variable_names ||= @original_path.scan(/(^|[^\\])[:\*]([a-zA-Z0-9_]+)/).map{|p| p.last.to_sym}
159
+ @significant_variable_names ||= @original_path.nil? ? [] : @original_path.scan(/(^|[^\\])[:\*]([a-zA-Z0-9_]+)/).map{|p| p.last.to_sym}
145
160
  end
146
161
 
147
162
  def matching_path(params, other_hash = nil)
@@ -161,6 +176,7 @@ class HttpRouter
161
176
 
162
177
  private
163
178
  def raw_paths
179
+ return [] if @original_path.nil?
164
180
  @raw_paths ||= begin
165
181
  start_index, end_index = 0, 1
166
182
  @raw_paths, chars = [""], @original_path.split('')
@@ -226,24 +242,27 @@ class HttpRouter
226
242
  def add_path_to_tree
227
243
  raise DoubleCompileError if compiled?
228
244
  @paths ||= begin
229
- raw_paths.map do |path|
230
- param_names = []
231
- node = @router.root
232
- path.split(/\//).each do |part|
233
- next if part == ''
234
- parts = part.scan(/\\.|[:*][a-z0-9_]+|[^:*\\]+/)
235
- node = parts.size == 1 ? add_normal_part(node, part, param_names) : add_complex_part(node, parts, param_names)
245
+ if raw_paths.empty?
246
+ add_non_path_to_tree(@router.root, nil, [])
247
+ else
248
+ raw_paths.map do |path|
249
+ param_names = []
250
+ node = @router.root
251
+ path.split(/\//).each do |part|
252
+ next if part == ''
253
+ parts = part.scan(/\\.|[:*][a-z0-9_]+|[^:*\\]+/)
254
+ node = parts.size == 1 ? add_normal_part(node, part, param_names) : add_complex_part(node, parts, param_names)
255
+ end
256
+ add_non_path_to_tree(node, path, param_names)
236
257
  end
237
- add_non_path_to_tree(node, path, param_names)
238
258
  end
239
259
  end
240
260
  end
241
261
 
242
262
  def add_non_path_to_tree(node, path, names)
243
- path_obj = Path.new(self, path, names)
244
263
  node = node.add_request(@conditions) unless @conditions.empty?
245
264
  @arbitrary.each{|a| node = node.add_arbitrary(a, match_partially?, names)} if @arbitrary
246
- node.add_destination(path_obj, @match_partially)
265
+ path_obj = node.add_destination(self, path, names)
247
266
  if dest.respond_to?(:url_mount=)
248
267
  urlmount = UrlMount.new(@original_path, @default_values)
249
268
  urlmount.url_mount = router.url_mount if router.url_mount
@@ -254,13 +273,9 @@ class HttpRouter
254
273
 
255
274
  def append_querystring_value(uri, key, value)
256
275
  case value
257
- when Array
258
- k = "#{key}[]"
259
- value.each{ |v| append_querystring_value(uri, k, v) }
260
- when Hash
261
- value.each{ |k, v| append_querystring_value(uri, "#{key}[#{k}]", v) }
262
- else
263
- uri << '&' << CGI.escape(key.to_s) << '=' << CGI.escape(value.to_s)
276
+ when Array then value.each{ |v| append_querystring_value(uri, "#{key}[]", v) }
277
+ when Hash then value.each{ |k, v| append_querystring_value(uri, "#{key}[#{k}]", v) }
278
+ else uri << '&' << CGI.escape(key.to_s) << '=' << CGI.escape(value.to_s)
264
279
  end
265
280
  end
266
281
 
@@ -0,0 +1,41 @@
1
+ class HttpRouter
2
+ module Util
3
+ def self.add_path_generation(target, route, path, path_validation_regex = nil)
4
+ regex_parts = path.split(/([:\*][a-zA-Z0-9_]+)/)
5
+ regex, code = '', ''
6
+ dynamic = false
7
+ regex_parts.each_with_index do |part, index|
8
+ case part[0]
9
+ when ?:, ?*
10
+ if index != 0 && regex_parts[index - 1][-1] == ?\\
11
+ regex << Regexp.quote(part) unless path_validation_regex
12
+ code << part
13
+ dynamic = true
14
+ else
15
+ regex << (route.matches_with[part[1, part.size].to_sym] || '.*?').to_s unless path_validation_regex
16
+ code << "\#{args.shift || (options && options.delete(:#{part[1, part.size]})) || return}"
17
+ dynamic = true
18
+ end
19
+ else
20
+ regex << Regexp.quote(part) unless path_validation_regex
21
+ code << part
22
+ end
23
+ end
24
+ path_validation_regex ||= Regexp.new("^#{regex}$") if dynamic
25
+ if path_validation_regex
26
+ target.instance_eval <<-EOT, __FILE__, __LINE__ + 1
27
+ def raw_url(args, options)
28
+ url = \"#{code}\"
29
+ #{path_validation_regex.inspect}.match(url) ? url : nil
30
+ end
31
+ EOT
32
+ else
33
+ target.instance_eval <<-EOT, __FILE__, __LINE__ + 1
34
+ def raw_url(args, options)
35
+ \"#{code}\"
36
+ end
37
+ EOT
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  class HttpRouter #:nodoc
3
- VERSION = '0.8.11'
3
+ VERSION = '0.9.3'
4
4
  end
data/lib/http_router.rb CHANGED
@@ -7,9 +7,9 @@ require 'http_router/node'
7
7
  require 'http_router/request'
8
8
  require 'http_router/response'
9
9
  require 'http_router/route'
10
- require 'http_router/path'
11
10
  require 'http_router/rack'
12
11
  require 'http_router/regex_route'
12
+ require 'http_router/util'
13
13
 
14
14
  class HttpRouter
15
15
 
@@ -20,6 +20,10 @@ class HttpRouter
20
20
  InvalidRouteException = Class.new(RuntimeError)
21
21
  # Raised when a Route is not able to be generated due to a missing parameter.
22
22
  MissingParameterException = Class.new(RuntimeError)
23
+ # Raised when a Route is compiled twice
24
+ DoubleCompileError = Class.new(RuntimeError)
25
+ # Raised an invalid request value is used
26
+ InvalidRequestValueError = Class.new(RuntimeError)
23
27
 
24
28
  # Creates a new HttpRouter.
25
29
  # Can be called with either <tt>HttpRouter.new(proc{|env| ... }, { .. options .. })</tt> or with the first argument omitted.
@@ -36,7 +40,6 @@ class HttpRouter
36
40
  @ignore_trailing_slash = options && options.key?(:ignore_trailing_slash) ? options[:ignore_trailing_slash] : true
37
41
  @redirect_trailing_slash = options && options.key?(:redirect_trailing_slash) ? options[:redirect_trailing_slash] : false
38
42
  @known_methods = Set.new(options && options[:known_methods] || [])
39
- @counter = 0
40
43
  reset!
41
44
  instance_eval(&blk) if blk
42
45
  end
@@ -53,10 +56,12 @@ class HttpRouter
53
56
  #
54
57
  # Routes can also contain optional parts. There are surrounded with <tt>( )</tt>'s. If you need to match on a bracket in the route itself, you can escape the parentheses with a backslash.
55
58
  #
56
- # The second argument, options, is an optional hash that can modify the route in further ways. See HttpRouter::Route#with_options for details. Typically, you want to add further options to the route by calling additional methods on it. See HttpRouter::Route for further details.
59
+ # As well, options can be passed in that modify the route in further ways. See HttpRouter::Route#with_options for details. Typically, you want to add further options to the route by calling additional methods on it. See HttpRouter::Route for further details.
57
60
  #
58
61
  # Returns the route object.
59
- def add(path, opts = {}, &app)
62
+ def add(*args, &app)
63
+ opts = args.last.is_a?(Hash) ? args.pop : {}
64
+ path = args.first
60
65
  route = add_route((Regexp === path ? RegexRoute : Route).new(self, path, opts))
61
66
  route.to(app) if app
62
67
  route
@@ -97,6 +102,7 @@ class HttpRouter
97
102
  # Returns the route object.
98
103
  def options(path, opts = {}, &app); add_with_request_method(path, :options, opts, &app); end
99
104
 
105
+ # Performs recoginition without actually calling the application.
100
106
  def recognize(env)
101
107
  call(env, false)
102
108
  end
@@ -121,7 +127,7 @@ class HttpRouter
121
127
 
122
128
  # Resets the router to a clean state.
123
129
  def reset!
124
- @routes, @named_routes, @root = [], {}, Node::Root.new(self)
130
+ @routes, @named_routes, @root = [], Hash.new{|h,k| h[k] = []}, Node::Root.new(self)
125
131
  @default_app = Proc.new{ |env| ::Rack::Response.new("Your request couldn't be found", 404).finish }
126
132
  end
127
133
 
@@ -146,16 +152,19 @@ class HttpRouter
146
152
  # # ==> "/123.html?fun=inthesun"
147
153
  def url(route, *args)
148
154
  case route
149
- when Symbol then @named_routes.key?(route) ? @named_routes[route].url(*args) : raise(InvalidRouteException)
150
- when Route then route.url(*args)
151
- else raise InvalidRouteException
155
+ when Symbol then @named_routes.key?(route) && @named_routes[route].each{|r| url = r.url(*args); return url if url}
156
+ when Route then return route.url(*args)
152
157
  end
158
+ raise(InvalidRouteException)
153
159
  end
154
160
 
161
+ # This method is invoked when a Path object gets called with an env. Override it to implement custom path processing.
155
162
  def process_destination_path(path, env)
156
163
  path.route.dest.call(env)
157
164
  end
158
165
 
166
+ # This method defines what sort of responses are considered "passes", and thus, route processing will continue. Override
167
+ # it to implement custom passing.
159
168
  def pass_on_response(response)
160
169
  response[1]['X-Cascade'] == 'pass'
161
170
  end
@@ -170,16 +179,6 @@ class HttpRouter
170
179
  @redirect_trailing_slash
171
180
  end
172
181
 
173
- def rewrite_partial_path_info(env, request)
174
- env['PATH_INFO'] = "/#{request.path.join('/')}"
175
- env['SCRIPT_NAME'] += request.rack_request.path_info[0, request.rack_request.path_info.size - env['PATH_INFO'].size]
176
- end
177
-
178
- def rewrite_path_info(env, request)
179
- env['SCRIPT_NAME'] += request.rack_request.path_info
180
- env['PATH_INFO'] = ''
181
- end
182
-
183
182
  # Creates a deep-copy of the router.
184
183
  def clone(klass = self.class)
185
184
  cloned_router = klass.new(@options)
@@ -196,10 +195,6 @@ class HttpRouter
196
195
  cloned_router
197
196
  end
198
197
 
199
- def next_counter
200
- @counter += 1
201
- end
202
-
203
198
  private
204
199
  def no_response(env, perform_call = true)
205
200
  supported_methods = @known_methods.select do |m|
@@ -1,3 +1,7 @@
1
+ {"a": "/:var"}
2
+ ["/test", "a", {"var":"test"}]
3
+ # ["/test", "a", ["test"]]
4
+
1
5
  {"a": "/"}
2
6
  {"b": "/test"}
3
7
  {"c": "/test/time"}
@@ -72,10 +76,12 @@
72
76
  ["/1/123", "a", {"entry": "123"}]
73
77
 
74
78
  {"a": "/:var"}
75
- ["/%C3%A4", "a", "ä"]
79
+ ["/%C3%A4", "a", ["ä"]]
80
+ ["/%C3%A4", "a", {"var": "ä"}]
76
81
 
77
82
  {"a": {"path": ":var", "var": {"regex": "\\d+"}}}
78
- [null, "a", "asd"]
83
+ [null, "a", "asd"]
84
+ ["/123", "a", "123"]
79
85
 
80
86
  {"a": "/var"}
81
87
  ["/var?foo%5B%5D=baz&foo%5B%5D=bar", "a", {"foo": ["baz", "bar"]}]
@@ -0,0 +1,58 @@
1
+ {"nothing":{"path":"/", "conditions": {"request_method": "GET"}}}
2
+ {"post":{"path":"/test", "conditions": {"request_method": "POST"}}}
3
+ {"put":{"path":"/test", "conditions": {"request_method": "PUT"}}}
4
+ ["post", {"path": "/test", "method": "POST"}]
5
+ [[405, {"Allow": "POST, PUT"}], {"path": "/test", "method": "GET"}]
6
+
7
+ {"router": {"path": "/test", "conditions": {"request_method": ["POST", "GET"]}}}
8
+ ["router", {"path": "/test", "method": "POST"}]
9
+ ["router", {"path": "/test", "method": "GET"}]
10
+ [[405, {"Allow": "GET, POST"}], {"path": "/test", "method": "PUT"}]
11
+
12
+ {"get": {"path": "/test(.:format)", "conditions": {"request_method": "GET"}}}
13
+ {"post": {"path": "/test(.:format)", "conditions": {"request_method": "POST"}}}
14
+ {"delete": {"path": "/test(.:format)", "conditions": {"request_method": "DELETE"}}}
15
+ ["get", {"path": "/test", "method": "GET"}]
16
+ ["post", {"path": "/test", "method": "POST"}]
17
+ ["delete", {"path": "/test", "method": "DELETE"}]
18
+ ["get", {"path": "/test.html", "method": "GET"}, {"format": "html"}]
19
+ ["post", {"path": "/test.html", "method": "POST"}, {"format": "html"}]
20
+ ["delete", {"path": "/test.html", "method": "DELETE"}, {"format": "html"}]
21
+ [[405, {"Allow": "DELETE, GET, POST"}], {"path": "/test", "method": "PUT"}]
22
+
23
+ {"post": {"path": "/test", "conditions": {"request_method": "POST"}}}
24
+ {"post_2": {"path": "/test/post", "conditions": {"request_method": "POST"}}}
25
+ {"get": {"path": "/test", "conditions": {"request_method": "GET"}}}
26
+ {"get_2": {"path": "/test/post", "conditions": {"request_method": "GET"}}}
27
+ {"any_2": "/test/post"}
28
+ {"any": "/test"}
29
+ ["post", {"path": "/test", "method": "POST"}]
30
+ ["get", {"path": "/test", "method": "GET"}]
31
+ ["any", {"path": "/test", "method": "PUT"}]
32
+ ["post_2", {"path": "/test/post", "method": "POST"}]
33
+ ["get_2", {"path": "/test/post", "method": "GET"}]
34
+ ["any_2", {"path": "/test/post", "method": "PUT"}]
35
+
36
+ {"post": {"path": "/test", "conditions": {"request_method": "POST"}}}
37
+ {"any": "/test"}
38
+ ["post", {"path": "/test", "method": "POST"}]
39
+ ["any", {"path": "/test", "method": "PUT"}]
40
+
41
+ {"host2_post": {"path": "/test", "conditions": {"request_method": "POST", "host": "host2"}}}
42
+ {"host2_get": {"path": "/test", "conditions": {"request_method": "GET", "host": "host2"}}}
43
+ {"host2": {"path": "/test", "conditions": {"host": "host2"}}}
44
+ {"post": {"path": "/test", "conditions": {"request_method": "POST"}}}
45
+ ["host2", {"path": "http://host2/test", "method": "PUT"}]
46
+ ["post", {"path": "http://host1/test", "method": "POST"}]
47
+ ["host2_get", {"path": "http://host2/test", "method": "GET"}]
48
+ ["host2_post", {"path": "http://host2/test", "method": "POST"}]
49
+
50
+ {"with": {"path": "/test", "conditions": {"request_method": "GET", "host": {"regex": "host1"}}}}
51
+ {"without": {"path": "/test", "conditions": {"request_method": "GET"}}}
52
+ ["without", "http://host2/test"]
53
+ ["with", "http://host2.host1.com/test"]
54
+
55
+ {"http": {"path": "/test", "conditions": {"scheme": "http"}}}
56
+ {"https": {"path": "/test", "conditions": {"scheme": "https"}}}
57
+ ["http", {"path": "/test", "scheme": "http"}]
58
+ ["https", {"path": "/test", "scheme": "https"}]
@@ -38,6 +38,9 @@
38
38
  ["route", "/test.html", {"format": "html"}]
39
39
  ["route", "/test"]
40
40
 
41
+ {"route": "/"}
42
+ ["route", "/"]
43
+
41
44
  [{"route": "(.:format)"}]
42
45
  ["route", "/.html", {"format": "html"}]
43
46
  ["route", "/"]
@@ -160,6 +163,9 @@
160
163
  [{"route": "test\\*variable"}]
161
164
  ["route", "/test*variable"]
162
165
 
166
+ [{"route": "testvariable\\*"}]
167
+ ["route", "/testvariable*"]
168
+
163
169
  [{"route": "/føø"}]
164
170
  ["route", "/f%C3%B8%C3%B8"]
165
171
 
@@ -176,16 +182,16 @@
176
182
  ["test", "/test/optional/", {"PATH_INFO": "/optional/"}]
177
183
  ["root", "/testing/optional", {"PATH_INFO": "/testing/optional"}]
178
184
 
179
- [{"route": "/one-:variable-time"}]
180
- ["route", "one-value-time", {"variable": "value"}]
185
+ {"route": "/one-:variable-time"}
186
+ ["route", "/one-value-time", {"variable": "value"}]
181
187
 
182
188
  [{"route": {"path": "/one-:variable-time", "variable": {"regex": "\\d+"}}}]
183
- ["route", "one-123-time", {"variable": "123"}]
184
- [null, "one-value-time"]
189
+ ["route", "/one-123-time", {"variable": "123"}]
190
+ [null, "/one-value-time"]
185
191
 
186
192
  [{"route": {"path": "/one-:variable-time", "variable": {"regex": "\\d+"}}}]
187
- ["route", "one-123-time", {"variable": "123"}]
188
- [null, "one-value-time"]
193
+ ["route", "/one-123-time", {"variable": "123"}]
194
+ [null, "/one-value-time"]
189
195
 
190
196
  [{"route": "hey.:greed.html"}]
191
197
  ["route", "/hey.greedybody.html", {"greed": "greedybody"}]
@@ -202,62 +208,3 @@
202
208
  {"without_regex": "/:common_variable.:unmatched"}
203
209
  ["with_regex", "/common.123", {"common_variable": "common", "matched": "123"}]
204
210
  ["without_regex", "/common.other", {"common_variable": "common", "unmatched": "other"}]
205
-
206
- {"nothing":{"path":"/", "conditions": {"request_method": "GET"}}}
207
- {"post":{"path":"/test", "conditions": {"request_method": "POST"}}}
208
- {"put":{"path":"/test", "conditions": {"request_method": "PUT"}}}
209
- ["post", {"path": "/test", "method": "POST"}]
210
- [[405, {"Allow": "POST, PUT"}], {"path": "/test", "method": "GET"}]
211
-
212
- {"router": {"path": "/test", "conditions": {"request_method": ["POST", "GET"]}}}
213
- ["router", {"path": "/test", "method": "POST"}]
214
- ["router", {"path": "/test", "method": "GET"}]
215
- [[405, {"Allow": "GET, POST"}], {"path": "/test", "method": "PUT"}]
216
-
217
- {"get": {"path": "/test(.:format)", "conditions": {"request_method": "GET"}}}
218
- {"post": {"path": "/test(.:format)", "conditions": {"request_method": "POST"}}}
219
- {"delete": {"path": "/test(.:format)", "conditions": {"request_method": "DELETE"}}}
220
- ["get", {"path": "/test", "method": "GET"}]
221
- ["post", {"path": "/test", "method": "POST"}]
222
- ["delete", {"path": "/test", "method": "DELETE"}]
223
- ["get", {"path": "/test.html", "method": "GET"}, {"format": "html"}]
224
- ["post", {"path": "/test.html", "method": "POST"}, {"format": "html"}]
225
- ["delete", {"path": "/test.html", "method": "DELETE"}, {"format": "html"}]
226
- [[405, {"Allow": "DELETE, GET, POST"}], {"path": "/test", "method": "PUT"}]
227
-
228
- {"post": {"path": "/test", "conditions": {"request_method": "POST"}}}
229
- {"post_2": {"path": "/test/post", "conditions": {"request_method": "POST"}}}
230
- {"get": {"path": "/test", "conditions": {"request_method": "GET"}}}
231
- {"get_2": {"path": "/test/post", "conditions": {"request_method": "GET"}}}
232
- {"any_2": "/test/post"}
233
- {"any": "/test"}
234
- ["post", {"path": "/test", "method": "POST"}]
235
- ["get", {"path": "/test", "method": "GET"}]
236
- ["any", {"path": "/test", "method": "PUT"}]
237
- ["post_2", {"path": "/test/post", "method": "POST"}]
238
- ["get_2", {"path": "/test/post", "method": "GET"}]
239
- ["any_2", {"path": "/test/post", "method": "PUT"}]
240
-
241
- {"post": {"path": "/test", "conditions": {"request_method": "POST"}}}
242
- {"any": "/test"}
243
- ["post", {"path": "/test", "method": "POST"}]
244
- ["any", {"path": "/test", "method": "PUT"}]
245
-
246
- {"host2_post": {"path": "/test", "conditions": {"request_method": "POST", "host": "host2"}}}
247
- {"host2_get": {"path": "/test", "conditions": {"request_method": "GET", "host": "host2"}}}
248
- {"host2": {"path": "/test", "conditions": {"host": "host2"}}}
249
- {"post": {"path": "/test", "conditions": {"request_method": "POST"}}}
250
- ["host2", {"path": "http://host2/test", "method": "PUT"}]
251
- ["post", {"path": "http://host1/test", "method": "POST"}]
252
- ["host2_get", {"path": "http://host2/test", "method": "GET"}]
253
- ["host2_post", {"path": "http://host2/test", "method": "POST"}]
254
-
255
- {"with": {"path": "/test", "conditions": {"request_method": "GET", "host": {"regex": "host1"}}}}
256
- {"without": {"path": "/test", "conditions": {"request_method": "GET"}}}
257
- ["without", "http://host2/test"]
258
- ["with", "http://host2.host1.com/test"]
259
-
260
- {"http": {"path": "/test", "conditions": {"scheme": "http"}}}
261
- {"https": {"path": "/test", "conditions": {"scheme": "https"}}}
262
- ["http", {"path": "/test", "scheme": "http"}]
263
- ["https", {"path": "/test", "scheme": "https"}]