rdf 3.0.11 → 3.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHORS +1 -1
  3. data/README.md +127 -95
  4. data/UNLICENSE +1 -1
  5. data/VERSION +1 -1
  6. data/etc/doap.nt +79 -85
  7. data/lib/rdf.rb +35 -23
  8. data/lib/rdf/changeset.rb +80 -19
  9. data/lib/rdf/cli.rb +7 -7
  10. data/lib/rdf/format.rb +17 -10
  11. data/lib/rdf/mixin/enumerable.rb +4 -3
  12. data/lib/rdf/mixin/mutable.rb +5 -15
  13. data/lib/rdf/mixin/queryable.rb +12 -4
  14. data/lib/rdf/mixin/transactable.rb +2 -2
  15. data/lib/rdf/mixin/writable.rb +9 -14
  16. data/lib/rdf/model/dataset.rb +1 -1
  17. data/lib/rdf/model/graph.rb +7 -4
  18. data/lib/rdf/model/list.rb +5 -5
  19. data/lib/rdf/model/literal.rb +3 -3
  20. data/lib/rdf/model/statement.rb +32 -9
  21. data/lib/rdf/model/uri.rb +53 -32
  22. data/lib/rdf/nquads.rb +6 -6
  23. data/lib/rdf/ntriples.rb +7 -5
  24. data/lib/rdf/ntriples/reader.rb +29 -7
  25. data/lib/rdf/ntriples/writer.rb +10 -1
  26. data/lib/rdf/query.rb +27 -35
  27. data/lib/rdf/query/hash_pattern_normalizer.rb +14 -12
  28. data/lib/rdf/query/pattern.rb +51 -18
  29. data/lib/rdf/query/solution.rb +20 -1
  30. data/lib/rdf/query/solutions.rb +15 -5
  31. data/lib/rdf/query/variable.rb +17 -5
  32. data/lib/rdf/reader.rb +76 -25
  33. data/lib/rdf/repository.rb +32 -18
  34. data/lib/rdf/transaction.rb +1 -1
  35. data/lib/rdf/util.rb +6 -5
  36. data/lib/rdf/util/cache.rb +2 -2
  37. data/lib/rdf/util/coercions.rb +60 -0
  38. data/lib/rdf/util/file.rb +20 -10
  39. data/lib/rdf/util/logger.rb +6 -6
  40. data/lib/rdf/util/uuid.rb +4 -4
  41. data/lib/rdf/vocab/owl.rb +401 -86
  42. data/lib/rdf/vocab/rdfs.rb +81 -18
  43. data/lib/rdf/vocab/rdfv.rb +147 -1
  44. data/lib/rdf/vocab/writer.rb +41 -3
  45. data/lib/rdf/vocab/xsd.rb +203 -2
  46. data/lib/rdf/vocabulary.rb +73 -15
  47. data/lib/rdf/writer.rb +33 -11
  48. metadata +34 -28
@@ -19,7 +19,7 @@ module RDF
19
19
  #
20
20
  # @example Querying for statements having a given predicate
21
21
  # queryable.query([nil, RDF::Vocab::DOAP.developer, nil])
22
- # queryable.query(predicate: RDF::Vocab::DOAP.developer) do |statement|
22
+ # queryable.query({predicate: RDF::Vocab::DOAP.developer}) do |statement|
23
23
  # puts statement.inspect
24
24
  # end
25
25
  #
@@ -50,7 +50,7 @@ module RDF
50
50
  solutions = RDF::Query::Solutions.new
51
51
  block = lambda {|solution| solutions << solution} unless block_given?
52
52
  before_query(pattern) if respond_to?(:before_query)
53
- query_execute(pattern, options, &block)
53
+ query_execute(pattern, **options, &block)
54
54
  after_query(pattern) if respond_to?(:after_query)
55
55
  # Returns the solutions, not an enumerator
56
56
  solutions
@@ -85,7 +85,7 @@ module RDF
85
85
 
86
86
  # Otherwise, we delegate to `#query_pattern`:
87
87
  else # pattern.variable?
88
- query_pattern(pattern, options, &block)
88
+ query_pattern(pattern, **options, &block)
89
89
  end
90
90
  after_query(pattern) if respond_to?(:after_query)
91
91
  enum
@@ -116,7 +116,7 @@ module RDF
116
116
  # query execution by breaking down the query into its constituent
117
117
  # triple patterns and invoking `RDF::Query::Pattern#execute` on each
118
118
  # pattern.
119
- query.execute(self, options, &block)
119
+ query.execute(self, **options, &block)
120
120
  end
121
121
  protected :query_execute
122
122
 
@@ -128,6 +128,14 @@ module RDF
128
128
  # method in order to provide for storage-specific optimized triple
129
129
  # pattern matching.
130
130
  #
131
+ # ## RDFStar (RDF*)
132
+ #
133
+ # Statements may have embedded statements as either a subject or object, recursively.
134
+ #
135
+ # Patterns may also have embedded patterns as either a subject or object, recursively.
136
+ #
137
+ # When matching, match an embedded pattern against embedded statements, recursively. (see {RDF::Query::Pattern#eql?})
138
+ #
131
139
  # @param [RDF::Query::Pattern] pattern
132
140
  # the query pattern to match
133
141
  # @param [Hash{Symbol => Object}] options ({})
@@ -21,14 +21,14 @@ module RDF
21
21
  #
22
22
  # @example running a transaction
23
23
  # repository.transaction(mutable: true) do |tx|
24
- # tx.insert [RDF::URI("http://rubygems.org/gems/rdf"), RDF::RDFS.label, "RDF.rb"]
24
+ # tx.insert [RDF::URI("https://rubygems.org/gems/rdf"), RDF::RDFS.label, "RDF.rb"]
25
25
  # end
26
26
  #
27
27
  # Raising an error within the transaction block causes automatic rollback.
28
28
  #
29
29
  # @example manipulating a live transaction
30
30
  # tx = repository.transaction(mutable: true)
31
- # tx.insert [RDF::URI("http://rubygems.org/gems/rdf"), RDF::RDFS.label, "RDF.rb"]
31
+ # tx.insert [RDF::URI("https://rubygems.org/gems/rdf"), RDF::RDFS.label, "RDF.rb"]
32
32
  # tx.execute
33
33
  #
34
34
  # @overload transaction(mutable: false)
@@ -7,6 +7,7 @@ module RDF
7
7
  # @see RDF::Repository
8
8
  module Writable
9
9
  extend RDF::Util::Aliasing::LateBound
10
+ include RDF::Util::Coercions
10
11
 
11
12
  ##
12
13
  # Returns `true` if `self` is writable.
@@ -53,31 +54,20 @@ module RDF
53
54
  # @overload insert(*statements)
54
55
  # @param [Array<RDF::Statement>] statements
55
56
  # @return [self]
57
+ # @raise [ArgumentError] on an attempt to insert an embedded statement when it is not supported
56
58
  #
57
59
  # @overload insert(statements)
58
60
  # @param [Enumerable<RDF::Statement>] statements
59
61
  # @return [self]
62
+ # @raise [ArgumentError] on an attempt to insert an embedded statement when it is not supported
60
63
  def insert(*statements)
61
- statements.map! do |value|
62
- case
63
- when value.respond_to?(:each_statement)
64
- insert_statements(value)
65
- nil
66
- when (statement = Statement.from(value))
67
- statement
68
- else
69
- raise ArgumentError.new("not a valid statement: #{value.inspect}")
70
- end
71
- end
72
- statements.compact!
73
- insert_statements(statements) unless statements.empty?
64
+ coerce_statements(statements) { |value| insert_statements value }
74
65
 
75
66
  return self
76
67
  end
77
68
  alias_method :insert!, :insert
78
69
 
79
70
  protected
80
-
81
71
  ##
82
72
  # Inserts statements from the given RDF reader into the underlying
83
73
  # storage or output stream.
@@ -132,10 +122,14 @@ module RDF
132
122
  #
133
123
  # @param [RDF::Enumerable] statements
134
124
  # @return [void]
125
+ # @raise [ArgumentError] on an attempt to insert an embedded statement when it is not supported
135
126
  # @since 0.1.6
136
127
  def insert_statements(statements)
137
128
  each = statements.respond_to?(:each_statement) ? :each_statement : :each
138
129
  statements.__send__(each) do |statement|
130
+ if statement.embedded? && respond_to?(:supports?) && !supports?(:rdfstar)
131
+ raise ArgumentError, "Wriable does not support embedded statements"
132
+ end
139
133
  insert_statement(statement)
140
134
  end
141
135
  end
@@ -150,6 +144,7 @@ module RDF
150
144
  #
151
145
  # @param [RDF::Statement] statement
152
146
  # @return [void]
147
+ # @raise [ArgumentError] on an attempt to insert an embedded statement when it is not supported
153
148
  # @abstract
154
149
  def insert_statement(statement)
155
150
  raise NotImplementedError.new("#{self.class}#insert_statement")
@@ -104,7 +104,7 @@ module RDF
104
104
  # @private
105
105
  # @see RDF::Enumerable#supports?
106
106
  def supports?(feature)
107
- return true if feature == :graph_name
107
+ return true if [:graph_name, :rdfstar].include?(feature)
108
108
  super
109
109
  end
110
110
 
@@ -211,7 +211,7 @@ module RDF
211
211
  # @return [Integer]
212
212
  # @see RDF::Enumerable#count
213
213
  def count
214
- @data.query(graph_name: graph_name || false).count
214
+ @data.query({graph_name: graph_name || false}).count
215
215
  end
216
216
 
217
217
  ##
@@ -237,7 +237,7 @@ module RDF
237
237
  # @see RDF::Enumerable#each_statement
238
238
  def each(&block)
239
239
  if @data.respond_to?(:query)
240
- @data.query(graph_name: graph_name || false, &block)
240
+ @data.query({graph_name: graph_name || false}, &block)
241
241
  elsif @data.respond_to?(:each)
242
242
  @data.each(&block)
243
243
  else
@@ -259,11 +259,11 @@ module RDF
259
259
  ##
260
260
  # Graph equivalence based on the contents of each graph being _exactly_
261
261
  # the same. To determine if the have the same _meaning_, consider
262
- # [rdf-isomorphic](http://rubygems.org/gems/rdf-isomorphic).
262
+ # [rdf-isomorphic](https://rubygems.org/gems/rdf-isomorphic).
263
263
  #
264
264
  # @param [RDF::Graph] other
265
265
  # @return [Boolean]
266
- # @see http://rubygems.org/gems/rdf-isomorphic
266
+ # @see https://rubygems.org/gems/rdf-isomorphic
267
267
  def ==(other)
268
268
  other.is_a?(RDF::Graph) &&
269
269
  graph_name == other.graph_name &&
@@ -283,6 +283,9 @@ module RDF
283
283
  # @private
284
284
  # @see RDF::Mutable#insert
285
285
  def insert_statement(statement)
286
+ if statement.embedded? && !@data.supports?(:rdfstar)
287
+ raise ArgumentError, "Graph does not support embedded statements"
288
+ end
286
289
  statement = statement.dup
287
290
  statement.graph_name = graph_name
288
291
  @data.insert(statement)
@@ -59,7 +59,7 @@ module RDF
59
59
  def initialize(subject: nil, graph: nil, values: nil, &block)
60
60
  @subject = subject || RDF.nil
61
61
  @graph = graph || RDF::Graph.new
62
- is_empty = @graph.query(subject: subject, predicate: RDF.first).empty?
62
+ is_empty = @graph.query({subject: subject, predicate: RDF.first}).empty?
63
63
 
64
64
  if subject && is_empty
65
65
  # An empty list with explicit subject and value initializers
@@ -115,7 +115,7 @@ module RDF
115
115
  list_nodes << li
116
116
  rest = nil
117
117
  firsts = rests = 0
118
- @graph.query(subject: li) do |st|
118
+ @graph.query({subject: li}) do |st|
119
119
  return false unless st.subject.node?
120
120
  case st.predicate
121
121
  when RDF.first
@@ -136,7 +136,7 @@ module RDF
136
136
 
137
137
  # All elements other than the head must be referenced exactly once
138
138
  return list_nodes.all? do |li|
139
- refs = @graph.query(object: li).count
139
+ refs = @graph.query({object: li}).count
140
140
  case refs
141
141
  when 0 then li == subject
142
142
  when 1 then true
@@ -479,7 +479,7 @@ module RDF
479
479
  # @return [Boolean]
480
480
  # @see http://ruby-doc.org/core-2.2.2/Array.html#method-i-empty-3F
481
481
  def empty?
482
- graph.query(subject: subject, predicate: RDF.first).empty?
482
+ graph.query({subject: subject, predicate: RDF.first}).empty?
483
483
  end
484
484
 
485
485
  ##
@@ -822,7 +822,7 @@ module RDF
822
822
  return enum_statement unless block_given?
823
823
 
824
824
  each_subject do |subject|
825
- graph.query(subject: subject, &block)
825
+ graph.query({subject: subject}, &block)
826
826
  end
827
827
  end
828
828
  alias_method :to_rdf, :each_statement
@@ -49,7 +49,7 @@ module RDF
49
49
  # RDF::Literal.new(123).datatype #=> XSD.integer
50
50
  # RDF::Literal.new(9223372036854775807).datatype #=> XSD.integer
51
51
  # RDF::Literal.new(3.1415).datatype #=> XSD.double
52
- # RDF::Literal.new(Time.now).datatype #=> XSD.time
52
+ # RDF::Literal.new(Time.now).datatype #=> XSD.dateTime
53
53
  # RDF::Literal.new(Date.new(2010)).datatype #=> XSD.date
54
54
  # RDF::Literal.new(DateTime.new(2010)).datatype #=> XSD.dateTime
55
55
  #
@@ -119,8 +119,8 @@ module RDF
119
119
  when ::Float then RDF::Literal::Double
120
120
  when ::BigDecimal then RDF::Literal::Decimal
121
121
  when ::DateTime then RDF::Literal::DateTime
122
+ when ::Time then RDF::Literal::DateTime
122
123
  when ::Date then RDF::Literal::Date
123
- when ::Time then RDF::Literal::Time # FIXME: Ruby's Time class can represent datetimes as well
124
124
  when ::Symbol then RDF::Literal::Token
125
125
  else self
126
126
  end
@@ -360,7 +360,7 @@ module RDF
360
360
  # @return [Boolean] `true` or `false`
361
361
  # @since 0.2.1
362
362
  def valid?
363
- return false if language? && language.to_s !~ /^[a-zA-Z]+(-[a-zA-Z0-9]+)*$/
363
+ return false if language? && language.to_s !~ /^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/
364
364
  return false if datatype? && datatype.invalid?
365
365
  grammar = self.class.const_get(:GRAMMAR) rescue nil
366
366
  grammar.nil? || value.match?(grammar)
@@ -3,7 +3,7 @@ module RDF
3
3
  # An RDF statement.
4
4
  #
5
5
  # @example Creating an RDF statement
6
- # s = RDF::URI.new("http://rubygems.org/gems/rdf")
6
+ # s = RDF::URI.new("https://rubygems.org/gems/rdf")
7
7
  # p = RDF::Vocab::DC.creator
8
8
  # o = RDF::URI.new("http://ar.to/#self")
9
9
  # RDF::Statement(s, p, o)
@@ -14,7 +14,7 @@ module RDF
14
14
  #
15
15
  # @example Creating an RDF statement from a `Hash`
16
16
  # RDF::Statement({
17
- # subject: RDF::URI.new("http://rubygems.org/gems/rdf"),
17
+ # subject: RDF::URI.new("https://rubygems.org/gems/rdf"),
18
18
  # predicate: RDF::Vocab::DC.creator,
19
19
  # object: RDF::URI.new("http://ar.to/#self"),
20
20
  # })
@@ -26,7 +26,7 @@ module RDF
26
26
  # RDF::Statement(s, p, "o")
27
27
  #
28
28
  class Statement
29
- include RDF::Value
29
+ include RDF::Resource
30
30
 
31
31
  ##
32
32
  # @private
@@ -112,7 +112,7 @@ module RDF
112
112
  elsif @subject.nil?
113
113
  nil
114
114
  else
115
- raise ArgumentError, "expected subject to be nil or a term, was #{@subject.inspect}"
115
+ raise ArgumentError, "expected subject to be nil or a resource, was #{@subject.inspect}"
116
116
  end
117
117
  @predicate = Node.intern(@predicate) if @predicate.is_a?(Symbol)
118
118
  @object = if @object.is_a?(Value)
@@ -124,6 +124,15 @@ module RDF
124
124
  else
125
125
  Literal.new(@object)
126
126
  end
127
+ @graph_name = if @graph_name.is_a?(Value)
128
+ @graph_name.to_term
129
+ elsif @graph_name.is_a?(Symbol)
130
+ Node.intern(@graph_name)
131
+ elsif !@graph_name
132
+ @graph_name
133
+ else
134
+ raise ArgumentError, "expected graph_name to be nil or a resource, was #{@graph_name.inspect}"
135
+ end
127
136
  end
128
137
 
129
138
  ##
@@ -140,10 +149,18 @@ module RDF
140
149
  #
141
150
  # @return [Boolean]
142
151
  def variable?
143
- !(has_subject? && subject.resource? &&
144
- has_predicate? && predicate.resource? &&
145
- has_object? && (object.resource? || object.literal?) &&
146
- (has_graph? ? graph_name.resource? : true))
152
+ !(has_subject? && subject.constant? &&
153
+ has_predicate? && predicate.constant? &&
154
+ has_object? && object.constant? &&
155
+ (has_graph? ? graph_name.constant? : true))
156
+ end
157
+
158
+ ##
159
+ # Returns `true` if any element of the statement is, itself, a statement.
160
+ #
161
+ # @return [Boolean]
162
+ def embedded?
163
+ subject && subject.statement? || object && object.statement?
147
164
  end
148
165
 
149
166
  ##
@@ -386,7 +403,13 @@ module RDF
386
403
  # @return [String]
387
404
  def to_s
388
405
  (graph_name ? to_quad : to_triple).map do |term|
389
- term.respond_to?(:to_base) ? term.to_base : term.inspect
406
+ if term.is_a?(Statement)
407
+ "<<#{term.to_s[0..-3]}>>"
408
+ elsif term.respond_to?(:to_base)
409
+ term.to_base
410
+ else
411
+ term.inspect
412
+ end
390
413
  end.join(" ") + " ."
391
414
  end
392
415
 
@@ -7,23 +7,23 @@ module RDF
7
7
  # Also compatible with International Resource Identifier (IRI)
8
8
  #
9
9
  # @example Creating a URI reference (1)
10
- # uri = RDF::URI.new("http://rubygems.org/gems/rdf")
10
+ # uri = RDF::URI.new("https://rubygems.org/gems/rdf")
11
11
  #
12
12
  # @example Creating a URI reference (2)
13
13
  # uri = RDF::URI.new(scheme: 'http', host: 'rubygems.org', path: '/gems/rdf')
14
- # #=> RDF::URI.new("http://rubygems.org/gems/rdf")
14
+ # #=> RDF::URI.new("https://rubygems.org/gems/rdf")
15
15
  #
16
16
  # @example Creating an interned URI reference
17
- # uri = RDF::URI.intern("http://rubygems.org/gems/rdf")
17
+ # uri = RDF::URI.intern("https://rubygems.org/gems/rdf")
18
18
  #
19
19
  # @example Getting the string representation of a URI
20
- # uri.to_s #=> "http://rubygems.org/gems/rdf"
20
+ # uri.to_s #=> "https://rubygems.org/gems/rdf"
21
21
  #
22
- # http://en.wikipedia.org/wiki/Internationalized_Resource_Identifier
23
- # @see http://en.wikipedia.org/wiki/Uniform_Resource_Identifier
24
- # @see http://www.ietf.org/rfc/rfc3986.txt
25
- # @see http://www.ietf.org/rfc/rfc3987.txt
26
- # @see http://www.rubydoc.info/gems/addressable
22
+ # @see https://en.wikipedia.org/wiki/Internationalized_Resource_Identifier
23
+ # @see https://en.wikipedia.org/wiki/Uniform_Resource_Identifier
24
+ # @see https://www.ietf.org/rfc/rfc3986.txt
25
+ # @see https://www.ietf.org/rfc/rfc3987.txt
26
+ # @see https://rubydoc.info/gems/addressable
27
27
  class URI
28
28
  include RDF::Resource
29
29
 
@@ -141,8 +141,8 @@ module RDF
141
141
  #
142
142
  # (see #initialize)
143
143
  # @return [RDF::URI] an immutable, frozen URI object
144
- def self.intern(str, *args)
145
- (cache[(str = str.to_s).to_sym] ||= self.new(str, *args)).freeze
144
+ def self.intern(str, *args, **options)
145
+ (cache[(str = str.to_s).to_sym] ||= self.new(str, *args, **options)).freeze
146
146
  end
147
147
 
148
148
  ##
@@ -225,11 +225,9 @@ module RDF
225
225
  @mutex = Mutex.new
226
226
  uri = args.first
227
227
  if uri
228
- @value = uri.to_s
229
- if @value.encoding != Encoding::UTF_8
230
- @value.dup.force_encoding(Encoding::UTF_8)
231
- @value.freeze
232
- end
228
+ @value = uri.to_s.dup
229
+ @value.dup.force_encoding(Encoding::UTF_8) if @value.encoding != Encoding::UTF_8
230
+ @value.freeze
233
231
  else
234
232
  %w(
235
233
  scheme
@@ -402,7 +400,7 @@ module RDF
402
400
  # @example Joining two URIs
403
401
  # RDF::URI.new('http://example.org/foo/bar').join('/foo')
404
402
  # #=> RDF::URI('http://example.org/foo')
405
- # @see <http://github.com/ruby-rdf/rdf-spec/blob/master/lib/rdf/spec/uri.rb>
403
+ # @see <https://github.com/ruby-rdf/rdf-spec/blob/master/lib/rdf/spec/uri.rb>
406
404
  # @see <http://tools.ietf.org/html/rfc3986#section-5.2>
407
405
  # @see RDF::URI#/
408
406
  # @see RDF::URI#+
@@ -431,7 +429,9 @@ module RDF
431
429
  joined_parts[:query] = uri.query
432
430
  else
433
431
  # Merge path segments from section 5.2.3
434
- base_path = path.to_s.sub(/\/[^\/]*$/, '/')
432
+ # Note that if the path includes no segments, the entire path is removed
433
+ # > return a string consisting of the reference's path component appended to all but the last segment of the base URI's path (i.e., excluding any characters after the right-most "/" in the base URI path, or excluding the entire base URI path if it does not contain any "/" characters).
434
+ base_path = path.to_s.include?('/') ? path.to_s.sub(/\/[^\/]*$/, '/') : ''
435
435
  joined_parts[:path] = self.class.normalize_path(base_path + uri.path)
436
436
  joined_parts[:query] = uri.query
437
437
  end
@@ -439,7 +439,7 @@ module RDF
439
439
  end
440
440
 
441
441
  # Return joined URI
442
- RDF::URI.new(joined_parts)
442
+ RDF::URI.new(**joined_parts)
443
443
  end
444
444
 
445
445
  ##
@@ -471,7 +471,7 @@ module RDF
471
471
  # @see RDF::URI#+
472
472
  # @see RDF::URI#join
473
473
  # @see <http://tools.ietf.org/html/rfc3986#section-5.2>
474
- # @see <http://github.com/ruby-rdf/rdf-spec/blob/master/lib/rdf/spec/uri.rb>
474
+ # @see <https://github.com/ruby-rdf/rdf-spec/blob/master/lib/rdf/spec/uri.rb>
475
475
  # @example Building a HTTP URL
476
476
  # RDF::URI.new('http://example.org') / 'jhacker' / 'foaf.ttl'
477
477
  # #=> RDF::URI('http://example.org/jhacker/foaf.ttl')
@@ -507,7 +507,7 @@ module RDF
507
507
  case fragment.to_s[0,1]
508
508
  when '#'
509
509
  # Base ending with '/', fragment beginning with '#'. The fragment wins, we use '#'.
510
- res.path = res.path.to_s.sub!(/\/*$/, '')
510
+ res.path = res.path.to_s.sub(/\/*$/, '')
511
511
  # Add fragment
512
512
  res.fragment = fragment.to_s.sub(/^#+/,'')
513
513
  else
@@ -572,7 +572,7 @@ module RDF
572
572
  self
573
573
  else
574
574
  RDF::URI.new(
575
- object.merge(path: '/').
575
+ **object.merge(path: '/').
576
576
  keep_if {|k, v| [:scheme, :authority, :path].include?(k)})
577
577
  end
578
578
  end
@@ -657,7 +657,7 @@ module RDF
657
657
  #
658
658
  # @return [RDF::URI]
659
659
  def dup
660
- self.class.new((@value || @object).dup)
660
+ self.class.new(@value, **(@object || {}))
661
661
  end
662
662
 
663
663
  ##
@@ -846,7 +846,7 @@ module RDF
846
846
  parts[:user] = (user.dup.force_encoding(Encoding::UTF_8) if user)
847
847
  parts[:password] = (password.dup.force_encoding(Encoding::UTF_8) if password)
848
848
  parts[:host] = (host.dup.force_encoding(Encoding::UTF_8) if host)
849
- parts[:port] = (::URI.decode(port).to_i if port)
849
+ parts[:port] = (URI.decode(port).to_i if port)
850
850
  parts[:path] = (path.to_s.dup.force_encoding(Encoding::UTF_8) unless path.empty?)
851
851
  parts[:query] = (query[1..-1].dup.force_encoding(Encoding::UTF_8) if query)
852
852
  parts[:fragment] = (fragment[1..-1].dup.force_encoding(Encoding::UTF_8) if fragment)
@@ -902,7 +902,7 @@ module RDF
902
902
  # Normalized version of user
903
903
  # @return [String]
904
904
  def normalized_user
905
- ::URI.encode(::URI.decode(user), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if user
905
+ URI.encode(URI.decode(user), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if user
906
906
  end
907
907
 
908
908
  ##
@@ -928,7 +928,7 @@ module RDF
928
928
  # Normalized version of password
929
929
  # @return [String]
930
930
  def normalized_password
931
- ::URI.encode(::URI.decode(password), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if password
931
+ URI.encode(URI.decode(password), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if password
932
932
  end
933
933
 
934
934
  HOST_FROM_AUTHORITY_RE = /(?:[^@]+@)?([^:]+)(?::.*)?$/.freeze
@@ -937,7 +937,7 @@ module RDF
937
937
  # @return [String]
938
938
  def host
939
939
  object.fetch(:host) do
940
- @object[:host] = ($1 if HOST_FROM_AUTHORITY_RE.match(@object[:authority]))
940
+ @object[:host] = ($1 if @object[:authority] && HOST_FROM_AUTHORITY_RE.match(@object[:authority]))
941
941
  end
942
942
  end
943
943
 
@@ -965,7 +965,7 @@ module RDF
965
965
  # @return [String]
966
966
  def port
967
967
  object.fetch(:port) do
968
- @object[:port] = ($1 if PORT_FROM_AUTHORITY_RE.match(@object[:authority]))
968
+ @object[:port] = ($1 if @object[:authority] && PORT_FROM_AUTHORITY_RE.match(@object[:authority]))
969
969
  end
970
970
  end
971
971
 
@@ -1180,8 +1180,8 @@ module RDF
1180
1180
  inject(return_type == Hash ? {} : []) do |memo,kv|
1181
1181
  k,v = kv.to_s.split('=', 2)
1182
1182
  next if k.to_s.empty?
1183
- k = ::URI.decode(k)
1184
- v = ::URI.decode(v) if v
1183
+ k = URI.decode(k)
1184
+ v = URI.decode(v) if v
1185
1185
  if return_type == Hash
1186
1186
  case memo[k]
1187
1187
  when nil then memo[k] = v
@@ -1293,9 +1293,9 @@ module RDF
1293
1293
  def normalize_segment(value, expr, downcase = false)
1294
1294
  if value
1295
1295
  value = value.dup.force_encoding(Encoding::UTF_8)
1296
- decoded = ::URI.decode(value)
1296
+ decoded = URI.decode(value)
1297
1297
  decoded.downcase! if downcase
1298
- ::URI.encode(decoded, /[^(?:#{expr})]/)
1298
+ URI.encode(decoded, /[^(?:#{expr})]/)
1299
1299
  end
1300
1300
  end
1301
1301
 
@@ -1314,6 +1314,27 @@ module RDF
1314
1314
  ""
1315
1315
  end
1316
1316
  end
1317
+
1318
+ # URI encode matching characters in value
1319
+ # From URI gem, as this is now generally deprecated
1320
+ def self.encode(str, expr)
1321
+ str.gsub(expr) do
1322
+ us = $&
1323
+ tmp = ''
1324
+ us.each_byte do |uc|
1325
+ tmp << sprintf('%%%02X', uc)
1326
+ end
1327
+ tmp
1328
+ end.force_encoding(Encoding::US_ASCII)
1329
+ end
1330
+
1331
+ # URI decode escape sequences in value
1332
+ # From URI gem, as this is now generally deprecated
1333
+ def self.decode(str)
1334
+ enc = str.encoding
1335
+ enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
1336
+ str.gsub(PCT_ENCODED) { [$&[1, 2]].pack('H2').force_encoding(enc) }
1337
+ end
1317
1338
  end
1318
1339
 
1319
1340
  # RDF::IRI is a synonym for RDF::URI