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