rdf 1.99.1 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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