pax_global_header 0000666 0000000 0000000 00000000064 12167333200 0014507 g ustar 00root root 0000000 0000000 52 comment=42b32353e30d2fff8fa8b1975993ba1052619b26 ruby-rack-accept-0.4.5/ 0000775 0000000 0000000 00000000000 12167333200 0014651 5 ustar 00root root 0000000 0000000 ruby-rack-accept-0.4.5/CHANGES 0000664 0000000 0000000 00000001304 12167333200 0015642 0 ustar 00root root 0000000 0000000 ## 0.4.3 / July 29, 2010 * Added support for Ruby 1.9.2 ## 0.4 / April 5, 2010 * Added support for media type queries with multiple range parameters * Changed Rack::Accept::Header#sort method to return only single values and moved previous functionality to Rack::Accept::Header#sort_with_qvalues ## 0.3 / April 3, 2010 * Enhanced Rack middleware component to be able to automatically send a 406 response when the request is not acceptable ## 0.2 / April 2, 2010 * Moved all common header methods into Rack::Accept::Header module * Many improvements to the documentation ## 0.1.1 / April 1, 2010 * Whoops, forgot to require Rack. :] ## 0.1 / April 1, 2010 * Initial release ruby-rack-accept-0.4.5/README.md 0000664 0000000 0000000 00000012461 12167333200 0016134 0 ustar 00root root 0000000 0000000 # Rack::Accept **Rack::Accept** is a suite of tools for Ruby/Rack applications that eases the complexity of building and interpreting the Accept* family of [HTTP request headers][rfc]. Some features of the library are: * Strict adherence to [RFC 2616][rfc], specifically [section 14][rfc-sec14] * Full support for the [Accept][rfc-sec14-1], [Accept-Charset][rfc-sec14-2], [Accept-Encoding][rfc-sec14-3], and [Accept-Language][rfc-sec14-4] HTTP request headers * May be used as [Rack][rack] middleware or standalone * A comprehensive [test suite][test] that covers many edge cases [rfc]: http://www.w3.org/Protocols/rfc2616/rfc2616.html [rfc-sec14]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html [rfc-sec14-1]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1 [rfc-sec14-2]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2 [rfc-sec14-3]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3 [rfc-sec14-4]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 [rack]: http://rack.rubyforge.org/ [test]: http://github.com/mjijackson/rack-accept/tree/master/test/ ## Installation **Using [RubyGems](http://rubygems.org/):** $ sudo gem install rack-accept **From a local copy:** $ git clone git://github.com/mjijackson/rack-accept.git $ cd rack-accept $ rake package && sudo rake install ## Usage **Rack::Accept** implements the Rack middleware interface and may be used with any Rack-based application. Simply insert the `Rack::Accept` module in your Rack middleware pipeline and access the `Rack::Accept::Request` object in the `rack-accept.request` environment key, as in the following example. ```ruby require 'rack/accept' use Rack::Accept app = lambda do |env| accept = env['rack-accept.request'] response = Rack::Response.new if accept.media_type?('text/html') response['Content-Type'] = 'text/html' response.write "
Hello. You accept text/html!
" else response['Content-Type'] = 'text/plain' response.write "Apparently you don't accept text/html. Too bad." end response.finish end run app ``` **Rack::Accept** can also construct automatic [406][406] responses if you set up the types of media, character sets, encoding, or languages your server is able to serve ahead of time. If you pass a configuration block to your `use` statement it will yield the `Rack::Accept::Context` object that is used for that invocation. [406]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.7 ```ruby require 'rack/accept' use(Rack::Accept) do |context| # We only ever serve content in English or Japanese from this site, so if # the user doesn't accept either of these we will respond with a 406. context.languages = %w< en jp > end app = ... run app ``` **Note:** _You should think carefully before using Rack::Accept in this way. Many user agents are careless about the types of Accept headers they send, and depend on apps not being too picky. Instead of automatically sending a 406, you should probably only send one when absolutely necessary._ Additionally, **Rack::Accept** may be used outside of a Rack context to provide any Ruby app the ability to construct and interpret Accept headers. ```ruby require 'rack/accept' mtype = Rack::Accept::MediaType.new mtype.qvalues = { 'text/html' => 1, 'text/*' => 0.8, '*/*' => 0.5 } mtype.to_s # => "Accept: text/html, text/*;q=0.8, */*;q=0.5" cset = Rack::Accept::Charset.new('unicode-1-1, iso-8859-5;q=0.8') cset.best_of(%w< iso-8859-5 unicode-1-1 >) # => "unicode-1-1" cset.accept?('iso-8859-1') # => true ``` The very last line in this example may look like a mistake to someone not familiar with the intricacies of [the spec][rfc-sec14-3], but it's actually correct. It just puts emphasis on the convenience of using this library so you don't have to worry about these kinds of details. ## Four-letter Words - Spec: [http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html][rfc-sec14] - Code: [http://github.com/mjijackson/rack-accept][code] - Bugs: [http://github.com/mjijackson/rack-accept/issues][bugs] - Docs: [http://mjijackson.github.com/rack-accept][docs] [code]: http://github.com/mjijackson/rack-accept [bugs]: http://github.com/mjijackson/rack-accept/issues [docs]: http://mjijackson.github.com/rack-accept ## License Copyright 2012 Michael Jackson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software. ruby-rack-accept-0.4.5/Rakefile 0000664 0000000 0000000 00000003177 12167333200 0016326 0 ustar 00root root 0000000 0000000 require 'rake/clean' require 'rake/testtask' task :default => :test # TESTS ####################################################################### Rake::TestTask.new(:test) do |t| t.test_files = FileList['test/*_test.rb'] end # DOCS ######################################################################## desc "Generate API documentation" task :api => FileList['lib/**/*.rb'] do |t| output_dir = ENV['OUTPUT_DIR'] || 'api' rm_rf output_dir sh((<<-SH).gsub(/[\s\n]+/, ' ').strip) hanna --op #{output_dir} --promiscuous --charset utf8 --fmt html --inline-source --line-numbers --accessor option_accessor=RW --main Rack::Accept --title 'Rack::Accept API Documentation' #{t.prerequisites.join(' ')} SH end CLEAN.include 'api' # PACKAGING & INSTALLATION #################################################### if defined?(Gem) $spec = eval("#{File.read('rack-accept.gemspec')}") directory 'dist' def package(ext='') "dist/#{$spec.name}-#{$spec.version}" + ext end file package('.gem') => %w< dist > + $spec.files do |f| sh "gem build rack-accept.gemspec" mv File.basename(f.name), f.name end file package('.tar.gz') => %w< dist > + $spec.files do |f| sh "git archive --format=tar HEAD | gzip > #{f.name}" end desc "Build packages" task :package => %w< .gem .tar.gz >.map {|e| package(e) } desc "Build and install as local gem" task :install => package('.gem') do |t| sh "gem install #{package('.gem')}" end desc "Upload gem to rubygems.org" task :release => package('.gem') do |t| sh "gem push #{package('.gem')}" end end CLOBBER.include 'dist' ruby-rack-accept-0.4.5/lib/ 0000775 0000000 0000000 00000000000 12167333200 0015417 5 ustar 00root root 0000000 0000000 ruby-rack-accept-0.4.5/lib/rack/ 0000775 0000000 0000000 00000000000 12167333200 0016337 5 ustar 00root root 0000000 0000000 ruby-rack-accept-0.4.5/lib/rack/accept.rb 0000664 0000000 0000000 00000001133 12167333200 0020121 0 ustar 00root root 0000000 0000000 require 'rack' # HTTP Accept* for Ruby/Rack. # # http://mjijackson.com/rack-accept module Rack::Accept # Enables Rack::Accept to be used as a Rack middleware. def self.new(app, &block) Context.new(app, &block) end autoload :Charset, 'rack/accept/charset' autoload :Context, 'rack/accept/context' autoload :Encoding, 'rack/accept/encoding' autoload :Header, 'rack/accept/header' autoload :Language, 'rack/accept/language' autoload :MediaType, 'rack/accept/media_type' autoload :Request, 'rack/accept/request' autoload :Response, 'rack/accept/response' end ruby-rack-accept-0.4.5/lib/rack/accept/ 0000775 0000000 0000000 00000000000 12167333200 0017576 5 ustar 00root root 0000000 0000000 ruby-rack-accept-0.4.5/lib/rack/accept/charset.rb 0000664 0000000 0000000 00000001736 12167333200 0021563 0 ustar 00root root 0000000 0000000 module Rack::Accept # Represents an HTTP Accept-Charset header according to the HTTP 1.1 # specification, and provides several convenience methods for determining # acceptable character sets. # # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2 class Charset include Header # The name of this header. def name 'Accept-Charset' end # Determines the quality factor (qvalue) of the given +charset+. def qvalue(charset) m = matches(charset) if m.empty? charset == 'iso-8859-1' ? 1 : 0 else normalize_qvalue(@qvalues[m.first]) end end # Returns an array of character sets from this header that match the given # +charset+, ordered by precedence. def matches(charset) values.select {|v| v == charset || v == '*' }.sort {|a, b| # "*" gets least precedence, any others should be equal. a == '*' ? 1 : (b == '*' ? -1 : 0) } end end end ruby-rack-accept-0.4.5/lib/rack/accept/context.rb 0000664 0000000 0000000 00000003542 12167333200 0021613 0 ustar 00root root 0000000 0000000 module Rack::Accept # Implements the Rack middleware interface. class Context # This error is raised when the server is not able to provide an acceptable # response. class AcceptError < StandardError; end attr_reader :app def initialize(app) @app = app @checks = {} @check_headers = [] yield self if block_given? end # Inserts a new Rack::Accept::Request object into the environment before # handing the request to the app immediately downstream. def call(env) request = env['rack-accept.request'] ||= Request.new(env) check!(request) unless @checks.empty? @app.call(env) rescue AcceptError response = Response.new response.not_acceptable! response.finish end # Defines the types of media this server is able to serve. def media_types=(media_types) add_check(:media_type, media_types) end # Defines the character sets this server is able to serve. def charsets=(charsets) add_check(:charset, charsets) end # Defines the types of encodings this server is able to serve. def encodings=(encodings) add_check(:encoding, encodings) end # Defines the languages this server is able to serve. def languages=(languages) add_check(:language, languages) end private def add_check(header_name, values) @checks[header_name] ||= [] @checks[header_name].concat(values) @check_headers << header_name unless @check_headers.include?(header_name) end # Raises an AcceptError if this server is not able to serve an acceptable # response. def check!(request) @check_headers.each do |header_name| values = @checks[header_name] header = request.send(header_name) raise AcceptError unless values.any? {|v| header.accept?(v) } end end end end ruby-rack-accept-0.4.5/lib/rack/accept/encoding.rb 0000664 0000000 0000000 00000001744 12167333200 0021717 0 ustar 00root root 0000000 0000000 module Rack::Accept # Represents an HTTP Accept-Encoding header according to the HTTP 1.1 # specification, and provides several convenience methods for determining # acceptable content encodings. # # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3 class Encoding include Header # The name of this header. def name 'Accept-Encoding' end # Determines the quality factor (qvalue) of the given +encoding+. def qvalue(encoding) m = matches(encoding) if m.empty? encoding == 'identity' ? 1 : 0 else normalize_qvalue(@qvalues[m.first]) end end # Returns an array of encodings from this header that match the given # +encoding+, ordered by precedence. def matches(encoding) values.select {|v| v == encoding || v == '*' }.sort {|a, b| # "*" gets least precedence, any others should be equal. a == '*' ? 1 : (b == '*' ? -1 : 0) } end end end ruby-rack-accept-0.4.5/lib/rack/accept/header.rb 0000664 0000000 0000000 00000012101 12167333200 0021346 0 ustar 00root root 0000000 0000000 module Rack::Accept # Contains methods that are useful for working with Accept-style HTTP # headers. The MediaType, Charset, Encoding, and Language classes all mixin # this module. module Header # Parses the value of an Accept-style request header into a hash of # acceptable values and their respective quality factors (qvalues). The # +join+ method may be used on the resulting hash to obtain a header # string that is the semantic equivalent of the one provided. def parse(header) qvalues = {} header.to_s.split(/,\s*/).each do |part| m = /^([^\s,]+?)(?:\s*;\s*q\s*=\s*(\d+(?:\.\d+)?))?$/.match(part) if m qvalues[m[1].downcase] = normalize_qvalue((m[2] || 1).to_f) else raise "Invalid header value: #{part.inspect}" end end qvalues end module_function :parse # Returns a string suitable for use as the value of an Accept-style HTTP # header from the map of acceptable values to their respective quality # factors (qvalues). The +parse+ method may be used on the resulting string # to obtain a hash that is the equivalent of the one provided. def join(qvalues) qvalues.map {|k, v| k + (v == 1 ? '' : ";q=#{v}") }.join(', ') end module_function :join # Parses a media type string into its relevant pieces. The return value # will be an array with three values: 1) the content type, 2) the content # subtype, and 3) the media type parameters. An empty array is returned if # no match can be made. def parse_media_type(media_type) m = media_type.to_s.match(/^([a-z*]+)\/([a-z0-9*\-.+]+)(?:;([a-z0-9=;]+))?$/) m ? [m[1], m[2], m[3] || ''] : [] end module_function :parse_media_type # Parses a string of media type range parameters into a hash of parameters # to their respective values. def parse_range_params(params) params.split(';').inject({}) do |m, p| k, v = p.split('=', 2) m[k] = v if v m end end module_function :parse_range_params # Converts 1.0 and 0.0 qvalues to 1 and 0 respectively. Used to maintain # consistency across qvalue methods. def normalize_qvalue(q) (q == 1 || q == 0) && q.is_a?(Float) ? q.to_i : q end module_function :normalize_qvalue module PublicInstanceMethods # A table of all values of this header to their respective quality # factors (qvalues). attr_accessor :qvalues def initialize(header='') @qvalues = parse(header) end # The name of this header. Should be overridden in classes that mixin # this module. def name '' end # Returns the quality factor (qvalue) of the given +value+. Should be # overridden in classes that mixin this module. def qvalue(value) 1 end # Returns the value of this header as a string. def value join(@qvalues) end # Returns an array of all values of this header, in no particular order. def values @qvalues.keys end # Determines if the given +value+ is acceptable (does not have a qvalue # of 0) according to this header. def accept?(value) qvalue(value) != 0 end # Returns a copy of the given +values+ array, sorted by quality factor # (qvalue). Each element of the returned array is itself an array # containing two objects: 1) the value's qvalue and 2) the original # value. # # It is important to note that this sort is a "stable sort". In other # words, the order of the original values is preserved so long as the # qvalue for each is the same. This expectation can be useful when # trying to determine which of a variety of options has the highest # qvalue. If the user prefers using one option over another (for any # number of reasons), he should put it first in +values+. He may then # use the first result with confidence that it is both most acceptable # to the client and most convenient for him as well. def sort_with_qvalues(values, keep_unacceptables=true) qvalues = {} values.each do |v| q = qvalue(v) if q != 0 || keep_unacceptables qvalues[q] ||= [] qvalues[q] << v end end order = qvalues.keys.sort.reverse order.inject([]) {|m, q| m.concat(qvalues[q].map {|v| [q, v] }) } end # Sorts the given +values+ according to the qvalue of each while # preserving the original order. See #sort_with_qvalues for more # information on exactly how the sort is performed. def sort(values, keep_unacceptables=false) sort_with_qvalues(values, keep_unacceptables).map {|q, v| v } end # A shortcut for retrieving the first result of #sort. def best_of(values, keep_unacceptables=false) sort(values, keep_unacceptables).first end # Returns a string representation of this header. def to_s [name, value].join(': ') end end include PublicInstanceMethods end end ruby-rack-accept-0.4.5/lib/rack/accept/language.rb 0000664 0000000 0000000 00000002205 12167333200 0021705 0 ustar 00root root 0000000 0000000 module Rack::Accept # Represents an HTTP Accept-Language header according to the HTTP 1.1 # specification, and provides several convenience methods for determining # acceptable content languages. # # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 class Language include Header attr_writer :first_level_match # The name of this header. def name 'Accept-Language' end # Determines the quality factor (qvalue) of the given +language+. def qvalue(language) return 1 if @qvalues.empty? m = matches(language) return 0 if m.empty? normalize_qvalue(@qvalues[m.first]) end # Returns an array of languages from this header that match the given # +language+, ordered by precedence. def matches(language) values.select {|v| v = v.match(/^(.+?)-/) ? $1 : v if @first_level_match v == language || v == '*' || (language.match(/^(.+?)-/) && v == $1) }.sort {|a, b| # "*" gets least precedence, any others are compared based on length. a == '*' ? -1 : (b == '*' ? 1 : a.length <=> b.length) }.reverse end end end ruby-rack-accept-0.4.5/lib/rack/accept/media_type.rb 0000664 0000000 0000000 00000003333 12167333200 0022245 0 ustar 00root root 0000000 0000000 module Rack::Accept # Represents an HTTP Accept header according to the HTTP 1.1 specification, # and provides several convenience methods for determining acceptable media # types. # # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1 class MediaType include Header # The name of this header. def name 'Accept' end # Determines the quality factor (qvalue) of the given +media_type+. def qvalue(media_type) return 1 if @qvalues.empty? m = matches(media_type) return 0 if m.empty? normalize_qvalue(@qvalues[m.first]) end # Returns an array of media types from this header that match the given # +media_type+, ordered by precedence. def matches(media_type) type, subtype, params = parse_media_type(media_type) values.select {|v| if v == media_type || v == '*/*' true else t, s, p = parse_media_type(v) t == type && (s == '*' || s == subtype) && (p == '' || params_match?(params, p)) end }.sort_by {|v| # Most specific gets precedence. v.length }.reverse end private def initialize(header) # Strip accept-extension for now. We may want to do something with this # later if people actually start to use it. header = header.to_s.split(/,\s*/).map {|part| part.sub(/(;\s*q\s*=\s*[\d.]+).*$/, '\1') }.join(', ') super(header) end # Returns true if all parameters and values in +match+ are also present in # +params+. def params_match?(params, match) return true if params == match parsed = parse_range_params(params) parsed == parsed.merge(parse_range_params(match)) end end end ruby-rack-accept-0.4.5/lib/rack/accept/request.rb 0000664 0000000 0000000 00000006044 12167333200 0021617 0 ustar 00root root 0000000 0000000 require 'rack/request' module Rack::Accept # A container class for convenience methods when Rack::Accept is used on the # request level as Rack middleware. Instances of this class also manage a # lightweight cache of various header instances to speed up execution. class Request < Rack::Request attr_reader :env def initialize(env) @env = env end # Provides access to the Rack::Accept::MediaType instance for this request. def media_type @media_type ||= MediaType.new(env['HTTP_ACCEPT']) end # Provides access to the Rack::Accept::Charset instance for this request. def charset @charset ||= Charset.new(env['HTTP_ACCEPT_CHARSET']) end # Provides access to the Rack::Accept::Encoding instance for this request. def encoding @encoding ||= Encoding.new(env['HTTP_ACCEPT_ENCODING']) end # Provides access to the Rack::Accept::Language instance for this request. def language @language ||= Language.new(env['HTTP_ACCEPT_LANGUAGE']) end # Returns true if the +Accept+ request header indicates the given media # type is acceptable, false otherwise. def media_type?(value) media_type.accept?(value) end # Returns true if the +Accept-Charset+ request header indicates the given # character set is acceptable, false otherwise. def charset?(value) charset.accept?(value) end # Returns true if the +Accept-Encoding+ request header indicates the given # encoding is acceptable, false otherwise. def encoding?(value) encoding.accept?(value) end # Returns true if the +Accept-Language+ request header indicates the given # language is acceptable, false otherwise. def language?(value) language.accept?(value) end # Determines the best media type to use in a response from the given media # types, if any is acceptable. For more information on how this value is # determined, see the documentation for # Rack::Accept::Header::PublicInstanceMethods#sort. def best_media_type(values) media_type.best_of(values) end # Determines the best character set to use in a response from the given # character sets, if any is acceptable. For more information on how this # value is determined, see the documentation for # Rack::Accept::Header::PublicInstanceMethods#sort. def best_charset(values) charset.best_of(values) end # Determines the best encoding to use in a response from the given # encodings, if any is acceptable. For more information on how this value # is determined, see the documentation for # Rack::Accept::Header::PublicInstanceMethods#sort. def best_encoding(values) encoding.best_of(values) end # Determines the best language to use in a response from the given # languages, if any is acceptable. For more information on how this value # is determined, see the documentation for # Rack::Accept::Header::PublicInstanceMethods#sort. def best_language(values) language.best_of(values) end end end ruby-rack-accept-0.4.5/lib/rack/accept/response.rb 0000664 0000000 0000000 00000001146 12167333200 0021763 0 ustar 00root root 0000000 0000000 require 'rack/response' module Rack::Accept # The base class for responses issued by Rack::Accept. class Response < Rack::Response # Marks this response as being unacceptable and clears the response body. # # Note: The HTTP spec advises servers to respond with an "entity" that # describes acceptable parameters, but it fails to go into detail about its # implementation. Thus, it is up to the user of this library to create such # an entity if one is desired. def not_acceptable! self.status = 406 self.body = [] header['Content-Length'] = '0' end end end ruby-rack-accept-0.4.5/lib/rack/accept/version.rb 0000664 0000000 0000000 00000000263 12167333200 0021611 0 ustar 00root root 0000000 0000000 module Rack module Accept VERSION = [0, 4, 5] # Returns the current version of Rack::Accept as a string. def self.version VERSION.join('.') end end end ruby-rack-accept-0.4.5/metadata.yml 0000664 0000000 0000000 00000004510 12167333200 0017154 0 ustar 00root root 0000000 0000000 --- !ruby/object:Gem::Specification name: rack-accept version: !ruby/object:Gem::Version version: 0.4.5 prerelease: platform: ruby authors: - Michael Jackson autorequire: bindir: bin cert_chain: [] date: 2012-06-15 00:00:00.000000000Z dependencies: - !ruby/object:Gem::Dependency name: rack requirement: &70171348874000 !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0.4' type: :runtime prerelease: false version_requirements: *70171348874000 - !ruby/object:Gem::Dependency name: rake requirement: &70171348873580 !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: *70171348873580 description: HTTP Accept, Accept-Charset, Accept-Encoding, and Accept-Language for Ruby/Rack email: mjijackson@gmail.com executables: [] extensions: [] extra_rdoc_files: - CHANGES - README.md files: - lib/rack/accept/charset.rb - lib/rack/accept/context.rb - lib/rack/accept/encoding.rb - lib/rack/accept/header.rb - lib/rack/accept/language.rb - lib/rack/accept/media_type.rb - lib/rack/accept/request.rb - lib/rack/accept/response.rb - lib/rack/accept/version.rb - lib/rack/accept.rb - test/charset_test.rb - test/context_test.rb - test/encoding_test.rb - test/header_test.rb - test/helper.rb - test/language_test.rb - test/media_type_test.rb - test/request_test.rb - CHANGES - rack-accept.gemspec - Rakefile - README.md homepage: http://mjijackson.github.com/rack-accept licenses: [] post_install_message: rdoc_options: - --line-numbers - --inline-source - --title - Rack::Accept - --main - Rack::Accept require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 1.8.17 signing_key: specification_version: 3 summary: HTTP Accept* for Ruby/Rack test_files: - test/charset_test.rb - test/context_test.rb - test/encoding_test.rb - test/header_test.rb - test/language_test.rb - test/media_type_test.rb - test/request_test.rb ruby-rack-accept-0.4.5/rack-accept.gemspec 0000664 0000000 0000000 00000001716 12167333200 0020400 0 ustar 00root root 0000000 0000000 $LOAD_PATH.unshift(File.expand_path('../lib', __FILE__)) require 'rack/accept/version' Gem::Specification.new do |s| s.name = 'rack-accept' s.version = Rack::Accept.version s.date = Time.now.strftime('%Y-%m-%d') s.summary = 'HTTP Accept* for Ruby/Rack' s.description = 'HTTP Accept, Accept-Charset, Accept-Encoding, and Accept-Language for Ruby/Rack' s.author = 'Michael Jackson' s.email = 'mjijackson@gmail.com' s.require_paths = %w< lib > s.files = Dir['doc/**/*'] + Dir['lib/**/*.rb'] + Dir['test/*.rb'] + %w< CHANGES rack-accept.gemspec Rakefile README.md > s.test_files = s.files.select {|path| path =~ /^test\/.*_test.rb/ } s.add_dependency('rack', '>= 0.4') s.add_development_dependency('rake') s.has_rdoc = true s.rdoc_options = %w< --line-numbers --inline-source --title Rack::Accept --main Rack::Accept > s.extra_rdoc_files = %w< CHANGES README.md > s.homepage = 'http://mjijackson.github.com/rack-accept' end ruby-rack-accept-0.4.5/test/ 0000775 0000000 0000000 00000000000 12167333200 0015630 5 ustar 00root root 0000000 0000000 ruby-rack-accept-0.4.5/test/charset_test.rb 0000664 0000000 0000000 00000002466 12167333200 0020655 0 ustar 00root root 0000000 0000000 require File.expand_path('../helper', __FILE__) class CharsetTest < Test::Unit::TestCase C = Rack::Accept::Charset def test_qvalue c = C.new('') assert_equal(0, c.qvalue('unicode-1-1')) assert_equal(1, c.qvalue('iso-8859-1')) c = C.new('unicode-1-1') assert_equal(1, c.qvalue('unicode-1-1')) assert_equal(0, c.qvalue('iso-8859-5')) assert_equal(1, c.qvalue('iso-8859-1')) c = C.new('unicode-1-1, *;q=0.5') assert_equal(1, c.qvalue('unicode-1-1')) assert_equal(0.5, c.qvalue('iso-8859-5')) assert_equal(0.5, c.qvalue('iso-8859-1')) c = C.new('iso-8859-1;q=0, *;q=0.5') assert_equal(0.5, c.qvalue('iso-8859-5')) assert_equal(0, c.qvalue('iso-8859-1')) c = C.new('*;q=0') assert_equal(0, c.qvalue('iso-8859-1')) end def test_matches c = C.new('iso-8859-1, iso-8859-5, *') assert_equal(%w{*}, c.matches('')) assert_equal(%w{iso-8859-1 *}, c.matches('iso-8859-1')) assert_equal(%w{*}, c.matches('unicode-1-1')) end def test_best_of c = C.new('iso-8859-5, unicode-1-1;q=0.8') assert_equal('iso-8859-5', c.best_of(%w< iso-8859-5 unicode-1-1 >)) assert_equal('iso-8859-5', c.best_of(%w< iso-8859-5 utf-8 >)) assert_equal('iso-8859-1', c.best_of(%w< iso-8859-1 utf-8 >)) assert_equal(nil, c.best_of(%w< utf-8 >)) end end ruby-rack-accept-0.4.5/test/context_test.rb 0000664 0000000 0000000 00000003052 12167333200 0020700 0 ustar 00root root 0000000 0000000 require File.expand_path('../helper', __FILE__) class ContextTest < Test::Unit::TestCase def media_types; Proc.new {|c| c.media_types = %w< text/html > } end def charsets; Proc.new {|c| c.charsets = %w< iso-8859-5 > } end def encodings; Proc.new {|c| c.encodings = %w< gzip > } end def languages; Proc.new {|c| c.languages = %w< en > } end def test_empty request assert_equal(200, status) end def test_media_types request('HTTP_ACCEPT' => 'text/html') assert_equal(200, status) request('HTTP_ACCEPT' => 'text/html', &media_types) assert_equal(200, status) request('HTTP_ACCEPT' => 'text/plain', &media_types) assert_equal(406, status) end def test_charsets request('HTTP_ACCEPT_CHARSET' => 'iso-8859-5') assert_equal(200, status) request('HTTP_ACCEPT_CHARSET' => 'iso-8859-5', &charsets) assert_equal(200, status) request('HTTP_ACCEPT_CHARSET' => 'unicode-1-1', &charsets) assert_equal(406, status) end def test_encodings request('HTTP_ACCEPT_ENCODING' => 'gzip') assert_equal(200, status) request('HTTP_ACCEPT_ENCODING' => 'gzip', &encodings) assert_equal(200, status) request('HTTP_ACCEPT_ENCODING' => 'compress', &encodings) assert_equal(406, status) end def test_languages request('HTTP_ACCEPT_LANGUAGE' => 'en') assert_equal(200, status) request('HTTP_ACCEPT_LANGUAGE' => 'en', &languages) assert_equal(200, status) request('HTTP_ACCEPT_LANGUAGE' => 'jp', &languages) assert_equal(406, status) end end ruby-rack-accept-0.4.5/test/encoding_test.rb 0000664 0000000 0000000 00000001414 12167333200 0021002 0 ustar 00root root 0000000 0000000 require File.expand_path('../helper', __FILE__) class EncodingTest < Test::Unit::TestCase E = Rack::Accept::Encoding def test_qvalue e = E.new('') assert_equal(0, e.qvalue('gzip')) assert_equal(1, e.qvalue('identity')) e = E.new('gzip, *;q=0.5') assert_equal(1, e.qvalue('gzip')) assert_equal(0.5, e.qvalue('identity')) end def test_matches e = E.new('gzip, identity, *') assert_equal(%w{*}, e.matches('')) assert_equal(%w{gzip *}, e.matches('gzip')) assert_equal(%w{*}, e.matches('compress')) end def test_best_of e = E.new('gzip, compress') assert_equal('gzip', e.best_of(%w< gzip compress >)) assert_equal('identity', e.best_of(%w< identity compress >)) assert_equal(nil, e.best_of(%w< zip >)) end end ruby-rack-accept-0.4.5/test/header_test.rb 0000664 0000000 0000000 00000004411 12167333200 0020444 0 ustar 00root root 0000000 0000000 require File.expand_path('../helper', __FILE__) class HeaderTest < Test::Unit::TestCase H = Rack::Accept::Header def test_parse_and_join # Accept header = 'text/plain; q=0.5, text/html, text/html;level=2, text/html;level=1;q=0.3, text/x-c, image/*; q=0.2' expect = { 'text/plain' => 0.5, 'text/html' => 1, 'text/html;level=2' => 1, 'text/html;level=1' => 0.3, 'text/x-c' => 1, 'image/*' => 0.2 } assert_equal(expect, H.parse(header)) assert_equal(expect, H.parse(H.join(expect))) # Accept-Charset header = 'iso-8859-5, unicode-1-1;q=0.8' expect = { 'iso-8859-5' => 1, 'unicode-1-1' => 0.8 } assert_equal(expect, H.parse(header)) assert_equal(expect, H.parse(H.join(expect))) # Accept-Encoding header = 'gzip;q=1.0, identity; q=0.5, *;q=0' expect = { 'gzip' => 1, 'identity' => 0.5, '*' => 0 } assert_equal(expect, H.parse(header)) assert_equal(expect, H.parse(H.join(expect))) # Accept-Language header = 'da, en-gb;q=0.8, en;q=0.7' expect = { 'da' => 1, 'en-gb' => 0.8, 'en' => 0.7 } assert_equal(expect, H.parse(header)) assert_equal(expect, H.parse(H.join(expect))) end def test_parse_media_type assert_equal([], H.parse_media_type('')) assert_equal(['*', '*', ''], H.parse_media_type('*/*')) assert_equal(['text', '*', ''], H.parse_media_type('text/*')) assert_equal(['text', 'html', ''], H.parse_media_type('text/html')) assert_equal(['text', 'html', 'level=1'], H.parse_media_type('text/html;level=1')) assert_equal(['text', 'html', 'level=1;answer=42'], H.parse_media_type('text/html;level=1;answer=42')) assert_equal(['text', 'x-dvi', ''], H.parse_media_type('text/x-dvi')) end def test_parse_range_params assert_equal({}, H.parse_range_params('')) assert_equal({}, H.parse_range_params('a')) assert_equal({'a' => 'a'}, H.parse_range_params('a=a')) assert_equal({'a' => 'a', 'b' => 'b'}, H.parse_range_params('a=a;b=b')) end def test_normalize_qvalue assert_equal(1, H.normalize_qvalue(1.0)) assert_equal(0, H.normalize_qvalue(0.0)) assert_equal(1, H.normalize_qvalue(1)) assert_equal(0, H.normalize_qvalue(0)) assert_equal(0.5, H.normalize_qvalue(0.5)) end end ruby-rack-accept-0.4.5/test/helper.rb 0000664 0000000 0000000 00000001565 12167333200 0017443 0 ustar 00root root 0000000 0000000 ENV['RACK_ENV'] = 'test' begin require 'rack' rescue LoadError require 'rubygems' require 'rack' end testdir = File.dirname(__FILE__) $LOAD_PATH.unshift(testdir) unless $LOAD_PATH.include?(testdir) libdir = File.dirname(File.dirname(__FILE__)) + '/lib' $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir) require 'test/unit' require 'rack/accept' class Test::Unit::TestCase attr_reader :context attr_reader :response def status @response && @response.status end def request(env={}, method='GET', uri='/') @context = Rack::Accept.new(fake_app) yield @context if block_given? mock_request = Rack::MockRequest.new(@context) @response = mock_request.request(method.to_s.upcase, uri, env) @response end def fake_app(status=200, headers={}, body=[]) lambda {|env| Rack::Response.new(body, status, headers).finish } end end ruby-rack-accept-0.4.5/test/language_test.rb 0000664 0000000 0000000 00000002425 12167333200 0021002 0 ustar 00root root 0000000 0000000 require File.expand_path('../helper', __FILE__) class LanguageTest < Test::Unit::TestCase L = Rack::Accept::Language def test_qvalue l = L.new('') assert_equal(1, l.qvalue('en')) l = L.new('en;q=0.5, en-gb') assert_equal(0.5, l.qvalue('en')) assert_equal(1, l.qvalue('en-gb')) assert_equal(0, l.qvalue('da')) end def test_matches l = L.new('da, *, en') assert_equal(%w{*}, l.matches('')) assert_equal(%w{da *}, l.matches('da')) assert_equal(%w{en *}, l.matches('en')) assert_equal(%w{en *}, l.matches('en-gb')) assert_equal(%w{*}, l.matches('eng')) l = L.new('en, en-gb') assert_equal(%w{en-gb en}, l.matches('en-gb')) end def test_best_of l = L.new('en;q=0.5, en-gb') assert_equal('en-gb', l.best_of(%w< en en-gb >)) assert_equal('en', l.best_of(%w< en da >)) assert_equal('en-us', l.best_of(%w< en-us en-au >)) assert_equal(nil, l.best_of(%w< da >)) l = L.new('en;q=0.5, en-GB, fr-CA') assert_equal('en-gb', l.best_of(%w< en en-gb >)) l = L.new('en-gb;q=0.5, EN, fr-CA') assert_equal('en', l.best_of(%w< en en-gb >)) l = L.new('en;q=0.5, fr-ca') assert_equal('en', l.best_of(%w< en fr >)) l.first_level_match = true assert_equal('fr', l.best_of(%w< en fr >)) end end ruby-rack-accept-0.4.5/test/media_type_test.rb 0000664 0000000 0000000 00000004174 12167333200 0021342 0 ustar 00root root 0000000 0000000 require File.expand_path('../helper', __FILE__) class MediaTypeTest < Test::Unit::TestCase M = Rack::Accept::MediaType def test_qvalue m = M.new('text/html, text/*;q=0.3, */*;q=0.5') assert_equal(0.5, m.qvalue('image/png')) assert_equal(0.3, m.qvalue('text/plain')) assert_equal(1, m.qvalue('text/html')) m = M.new('text/html') assert_equal(0, m.qvalue('image/png')) m = M.new('') assert_equal(1, m.qvalue('text/html')) end def test_matches m = M.new('text/*, text/html, text/html;level=1, */*') assert_equal(%w{*/*}, m.matches('')) assert_equal(%w{*/*}, m.matches('image/jpeg')) assert_equal(%w{text/* */*}, m.matches('text/plain')) assert_equal(%w{text/html text/* */*}, m.matches('text/html')) assert_equal(%w{text/html;level=1 text/html text/* */*}, m.matches('text/html;level=1')) assert_equal(%w{text/html;level=1 text/html text/* */*}, m.matches('text/html;level=1;answer=42')) end def test_best_of m = M.new('text/*;q=0.5, text/html') assert_equal('text/html', m.best_of(%w< text/plain text/html >)) assert_equal('text/plain', m.best_of(%w< text/plain image/png >)) assert_equal('text/plain', m.best_of(%w< text/plain text/javascript >)) assert_equal(nil, m.best_of(%w< image/png >)) m = M.new('text/*') assert_equal('text/html', m.best_of(%w< text/html text/xml >)) assert_equal('text/xml', m.best_of(%w< text/xml text/html >)) m = M.new('TEXT/*') assert_equal('text/html', m.best_of(%w< text/html text/xml >)) assert_equal('text/xml', m.best_of(%w< text/xml text/html >)) end def test_extension m = M.new('text/*;q=0.5;a=42') assert_equal(0.5, m.qvalue('text/plain')) end def test_vendored_types m = M.new("application/vnd.ms-excel") assert_equal(nil, m.best_of(%w< application/vnd.ms-powerpoint >)) m = M.new("application/vnd.api-v1+json") assert_equal(false, m.accept?("application/vnd.api-v2+json")) v1, v2 = "application/vnd.api-v1+json", "application/vnd.api-v2+json" m = M.new("#{v1},#{v2}") assert_equal(v1, m.best_of([v1, v2])) assert_equal(v2, m.best_of([v2, v1])) end end ruby-rack-accept-0.4.5/test/request_test.rb 0000664 0000000 0000000 00000003314 12167333200 0020705 0 ustar 00root root 0000000 0000000 require File.expand_path('../helper', __FILE__) class RequestTest < Test::Unit::TestCase R = Rack::Accept::Request def test_media_type r = R.new('HTTP_ACCEPT' => 'text/*;q=0, text/html') assert(r.media_type?('text/html')) assert(r.media_type?('text/html;level=1')) assert(!r.media_type?('text/plain')) assert(!r.media_type?('image/png')) request = R.new('HTTP_ACCEPT' => '*/*') assert(request.media_type?('image/png')) end def test_charset r = R.new('HTTP_ACCEPT_CHARSET' => 'iso-8859-5, unicode-1-1;q=0.8') assert(r.charset?('iso-8859-5')) assert(r.charset?('unicode-1-1')) assert(r.charset?('iso-8859-1')) assert(!r.charset?('utf-8')) r = R.new('HTTP_ACCEPT_CHARSET' => 'iso-8859-1;q=0') assert(!r.charset?('iso-8859-1')) end def test_encoding r = R.new('HTTP_ACCEPT_ENCODING' => '') assert(r.encoding?('identity')) assert(!r.encoding?('gzip')) r = R.new('HTTP_ACCEPT_ENCODING' => 'gzip') assert(r.encoding?('identity')) assert(r.encoding?('gzip')) assert(!r.encoding?('compress')) r = R.new('HTTP_ACCEPT_ENCODING' => 'gzip;q=0, *') assert(r.encoding?('compress')) assert(r.encoding?('identity')) assert(!r.encoding?('gzip')) r = R.new('HTTP_ACCEPT_ENCODING' => 'identity;q=0') assert(!r.encoding?('identity')) r = R.new('HTTP_ACCEPT_ENCODING' => '*;q=0') assert(!r.encoding?('identity')) end def test_language request = R.new({}) assert(request.language?('en')) assert(request.language?('da')) request = R.new('HTTP_ACCEPT_LANGUAGE' => 'en;q=0.5, en-gb') assert(request.language?('en')) assert(request.language?('en-gb')) assert(!request.language?('da')) end end