├── .document ├── .gitignore ├── Gemfile ├── LICENSE ├── README.rdoc ├── Rakefile ├── VERSION.yml ├── lib └── sinatra │ └── url_for.rb ├── sinatra-url-for.gemspec └── spec ├── spec_helper.rb └── url_for_spec.rb /.document: -------------------------------------------------------------------------------- 1 | README.rdoc 2 | lib/**/*.rb 3 | bin/* 4 | features/**/*.feature 5 | LICENSE 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.sw? 2 | .DS_Store 3 | coverage 4 | rdoc 5 | pkg 6 | *~ 7 | Gemfile.lock 8 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | sinatra-url-for - Construct absolute paths and full URLs 2 | Copyright 2009 Eric Kidd 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = sinatra-url-for 2 | 3 | sinatra-url-for constructs absolute paths and full URLs for 4 | handlers in a Sinatra application. Assuming that your application is 5 | running on example.com, and that it has been mapped to 6 | /myapp, you should be able call +url_for+ from within a 7 | handler as follows: 8 | 9 | url_for "/" # Returns "/myapp/" 10 | url_for "/foo" # Returns "/myapp/foo" 11 | url_for "/foo", :full # Returns "http://example.com/myapp/foo" 12 | 13 | To install it, run: 14 | 15 | sudo gem install emk-sinatra-url-for -s http://gems.github.com 16 | 17 | To include it in a Sinatra application, write: 18 | 19 | require 'rubygems' 20 | gem 'emk-sinatra-url-for' 21 | require 'sinatra/url_for' 22 | 23 | If you're subclassing Sinatra::Base, then you need to call 24 | helpers manually: 25 | 26 | class MyApp < Sinatra::Base 27 | helpers Sinatra::UrlForHelper 28 | # ... 29 | end 30 | 31 | Thanks to "cypher23" on #mephisto and the folks on #rack for pointing me in 32 | the right direction. If this gem fails to work correctly on your 33 | system, please feel free to submit patches and/or bug reports! 34 | 35 | == Copyright 36 | 37 | Copyright 2009 Eric Kidd. See LICENSE for details. 38 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'rake' 3 | 4 | begin 5 | require 'jeweler' 6 | Jeweler::Tasks.new do |gem| 7 | gem.name = "sinatra-url-for" 8 | gem.summary = %Q{Construct absolute paths and full URLs for a Sinatra application} 9 | gem.email = "git@randomhacks.net" 10 | gem.homepage = "http://github.com/emk/sinatra-url-for" 11 | gem.authors = ["Eric Kidd"] 12 | 13 | gem.add_runtime_dependency 'sinatra', ['>= 0.9.1.1'] 14 | gem.add_development_dependency 'rspec', ['>= 1.1.11'] 15 | 16 | # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings 17 | end 18 | rescue LoadError 19 | puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com" 20 | end 21 | 22 | require 'spec/rake/spectask' 23 | Spec::Rake::SpecTask.new(:spec) do |spec| 24 | spec.libs << 'lib' << 'spec' 25 | spec.spec_files = FileList['spec/**/*_spec.rb'] 26 | end 27 | 28 | Spec::Rake::SpecTask.new(:rcov) do |spec| 29 | spec.libs << 'lib' << 'spec' 30 | spec.pattern = 'spec/**/*_spec.rb' 31 | spec.rcov = true 32 | end 33 | 34 | 35 | task :default => :spec 36 | 37 | require 'rake/rdoctask' 38 | Rake::RDocTask.new do |rdoc| 39 | if File.exist?('VERSION.yml') 40 | config = YAML.load(File.read('VERSION.yml')) 41 | version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}" 42 | else 43 | version = "" 44 | end 45 | 46 | rdoc.rdoc_dir = 'rdoc' 47 | rdoc.title = "sinatra-url-for #{version}" 48 | rdoc.rdoc_files.include('README*') 49 | rdoc.rdoc_files.include('lib/**/*.rb') 50 | end 51 | 52 | -------------------------------------------------------------------------------- /VERSION.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :major: 0 3 | :minor: 2 4 | :patch: 1 5 | -------------------------------------------------------------------------------- /lib/sinatra/url_for.rb: -------------------------------------------------------------------------------- 1 | module Sinatra 2 | module UrlForHelper 3 | # Construct a link to +url_fragment+, which should be given relative to 4 | # the base of this Sinatra app. The mode should be either 5 | # :path_only, which will generate an absolute path within 6 | # the current domain (the default), or :full, which will 7 | # include the site name and port number. (The latter is typically 8 | # necessary for links in RSS feeds.) Example usage: 9 | # 10 | # url_for "/" # Returns "/myapp/" 11 | # url_for "/foo" # Returns "/myapp/foo" 12 | # url_for "/foo", :full # Returns "http://example.com/myapp/foo" 13 | # 14 | # You can also pass in a hash of options, which will be appended to the 15 | # URL as escaped parameters, like so: 16 | # 17 | # url_for "/", :x => "y" # Returns "/myapp/?x=y" 18 | # url_for "/foo", :x => "M&Ms" # Returns "/myapp/foo?x=M%26Ms" 19 | # 20 | # You can also specify the mode: 21 | # 22 | # url_for "/foo", :full, :x => "y" # Returns "http://example.com/myapp/foo?x=y" 23 | # 24 | #-- 25 | # See README.rdoc for a list of some of the people who helped me clean 26 | # up earlier versions of this code. 27 | def url_for url_fragment, mode=nil, options = nil 28 | if mode.is_a? Hash 29 | options = mode 30 | mode = nil 31 | end 32 | 33 | if mode.nil? 34 | mode = :path_only 35 | end 36 | 37 | mode = mode.to_sym unless mode.is_a? Symbol 38 | optstring = nil 39 | 40 | if options.is_a? Hash 41 | optstring = '?' + options.map { |k,v| "#{k}=#{URI.escape(v.to_s, /[^#{URI::PATTERN::UNRESERVED}]/)}" }.join('&') 42 | end 43 | 44 | case mode 45 | when :path_only 46 | base = request.script_name 47 | when :full 48 | scheme = request.scheme 49 | if (scheme == 'http' && request.port == 80 || 50 | scheme == 'https' && request.port == 443) 51 | port = "" 52 | else 53 | port = ":#{request.port}" 54 | end 55 | base = "#{scheme}://#{request.host}#{port}#{request.script_name}" 56 | else 57 | raise TypeError, "Unknown url_for mode #{mode.inspect}" 58 | end 59 | "#{base}#{url_fragment}#{optstring}" 60 | end 61 | end 62 | 63 | helpers UrlForHelper 64 | end 65 | -------------------------------------------------------------------------------- /sinatra-url-for.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | Gem::Specification.new do |s| 4 | s.name = %q{sinatra-url-for} 5 | s.version = "0.2.1" 6 | 7 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= 8 | s.authors = ["Eric Kidd"] 9 | s.date = %q{2009-04-22} 10 | s.email = %q{git@randomhacks.net} 11 | s.extra_rdoc_files = ["README.rdoc", "LICENSE"] 12 | s.files = ["README.rdoc", "VERSION.yml", "lib/sinatra", "lib/sinatra/url_for.rb", "spec/spec_helper.rb", "spec/url_for_spec.rb", "LICENSE"] 13 | s.has_rdoc = true 14 | s.homepage = %q{http://github.com/emk/sinatra-url-for} 15 | s.rdoc_options = ["--inline-source", "--charset=UTF-8"] 16 | s.require_paths = ["lib"] 17 | s.rubygems_version = %q{1.3.1} 18 | s.summary = %q{Construct absolute paths and full URLs for a Sinatra application} 19 | 20 | if s.respond_to? :specification_version then 21 | current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION 22 | s.specification_version = 2 23 | 24 | if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then 25 | s.add_runtime_dependency(%q, [">= 0.9.1.1"]) 26 | s.add_development_dependency(%q, ["~> 1.1.11"]) 27 | s.add_development_dependency(%q) 28 | else 29 | s.add_dependency(%q, [">= 0.9.1.1"]) 30 | s.add_dependency(%q, [">= 1.1.11"]) 31 | end 32 | else 33 | s.add_dependency(%q, [">= 0.9.1.1"]) 34 | s.add_dependency(%q, [">= 1.1.11"]) 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'spec' 3 | 4 | $LOAD_PATH.unshift(File.dirname(__FILE__)) 5 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) 6 | 7 | Spec::Runner.configure do |config| 8 | 9 | end 10 | -------------------------------------------------------------------------------- /spec/url_for_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'sinatra' 3 | require 'sinatra/url_for' 4 | require 'rack/test' 5 | 6 | # HTML exception pages in tests isn't useful; raise them to rspec so it can 7 | # tell us about them 8 | disable :show_exceptions 9 | enable :raise_errors 10 | 11 | get "/" do 12 | content_type "text/plain" 13 | url_for params[:url], params[:mode], params[:options] 14 | end 15 | 16 | get "/nomode" do 17 | content_type "text/plain" 18 | url_for params[:url], params[:options] 19 | end 20 | 21 | describe Sinatra::UrlForHelper do 22 | include Rack::Test::Methods 23 | 24 | def app 25 | Sinatra::Application 26 | end 27 | 28 | it "should handle the root URL" do 29 | get "/", :url => "/" 30 | 31 | last_response.should be_ok 32 | last_response.body.should == "/" 33 | end 34 | 35 | it "should handle sub-URLs" do 36 | get "/", :url => "/foo" 37 | 38 | last_response.should be_ok 39 | last_response.body.should == "/foo" 40 | end 41 | 42 | it "should provide full paths if asked" do 43 | get "/", :url => "/foo", :mode => :full 44 | 45 | last_response.should be_ok 46 | last_response.body.should == "http://example.org/foo" 47 | end 48 | 49 | it "should accept options" do 50 | get "/", :url => "/foo", :options => { :x => "y" } 51 | 52 | last_response.should be_ok 53 | last_response.body.should == "/foo?x=y" 54 | end 55 | 56 | it "should accept multiple options" do 57 | get "/", :url => "/foo", :options => { :x => "y", :bar => "wombat" } 58 | 59 | last_response.should be_ok 60 | last_response.body.should == "/foo?x=y&bar=wombat" 61 | end 62 | 63 | it "should escape option values" do 64 | get "/", :url => "/foo", :options => { :x => "M&Ms", :amount => "15%", :equals => "=" } 65 | 66 | last_response.should be_ok 67 | last_response.body.should == "/foo?x=M%26Ms&amount=15%25&equals=%3D" 68 | end 69 | 70 | it "should even escape URLs" do 71 | get "/", :url => "/foo", :options => { :return_to => "http://example.com/bar?x=y" } 72 | 73 | last_response.should be_ok 74 | last_response.body.should == "/foo?return_to=http%3A%2F%2Fexample.com%2Fbar%3Fx%3Dy" 75 | end 76 | 77 | it "should handle not being passed a mode" do 78 | get "/nomode", :url => "/foo", :options => { :x => "y" } 79 | 80 | last_response.should be_ok 81 | last_response.body.should == "/foo?x=y" 82 | end 83 | end 84 | --------------------------------------------------------------------------------