Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge remote-tracking branch 'origin/master'

Conflicts:
	Gemfile.lock
	lib/rdf/model/graph.rb
  • Loading branch information...
commit 24f1ff2922b55a5d8b24e33d1e0d64d9f1084214 2 parents ee26b08 + 864cb94
@gkellogg gkellogg authored
View
25 lib/rdf/model/graph.rb
@@ -36,6 +36,7 @@ class Graph
##
# @return [RDF::Resource]
+ # @deprecated In the next release, graphs will have no name
attr_accessor :context
##
@@ -67,11 +68,22 @@ def self.load(url, options = {}, &block)
end
##
- # @param [RDF::Resource] context
- # @param [Hash{Symbol => Object}] options
+ # @overload initialize(context, options)
+ # @param [RDF::Resource] context
+ # The context only provides a context for loading relative documents
+ # @param [Hash{Symbol => Object}] options
+ # @deprecated Graph context will be removed in the next release.
+ # This is because context relates to a Named Graph in RDF 1.1
+ # and a default graph has no context/name.
+ # @overload initialize(options)
+ # @param [Hash{Symbol => Object}] options
# @yield [graph]
# @yieldparam [Graph]
- def initialize(context = nil, options = {}, &block)
+ # @note Currently, context makes this a named garph;
+ # in the next release it will not
+ def initialize(*args, &block)
+ context = args.shift unless args.first.is_a?(Hash)
+ options = args.first || {}
@context = case context
when nil then nil
when RDF::Resource then context
@@ -91,6 +103,7 @@ def initialize(context = nil, options = {}, &block)
##
# @return [void]
+ # @note The next release, graphs will not be named
def load!(*args)
case
when args.empty?
@@ -111,6 +124,7 @@ def graph?
# Returns `true` if this is a named graph.
#
# @return [Boolean]
+ # @note The next release, graphs will not be named, this will return false
def named?
!unnamed?
end
@@ -119,6 +133,7 @@ def named?
# Returns `true` if this is a unnamed graph.
#
# @return [Boolean]
+ # @note The next release, graphs will not be named, this will return true
def unnamed?
context.nil?
end
@@ -144,6 +159,7 @@ def contexts(options = {})
# Returns the URI representation of this graph.
#
# @return [RDF::URI]
+ # @note The next release, graphs will not be named, this will return nil
def to_uri
context
end
@@ -169,6 +185,7 @@ def empty?
# Returns `true` if this graph has an anonymous context, `false` otherwise.
#
# @return [Boolean]
+ # @note The next release, graphs will not be named, this will return true
def anonymous?
context.nil? ? false : context.anonymous?
end
@@ -190,7 +207,7 @@ def count
# @see RDF::Enumerable#has_statement?
def has_statement?(statement)
statement = statement.dup
- statement.context = context
+ statement.context = context # TODO: going away
@data.has_statement?(statement)
end
View
2  lib/rdf/model/list.rb
@@ -236,7 +236,7 @@ def <<(value)
end
graph.insert([new_subject, RDF.type, RDF.List])
- graph.insert([new_subject, RDF.first, value])
+ graph.insert([new_subject, RDF.first, value.is_a?(RDF::List) ? value.subject : value])
graph.insert([new_subject, RDF.rest, RDF.nil])
self
View
25 lib/rdf/model/literal.rb
@@ -279,13 +279,15 @@ def valid?
end
##
- # Returns `true` if the value does not adhere to the defined grammar of
- # the datatype.
+ # Validates the value using {#valid?}, raising an error if the value is
+ # invalid.
#
- # @return [Boolean] `true` or `false`
+ # @return [RDF::Literal] `self`
+ # @raise [ArgumentError] if the value is invalid
# @since 0.2.1
- def invalid?
- !valid?
+ def validate!
+ raise ArgumentError, "#{to_s.inspect} is not a valid <#{datatype.to_s}> literal" if invalid?
+ self
end
##
@@ -317,19 +319,6 @@ def comperable_datatype?(other)
end
##
- # Validates the value using {#valid?}, raising an error if the value is
- # invalid.
- #
- # @return [RDF::Literal] `self`
- # @raise [ArgumentError] if the value is invalid
- # @since 0.2.1
- def validate!
- raise ArgumentError, "#{to_s.inspect} is not a valid <#{datatype.to_s}> literal" if invalid?
- self
- end
- alias_method :validate, :validate!
-
- ##
# Returns a copy of this literal converted into its canonical lexical
# representation.
#
View
5 lib/rdf/model/literal/datetime.rb
@@ -24,11 +24,12 @@ def initialize(value, options = {})
##
# Converts this literal into its canonical lexical representation.
+ # with date and time normalized to UTC.
#
# @return [RDF::Literal] `self`
# @see http://www.w3.org/TR/xmlschema-2/#dateTime
def canonicalize!
- @string = @object.new_offset(0).strftime('%Y-%m-%dT%H:%M:%S%Z').sub(/\+00:00|UTC|GMT/, 'Z') if self.valid?
+ @string = @object.new_offset(0).strftime('%Y-%m-%dT%H:%M:%SZ') if self.valid?
self
end
@@ -49,7 +50,7 @@ def valid?
#
# @return [String]
def to_s
- @string || @object.strftime('%Y-%m-%dT%H:%M:%S%Z').sub(/\+00:00|UTC|GMT/, 'Z')
+ @string || @object.strftime('%Y-%m-%dT%H:%M:%S%:z').sub(/\+00:00|UTC|GMT/, 'Z')
end
##
View
2  lib/rdf/model/literal/double.rb
@@ -47,7 +47,7 @@ def canonicalize!
when @object.infinite? then @object.to_s[0...-'inity'.length].upcase
when @object.zero? then '0.0E0'
else
- i, f, e = ('%.16E' % @object.to_f).split(/[\.E]/)
+ i, f, e = ('%.15E' % @object.to_f).split(/[\.E]/)
f.sub!(/0*$/, '') # remove any trailing zeroes
f = '0' if f.empty? # ...but there must be a digit to the right of the decimal point
e.sub!(/^\+?0+(\d)$/, '\1') # remove the optional leading '+' sign and any extra leading zeroes
View
14 lib/rdf/model/literal/time.rb
@@ -41,7 +41,7 @@ def initialize(value, options = {})
# @return [RDF::Literal] `self`
# @see http://www.w3.org/TR/xmlschema-2/#time
def canonicalize!
- @string = @object.utc.strftime('%H:%M:%S%Z').sub(/\+00:00|UTC|GMT/, 'Z') if self.valid?
+ @string = @object.utc.strftime('%H:%M:%SZ') if self.valid?
self
end
@@ -54,15 +54,23 @@ def canonicalize!
# @return [Boolean]
# @since 0.2.1
def valid?
- super && object
+ super && !object.nil?
end
##
# Returns the value as a string.
+ # Does not normalize timezone
#
# @return [String]
def to_s
- @string || @object.strftime('%H:%M:%S%Z').sub(/\+00:00|UTC|GMT/, 'Z')
+ @string || if RUBY_VERSION >= '1.9' && RUBY_PLATFORM != 'java'
+ @object.strftime('%H:%M:%S%:z').
+ sub(/\+00:00|UTC|GMT/, 'Z')
+ else
+ # Ruby 1.8 doesn't do timezone's properly, use utc_offset
+ off = @object.utc_offset == 0 ? "Z" : ("%0.2d:00" % (@object.utc_offset/3600))
+ @object.strftime("%H:%M:%S#{off}")
+ end
end
##
View
4 lib/rdf/model/statement.rb
@@ -113,7 +113,9 @@ def invalid?
##
# @return [Boolean]
def valid?
- has_subject? && has_predicate? && has_object?
+ has_subject? && subject.valid? &&
+ has_predicate? && predicate.valid? &&
+ has_object? && object.valid?
end
##
View
110 lib/rdf/model/uri.rb
@@ -3,6 +3,7 @@
module RDF
##
# A Uniform Resource Identifier (URI).
+ # Also compatible with International Resource Identifier (IRI)
#
# `RDF::URI` supports all the instance methods of `Addressable::URI`.
#
@@ -19,6 +20,8 @@ module RDF
# uri.to_s #=> "http://rdf.rubyforge.org/"
#
# @see http://en.wikipedia.org/wiki/Uniform_Resource_Identifier
+ # @see http://www.ietf.org/rfc/rfc3986.txt
+ # @see http://www.ietf.org/rfc/rfc3987.txt
# @see http://addressable.rubyforge.org/
class URI
include RDF::Resource
@@ -27,7 +30,66 @@ class URI
# Defines the maximum number of interned URI references that can be held
# cached in memory at any one time.
CACHE_SIZE = -1 # unlimited by default
-
+
+ # IRI components
+ if RUBY_VERSION >= '1.9'
+ UCSCHAR = Regexp.compile(<<-EOS.gsub(/\s+/, ''))
+ [\\u00A0-\\uD7FF]|[\\uF900-\\uFDCF]|[\\uFDF0-\\uFFEF]|
+ [\\u{10000}-\\u{1FFFD}]|[\\u{20000}-\\u{2FFFD}]|[\\u{30000}-\\u{3FFFD}]|
+ [\\u{40000}-\\u{4FFFD}]|[\\u{50000}-\\u{5FFFD}]|[\\u{60000}-\\u{6FFFD}]|
+ [\\u{70000}-\\u{7FFFD}]|[\\u{80000}-\\u{8FFFD}]|[\\u{90000}-\\u{9FFFD}]|
+ [\\u{A0000}-\\u{AFFFD}]|[\\u{B0000}-\\u{BFFFD}]|[\\u{C0000}-\\u{CFFFD}]|
+ [\\u{D0000}-\\u{DFFFD}]|[\\u{E0000}-\\u{EFFFD}]
+ EOS
+ IPRIVATE = Regexp.compile("[\\uE000-\\uF8FF]|[\\u{F0000}-\\u{FFFFD}]|[\\u100000-\\u10FFFD]")
+ end
+
+ SCHEME = Regexp.compile("[A-za-z](?:[A-Za-z0-9+-\.])*")
+ PORT = Regexp.compile("[0-9]*")
+ IP_literal = Regexp.compile("\\[[0-9A-Fa-f:\\.]*\\]") # Simplified, no IPvFuture
+ PCT_ENCODED = Regexp.compile("%[0-9A-Fa-f]{2}")
+ GEN_DELIMS = Regexp.compile("[:/\\?\\#\\[\\]@]")
+ SUB_DELIMS = Regexp.compile("[!\\$&'\\(\\)\\*\\+,;=]")
+ RESERVED = Regexp.compile("(?:#{GEN_DELIMS}|#{SUB_DELIMS})")
+ UNRESERVED = Regexp.compile("[A-Za-z0-9]|-|\\.|_|~")
+
+ if RUBY_VERSION >= '1.9'
+ IUNRESERVED = Regexp.compile("[A-Za-z0-9]|-|\\.|_|~|#{UCSCHAR}")
+ else
+ IUNRESERVED = Regexp.compile("[A-Za-z0-9]|-|\\.|_|~")
+ end
+
+ IPCHAR = Regexp.compile("(?:#{IUNRESERVED}|#{PCT_ENCODED}|#{SUB_DELIMS}|:|@)")
+
+ if RUBY_VERSION >= '1.9'
+ IQUERY = Regexp.compile("(?:#{IPCHAR}|#{IPRIVATE}|/|\\?)*")
+ else
+ IQUERY = Regexp.compile("(?:#{IPCHAR}|/|\\?)*")
+ end
+
+ IFRAGMENT = Regexp.compile("(?:#{IPCHAR}|/|\\?)*")
+
+ ISEGMENT = Regexp.compile("(?:#{IPCHAR})*")
+ ISEGMENT_NZ = Regexp.compile("(?:#{IPCHAR})+")
+ ISEGMENT_NZ_NC = Regexp.compile("(?:(?:#{IUNRESERVED})|(?:#{PCT_ENCODED})|(?:#{SUB_DELIMS})|@)+")
+
+ IPATH_ABEMPTY = Regexp.compile("(?:/#{ISEGMENT})*")
+ IPATH_ABSOLUTE = Regexp.compile("/(?:(?:#{ISEGMENT_NZ})(/#{ISEGMENT})*)?")
+ IPATH_NOSCHEME = Regexp.compile("(?:#{ISEGMENT_NZ_NC})(?:/#{ISEGMENT})*")
+ IPATH_ROOTLESS = Regexp.compile("(?:#{ISEGMENT_NZ})(?:/#{ISEGMENT})*")
+ IPATH_EMPTY = Regexp.compile("")
+
+ IREG_NAME = Regexp.compile("(?:(?:#{IUNRESERVED})|(?:#{PCT_ENCODED})|(?:#{SUB_DELIMS}))*")
+ IHOST = Regexp.compile("(?:#{IP_literal})|(?:#{IREG_NAME})")
+ IUSERINFO = Regexp.compile("(?:(?:#{IUNRESERVED})|(?:#{PCT_ENCODED})|(?:#{SUB_DELIMS})|:)*")
+ IAUTHORITY = Regexp.compile("(?:#{IUSERINFO}@)?#{IHOST}(?:#{PORT})?")
+
+ IRELATIVE_PART = Regexp.compile("(?:(?://#{IAUTHORITY}(?:#{IPATH_ABEMPTY}))|(?:#{IPATH_ABSOLUTE})|(?:#{IPATH_NOSCHEME})|(?:#{IPATH_EMPTY}))")
+ IRELATIVE_REF = Regexp.compile("^#{IRELATIVE_PART}(?:\\?#{IQUERY})?(?:\\##{IFRAGMENT})?$")
+
+ IHIER_PART = Regexp.compile("(?:(?://#{IAUTHORITY}#{IPATH_ABEMPTY})|(?:#{IPATH_ABSOLUTE})|(?:#{IPATH_ROOTLESS})|(?:#{IPATH_EMPTY}))")
+ IRI = Regexp.compile("^#{SCHEME}:(?:#{IHIER_PART})(?:\\?#{IQUERY})?(?:\\##{IFRAGMENT})?$")
+
##
# @return [RDF::Util::Cache]
# @private
@@ -143,16 +205,28 @@ def length
alias_method :size, :length
##
+ # Determine if the URI is avalid according to RFC3987
+ #
+ # Note, for Ruby versions < 1.9, this always returns true.
+ #
+ # @return [Boolean] `true` or `false`
+ # @since 0.3.9
+ def valid?
+ # As Addressable::URI does not perform adequate validation, validate
+ # relative to RFC3987
+ to_s.match(RDF::URI::IRI) || to_s.match(RDF::URI::IRELATIVE_REF) || false
+ end
+
+ ##
# Validates this URI, raising an error if it is invalid.
#
# @return [RDF::URI] `self`
# @raise [ArgumentError] if the URI is invalid
# @since 0.3.0
def validate!
- # TODO: raise error if the URI fails validation
+ raise ArgumentError, "#{to_s.inspect} is not a valid IRI" if invalid?
self
end
- alias_method :validate, :validate!
##
# Returns a copy of this URI converted into its canonical lexical
@@ -170,7 +244,7 @@ def canonicalize
# @return [RDF::URI] `self`
# @since 0.3.0
def canonicalize!
- # TODO: canonicalize this URI
+ @uri.normalize!
self
end
@@ -250,21 +324,21 @@ def /(fragment)
RDF::URI.intern(to_s.sub(/:+$/,'') + ':' + fragment.to_s.sub(/^:+/,''))
else # !urn?
case to_s[-1].chr
- when '#'
- case fragment.to_s[0].chr
- when '/' then # Base ending with '#', fragment beginning with '/'. The fragment wins, we use '/'.
- RDF::URI.intern(to_s.sub(/#+$/,'') + '/' + fragment.to_s.sub(/^\/+/,''))
- else
- RDF::URI.intern(to_s.sub(/#+$/,'') + '#' + fragment.to_s.sub(/^#+/,''))
- end
- else # includes '/'. Results from bases ending in '/' are the same as if there were no trailing slash.
- case fragment.to_s[0].chr
- when '#' then # Base ending with '/', fragment beginning with '#'. The fragment wins, we use '#'.
- RDF::URI.intern(to_s.sub(/\/+$/,'') + '#' + fragment.to_s.sub(/^#+/,''))
- else
- RDF::URI.intern(to_s.sub(/\/+$/,'') + '/' + fragment.to_s.sub(/^\/+/,''))
- end
+ when '#'
+ case fragment.to_s[0].chr
+ when '/' then # Base ending with '#', fragment beginning with '/'. The fragment wins, we use '/'.
+ RDF::URI.intern(to_s.sub(/#+$/,'') + '/' + fragment.to_s.sub(/^\/+/,''))
+ else
+ RDF::URI.intern(to_s.sub(/#+$/,'') + '#' + fragment.to_s.sub(/^#+/,''))
end
+ else # includes '/'. Results from bases ending in '/' are the same as if there were no trailing slash.
+ case fragment.to_s[0].chr
+ when '#' then # Base ending with '/', fragment beginning with '#'. The fragment wins, we use '#'.
+ RDF::URI.intern(to_s.sub(/\/+$/,'') + '#' + fragment.to_s.sub(/^#+/,''))
+ else
+ RDF::URI.intern(to_s.sub(/\/+$/,'') + '/' + fragment.to_s.sub(/^\/+/,''))
+ end
+ end
end
end
View
28 lib/rdf/model/value.rb
@@ -94,6 +94,34 @@ def variable?
end
##
+ # Returns `true` if the value has a valid representation
+ #
+ # @return [Boolean] `true` or `false`
+ # @since 0.3.9
+ def valid?
+ true
+ end
+
+ ##
+ # Returns `true` if value is not valid
+ #
+ # @return [Boolean] `true` or `false`
+ # @since 0.2.1
+ def invalid?
+ !valid?
+ end
+
+ ##
+ # Default validate! implementation, overridden in concrete classes
+ # @return [RDF::Literal] `self`
+ # @raise [ArgumentError] if the value is invalid
+ # @since 0.3.9
+ def validate!
+ raise ArgumentError if invalid?
+ end
+ alias_method :validate, :validate!
+
+ ##
# Returns an `RDF::Value` representation of `self`.
#
# @return [RDF::Value]
View
2  lib/rdf/ntriples/reader.rb
@@ -124,7 +124,7 @@ def self.parse_literal(input)
# @see http://blog.grayproductions.net/articles/understanding_m17n
# @see http://yehudakatz.com/2010/05/17/encodings-unabridged/
def self.unescape(string)
- string.force_encoding(Encoding::ASCII_8BIT) if string.respond_to?(:force_encoding)
+ string = string.dup.force_encoding(Encoding::ASCII_8BIT) if string.respond_to?(:force_encoding)
# Decode \t|\n|\r|\"|\\ character escapes:
ESCAPE_CHARS.each { |escape| string.gsub!(escape.inspect[1...-1], escape) }
View
3  lib/rdf/ntriples/writer.rb
@@ -80,8 +80,7 @@ def self.escape(string, encoding = nil)
buffer.string
end
end
- ret.force_encoding(encoding) if ret.respond_to?(:force_encoding) && encoding
- ret
+ ret.respond_to?(:force_encoding) && encoding ? ret.dup.force_encoding(encoding) : ret
end
##
View
3  lib/rdf/writer.rb
@@ -136,7 +136,10 @@ def self.dump(data, io = nil, options = {})
# @yieldparam [RDF::Writer] writer
# @yieldreturn [void]
# @return [String]
+ # @raise [ArgumentError] if no block is provided
def self.buffer(*args, &block)
+ raise ArgumentError, "block expected" unless block_given?
+
StringIO.open do |buffer|
self.new(buffer, *args) { |writer| block.call(writer) }
buffer.string
View
9 spec/model_list_spec.rb
@@ -42,8 +42,13 @@
end
it "accepts array arguments" do
- lambda { RDF::List[[]] }.should_not raise_error
- RDF::List[[]].should == RDF::List[RDF::List[]]
+ lambda { RDF::List[[1]] }.should_not raise_error
+ l1 = RDF::List[[1]]
+ l1.size.should == 1
+ l1.first.should be_a(RDF::Node)
+ lambda { RDF::List.new(l1.first, l1.graph) }.should_not raise_error
+ l2 = RDF::List.new(l1.first, l1.graph)
+ l2.first.should == RDF::Literal(1)
end
it "accepts blank node arguments" do
View
7 spec/model_literal_spec.rb
@@ -168,6 +168,13 @@ def self.literals(*selector)
end
end
+ # Native representations
+ [Date.today, Time.now, DateTime.now].each do |v|
+ it "creates a valid literal from #{v.inspect}" do
+ RDF::Literal(v, :canonicalize => true).should be_valid
+ end
+ end
+
# DateTime
{
"2010-01-01T00:00:00Z" => "2010-01-01T00:00:00Z",
View
155 spec/model_uri_spec.rb
@@ -1,3 +1,4 @@
+# coding: utf-8
require File.join(File.dirname(__FILE__), 'spec_helper')
describe RDF::URI do
@@ -71,6 +72,160 @@
@new.call('http://example.org').should_not be_anonymous
end
+ context "validation" do
+ subject {RDF::URI("http://example/for/validation")}
+
+ describe "#valid?" do
+ let(:refs) {
+ %W(a d z A D Z 0 5 99 - . _ ~ \u0053 \u00D6 foo %20) +
+ (RUBY_VERSION >= "1.9" ? %W(\U00000053 Dürst) : [])
+ }
+ {
+ "" => "%s",
+ "and query" => "%s?%s",
+ "and fragment" => "%s#%s",
+ "and query and fragment" => "%s?%s#%s",
+ }.each do |mod, fmt|
+ it "validates IRI with authority and abempty #{mod}" do
+ refs.each do |c|
+ RDF::URI("scheme:auth//#{fmt}" % ["", c, c]).should be_valid
+ RDF::URI("scheme:auth//#{fmt}" % [c, c, c]).should be_valid
+ RDF::URI("scheme:auth//#{fmt}" % ["#{c}/#{c}", c, c]).should be_valid
+ end
+ end
+ it "validates IRI with ipath-absolute #{mod}" do
+ refs.each do |c|
+ RDF::URI("scheme:/#{fmt}" % ["", c, c]).should be_valid
+ RDF::URI("scheme:/#{fmt}" % [c, c, c]).should be_valid
+ RDF::URI("scheme:/#{fmt}" % ["#{c}/#{c}", c, c]).should be_valid
+ end
+ end
+ it "validates IRI with ipath-rootless #{mod}" do
+ refs.each do |c|
+ RDF::URI("scheme:#{fmt}" % [c, c, c]).should be_valid
+ RDF::URI("scheme:#{fmt}" % ["#{c}/#{c}", c, c]).should be_valid
+ end
+ end
+ it "validates IRI with ipath-empty #{mod}", :pending => "Addressable bug" do
+ refs.each do |c|
+ RDF::URI("scheme:#{fmt}" % ["", c, c]).should be_valid
+ end
+ end
+
+ it "validates irelative-ref with authority #{mod}" do
+ refs.each do |c|
+ RDF::URI("//auth/#{fmt}" % [c, c, c]).should be_valid
+ end
+ end
+ it "validates irelative-ref with ipath-absolute #{mod}" do
+ refs.each do |c|
+ RDF::URI("/#{fmt}" % [c, c, c]).should be_valid
+ RDF::URI("/#{fmt}" % ["#{c}/", c, c]).should be_valid
+ RDF::URI("/#{fmt}" % ["#{c}/#{c}", c, c]).should be_valid
+ end
+ end
+ it "validates irelative-ref with ipath-noscheme #{mod}" do
+ refs.each do |c|
+ RDF::URI("#{fmt}" % [c, c, c]).should be_valid
+ RDF::URI("#{fmt}" % ["#{c}/", c, c]).should be_valid
+ RDF::URI("#{fmt}" % ["#{c}/#{c}", c, c]).should be_valid
+ end
+ end
+ it "validates irelative-ref with ipath-empty #{mod}" do
+ refs.each do |c|
+ RDF::URI("#{fmt}" % ["", c, c]).should be_valid
+ end
+ end
+ end
+
+ [" ", "<", ">", "'" '"'].each do |c|
+ it "does not validate <http://example/#{c}>" do
+ RDF::URI("http://example/#{c}").should_not be_valid
+ end
+ end
+ end
+
+ describe "#invalid?" do
+ it "is invalid if not valid" do
+ subject.should_receive(:valid?).and_return(false)
+ subject.should be_invalid
+ end
+ end
+
+ describe "#validate" do
+ it "raises ArgumentError if not valid" do
+ subject.should_receive(:valid?).and_return(false)
+ lambda { subject.validate }.should raise_error(ArgumentError)
+ end
+ end
+
+ describe "#validate!" do
+ it "raises ArgumentError if not valid" do
+ subject.should_receive(:valid?).and_return(false)
+ lambda { subject.validate! }.should raise_error(ArgumentError)
+ end
+ end
+ end
+
+ context "normalization" do
+ {
+ "syntax-based normalization" => [
+ "eXAMPLE://a/./b/../b/%63/%7bfoo%7d/ros%C3%A9",
+ "example://a/b/c/%7Bfoo%7D/ros&#xE9;",
+ true
+ ],
+ "syntax-based normalization (addressable)" => [
+ "eXAMPLE://a/./b/../b/%63/%7bfoo%7d/ros%C3%A9",
+ "example://a/b/c/%7Bfoo%7D/ros%C3%A9",
+ true
+ ],
+ "case normalization(1)" => [
+ "http://example.com/%e1%cf",
+ "http://example.com/%E1%CF",
+ true
+ ],
+ "case normalization(2)" => [
+ "http://eXaMpLe.com/",
+ "http://example.com/",
+ true
+ ],
+ "percent-encoding normalization(1)" => [
+ "http://example.com/%7euser",
+ "http://example.com/~user",
+ true
+ ],
+ "percent-encoding normalization(2)" => [
+ "http://example.com/%7Euser",
+ "http://example.com/~user",
+ true
+ ],
+ "path-segment normalization(1)" => [
+ "http://example.com/./foo",
+ "http://example.com/foo/",
+ true
+ ],
+ "path-segment normalization(1)" => [
+ "http://example.com/foo/bar/..",
+ "http://example.com/foo/",
+ true
+ ],
+ }.each do |name, (input, output, pending)|
+ let(:u1) {RDF::URI(input)}
+ let(:u2) {RDF::URI(output)}
+ it "#canonicalize #{name}", :pending => (pending ? "Addressable" : false) do
+ u1.canonicalize.to_s.should == u2.to_s
+ u1.should == u1
+ end
+ end
+ it "#canonicalize! alters resource" do
+ u1 = RDF::URI("eXAMPLE:example.com/foo")
+ u2 = RDF::URI("example:example.com/foo")
+ u1.canonicalize!.to_s.should == u2.to_s
+ u1.should == u2
+ end
+ end
+
+
context "using the smart separator (/)" do
{
# #!! means that I'm not sure I like the semantics, but they are cases for
Please sign in to comment.
Something went wrong with that request. Please try again.