diff --git a/README.md b/README.md
index 71da5a72..5ae49a60 100644
--- a/README.md
+++ b/README.md
@@ -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.
+
mustermann_opts
+
+ A default hash of options to pass to Mustermann.new when compiling routing
+ paths.
+
+
port
Port to listen on. Only used for built-in server.
diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb
index 97777788..3d83652f 100644
--- a/lib/sinatra/base.rb
+++ b/lib/sinatra/base.rb
@@ -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
diff --git a/test/compile_test.rb b/test/compile_test.rb
index 4c0a7975..097cc143 100644
--- a/test/compile_test.rb
+++ b/test/compile_test.rb
@@ -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