Skip to content

Commit

Permalink
Support options passed to url_for
Browse files Browse the repository at this point in the history
I decided to mangle the existing test suite while I was at it, to make it
generic and easier to extend with more tests in the future.
  • Loading branch information
mpalmer committed Mar 6, 2011
1 parent a9eab6d commit f1ff199
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 15 deletions.
28 changes: 25 additions & 3 deletions lib/sinatra/url_for.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,32 @@ module UrlForHelper
# url_for "/" # Returns "/myapp/"
# url_for "/foo" # Returns "/myapp/foo"
# url_for "/foo", :full # Returns "http://example.com/myapp/foo"
#
# You can also pass in a hash of options, which will be appended to the
# URL as escaped parameters, like so:
#
# url_for "/", :x => "y" # Returns "/myapp/?x=y"
# url_for "/foo", :x => "M&Ms" # Returns "/myapp/foo?x=M%26Ms"
#
# You can also specify the mode:
#
# url_for "/foo", :full, :x => "y" # Returns "http://example.com/myapp/foo?x=y"
#
#--
# See README.rdoc for a list of some of the people who helped me clean
# up earlier versions of this code.
def url_for url_fragment, mode=:path_only
def url_for url_fragment, mode=nil, options = nil
if mode.nil?
mode = :path_only
end

mode = mode.to_sym unless mode.is_a? Symbol
optstring = nil

if options.is_a? Hash
optstring = '?' + options.map { |k,v| "#{k}=#{URI.escape(v, /[^#{URI::PATTERN::UNRESERVED}]/)}" }.join('&')
end

case mode
when :path_only
base = request.script_name
Expand All @@ -27,9 +49,9 @@ def url_for url_fragment, mode=:path_only
end
base = "#{scheme}://#{request.host}#{port}#{request.script_name}"
else
raise TypeError, "Unknown url_for mode #{mode}"
raise TypeError, "Unknown url_for mode #{mode.inspect}"
end
"#{base}#{url_fragment}"
"#{base}#{url_fragment}#{optstring}"
end
end

Expand Down
64 changes: 52 additions & 12 deletions spec/url_for_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
require 'sinatra/url_for'
require 'rack/test'

# HTML exception pages in tests isn't useful; raise them to rspec so it can
# tell us about them
disable :show_exceptions
enable :raise_errors

get "/" do
content_type "text/plain"
<<"EOD"
#{url_for("/")}
#{url_for("/foo")}
#{url_for("/foo", :full)}
EOD
url_for params[:url], params[:mode], params[:options]
end

describe Sinatra::UrlForHelper do
Expand All @@ -19,13 +20,52 @@ def app
Sinatra::Application
end

it "should return absolute paths and full URLs" do
get "/"
it "should handle the root URL" do
get "/", :url => "/"

last_response.should be_ok
last_response.body.should == "/"
end

it "should handle sub-URLs" do
get "/", :url => "/foo"

last_response.should be_ok
last_response.body.should == "/foo"
end

it "should provide full paths if asked" do
get "/", :url => "/foo", :mode => :full

last_response.should be_ok
last_response.body.should == "http://example.org/foo"
end

it "should accept options" do
get "/", :url => "/foo", :options => { :x => "y" }

last_response.should be_ok
last_response.body.should == "/foo?x=y"
end

it "should accept multiple options" do
get "/", :url => "/foo", :options => { :x => "y", :bar => "wombat" }

last_response.should be_ok
last_response.body.should == "/foo?x=y&bar=wombat"
end

it "should escape option values" do
get "/", :url => "/foo", :options => { :x => "M&Ms", :amount => "15%", :equals => "=" }

last_response.should be_ok
last_response.body.should == "/foo?x=M%26Ms&amount=15%25&equals=%3D"
end

it "should even escape URLs" do
get "/", :url => "/foo", :options => { :return_to => "http://example.com/bar?x=y" }

last_response.should be_ok
last_response.body.should == <<EOD
/
/foo
http://example.org/foo
EOD
last_response.body.should == "/foo?return_to=http%3A%2F%2Fexample.com%2Fbar%3Fx%3Dy"
end
end

0 comments on commit f1ff199

Please sign in to comment.