From 1d7be066cbe7f21bc53eff7f4aab970184c4241a Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Sat, 16 Feb 2013 04:30:30 +0100 Subject: [PATCH] Make it easy to check if Accept::Entry accepts given mime type --- lib/travis/api/app/helpers/accept.rb | 39 ++++++++++++++++++---------- spec/unit/helpers/accept_spec.rb | 27 ++++++++++++++++++- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/lib/travis/api/app/helpers/accept.rb b/lib/travis/api/app/helpers/accept.rb index b1ffc82b..d5dd97c1 100644 --- a/lib/travis/api/app/helpers/accept.rb +++ b/lib/travis/api/app/helpers/accept.rb @@ -10,31 +10,29 @@ class Travis::Api::App class Entry SEPARATORS = Regexp.escape("()<>@,;:\/[]?={}\t ") TOKEN = /[^#{SEPARATORS}]+/ - attr_reader :type, :subtype, :quality, :params + attr_reader :type, :subtype, :quality, :version, :params def initialize(accept_string) - @type, @subtype, @quality, @params = parse(accept_string) + @type, @subtype, @quality, @version, @params = parse(accept_string) end def <=>(other) - [1 - quality, full_type.count('*'), 1 - params.size] <=> - [1 - other.quality, other.full_type.count('*'), 1 - other.params.size] - end - - def full_type - "#{type}/#{subtype}" + [1 - quality, mime_type.count('*'), 1 - params.size] <=> + [1 - other.quality, other.mime_type.count('*'), 1 - other.params.size] end def mime_type - subtype = self.subtype =~ HEADER_FORMAT ? $2 : self.subtype "#{type}/#{subtype}" end - def version - $1 if subtype =~ HEADER_FORMAT + def accepts?(mime_type) + return true if self.mime_type == '*/*' + + type, subtype = mime_type.scan(%r{(#{TOKEN})/(#{TOKEN})}).flatten + type == self.type && (self.subtype == '*' || subtype == self.subtype) end def to_s - str = "#{full_type}; q=#{quality}" + str = "#{mime_type}; q=#{quality}" str << "; #{params.map { |k,v| "#{k}=#{v}" }.join('; ')}" if params.length > 0 str end @@ -45,12 +43,19 @@ class Travis::Api::App # contain, only the simplest cases, no quoted strings etc. type, subtype, params = str.scan(%r{(#{TOKEN})/(#{TOKEN})(.*)}).flatten quality = 1 + + version = nil if params params = Hash[*params.split(';').map { |p| p.scan /(#{TOKEN})=(#{TOKEN})/ }.flatten] quality = params.delete('q').to_f if params['q'] end - [type, subtype, quality, params] + if subtype =~ HEADER_FORMAT + subtype = $2 + version = $1 + end + + [type, subtype, quality, version, params] end end @@ -59,6 +64,14 @@ class Travis::Api::App entries.empty? ? [Entry.new('*/*')] : entries.sort end + def acceptable_formats + if format = env['travis.format_from_path'] + [Entry.new(Rack::Mime.mime_type(".#{format}"))] + else + accept_entries + end + end + def accept_version @accept_version ||= request.accept.join =~ HEADER_FORMAT && "v#{$1}" || DEFAULT_VERSION end diff --git a/spec/unit/helpers/accept_spec.rb b/spec/unit/helpers/accept_spec.rb index 11f845ec..1ce845c6 100644 --- a/spec/unit/helpers/accept_spec.rb +++ b/spec/unit/helpers/accept_spec.rb @@ -9,7 +9,7 @@ module Travis::Api::App::Helpers it 'returns accept entries sorted properly' do accept = "text/html; q=0.2; level=1, application/vnd.travis-ci.2+json, text/*, text/html;level=2; q=0.5" FakeApp.new('HTTP_ACCEPT' => accept).accept_entries.map(&:to_s).should == - ["application/vnd.travis-ci.2+json; q=1", "text/*; q=1", "text/html; q=0.5; level=2", "text/html; q=0.2; level=1"] + ["application/json; q=1", "text/*; q=1", "text/html; q=0.5; level=2", "text/html; q=0.2; level=1"] end it 'properly parses params, quality and version' do @@ -25,5 +25,30 @@ module Travis::Api::App::Helpers accept_entry = FakeApp.new({}).accept_entries.first accept_entry.mime_type.should == '*/*' end + + describe Accept::Entry do + describe 'accepts?' do + it 'accepts everything with */* type' do + entry = Accept::Entry.new('*/*') + entry.accepts?('application/json').should be_true + entry.accepts?('foo/bar').should be_true + end + + it 'accepts every subtype with application/* type' do + entry = Accept::Entry.new('application/*') + + entry.accepts?('application/foo').should be_true + entry.accepts?('application/bar').should be_true + entry.accepts?('text/plain').should be_false + end + + it 'accepts when type and subtype match' do + entry = Accept::Entry.new('application/json') + + entry.accepts?('application/json').should be_true + entry.accepts?('application/xml').should be_false + end + end + end end end