diff --git a/sinatra-contrib/lib/sinatra/link_header.rb b/sinatra-contrib/lib/sinatra/link_header.rb new file mode 100644 index 00000000..c7fc1903 --- /dev/null +++ b/sinatra-contrib/lib/sinatra/link_header.rb @@ -0,0 +1,84 @@ +require 'sinatra/base' + +module Sinatra + ## + # Helper methods for generating Link HTTP headers and HTML tags. + module LinkHeader + ## + # Set Link HTTP header and returns HTML tags for telling the browser to + # prefetch given resources (only supported by Opera and Firefox at the + # moment). + def prefetch(*urls) + link(:prefetch, *urls) + end + + ## + # Sets Link HTTP header and returns HTML tags for using stylesheets. + def stylesheet(*urls) + urls << {} unless urls.last.respond_to? :to_hash + urls.last[:type] ||= mime_type(:css) + link(:stylesheet, *urls) + end + + ## + # Sets Link HTTP header and returns corresponding HTML tags. + # + # Example: + # + # # Sets header: + # # Link: ; rel="next" + # # Returns String: + # # '' + # link '/foo', :rel => :next + # + # # Multiple URLs + # link :stylesheet, '/a.css', '/b.css' + def link(*urls) + opts = urls.last.respond_to?(:to_hash) ? urls.pop : {} + opts[:rel] = urls.shift unless urls.first.respond_to? :to_str + options = opts.map { |k, v| " #{k}=#{v.to_s.inspect}" } + html_pattern = "" + http_pattern = ["<%s>", *options].join ";" + link = (response["Link"] ||= "") + + urls.map do |url| + link << "\n" unless link.empty? + link << (http_pattern % url) + html_pattern % url + end.join "\n" + end + + ## + # Takes the current value of th Link header(s) and generates HTML tags + # from it. + # + # Example: + # + # get '/' do + # # You can of course use fancy helpers like #link, #stylesheet + # # or #prefetch + # response["Link"] = '; rel="next"' + # haml :some_page + # end + # + # __END__ + # + # @@ layout + # %head= link_headers + # %body= yield + def link_headers + yield if block_given? + return "" unless response.include? "Link" + response["Link"].lines.map do |line| + url, *opts = line.split(';').map(&:strip) + "" + end.join "\n" + end + + def self.registered(base) + puts "WARNING: #{self} is a helpers module, not an extension." + end + end + + helpers LinkHeader +end diff --git a/sinatra-contrib/spec/link_header_spec.rb b/sinatra-contrib/spec/link_header_spec.rb new file mode 100644 index 00000000..cf8d30b0 --- /dev/null +++ b/sinatra-contrib/spec/link_header_spec.rb @@ -0,0 +1,100 @@ +require 'backports' +require_relative 'spec_helper' + +describe Sinatra::LinkHeader do + before do + mock_app do + helpers Sinatra::LinkHeader + before('/') { link 'something', :rel => 'from-filter', :foo => :bar } + + get '/' do + link :something, 'booyah' + end + + get '/style' do + stylesheet '/style.css' + end + + get '/prefetch' do + prefetch '/foo' + end + + get '/link_headers' do + response['Link'] = " ;bar=\"baz\"" + stylesheet '/style.css' + prefetch '/foo' + link_headers + end + end + end + + describe :link do + it "sets link headers" do + get '/' + headers['Link'].lines.should include('; rel="something"') + end + + it "returns link html tags" do + get '/' + body.should == '' + end + + it "takes an options hash" do + get '/' + elements = ["", "foo=\"bar\"", "rel=\"from-filter\""] + headers['Link'].lines.first.strip.split('; ').sort.should == elements + end + end + + describe :stylesheet do + it 'sets link headers' do + get '/style' + headers['Link'].should match(%r{^;}) + end + + it 'sets type to text/css' do + get '/style' + headers['Link'].should include('type="text/css"') + end + + it 'sets rel to stylesheet' do + get '/style' + headers['Link'].should include('rel="stylesheet"') + end + + it 'returns html tag' do + get '/style' + body.should match(%r{^;}) + end + + it 'sets rel to prefetch' do + get '/prefetch' + headers['Link'].should include('rel="prefetch"') + end + + it 'returns html tag' do + get '/prefetch' + body.should == '' + end + end + + describe :link_headers do + it 'generates html for all link headers' do + get '/link_headers' + body.should include('') + body.should include('') + end + end +end