Expose global and per-route Mustermann options

This commit is contained in:
Mike Pastore 2017-01-13 16:38:04 -06:00
parent 004daf4922
commit 910a9f72a8
3 changed files with 46 additions and 9 deletions

View File

@ -257,6 +257,20 @@ end
By the way, unless you disable the path traversal attack protection (see below),
the request path might be modified before matching against your routes.
You may customize the Mustermann options used for a given route by passing in a
`:mustermann_opts` hash:
```ruby
get '\A/posts\z', :mustermann_opts => { :type => :regexp, :check_anchors => false } do
# matches /posts exactly, with explicit anchoring
"If you match an anchored pattern clap your hands!"
end
```
It looks like a [condition](#conditions), but it isn't one! These options will
be merged into the global `:mustermann_opts` hash described
[below](#available-settings).
## Conditions
Routes may include a variety of matching conditions, such as the user agent:
@ -2254,6 +2268,12 @@ set :protection, :session => true
don't support it.
</dd>
<dt>mustermann_opts</dt>
<dd>
A default hash of options to pass to Mustermann.new when compiling routing
paths.
</dd>
<dt>port</dt>
<dd>Port to listen on. Only used for built-in server.</dd>

View File

@ -1607,8 +1607,6 @@ module Sinatra
end
def route(verb, path, options = {}, &block)
# Because of self.options.host
host_name(options.delete(:host)) if options.key?(:host)
enable :empty_path_info if path == "" and empty_path_info.nil?
signature = compile!(verb, path, block, options)
(@routes[verb] ||= []) << signature
@ -1628,9 +1626,14 @@ module Sinatra
end
def compile!(verb, path, block, **options)
# Because of self.options.host
host_name(options.delete(:host)) if options.key?(:host)
# Pass Mustermann opts to compile()
route_mustermann_opts = options.key?(:mustermann_opts) ? options.delete(:mustermann_opts) : {}.freeze
options.each_pair { |option, args| send(option, *args) }
pattern = compile(path)
pattern = compile(path, route_mustermann_opts)
method_name = "#{verb} #{path}"
unbound_method = generate_method(method_name, &block)
conditions, @conditions = @conditions, []
@ -1641,8 +1644,8 @@ module Sinatra
[ pattern, conditions, wrapper ]
end
def compile(path)
Mustermann.new(path)
def compile(path, route_mustermann_opts = {})
Mustermann.new(path, mustermann_opts.merge(route_mustermann_opts))
end
def setup_default_middleware(builder)
@ -1786,6 +1789,7 @@ module Sinatra
set :x_cascade, true
set :add_charset, %w[javascript xml xhtml+xml].map { |t| "application/#{t}" }
settings.add_charset << /^text\//
set :mustermann_opts, {}
# explicitly generating a session secret eagerly to play nice with preforking
begin

View File

@ -2,9 +2,9 @@
require File.expand_path('../helper', __FILE__)
class CompileTest < Minitest::Test
def self.parses pattern, example, expected_params
def self.parses pattern, example, expected_params, mtype = :sinatra, mopts = {}
it "parses #{example} with #{pattern} into params #{expected_params}" do
compiled = mock_app {}.send(:compile, pattern)
compiled = mock_app { set :mustermann_opts, :type => mtype }.send(:compile, pattern, mopts)
params = compiled.params(example)
fail %Q{"#{example}" does not parse on pattern "#{pattern}".} unless params
@ -12,14 +12,22 @@ class CompileTest < Minitest::Test
end
end
def self.fails pattern, example
def self.fails pattern, example, mtype = :sinatra, mopts = {}
it "does not parse #{example} with #{pattern}" do
compiled = mock_app {}.send(:compile, pattern)
compiled = mock_app { set :mustermann_opts, :type => mtype }.send(:compile, pattern, mopts)
match = compiled.match(example)
fail %Q{"#{pattern}" does parse "#{example}" but it should fail} if match
end
end
def self.raises pattern, mtype = :sinatra, mopts = {}
it "does not compile #{pattern}" do
assert_raises(Mustermann::CompileError, %Q{Pattern "#{pattern}" compiles but it should not}) do
mock_app { set :mustermann_opts, :type => mtype }.send(:compile, pattern, mopts)
end
end
end
parses "/", "/", {}
parses "/foo", "/foo", {}
@ -129,4 +137,9 @@ class CompileTest < Minitest::Test
# From issue #688.
#
parses "/articles/10.1103/:doi", "/articles/10.1103/PhysRevLett.110.026401", "doi" => "PhysRevLett.110.026401"
# Mustermann anchoring
fails "/bar", "/foo/bar", :regexp
raises "^/foo/bar$", :regexp
parses "^/foo/bar$", "/foo/bar", {}, :regexp, :check_anchors => false
end