rdf 1.99.1 → 2.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/{README → README.md} +9 -44
  3. data/VERSION +1 -1
  4. data/bin/rdf +1 -1
  5. data/lib/rdf.rb +40 -49
  6. data/lib/rdf/changeset.rb +161 -0
  7. data/lib/rdf/cli.rb +195 -33
  8. data/lib/rdf/cli/vocab-loader.rb +13 -3
  9. data/lib/rdf/format.rb +44 -26
  10. data/lib/rdf/mixin/enumerable.rb +133 -97
  11. data/lib/rdf/mixin/enumerator.rb +8 -0
  12. data/lib/rdf/mixin/indexable.rb +1 -1
  13. data/lib/rdf/mixin/mutable.rb +101 -22
  14. data/lib/rdf/mixin/queryable.rb +21 -32
  15. data/lib/rdf/mixin/transactable.rb +94 -0
  16. data/lib/rdf/mixin/writable.rb +12 -3
  17. data/lib/rdf/model/dataset.rb +48 -0
  18. data/lib/rdf/model/graph.rb +73 -43
  19. data/lib/rdf/model/list.rb +61 -33
  20. data/lib/rdf/model/literal.rb +20 -19
  21. data/lib/rdf/model/literal/double.rb +20 -4
  22. data/lib/rdf/model/literal/numeric.rb +15 -13
  23. data/lib/rdf/model/node.rb +15 -16
  24. data/lib/rdf/model/statement.rb +1 -43
  25. data/lib/rdf/model/term.rb +10 -8
  26. data/lib/rdf/model/uri.rb +35 -34
  27. data/lib/rdf/model/value.rb +1 -1
  28. data/lib/rdf/nquads.rb +2 -11
  29. data/lib/rdf/ntriples.rb +1 -1
  30. data/lib/rdf/ntriples/reader.rb +33 -46
  31. data/lib/rdf/ntriples/writer.rb +42 -5
  32. data/lib/rdf/query.rb +6 -40
  33. data/lib/rdf/query/pattern.rb +4 -17
  34. data/lib/rdf/query/solutions.rb +6 -6
  35. data/lib/rdf/reader.rb +65 -14
  36. data/lib/rdf/repository.rb +365 -229
  37. data/lib/rdf/transaction.rb +211 -84
  38. data/lib/rdf/util.rb +1 -0
  39. data/lib/rdf/util/cache.rb +5 -5
  40. data/lib/rdf/util/file.rb +12 -9
  41. data/lib/rdf/util/logger.rb +272 -0
  42. data/lib/rdf/version.rb +2 -2
  43. data/lib/rdf/vocab/owl.rb +82 -77
  44. data/lib/rdf/vocab/rdfs.rb +22 -17
  45. data/lib/rdf/vocab/xsd.rb +5 -0
  46. data/lib/rdf/vocabulary.rb +50 -56
  47. data/lib/rdf/writer.rb +104 -52
  48. metadata +45 -90
  49. data/lib/rdf/mixin/inferable.rb +0 -5
  50. data/lib/rdf/vocab/cc.rb +0 -128
  51. data/lib/rdf/vocab/cert.rb +0 -245
  52. data/lib/rdf/vocab/dc.rb +0 -948
  53. data/lib/rdf/vocab/dc11.rb +0 -167
  54. data/lib/rdf/vocab/dcat.rb +0 -214
  55. data/lib/rdf/vocab/doap.rb +0 -337
  56. data/lib/rdf/vocab/exif.rb +0 -941
  57. data/lib/rdf/vocab/foaf.rb +0 -614
  58. data/lib/rdf/vocab/geo.rb +0 -157
  59. data/lib/rdf/vocab/gr.rb +0 -1501
  60. data/lib/rdf/vocab/ht.rb +0 -236
  61. data/lib/rdf/vocab/ical.rb +0 -528
  62. data/lib/rdf/vocab/ma.rb +0 -513
  63. data/lib/rdf/vocab/mo.rb +0 -2412
  64. data/lib/rdf/vocab/og.rb +0 -222
  65. data/lib/rdf/vocab/ogc.rb +0 -58
  66. data/lib/rdf/vocab/prov.rb +0 -1550
  67. data/lib/rdf/vocab/rsa.rb +0 -72
  68. data/lib/rdf/vocab/rss.rb +0 -66
  69. data/lib/rdf/vocab/schema.rb +0 -10569
  70. data/lib/rdf/vocab/sioc.rb +0 -669
  71. data/lib/rdf/vocab/skos.rb +0 -238
  72. data/lib/rdf/vocab/skosxl.rb +0 -57
  73. data/lib/rdf/vocab/v.rb +0 -383
  74. data/lib/rdf/vocab/vcard.rb +0 -841
  75. data/lib/rdf/vocab/vmd.rb +0 -383
  76. data/lib/rdf/vocab/void.rb +0 -186
  77. data/lib/rdf/vocab/vs.rb +0 -28
  78. data/lib/rdf/vocab/wdrs.rb +0 -134
  79. data/lib/rdf/vocab/wot.rb +0 -167
  80. data/lib/rdf/vocab/xhtml.rb +0 -8
  81. data/lib/rdf/vocab/xhv.rb +0 -505
@@ -148,6 +148,7 @@ module RDF
148
148
  #
149
149
  # @param [Object] value
150
150
  # @option options [Symbol] :language (nil)
151
+ # Language is downcased to ensure proper matching
151
152
  # @option options [String] :lexical (nil)
152
153
  # Supplied lexical representation of this literal,
153
154
  # otherwise it comes from transforming `value` to a string form
@@ -166,7 +167,7 @@ module RDF
166
167
  @string = value if !defined?(@string) && value.is_a?(String)
167
168
  @string = @string.encode(Encoding::UTF_8) if @string
168
169
  @object = @string if @string && @object.is_a?(String)
169
- @language = options[:language].to_s.to_sym if options[:language]
170
+ @language = options[:language].to_s.downcase.to_sym if options[:language]
170
171
  @datatype = RDF::URI(options[:datatype]) if options[:datatype]
171
172
  @datatype ||= self.class.const_get(:DATATYPE) if self.class.const_defined?(:DATATYPE)
172
173
  @datatype ||= @language ? RDF.langString : RDF::XSD.string
@@ -195,14 +196,6 @@ module RDF
195
196
  true
196
197
  end
197
198
 
198
- ##
199
- # Returns `false`.
200
- #
201
- # @return [Boolean] `true` or `false`
202
- def anonymous?
203
- false
204
- end
205
-
206
199
  ##
207
200
  # Term compatibility according to SPARQL
208
201
  #
@@ -275,7 +268,7 @@ module RDF
275
268
  (self.class.eql?(other.class) &&
276
269
  self.value_hash == other.value_hash &&
277
270
  self.value.eql?(other.value) &&
278
- self.language.to_s.downcase.eql?(other.language.to_s.downcase) &&
271
+ self.language.to_s.eql?(other.language.to_s) &&
279
272
  self.datatype.eql?(other.datatype))
280
273
  end
281
274
 
@@ -296,7 +289,7 @@ module RDF
296
289
  case
297
290
  when self.eql?(other)
298
291
  true
299
- when self.has_language? && self.language.to_s.downcase == other.language.to_s.downcase
292
+ when self.has_language? && self.language.to_s == other.language.to_s
300
293
  # Literals with languages can compare if languages are identical
301
294
  self.value_hash == other.value_hash && self.value == other.value
302
295
  when self.simple? && other.simple?
@@ -412,19 +405,27 @@ module RDF
412
405
  # @return [RDF::Literal] `self`
413
406
  # @since 0.3.0
414
407
  def canonicalize!
415
- @language = @language.to_s.downcase.to_sym if @language
416
408
  self
417
409
  end
418
410
 
419
411
  ##
420
- # Returns the base representation of this URI.
412
+ # Escape a literal using ECHAR escapes.
413
+ #
414
+ # ECHAR ::= '\' [tbnrf"'\]
421
415
  #
422
- # @return [Sring]
423
- def to_base
424
- text = %("#{escape(value)}")
425
- text << "@#{language}" if has_language?
426
- text << "^^#{datatype.to_base}" if has_datatype?
427
- text
416
+ # @note N-Triples only requires '\"\n\r' to be escaped.
417
+ #
418
+ # @param [String] string
419
+ # @return [String]
420
+ # @see {RDF::Term#escape}
421
+ def escape(string)
422
+ string.gsub('\\', '\\\\').
423
+ gsub("\t", '\\t').
424
+ gsub("\b", '\\b').
425
+ gsub("\n", '\\n').
426
+ gsub("\r", '\\r').
427
+ gsub("\f", '\\f').
428
+ gsub('"', '\\"')
428
429
  end
429
430
 
430
431
  ##
@@ -18,7 +18,6 @@ module RDF; class Literal
18
18
  # @param [Float, #to_f] value
19
19
  # @option options [String] :lexical (nil)
20
20
  def initialize(value, options = {})
21
- #require 'byebug'; byebug
22
21
  @datatype = RDF::URI(options[:datatype] || self.class.const_get(:DATATYPE))
23
22
  @string = options[:lexical] if options.has_key?(:lexical)
24
23
  @string ||= value if value.is_a?(String)
@@ -66,6 +65,21 @@ module RDF; class Literal
66
65
  self
67
66
  end
68
67
 
68
+ ##
69
+ # Returns `true` if this literal is equal to `other`.
70
+ #
71
+ # @param [Object] other
72
+ # @return [Boolean] `true` or `false`
73
+ # @since 0.3.0
74
+ def ==(other)
75
+ if valid? && infinite? && other.respond_to?(:infinite?) && other.infinite?
76
+ infinite? == other.infinite?
77
+ # JRuby INF comparisons differ from MRI
78
+ else
79
+ super
80
+ end
81
+ end
82
+
69
83
  ##
70
84
  # Compares this literal to `other` for sorting purposes.
71
85
  #
@@ -75,9 +89,11 @@ module RDF; class Literal
75
89
  def <=>(other)
76
90
  case other
77
91
  when ::Numeric
78
- to_d <=> other
79
- when RDF::Literal::Decimal, RDF::Literal::Double
80
- to_d <=> other.to_d
92
+ to_f <=> other
93
+ when RDF::Literal::Decimal
94
+ to_f <=> other.to_d
95
+ when RDF::Literal::Double
96
+ to_f <=> other.to_f
81
97
  else super
82
98
  end
83
99
  end
@@ -14,6 +14,8 @@ module RDF; class Literal
14
14
  case other
15
15
  when ::Numeric
16
16
  to_d <=> other
17
+ when Double
18
+ to_f <=> other.to_f
17
19
  when Numeric
18
20
  to_d <=> other.to_d
19
21
  else super
@@ -72,9 +74,9 @@ module RDF; class Literal
72
74
  # @since 0.2.3
73
75
  # @see http://www.w3.org/TR/xpath-functions/#func-numeric-add
74
76
  def +(other)
75
- if self.class == Double || other.class == Double
77
+ if self.class == Double || [Double, ::Float].include?(other.class)
76
78
  RDF::Literal::Double.new(to_f + other.to_f)
77
- elsif self.class == Float || other.class == Float
79
+ elsif ((self.class == RDF::Literal::Float || other.class == RDF::Literal::Float) rescue false)
78
80
  RDF::Literal::Float.new(to_f + other.to_f)
79
81
  elsif self.class == Decimal || other.class == Decimal
80
82
  RDF::Literal::Decimal.new(to_d + (other.respond_to?(:to_d) ? other.to_d : BigDecimal(other.to_s)))
@@ -91,9 +93,9 @@ module RDF; class Literal
91
93
  # @since 0.2.3
92
94
  # @see http://www.w3.org/TR/xpath-functions/#func-numeric-subtract
93
95
  def -(other)
94
- if self.class == Double || other.class == Double
96
+ if self.class == Double || [Double, ::Float].include?(other.class)
95
97
  RDF::Literal::Double.new(to_f - other.to_f)
96
- elsif self.class == Float || other.class == Float
98
+ elsif ((self.class == RDF::Literal::Float || other.class == RDF::Literal::Float) rescue false)
97
99
  RDF::Literal::Float.new(to_f - other.to_f)
98
100
  elsif self.class == Decimal || other.class == Decimal
99
101
  RDF::Literal::Decimal.new(to_d - (other.respond_to?(:to_d) ? other.to_d : BigDecimal(other.to_s)))
@@ -110,9 +112,9 @@ module RDF; class Literal
110
112
  # @since 0.2.3
111
113
  # @see http://www.w3.org/TR/xpath-functions/#func-numeric-multiply
112
114
  def *(other)
113
- if self.class == Double || other.class == Double
115
+ if self.class == Double || [Double, ::Float].include?(other.class)
114
116
  RDF::Literal::Double.new(to_f * other.to_f)
115
- elsif self.class == Float || other.class == Float
117
+ elsif ((self.class == RDF::Literal::Float || other.class == RDF::Literal::Float) rescue false)
116
118
  RDF::Literal::Float.new(to_f * other.to_f)
117
119
  elsif self.class == Decimal || other.class == Decimal
118
120
  RDF::Literal::Decimal.new(to_d * (other.respond_to?(:to_d) ? other.to_d : BigDecimal(other.to_s)))
@@ -124,8 +126,8 @@ module RDF; class Literal
124
126
  ##
125
127
  # Returns the quotient of `self` divided by `other`.
126
128
  #
127
- # As a special case, if the types of both $arg1 and $arg2 are xs:integer,
128
- # then the return type is xs:decimal.
129
+ # As a special case, if the types of both $arg1 and $arg2 are xsd:integer,
130
+ # then the return type is xsd:decimal.
129
131
  #
130
132
  # @param [Literal::Numeric, #to_i, #to_f, #to_d] other
131
133
  # @return [RDF::Literal::Numeric]
@@ -133,14 +135,12 @@ module RDF; class Literal
133
135
  # @since 0.2.3
134
136
  # @see http://www.w3.org/TR/xpath-functions/#func-numeric-divide
135
137
  def /(other)
136
- if self.class == Double || other.class == Double
138
+ if self.class == Double || [Double, ::Float].include?(other.class)
137
139
  RDF::Literal::Double.new(to_f / other.to_f)
138
- elsif self.class == Float || other.class == Float
140
+ elsif ((self.class == RDF::Literal::Float || other.class == RDF::Literal::Float) rescue false)
139
141
  RDF::Literal::Float.new(to_f / other.to_f)
140
- elsif self.class == Decimal || other.class == Decimal
141
- RDF::Literal::Decimal.new(to_d / (other.respond_to?(:to_d) ? other.to_d : BigDecimal(other.to_s)))
142
142
  else
143
- RDF::Literal::Integer.new(to_i / other.to_i)
143
+ RDF::Literal::Decimal.new(to_d / (other.respond_to?(:to_d) ? other.to_d : BigDecimal(other.to_s)))
144
144
  end
145
145
  end
146
146
 
@@ -211,6 +211,8 @@ module RDF; class Literal
211
211
  # @return [BigDecimal]
212
212
  def to_d
213
213
  @object.respond_to?(:to_d) ? @object.to_d : BigDecimal(@object.to_s)
214
+ rescue FloatDomainError
215
+ ::Float::NAN
214
216
  end
215
217
 
216
218
  ##
@@ -30,18 +30,17 @@ module RDF
30
30
  ##
31
31
  # Returns a blank node with a random UUID-based identifier.
32
32
  #
33
- # @param [Hash{Symbol => Object}] options
34
- # @option options [Regexp] :grammar (nil)
33
+ # @param [Regexp] grammar (nil)
35
34
  # a grammar specification that the generated UUID must match
36
35
  # @return [RDF::Node]
37
- def self.uuid(options = {})
36
+ def self.uuid(grammar: nil)
38
37
  case
39
- when options[:grammar]
38
+ when grammar
40
39
  # The UUID is generated such that its initial part is guaranteed
41
40
  # to match the given `grammar`, e.g. `/^[A-Za-z][A-Za-z0-9]*/`.
42
41
  # Some RDF storage systems (e.g. AllegroGraph) require this.
43
42
  # @see http://github.com/bendiken/rdf/pull/43
44
- uuid = RDF::Util::UUID.generate(options) until uuid =~ options[:grammar]
43
+ uuid = RDF::Util::UUID.generate(options) until uuid =~ grammar
45
44
  else
46
45
  uuid = RDF::Util::UUID.generate(options)
47
46
  end
@@ -121,7 +120,7 @@ module RDF
121
120
  end
122
121
 
123
122
  ##
124
- # Determins if `self` is the same term as `other`.
123
+ # Determines if `self` is the same term as `other`.
125
124
  #
126
125
  # In this case, nodes must be the same object
127
126
  #
@@ -148,25 +147,25 @@ module RDF
148
147
  else
149
148
  other.respond_to?(:node?) && other.node? &&
150
149
  self.hash == other.to_term.hash &&
151
- other.respond_to?(:id) && @id == other.id
150
+ other.respond_to?(:id) && @id == other.to_term.id
152
151
  end
153
152
  end
154
153
  alias_method :===, :==
155
154
 
156
- ##
157
- # Returns the base representation of this node.
158
- #
159
- # @return [Sring]
160
- def to_base
161
- to_s
162
- end
163
-
164
155
  ##
165
156
  # Returns a representation of this node independent of any identifier used to initialize it
166
157
  #
167
158
  # @return [String]
168
159
  def to_unique_base
169
- "_:g#{__id__.to_i.abs}"
160
+ original ? original.to_unique_base : "_:g#{__id__.to_i.abs}"
161
+ end
162
+
163
+ ##
164
+ # Make this term identifier unique, if it is found to be shared with another node having the same identifier
165
+ # @return [self]
166
+ def make_unique!
167
+ @id = to_unique_base[2..-1]
168
+ self
170
169
  end
171
170
 
172
171
  ##
@@ -48,28 +48,6 @@ module RDF
48
48
  # @return [RDF::Resource]
49
49
  attr_accessor :graph_name
50
50
 
51
- ##
52
- # Name of this graph, if it is part of an {RDF::Repository}
53
- # @!attribute [rw] graph_name
54
- # @return [RDF::Resource]
55
- # @since 1.1.0
56
- # @deprecated Use {#graph_name} instead.
57
- def context
58
- warn "[DEPRECATION] Statement#context is being replaced with Statement@graph_name in RDF.rb 2.0. Called from #{Gem.location_of_caller.join(':')}"
59
- graph_name
60
- end
61
-
62
- ##
63
- # Name of this graph, if it is part of an {RDF::Repository}
64
- # @!attribute [rw] graph_name
65
- # @return [RDF::Resource]
66
- # @since 1.1.0
67
- # @deprecated Use {#graph_name=} instead.
68
- def context=(value)
69
- warn "[DEPRECATION] Statement#context= is being replaced with Statement@graph_name= in RDF.rb 2.0. Called from #{Gem.location_of_caller.join(':')}"
70
- self.graph_name = value
71
- end
72
-
73
51
  # @return [RDF::Resource]
74
52
  attr_accessor :subject
75
53
 
@@ -87,8 +65,6 @@ module RDF
87
65
  # @option options [RDF::URI] :predicate (nil)
88
66
  # @option options [RDF::Resource] :object (nil)
89
67
  # if not a {Resource}, it is coerced to {Literal} or {Node} depending on if it is a symbol or something other than a {Term}.
90
- # @option options [RDF::Term] :context (nil)
91
- # Alias for :graph_name, :context is deprecated in RDF.rb.
92
68
  # @option options [RDF::Term] :graph_name (nil)
93
69
  # Note, in RDF 1.1, a graph name MUST be an {Resource}.
94
70
  # @return [RDF::Statement]
@@ -100,8 +76,6 @@ module RDF
100
76
  # @param [RDF::Resource] object
101
77
  # if not a {Resource}, it is coerced to {Literal} or {Node} depending on if it is a symbol or something other than a {Term}.
102
78
  # @param [Hash{Symbol => Object}] options
103
- # @option options [RDF::Term] :context (nil)
104
- # Alias for :graph_name, :context is deprecated in RDF.rb.
105
79
  # @option options [RDF::Term] :graph_name (nil)
106
80
  # Note, in RDF 1.1, a graph name MUST be an {Resource}.
107
81
  # @return [RDF::Statement]
@@ -117,10 +91,6 @@ module RDF
117
91
  @predicate = predicate
118
92
  @object = object
119
93
  end
120
- if @options.has_key?(:context)
121
- warn "[DEPRECATION] the :contexts option to Mutable#load is deprecated in RDF.rb 2.0, use :graph_name instead. Called from #{Gem.location_of_caller.join(':')}"
122
- @options[:graph_name] ||= @options.delete(:context)
123
- end
124
94
  @id = @options.delete(:id) if @options.has_key?(:id)
125
95
  @graph_name = @options.delete(:graph_name)
126
96
  initialize!
@@ -229,14 +199,6 @@ module RDF
229
199
  end
230
200
  alias_method :has_name?, :has_graph?
231
201
 
232
- ##
233
- # @return [Boolean]
234
- # @deprecated Use {#has_graph?} instead.
235
- def has_context?
236
- warn "[DEPRECATION] Statement#has_context? is being replaced with Statement#has_grap in RDF.rb 2.0. Called from #{Gem.location_of_caller.join(':')}"
237
- !!context
238
- end
239
-
240
202
  ##
241
203
  # @return [Boolean]
242
204
  def has_subject?
@@ -386,11 +348,7 @@ module RDF
386
348
  # @return [RDF::Graph]
387
349
  # @see http://www.w3.org/TR/rdf-primer/#reification
388
350
  def reified(options = {})
389
- if options.has_key?(:context)
390
- warn "[DEPRECATION] the :contexts option to Mutable#load is deprecated in RDF.rb 2.0, use :graph_name instead. Called from #{Gem.location_of_caller.join(':')}"
391
- options[:graph_name] ||= options.delete(:context)
392
- end
393
- RDF::Graph.new(options[:graph_name]) do |graph|
351
+ RDF::Graph.new(graph_name: options[:graph_name]) do |graph|
394
352
  subject = options[:subject] || RDF::Node.new(options[:id])
395
353
  graph << [subject, RDF.type, RDF[:Statement]]
396
354
  graph << [subject, RDF.subject, self.subject]
@@ -80,6 +80,14 @@ module RDF
80
80
  self
81
81
  end
82
82
 
83
+ ##
84
+ # Returns the base representation of this term.
85
+ #
86
+ # @return [Sring]
87
+ def to_base
88
+ RDF::NTriples.serialize(self)
89
+ end
90
+
83
91
  ##
84
92
  # Term compatibility according to SPARQL
85
93
  #
@@ -91,18 +99,12 @@ module RDF
91
99
 
92
100
  protected
93
101
  ##
94
- # Escape a term using standard character escapes
102
+ # Escape a term using escapes. This should be implemented as appropriate for the given type of term.
95
103
  #
96
104
  # @param [String] string
97
105
  # @return [String]
98
106
  def escape(string)
99
- string.gsub('\\', '\\\\').
100
- gsub("\b", '\\b').
101
- gsub("\f", '\\f').
102
- gsub("\t", '\\t').
103
- gsub("\n", '\\n').
104
- gsub("\r", '\\r').
105
- gsub('"', '\\"')
107
+ raise NotImplementedError, "#{self.class}#escape"
106
108
  end
107
109
 
108
110
  end # Term
@@ -10,7 +10,7 @@ module RDF
10
10
  # uri = RDF::URI.new("http://rubygems.org/gems/rdf")
11
11
  #
12
12
  # @example Creating a URI reference (2)
13
- # uri = RDF::URI.new(scheme: 'http', host: 'rubygems.org', path: '/rdf')
13
+ # uri = RDF::URI.new(scheme: 'http', host: 'rubygems.org', path: '/gems/rdf')
14
14
  # #=> RDF::URI.new("http://rubygems.org/gems/rdf")
15
15
  #
16
16
  # @example Creating an interned URI reference
@@ -39,7 +39,7 @@ module RDF
39
39
  [\\u{40000}-\\u{4FFFD}]|[\\u{50000}-\\u{5FFFD}]|[\\u{60000}-\\u{6FFFD}]|
40
40
  [\\u{70000}-\\u{7FFFD}]|[\\u{80000}-\\u{8FFFD}]|[\\u{90000}-\\u{9FFFD}]|
41
41
  [\\u{A0000}-\\u{AFFFD}]|[\\u{B0000}-\\u{BFFFD}]|[\\u{C0000}-\\u{CFFFD}]|
42
- [\\u{D0000}-\\u{DFFFD}]|[\\u{E0000}-\\u{EFFFD}]
42
+ [\\u{D0000}-\\u{DFFFD}]|[\\u{E1000}-\\u{EFFFD}]
43
43
  EOS
44
44
  IPRIVATE = Regexp.compile("[\\uE000-\\uF8FF]|[\\u{F0000}-\\u{FFFFD}]|[\\u100000-\\u10FFFD]").freeze
45
45
  SCHEME = Regexp.compile("[A-za-z](?:[A-Za-z0-9+-\.])*").freeze
@@ -202,14 +202,9 @@ module RDF
202
202
  ##
203
203
  # @overload URI(uri, options = {})
204
204
  # @param [URI, String, #to_s] uri
205
- # @param [Hash{Symbol => Object}] options
206
- # @option options [Boolean] :validate (false)
207
- # @option options [Boolean] :canonicalize (false)
208
205
  #
209
206
  # @overload URI(options = {})
210
207
  # @param [Hash{Symbol => Object}] options
211
- # @option options [Boolean] :validate (false)
212
- # @option options [Boolean] :canonicalize (false)
213
208
  # @option [String, #to_s] :scheme The scheme component.
214
209
  # @option [String, #to_s] :user The user component.
215
210
  # @option [String, #to_s] :password The password component.
@@ -224,33 +219,34 @@ module RDF
224
219
  # @option [String, #to_s] :path The path component.
225
220
  # @option [String, #to_s] :query The query component.
226
221
  # @option [String, #to_s] :fragment The fragment component.
227
- def initialize(*args)
228
- options = args.last.is_a?(Hash) ? args.last : {}
222
+ #
223
+ # @param [Boolean] validate (false)
224
+ # @param [Boolean] canonicalize (false)
225
+ def initialize(*args, validate: false, canonicalize: false, **options)
229
226
  uri = args.first
230
- case uri
231
- when Hash
227
+ if uri
228
+ @value = uri.to_s
229
+ if @value.encoding != Encoding::UTF_8
230
+ @value = @value.dup if @value.frozen?
231
+ @value.force_encoding(Encoding::UTF_8)
232
+ end
233
+ else
232
234
  %w(
233
235
  scheme
234
236
  user password userinfo
235
237
  host port authority
236
238
  path query fragment
237
239
  ).map(&:to_sym).each do |meth|
238
- if uri.has_key?(meth)
239
- self.send("#{meth}=".to_sym, uri[meth])
240
+ if options.has_key?(meth)
241
+ self.send("#{meth}=".to_sym, options[meth])
240
242
  else
241
243
  self.send(meth)
242
244
  end
243
245
  end
244
- else
245
- @value = uri.to_s
246
- if @value.encoding != Encoding::UTF_8
247
- @value = @value.dup if @value.frozen?
248
- @value.force_encoding(Encoding::UTF_8)
249
- end
250
246
  end
251
247
 
252
- validate! if options[:validate]
253
- canonicalize! if options[:canonicalize]
248
+ validate! if validate
249
+ canonicalize! if canonicalize
254
250
  end
255
251
 
256
252
  ##
@@ -341,10 +337,11 @@ module RDF
341
337
  ##
342
338
  # Determine if the URI is a valid according to RFC3987
343
339
  #
340
+ # Note that RDF URIs syntactically can contain Unicode escapes, which are unencoded in the internal representation. To validate, %-encode specifically excluded characters from IRIREF
341
+ #
344
342
  # @return [Boolean] `true` or `false`
345
343
  # @since 0.3.9
346
344
  def valid?
347
- # Validate relative to RFC3987
348
345
  to_s.match(RDF::URI::IRI) || false
349
346
  end
350
347
 
@@ -355,7 +352,7 @@ module RDF
355
352
  # @raise [ArgumentError] if the URI is invalid
356
353
  # @since 0.3.0
357
354
  def validate!
358
- raise ArgumentError, "#{to_s.inspect} is not a valid IRI" if invalid?
355
+ raise ArgumentError, "#{to_base.inspect} is not a valid IRI" if invalid?
359
356
  self
360
357
  end
361
358
 
@@ -475,7 +472,7 @@ module RDF
475
472
  # @example Building a HTTP URL
476
473
  # RDF::URI.new('http://example.org') / 'jhacker' / 'foaf.ttl'
477
474
  # #=> RDF::URI('http://example.org/jhacker/foaf.ttl')
478
- # @example Building a HTTP URL
475
+ # @example Building a HTTP URL (absolute path components)
479
476
  # RDF::URI.new('http://example.org/') / '/jhacker/' / '/foaf.ttl'
480
477
  # #=> RDF::URI('http://example.org/jhacker/foaf.ttl')
481
478
  # @example Using an anchored base URI
@@ -790,14 +787,6 @@ module RDF
790
787
  self
791
788
  end
792
789
 
793
- ##
794
- # Returns the base representation of this URI.
795
- #
796
- # @return [Sring]
797
- def to_base
798
- "<#{escape(to_s)}>"
799
- end
800
-
801
790
  ##
802
791
  # Returns the string representation of this URI.
803
792
  #
@@ -1216,16 +1205,22 @@ module RDF
1216
1205
  # Sets the query component for this URI from a Hash object.
1217
1206
  # An empty Hash or Array will result in an empty query string.
1218
1207
  #
1219
- # @example
1208
+ # @example Hash with single and array values
1220
1209
  # uri.query_values = {a: "a", b: ["c", "d", "e"]}
1221
1210
  # uri.query
1222
1211
  # # => "a=a&b=c&b=d&b=e"
1212
+ #
1213
+ # @example Array with Array values including repeated variables
1223
1214
  # uri.query_values = [['a', 'a'], ['b', 'c'], ['b', 'd'], ['b', 'e']]
1224
1215
  # uri.query
1225
1216
  # # => "a=a&b=c&b=d&b=e"
1217
+ #
1218
+ # @example Array with Array values including multiple elements
1226
1219
  # uri.query_values = [['a', 'a'], ['b', ['c', 'd', 'e']]]
1227
1220
  # uri.query
1228
1221
  # # => "a=a&b=c&b=d&b=e"
1222
+ #
1223
+ # @example Array with Array values having only one entry
1229
1224
  # uri.query_values = [['flag'], ['key', 'value']]
1230
1225
  # uri.query
1231
1226
  # # => "flag&key=value"
@@ -1245,7 +1240,13 @@ module RDF
1245
1240
  if v.nil?
1246
1241
  k
1247
1242
  else
1248
- "#{k}=#{normalize_segment(v.to_s, UNRESERVED)}"
1243
+ Array(v).map do |vv|
1244
+ if vv === TrueClass
1245
+ k
1246
+ else
1247
+ "#{k}=#{normalize_segment(vv.to_s, UNRESERVED)}"
1248
+ end
1249
+ end.join("&")
1249
1250
  end
1250
1251
  end
1251
1252
  when Hash