Skip to content

Commit

Permalink
Add Format.accept_types and Format.accept_type. This allows `Form…
Browse files Browse the repository at this point in the history
…at.content_type` to be provided with priority parameters for the `type`, and `aliases`. These are stripped out to allow `Format.reader_types` and so-forth, to continue to return values without parameters.

Fixes #327.
  • Loading branch information
gkellogg committed Sep 10, 2016
1 parent e46839c commit ad025bc
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 30 deletions.
40 changes: 38 additions & 2 deletions lib/rdf/format.rb
Expand Up @@ -207,6 +207,19 @@ def self.reader_types
reader_symbols.flat_map {|s| RDF::Format.for(s).content_type}.uniq
end

##
# Returns the set of content types with quality for available RDF::Reader subclasses.
#
# @example
#
# accept_types = RDF::Format.accept_types
# # => %w(text/html;q=0.5 text/turtle ...)
#
# @return [Array<String>]
def self.accept_types
reader_symbols.flat_map {|s| RDF::Format.for(s).accept_type}.uniq
end

##
# Returns the set of format symbols for available RDF::Writer subclasses.
#
Expand Down Expand Up @@ -400,6 +413,11 @@ class << self
# extensions, that should be mapped to the given MIME type and handled
# by this class.
#
# Optionally, both `type`, `alias`, and `aliases`, may be parameterized
# for expressing quality.
#
# content_type "text/html;q=0.4"
#
# @param [String] type
# @param [Hash{Symbol => Object}] options
# @option options [String] :alias (nil)
Expand All @@ -420,10 +438,14 @@ def self.content_type(type = nil, options = {})
[@@content_type[self], @@content_types.map {
|ct, cl| (cl.include?(self) && ct != @@content_type[self]) ? ct : nil }].flatten.compact
else
accept_type, type = type, type.split(';').first
@@content_type[self] = type
@@content_types[type] ||= []
@@content_types[type] << self unless @@content_types[type].include?(self)

@@accept_types[accept_type] ||= []
@@accept_types[accept_type] << self unless @@accept_types[accept_type].include?(self)

if extensions = (options[:extension] || options[:extensions])
extensions = Array(extensions).map(&:to_sym)
extensions.each do |ext|
Expand All @@ -433,13 +455,26 @@ def self.content_type(type = nil, options = {})
end
if aliases = (options[:alias] || options[:aliases])
aliases = Array(aliases).each do |a|
@@content_types[a] ||= []
@@content_types[a] << self unless @@content_types[a].include?(self)
aa = a.split(';').first
@@accept_types[a] ||= []
@@accept_types[a] << self unless @@accept_types[a].include?(self)

@@content_types[aa] ||= []
@@content_types[aa] << self unless @@content_types[aa].include?(self)
end
end
end
end

##
# Returns an array of values appropriate for an Accept header.
# Same as `self.content_type`, if no parameter is given when defined.
#
# @return [Array<String>]
def self.accept_type
@@accept_types.map {|t, formats| t if formats.include?(self)}.compact
end

##
# Retrieves or defines file extensions for this RDF serialization format.
#
Expand Down Expand Up @@ -488,6 +523,7 @@ def self.content_encoding(encoding = nil)
@@content_type = {} # @private
@@content_types = {} # @private
@@content_encoding = {} # @private
@@accept_types = {} # @private
@@readers = {} # @private
@@writers = {} # @private
@@subclasses = [] # @private
Expand Down
2 changes: 1 addition & 1 deletion lib/rdf/nquads.rb
Expand Up @@ -20,7 +20,7 @@ module NQuads
# @see http://www.w3.org/TR/n-quads/
# @since 0.4.0
class Format < RDF::Format
content_type 'application/n-quads', extension: :nq, alias: ['text/x-nquads']
content_type 'application/n-quads', extension: :nq, alias: 'text/x-nquads;q=0.2'
content_encoding 'utf-8'

reader { RDF::NQuads::Reader }
Expand Down
2 changes: 1 addition & 1 deletion lib/rdf/ntriples/format.rb
Expand Up @@ -16,7 +16,7 @@ module RDF::NTriples
# @see http://www.w3.org/TR/rdf-testcases/#ntriples
# @see http://www.w3.org/TR/n-triples/
class Format < RDF::Format
content_type 'application/n-triples', extension: :nt, alias: ['text/plain']
content_type 'application/n-triples', extension: :nt, alias: 'text/plain;q=0.2'
content_encoding 'utf-8'

reader { RDF::NTriples::Reader }
Expand Down
19 changes: 1 addition & 18 deletions lib/rdf/util/file.rb
Expand Up @@ -39,24 +39,7 @@ def self.headers options
##
# @return [String] the value for an Accept header
def self.default_accept_header
# Receive text/html and text/plain at a lower priority than other formats. Also special cases for other formats.
# TODO: Associate priority level when setting `content_type` and use in an alternative to `reader_types`, or to simply change `reader_types`.
reader_types = RDF::Format.reader_types.map do |t|
case t.to_s
when /text\/plain/
"#{t};q=0.2"
when /text\/(?:csv|tab-separated-values)/
"#{t};q=0.4"
when /text\/html/
"#{t};q=0.5"
when /application\/xhtml\+xml/
"#{t};q=0.7"
else
t
end
end

(reader_types + %w(*/*;q=0.1)).join(", ")
(RDF::Format.accept_types + %w(*/*;q=0.1)).join(", ")
end

##
Expand Down
25 changes: 18 additions & 7 deletions spec/format_spec.rb
Expand Up @@ -4,7 +4,8 @@
require 'rdf/nquads'

class RDF::Format::FooFormat < RDF::Format
content_type 'application/test', extension: :test
content_type 'application/test;q=1',
extension: :test
reader { RDF::NTriples::Reader }
def self.detect(sample)
sample == "foo"
Expand All @@ -13,7 +14,9 @@ def self.to_sym; :foo_bar; end
end

class RDF::Format::BarFormat < RDF::Format
content_type 'application/test', extension: :test
content_type 'application/test',
extension: :test,
alias: 'application/x-test;q=0.1'
reader { RDF::NTriples::Reader }
def self.detect(sample)
sample == "bar"
Expand Down Expand Up @@ -68,13 +71,21 @@ def self.to_sym; :foo_bar; end

describe ".reader_types" do
it "returns content-types of available readers" do
%w(
expect(RDF::Format.reader_types).to include(*%w(
application/n-triples text/plain
application/n-quads text/x-nquads
application/test
).each do |ct|
expect(RDF::Format.reader_types).to include(ct)
end
application/test application/x-test
))
end
end

describe ".accept_types" do
it "returns accept-types of available readers with quality" do
expect(RDF::Format.accept_types).to include(*%w(
application/n-triples text/plain;q=0.2
application/n-quads text/x-nquads;q=0.2
application/test application/x-test;q=0.1
))
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/util_file_spec.rb
Expand Up @@ -31,7 +31,7 @@
describe ".default_accept_header" do
subject { RDF::Util::File::HttpAdapter.default_accept_header.split(", ") }
before do
allow(RDF::Format).to receive(:reader_types).and_return(["text/html", "text/plain", "application/xhtml+xml", "text/csv", "text/tab-separated-values"])
allow(RDF::Format).to receive(:accept_types).and_return(["text/html;q=0.5", "text/plain;q=0.2", "application/xhtml+xml;q=0.7", "text/csv;q=0.4", "text/tab-separated-values;q=0.4"])
end
it "should demote text/plain to q=0.2" do
expect(subject).to include "text/plain;q=0.2"
Expand Down

0 comments on commit ad025bc

Please sign in to comment.