require File.join(File.dirname(__FILE__), "..", "spec_helper") describe "When recognizing requests," do describe "a route with a String path condition" do before(:each) do Merb::Router.prepare do match("/info").to(:controller => "info", :action => "foo") end end it "should match the path and return the parameters passed to #to" do route_for("/info").should have_route(:controller => "info", :action => "foo", :id => nil) end it "should not match a different path" do lambda { route_for("/notinfo") }.should raise_not_found end it "should ignore trailing slashes" do Merb::Router.prepare do match("/hello/").to(:controller => "world") end route_for("/hello").should have_route(:controller => "world") end it "should ignore repeated slashes" do Merb::Router.prepare do match("/foo///bar").to(:controller => "fubar") match("/hello//world").to(:controller => "greetings") end route_for("/foo/bar").should have_route(:controller => "fubar") route_for("/hello/world").should have_route(:controller => "greetings") end end describe "a route with a Request method condition" do before(:each) do Merb::Router.prepare do match(:method => :post).to(:controller => "all", :action => "posting") end end it "should match any path with a post method" do route_for("/foo/create/12", :method => "post").should have_route(:controller => "all", :action => "posting") route_for("", :method => "post").should have_route(:controller => "all", :action => "posting") end it "should not match any paths that don't have a post method" do lambda { route_for("/foo/create/12", :method => "get") }.should raise_not_found lambda { route_for("", :method => "get") }.should raise_not_found end it "should combine Array elements using OR" do Merb::Router.prepare do match(:method => [:get, :post]).to(:controller => "hello") end route_for('/anything', :method => "get").should have_route(:controller => "hello") route_for('/anything', :method => "post").should have_route(:controller => "hello") lambda { route_for('/anything', :method => "put") }.should raise_not_found lambda { route_for('/anything', :method => "delete") }.should raise_not_found end it "should be able to handle Regexps inside of condition arrays" do Merb::Router.prepare do match(:method => [/^g[aeiou]?t$/, :post]).to(:controller => "hello") end route_for('/anything', :method => "get").should have_route(:controller => "hello") route_for('/anything', :method => "post").should have_route(:controller => "hello") lambda { route_for('/anything', :method => "put") }.should raise_not_found lambda { route_for('/anything', :method => "delete") }.should raise_not_found end it "should ignore nil values" do Merb::Router.prepare do match("/hello", :method => nil).to(:controller => "all") end [:get, :post, :puts, :delete].each do |method| route_for("/hello", :method => method).should have_route(:controller => "all") end end end describe "a route with Request method condition and a path condition" do before(:each) do Merb::Router.prepare do match("/foo", :protocol => "http").to(:controller => "plain", :action => "text") end end it "should match the route if the path and the protocol match" do route_for("/foo", :protocol => "http").should have_route(:controller => "plain", :action => "text") end it "should not match if the route does not match" do lambda { route_for("/bar", :protocol => "http") }.should raise_not_found end it "should not match if the protocol does not match" do lambda { route_for("/foo", :protocol => "https") }.should raise_not_found end it "should combine Array elements using OR" do Merb::Router.prepare do match("/hello", :method => [:get, :post]).to(:controller => "hello") end route_for("/hello", :method => "get").should have_route(:controller => "hello") route_for("/hello", :method => "post").should have_route(:controller => "hello") lambda { route_for("/hello", :method => "put") }.should raise_not_found lambda { route_for("/hello", :method => "delete") }.should raise_not_found lambda { route_for("/goodbye", :method => "get") }.should raise_not_found lambda { route_for("/goodbye", :method => "post") }.should raise_not_found lambda { route_for("/goodbye", :method => "put") }.should raise_not_found lambda { route_for("/goodbye", :method => "delete") }.should raise_not_found end end describe "a route containing path variable conditions" do it "should match only if the condition is satisfied" do Merb::Router.prepare do match("/foo/:bar", :bar => /\d+/).register end route_for("/foo/123").should have_route(:bar => "123") lambda { route_for("/foo/abc") }.should raise_not_found end it "should be able to handle conditions with anchors" do Merb::Router.prepare do match("/foo/:bar") do match(:bar => /^\d+$/).to(:controller => "both") match(:bar => /^\d+/ ).to(:controller => "start") match(:bar => /\d+$/ ).to(:controller => "end") match(:bar => /\d+/ ).to(:controller => "none") end end route_for("/foo/123456").should have_route(:controller => "both", :bar => "123456") route_for("/foo/123abc").should have_route(:controller => "start", :bar => "123abc") route_for("/foo/abc123").should have_route(:controller => "end", :bar => "abc123") route_for("/foo/ab123c").should have_route(:controller => "none", :bar => "ab123c") lambda { route_for("/foo/abcdef") }.should raise_not_found end it "should match only if all conditions are satisied" do Merb::Router.prepare do match("/:foo/:bar", :foo => /abc/, :bar => /123/).register end route_for("/abc/123").should have_route(:foo => "abc", :bar => "123") route_for("/abcd/123").should have_route(:foo => "abcd", :bar => "123") route_for("/abc/1234").should have_route(:foo => "abc", :bar => "1234") route_for("/abcd/1234").should have_route(:foo => "abcd", :bar => "1234") lambda { route_for("/ab/123") }.should raise_not_found lambda { route_for("/abc/12") }.should raise_not_found lambda { route_for("/ab/12") }.should raise_not_found end it "should allow creating conditions that span default segment dividers" do Merb::Router.prepare do match("/:controller", :controller => %r[^[a-z]+/[a-z]+$]).register end lambda { route_for("/somewhere") }.should raise_not_found route_for("/somewhere/somehow").should have_route(:controller => "somewhere/somehow") end it "should allow creating conditions that match everything" do Merb::Router.prepare do match("/:glob", :glob => /.*/).register end %w(somewhere somewhere/somehow 123/456/789 i;just/dont-understand).each do |path| route_for("/#{path}").should have_route(:glob => path) end end it "should allow greedy matches to preceed segments" do Merb::Router.prepare do match("/foo/:bar/something/:else", :bar => /.*/).register end %w(somewhere somewhere/somehow 123/456/789 i;just/dont-understand).each do |path| route_for("/foo/#{path}/something/wonderful").should have_route(:bar => path, :else => "wonderful") end end it "should allow creating conditions that proceed a glob" do Merb::Router.prepare do match("/:foo/bar/:glob", :glob => /.*/).register end %w(somewhere somewhere/somehow 123/456/789 i;just/dont-understand).each do |path| route_for("/superblog/bar/#{path}").should have_route(:foo => "superblog", :glob => path) lambda { route_for("/notablog/foo/#{path}") }.should raise_not_found end end it "should match only if all mixed conditions are satisied" do Merb::Router.prepare do match("/:blog/post/:id", :blog => %r{^[a-zA-Z]+$}, :id => %r{^[0-9]+$}).register end route_for("/superblog/post/123").should have_route(:blog => "superblog", :id => "123") route_for("/superblawg/post/321").should have_route(:blog => "superblawg", :id => "321") lambda { route_for("/superblog/post/asdf") }.should raise_not_found lambda { route_for("/superblog1/post/123") }.should raise_not_found lambda { route_for("/ab/12") }.should raise_not_found end it "should raise an error when :path is used as a variable in the path" do bad_path = lambda do Merb::Router.prepare do match("/:path").register end end bad_path.should raise_error(Merb::Router::Behavior::Error) end end describe "a route built with nested conditions" do it "should support block matchers as a path namespace" do Merb::Router.prepare do match("/foo") do match("/bar").to(:controller => "one/two", :action => "baz") end end route_for("/foo/bar").should have_route(:controller => "one/two", :action => "baz") end it "should yield the builder object" do Merb::Router.prepare do match("/foo") do |path| path.match("/bar").to(:controller => "one/two", :action => "baz") end end route_for("/foo/bar").should have_route(:controller => "one/two", :action => "baz") end it "should be able to nest named segment variables" do Merb::Router.prepare do match("/:first") do match("/:second").register end end route_for("/one/two").should have_route(:first => "one", :second => "two") lambda { route_for("/one") }.should raise_not_found end it "should ignore trailing slashes" do Merb::Router.prepare do match("/hello") do match("/").to(:controller => "greetings") end end route_for("/hello").should have_route(:controller => "greetings") end it "should ignore double slashes" do Merb::Router.prepare do match("/hello/") do match("/world").to(:controller => "greetings") end end route_for("/hello/world").should have_route(:controller => "greetings") end it "should be able to define a route and still use the context for more route definition" do Merb::Router.prepare do match("/hello") do to(:controller => "foo", :action => "bar") match("/world").to(:controller => "hello", :action => "world") end end route_for("/hello").should have_route(:controller => "foo", :action => "bar") route_for("/hello/world").should have_route(:controller => "hello", :action => "world") end it "should be able to add blank paths without effecting the actual path" do Merb::Router.prepare do match("/foo") do match("").to(:controller => "one/two", :action => "index") end end route_for("/foo").should have_route(:controller => "one/two", :action => "index") end it "should be able to merge path and request method conditions" do Merb::Router.prepare do match("/:controller") do match(:protocol => "https").to(:action => "bar") end end lambda { route_for("/foo") }.should raise_not_found route_for("/foo", :protocol => "https").should have_route(:controller => "foo", :action => "bar") end it "should be able to override previously set Request method conditions" do Merb::Router.prepare do match(:domain => "foo.com") do match("/", :domain => "bar.com").to(:controller => "bar", :action => "com") end end lambda { route_for("/") }.should raise_not_found lambda { route_for("/", :domain => "foo.com") }.should raise_not_found route_for("/", :domain => "bar.com").should have_route(:controller => "bar", :action => "com") end it "should be able to override previously set named segment variable conditions" do Merb::Router.prepare do match("/:account", :account => /^\d+$/) do match(:account => /^[a-z]+$/).register end end route_for("/abc").should have_route(:account => "abc") lambda { route_for("/123") }.should raise_not_found end it "should be able to set conditions on named segment variables that haven't been used yet" do Merb::Router.prepare do match(:account => /^[a-z]+$/) do match("/:account").register end end route_for("/abc").should have_route(:account => "abc") lambda { route_for("/123") }.should raise_not_found end it "should be able to merge path and request method conditions when both kinds are specified in the parent match statement" do Merb::Router.prepare do match("/:controller", :protocol => "https") do match("/greets").to(:action => "bar") end end lambda { route_for("/foo") }.should raise_not_found lambda { route_for("/foo/greets") }.should raise_not_found lambda { route_for("/foo", :protocol => "https") }.should raise_not_found route_for("/foo/greets", :protocol => "https").should have_route(:controller => "foo", :action => "bar") end it "allows wrapping of nested routes all having shared argument with PREDEFINED VALUES" do Merb::Router.prepare do match(%r{/?(en|es|fr|be|nl)?}).to(:language => "[1]") do match("/guides/:action/:id").to(:controller => "tour_guides") end end route_for('/nl/guides/search/denboss').should have_route(:controller => 'tour_guides', :action => "search", :id => "denboss", :language => "nl") route_for('/es/guides/search/barcelona').should have_route(:controller => 'tour_guides', :action => "search", :id => "barcelona", :language => "es") route_for('/fr/guides/search/lille').should have_route(:controller => 'tour_guides', :action => "search", :id => "lille", :language => "fr") route_for('/en/guides/search/london').should have_route(:controller => 'tour_guides', :action => "search", :id => "london", :language => "en") route_for('/be/guides/search/brussels').should have_route(:controller => 'tour_guides', :action => "search", :id => "brussels", :language => "be") route_for('/guides/search/brussels').should have_route(:controller => 'tour_guides', :action => "search", :id => "brussels") end end describe "multiple routes" do # --- Catches a weird bug --- it "should not leak conditions" do Merb::Router.prepare do match("/root") do |r| r.match('/foo').to r.match('/bar').to(:hello => "world") end end route_for("/root/bar").should have_route(:hello => "world") end end end