module Roda::RodaPlugins::Base::RequestMethods
Instance methods for RodaRequest
, mostly related to handling routing for the request.
Constants
- EMPTY_STRING
- GET_REQUEST_METHOD
- PATH_INFO
- REQUEST_METHOD
- SCRIPT_NAME
- SEGMENT
- SLASH
- TERM
- TERM_INSPECT
Attributes
The current captures for the request. This gets modified as routing occurs.
Public Class Methods
Store the roda instance and environment.
# File lib/roda.rb, line 433 def initialize(scope, env) @scope = scope @captures = [] super(env) end
Public Instance Methods
Handle match block return values. By default, if a string is given and the response is empty, use the string as the response body.
# File lib/roda.rb, line 473 def block_result(result) res = response if res.empty? && (body = block_result_body(result)) res.write(body) end end
As request routing modifies SCRIPT_NAME
and PATH_INFO
, this exists as a helper method to get the full path of the request.
r.env['SCRIPT_NAME'] = '/foo' r.env['PATH_INFO'] = '/bar' r.full_path_info # => '/foo/bar'
# File lib/roda.rb, line 446 def full_path_info "#{@env[SCRIPT_NAME]}#{@env[PATH_INFO]}" end
Immediately stop execution of the route block and return the given rack response array of status, headers, and body. If no argument is given, uses the current response.
r.halt [200, {'Content-Type'=>'text/html'}, ['Hello World!']] response.status = 200 response['Content-Type'] = 'text/html' response.write 'Hello World!' r.halt
# File lib/roda.rb, line 460 def halt(res=response.finish) throw :halt, res end
Show information about current request, including request class, request method and full path.
r.inspect # => '#<Roda::RodaRequest GET /foo/bar>'
# File lib/roda.rb, line 485 def inspect "#<#{self.class.inspect} #{@env[REQUEST_METHOD]} #{full_path_info}>" end
Does a terminal match on the current path, matching only if the arguments have fully matched the path. If it matches, the match block is executed, and when the match block returns, the rack response is returned.
r.path_info # => "/foo/bar" r.is 'foo' do # does not match, as path isn't fully matched (/bar remaining) end r.is 'foo/bar' do # matches as path is empty after matching end
If no arguments are given, matches if the path is already fully matched.
r.on 'foo/bar' do r.is do # matches as path is already empty end end
Note that this matches only if the path after matching the arguments is empty, not if it still contains a trailing slash:
r.path_info # => "/foo/bar/" r.is 'foo/bar' do # does not match, as path isn't fully matched (/ remaining) end r.is 'foo/bar/' do # matches as path is empty after matching end r.on 'foo/bar' do r.is "" do # matches as path is empty after matching end end
# File lib/roda.rb, line 532 def is(*args, &block) if args.empty? if @env[PATH_INFO] == EMPTY_STRING always(&block) end else args << TERM if_match(args, &block) end end
Optimized method for whether this request is a GET
request. Similar to the default Rack::Request get? method, but can be overridden without changing rack’s behavior.
# File lib/roda.rb, line 467 def is_get? @env[REQUEST_METHOD] == GET_REQUEST_METHOD end
Does a match on the path, matching only if the arguments have matched the path. Because this doesn’t fully match the path, this is usually used to setup branches of the routing tree, not for final handling of the request.
r.path_info # => "/foo/bar" r.on 'foo' do # matches, path is /bar after matching end r.on 'bar' do # does not match end
Like other routing methods, If it matches, the match block is executed, and when the match block returns, the rack response is returned. However, in general you will call another routing method inside the match block that fully matches the path and does the final handling for the request:
r.on 'foo' do r.is 'bar' do # handle /foo/bar request end end
# File lib/roda.rb, line 570 def on(*args, &block) if args.empty? always(&block) else if_match(args, &block) end end
Immediately redirect to the path using the status code. This ends the processing of the request:
r.redirect '/page1', 301 if r['param'] == 'value1' r.redirect '/page2' # uses 302 status code response.status = 404 # not reached
If you do not provide a path, by default it will redirect to the same path if the request is not a GET
request. This is designed to make it easy to use where a POST
request to a URL changes state, GET
returns the current state, and you want to show the current state after changing:
r.is "foo" do r.get do # show state end r.post do # change state r.redirect end end
# File lib/roda.rb, line 611 def redirect(path=default_redirect_path, status=302) response.redirect(path, status) throw :halt, response.finish end
The response related to the current request. See ResponseMethods
for instance methods for the response, but in general the most common usage is to override the response status and headers:
response.status = 200 response['Header-Name'] = 'Header value'
# File lib/roda.rb, line 584 def response scope.response end
Routing matches that only matches GET
requests where the current path is /
. If it matches, the match block is executed, and when the match block returns, the rack response is returned.
[r.request_method, r.path_info] # => ['GET', '/'] r.root do # matches end
This is usuable inside other match blocks:
[r.request_method, r.path_info] # => ['GET', '/foo/'] r.on 'foo' do r.root do # matches end end
Note that this does not match non-GET
requests:
[r.request_method, r.path_info] # => ['POST', '/'] r.root do # does not match end
Use r.post ""
for POST
requests where the current path is /
.
Nor does it match empty paths:
[r.request_method, r.path_info] # => ['GET', '/foo'] r.on 'foo' do r.root do # does not match end end
Use r.get true
to handle GET
requests where the current path is empty.
# File lib/roda.rb, line 663 def root(&block) if @env[PATH_INFO] == SLASH && is_get? always(&block) end end
Call the given rack app with the environment and return the response from the rack app as the response for this request. This ends the processing of the request:
r.run(proc{[403, {}, []]}) unless r['letmein'] == '1' r.run(proc{[404, {}, []]}) response.status = 404 # not reached
# File lib/roda.rb, line 676 def run(app) throw :halt, app.call(@env) end
Private Instance Methods
Match any of the elements in the given array. Return at the first match without evaluating future matches. Returns false if no elements in the array match.
# File lib/roda.rb, line 685 def _match_array(matcher) matcher.any? do |m| if matched = match(m) if m.is_a?(String) captures.push(m) end end matched end end
Match the given hash if all hash matchers match.
# File lib/roda.rb, line 703 def _match_hash(hash) hash.all?{|k,v| send("match_#{k}", v)} end
Match the given regexp exactly if it matches a full segment.
# File lib/roda.rb, line 698 def _match_regexp(re) consume(self.class.cached_matcher(re){re}) end
Match the given string to the request path. Regexp escapes the string so that regexp metacharacters are not matched, and recognizes colon tokens for placeholders.
# File lib/roda.rb, line 710 def _match_string(str) consume(self.class.cached_matcher(str){Regexp.escape(str).gsub(/:(\w+)/){|m| _match_symbol_regexp($1)}}) end
Match the given symbol if any segment matches.
# File lib/roda.rb, line 715 def _match_symbol(sym) consume(self.class.cached_matcher(sym){_match_symbol_regexp(sym)}) end
The regular expression to use for matching symbols. By default, any non-empty segment matches.
# File lib/roda.rb, line 721 def _match_symbol_regexp(s) SEGMENT end
Backbone of the verb method support, using a terminal match if args is not empty, or a regular match if it is empty.
# File lib/roda.rb, line 727 def _verb(args, &block) if args.empty? always(&block) else args << TERM if_match(args, &block) end end
Yield to the match block and return rack response after the block returns.
# File lib/roda.rb, line 737 def always block_result(yield) throw :halt, response.finish end
The body to use for the response if the response does not return a body. By default, a String is returned directly, and nil is returned otherwise.
# File lib/roda.rb, line 745 def block_result_body(result) if result.is_a?(String) result end end
Attempts to match the pattern to the current path. If there is no match, returns false without changes. Otherwise, modifies SCRIPT_NAME
to include the matched path, removes the matched path from PATH_INFO
, and updates captures with any regex captures.
# File lib/roda.rb, line 755 def consume(pattern) env = @env return unless matchdata = env[PATH_INFO].match(pattern) vars = matchdata.captures # Don't mutate SCRIPT_NAME, breaks try env[SCRIPT_NAME] += vars.shift env[PATH_INFO] = matchdata.post_match captures.concat(vars) end
The default path to use for redirects when a path is not given. For non-GET requests, redirects to the current path, which will trigger a GET request. This is to make the common case where a POST request will redirect to a GET request at the same location will work fine.
If the current request is a GET request, raise an error, as otherwise it is easy to create an infinite redirect.
# File lib/roda.rb, line 776 def default_redirect_path raise RodaError, "must provide path argument to redirect for get requests" if is_get? full_path_info end
If all of the arguments match, yields to the match block and returns the rack response when the block returns. If any of the match arguments doesn’t match, does nothing.
# File lib/roda.rb, line 784 def if_match(args) env = @env script = env[SCRIPT_NAME] path = env[PATH_INFO] # For every block, we make sure to reset captures so that # nesting matchers won't mess with each other's captures. captures.clear return unless match_all(args) block_result(yield(*captures)) throw :halt, response.finish ensure env[SCRIPT_NAME] = script env[PATH_INFO] = path end
Attempt to match the argument to the given request, handling common ruby types.
# File lib/roda.rb, line 803 def match(matcher) case matcher when String _match_string(matcher) when Regexp _match_regexp(matcher) when Symbol _match_symbol(matcher) when TERM @env[PATH_INFO] == EMPTY_STRING when Hash _match_hash(matcher) when Array _match_array(matcher) when Proc matcher.call else matcher end end
Match only if all of the arguments in the given array match.
# File lib/roda.rb, line 825 def match_all(args) args.all?{|arg| match(arg)} end
Match files with the given extension. Requires that the request path end with the extension.
# File lib/roda.rb, line 831 def match_extension(ext) consume(self.class.cached_matcher([:extension, ext]){/([^\\\/]+)\.#{ext}/}) end
Match by request method. This can be an array if you want to match on multiple methods.
# File lib/roda.rb, line 837 def match_method(type) if type.is_a?(Array) type.any?{|t| match_method(t)} else type.to_s.upcase == @env[REQUEST_METHOD] end end
Match the given parameter if present, even if the parameter is empty. Adds any match to the captures.
# File lib/roda.rb, line 847 def match_param(key) if v = self[key] captures << v end end
Match the given parameter if present and not empty. Adds any match to the captures.
# File lib/roda.rb, line 855 def match_param!(key) if (v = self[key]) && !v.empty? captures << v end end