rdf 3.0.13 → 3.1.4

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.
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- require 'uri'
2
+ require 'cgi'
3
3
 
4
4
  module RDF
5
5
  ##
@@ -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#+
@@ -441,7 +439,7 @@ module RDF
441
439
  end
442
440
 
443
441
  # Return joined URI
444
- RDF::URI.new(joined_parts)
442
+ RDF::URI.new(**joined_parts)
445
443
  end
446
444
 
447
445
  ##
@@ -473,7 +471,7 @@ module RDF
473
471
  # @see RDF::URI#+
474
472
  # @see RDF::URI#join
475
473
  # @see <http://tools.ietf.org/html/rfc3986#section-5.2>
476
- # @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>
477
475
  # @example Building a HTTP URL
478
476
  # RDF::URI.new('http://example.org') / 'jhacker' / 'foaf.ttl'
479
477
  # #=> RDF::URI('http://example.org/jhacker/foaf.ttl')
@@ -509,7 +507,7 @@ module RDF
509
507
  case fragment.to_s[0,1]
510
508
  when '#'
511
509
  # Base ending with '/', fragment beginning with '#'. The fragment wins, we use '#'.
512
- res.path = res.path.to_s.sub!(/\/*$/, '')
510
+ res.path = res.path.to_s.sub(/\/*$/, '')
513
511
  # Add fragment
514
512
  res.fragment = fragment.to_s.sub(/^#+/,'')
515
513
  else
@@ -574,7 +572,7 @@ module RDF
574
572
  self
575
573
  else
576
574
  RDF::URI.new(
577
- object.merge(path: '/').
575
+ **object.merge(path: '/').
578
576
  keep_if {|k, v| [:scheme, :authority, :path].include?(k)})
579
577
  end
580
578
  end
@@ -659,7 +657,7 @@ module RDF
659
657
  #
660
658
  # @return [RDF::URI]
661
659
  def dup
662
- self.class.new((@value || @object).dup)
660
+ self.class.new(@value, **(@object || {}))
663
661
  end
664
662
 
665
663
  ##
@@ -848,7 +846,7 @@ module RDF
848
846
  parts[:user] = (user.dup.force_encoding(Encoding::UTF_8) if user)
849
847
  parts[:password] = (password.dup.force_encoding(Encoding::UTF_8) if password)
850
848
  parts[:host] = (host.dup.force_encoding(Encoding::UTF_8) if host)
851
- parts[:port] = (::URI.decode(port).to_i if port)
849
+ parts[:port] = (CGI.unescape(port).to_i if port)
852
850
  parts[:path] = (path.to_s.dup.force_encoding(Encoding::UTF_8) unless path.empty?)
853
851
  parts[:query] = (query[1..-1].dup.force_encoding(Encoding::UTF_8) if query)
854
852
  parts[:fragment] = (fragment[1..-1].dup.force_encoding(Encoding::UTF_8) if fragment)
@@ -904,7 +902,7 @@ module RDF
904
902
  # Normalized version of user
905
903
  # @return [String]
906
904
  def normalized_user
907
- ::URI.encode(::URI.decode(user), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if user
905
+ URI.encode(CGI.unescape(user), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if user
908
906
  end
909
907
 
910
908
  ##
@@ -930,7 +928,7 @@ module RDF
930
928
  # Normalized version of password
931
929
  # @return [String]
932
930
  def normalized_password
933
- ::URI.encode(::URI.decode(password), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if password
931
+ URI.encode(CGI.unescape(password), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if password
934
932
  end
935
933
 
936
934
  HOST_FROM_AUTHORITY_RE = /(?:[^@]+@)?([^:]+)(?::.*)?$/.freeze
@@ -939,7 +937,7 @@ module RDF
939
937
  # @return [String]
940
938
  def host
941
939
  object.fetch(:host) do
942
- @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]))
943
941
  end
944
942
  end
945
943
 
@@ -967,7 +965,7 @@ module RDF
967
965
  # @return [String]
968
966
  def port
969
967
  object.fetch(:port) do
970
- @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]))
971
969
  end
972
970
  end
973
971
 
@@ -1182,8 +1180,8 @@ module RDF
1182
1180
  inject(return_type == Hash ? {} : []) do |memo,kv|
1183
1181
  k,v = kv.to_s.split('=', 2)
1184
1182
  next if k.to_s.empty?
1185
- k = ::URI.decode(k)
1186
- v = ::URI.decode(v) if v
1183
+ k = CGI.unescape(k)
1184
+ v = CGI.unescape(v) if v
1187
1185
  if return_type == Hash
1188
1186
  case memo[k]
1189
1187
  when nil then memo[k] = v
@@ -1295,9 +1293,9 @@ module RDF
1295
1293
  def normalize_segment(value, expr, downcase = false)
1296
1294
  if value
1297
1295
  value = value.dup.force_encoding(Encoding::UTF_8)
1298
- decoded = ::URI.decode(value)
1296
+ decoded = CGI.unescape(value)
1299
1297
  decoded.downcase! if downcase
1300
- ::URI.encode(decoded, /[^(?:#{expr})]/)
1298
+ URI.encode(decoded, /[^(?:#{expr})]/)
1301
1299
  end
1302
1300
  end
1303
1301
 
@@ -1316,6 +1314,27 @@ module RDF
1316
1314
  ""
1317
1315
  end
1318
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
1319
1338
  end
1320
1339
 
1321
1340
  # RDF::IRI is a synonym for RDF::URI
@@ -69,9 +69,9 @@ module RDF
69
69
 
70
70
  begin
71
71
  unless blank? || read_comment
72
- subject = read_uriref || read_node || fail_subject
72
+ subject = read_uriref || read_node || read_rdfstar || fail_subject
73
73
  predicate = read_uriref(intern: true) || fail_predicate
74
- object = read_uriref || read_node || read_literal || fail_object
74
+ object = read_uriref || read_node || read_literal || read_rdfstar || fail_object
75
75
  graph_name = read_uriref || read_node
76
76
  if validate? && !read_eos
77
77
  log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
@@ -96,7 +96,7 @@ module RDF
96
96
  # @param [RDF::Term] object
97
97
  # @return [void]
98
98
  def write_quad(subject, predicate, object, graph_name)
99
- puts format_quad(subject, predicate, object, graph_name, @options)
99
+ puts format_quad(subject, predicate, object, graph_name, **@options)
100
100
  end
101
101
 
102
102
  ##
@@ -107,7 +107,7 @@ module RDF
107
107
  # @return [String]
108
108
  # @since 0.4.0
109
109
  def format_statement(statement, **options)
110
- format_quad(*statement.to_quad, options)
110
+ format_quad(*statement.to_quad, **options)
111
111
  end
112
112
 
113
113
  ##
@@ -120,8 +120,8 @@ module RDF
120
120
  # @param [Hash{Symbol => Object}] options = ({})
121
121
  # @return [String]
122
122
  def format_quad(subject, predicate, object, graph_name, **options)
123
- s = "%s %s %s " % [subject, predicate, object].map { |value| format_term(value, options) }
124
- s += format_term(graph_name, options) + " " if graph_name
123
+ s = "%s %s %s " % [subject, predicate, object].map { |value| format_term(value, **options) }
124
+ s += format_term(graph_name, **options) + " " if graph_name
125
125
  s + "."
126
126
  end
127
127
  end # Writer
@@ -15,15 +15,17 @@ module RDF
15
15
  #
16
16
  # <https://rubygems.org/gems/rdf> <http://purl.org/dc/terms/title> "rdf" .
17
17
  #
18
- # Installation
19
- # ------------
18
+ # ## RDFStar (RDF*)
19
+ #
20
+ # Supports statements as resources using `<<s p o>>`.
21
+ #
22
+ # ## Installation
20
23
  #
21
24
  # This is the only RDF serialization format that is directly supported by
22
25
  # RDF.rb. Support for other formats is available in the form of add-on
23
26
  # gems, e.g. 'rdf-xml' or 'rdf-json'.
24
27
  #
25
- # Documentation
26
- # -------------
28
+ # ## Documentation
27
29
  #
28
30
  # * {RDF::NTriples::Format}
29
31
  # * {RDF::NTriples::Reader}
@@ -1,4 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
+
3
+ require 'strscan'
4
+
2
5
  module RDF::NTriples
3
6
  ##
4
7
  # N-Triples parser.
@@ -25,6 +28,10 @@ module RDF::NTriples
25
28
  # end
26
29
  # end
27
30
  #
31
+ # ** RDFStar (RDF*)
32
+ #
33
+ # Supports statements as resources using `<<s p o>>`.
34
+ #
28
35
  # @see http://www.w3.org/TR/rdf-testcases/#ntriples
29
36
  # @see http://www.w3.org/TR/n-triples/
30
37
  class Reader < RDF::Reader
@@ -70,6 +77,10 @@ module RDF::NTriples
70
77
  # 22
71
78
  STRING_LITERAL_QUOTE = /"((?:[^\"\\\n\r]|#{ECHAR}|#{UCHAR})*)"/.freeze
72
79
 
80
+ # RDF*
81
+ ST_START = /^<</.freeze
82
+ ST_END = /^\s*>>/.freeze
83
+
73
84
  # @see http://www.w3.org/TR/rdf-testcases/#ntrip_grammar
74
85
  COMMENT = /^#\s*(.*)$/.freeze
75
86
  NODEID = /^#{BLANK_NODE_LABEL}/.freeze
@@ -96,7 +107,7 @@ module RDF::NTriples
96
107
  def self.unserialize(input, **options)
97
108
  case input
98
109
  when nil then nil
99
- else self.new(input, {logger: []}.merge(options)).read_value
110
+ else self.new(input, logger: [], **options).read_value
100
111
  end
101
112
  end
102
113
 
@@ -104,20 +115,20 @@ module RDF::NTriples
104
115
  # (see unserialize)
105
116
  # @return [RDF::Resource]
106
117
  def self.parse_subject(input, **options)
107
- parse_uri(input, options) || parse_node(input, options)
118
+ parse_uri(input, **options) || parse_node(input, **options)
108
119
  end
109
120
 
110
121
  ##
111
122
  # (see unserialize)
112
123
  # @return [RDF::URI]
113
- def self.parse_predicate(input, *options)
124
+ def self.parse_predicate(input, **options)
114
125
  parse_uri(input, intern: true)
115
126
  end
116
127
 
117
128
  ##
118
129
  # (see unserialize)
119
130
  def self.parse_object(input, **options)
120
- parse_uri(input, options) || parse_node(input, options) || parse_literal(input, options)
131
+ parse_uri(input, **options) || parse_node(input, **options) || parse_literal(input, **options)
121
132
  end
122
133
 
123
134
  ##
@@ -202,7 +213,7 @@ module RDF::NTriples
202
213
  begin
203
214
  read_statement
204
215
  rescue RDF::ReaderError
205
- value = read_uriref || read_node || read_literal
216
+ value = read_uriref || read_node || read_literal || read_rdfstar
206
217
  log_recover
207
218
  value
208
219
  end
@@ -218,9 +229,9 @@ module RDF::NTriples
218
229
 
219
230
  begin
220
231
  unless blank? || read_comment
221
- subject = read_uriref || read_node || fail_subject
232
+ subject = read_uriref || read_node || read_rdfstar || fail_subject
222
233
  predicate = read_uriref(intern: true) || fail_predicate
223
- object = read_uriref || read_node || read_literal || fail_object
234
+ object = read_uriref || read_node || read_literal || read_rdfstar || fail_object
224
235
 
225
236
  if validate? && !read_eos
226
237
  log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
@@ -234,6 +245,20 @@ module RDF::NTriples
234
245
  end
235
246
  end
236
247
 
248
+ ##
249
+ # @return [RDF::Statement]
250
+ def read_rdfstar
251
+ if @options[:rdfstar] && match(ST_START)
252
+ subject = read_uriref || read_node || read_rdfstar || fail_subject
253
+ predicate = read_uriref(intern: true) || fail_predicate
254
+ object = read_uriref || read_node || read_literal || read_rdfstar || fail_object
255
+ if !match(ST_END)
256
+ log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
257
+ end
258
+ RDF::Statement.new(subject, predicate, object)
259
+ end
260
+ end
261
+
237
262
  ##
238
263
  # @return [Boolean]
239
264
  # @see http://www.w3.org/TR/rdf-testcases/#ntrip_grammar (comment)
@@ -208,7 +208,7 @@ module RDF::NTriples
208
208
  # @param [RDF::Term] object
209
209
  # @return [void]
210
210
  def write_triple(subject, predicate, object)
211
- puts format_triple(subject, predicate, object, @options)
211
+ puts format_triple(subject, predicate, object, **@options)
212
212
  end
213
213
 
214
214
  ##
@@ -221,6 +221,15 @@ module RDF::NTriples
221
221
  format_triple(*statement.to_triple, **options)
222
222
  end
223
223
 
224
+ ##
225
+ # Returns the N-Triples representation of an RDF* reified statement.
226
+ #
227
+ # @param [RDF::Statement] statement
228
+ # @param [Hash{Symbol => Object}] options ({})
229
+ # @return [String]
230
+ def format_rdfstar(statement, **options)
231
+ "<<%s %s %s>>" % statement.to_a.map { |value| format_term(value, **options) }
232
+ end
224
233
  ##
225
234
  # Returns the N-Triples representation of a triple.
226
235
  #
@@ -90,7 +90,7 @@ module RDF
90
90
  # the resulting solution sequence
91
91
  # @see RDF::Query#execute
92
92
  def self.execute(queryable, patterns = {}, options = {}, &block)
93
- self.new(patterns, options, &block).execute(queryable, options)
93
+ self.new(patterns, **options, &block).execute(queryable, **options)
94
94
  end
95
95
 
96
96
  ##
@@ -134,6 +134,12 @@ module RDF
134
134
  # @return [Hash]
135
135
  attr_reader :options
136
136
 
137
+ ##
138
+ # Scope the query to named graphs matching value
139
+ #
140
+ # @return [RDF::Resource, RDF::Query::Variable, false] graph_name
141
+ attr_accessor :graph_name
142
+
137
143
  ##
138
144
  # Initializes a new basic graph pattern query.
139
145
  #
@@ -180,6 +186,7 @@ module RDF
180
186
  @options = options.dup
181
187
  @solutions = Query::Solutions(solutions)
182
188
  graph_name = name if graph_name.nil?
189
+ @graph_name = graph_name
183
190
 
184
191
  patterns << @options if patterns.empty?
185
192
 
@@ -189,8 +196,6 @@ module RDF
189
196
  else patterns
190
197
  end
191
198
 
192
- self.graph_name = graph_name
193
-
194
199
  if block_given?
195
200
  case block.arity
196
201
  when 1 then block.call(self)
@@ -223,7 +228,7 @@ module RDF
223
228
  # whether this is an optional pattern
224
229
  # @return [void] self
225
230
  def pattern(pattern, **options)
226
- @patterns << Pattern.from(pattern, options)
231
+ @patterns << Pattern.from(pattern, **options)
227
232
  self
228
233
  end
229
234
 
@@ -235,7 +240,7 @@ module RDF
235
240
  # @return [RDF::Query] a copy of `self`
236
241
  # @since 0.3.0
237
242
  def optimize(**options)
238
- self.dup.optimize!(options)
243
+ self.dup.optimize!(**options)
239
244
  end
240
245
 
241
246
  ##
@@ -284,6 +289,8 @@ module RDF
284
289
  # any additional keyword options
285
290
  # @option options [Hash{Symbol => RDF::Term}] bindings
286
291
  # optional variable bindings to use
292
+ # @option options [Boolean] :optimize
293
+ # Optimize query before execution.
287
294
  # @option options [RDF::Query::Solutions] solutions
288
295
  # optional initial solutions for chained queries
289
296
  # @yield [solution]
@@ -294,9 +301,7 @@ module RDF
294
301
  # the resulting solution sequence
295
302
  # @see http://www.holygoat.co.uk/blog/entry/2005-10-25-1
296
303
  # @see http://www.w3.org/TR/sparql11-query/#emptyGroupPattern
297
- def execute(queryable, solutions: Solution.new, graph_name: nil, name: nil, **options, &block)
298
- options = {bindings: {}}.merge(options)
299
-
304
+ def execute(queryable, bindings: {}, solutions: Solution.new, graph_name: nil, name: nil, **options, &block)
300
305
  # Use provided solutions to allow for query chaining
301
306
  # Otherwise, a quick empty solution simplifies the logic below; no special case for
302
307
  # the first pattern
@@ -308,17 +313,17 @@ module RDF
308
313
  return @solutions
309
314
  end
310
315
 
316
+ self.optimize! if options[:optimize]
311
317
  patterns = @patterns
312
318
  graph_name = name if graph_name.nil?
313
- graph_name = self.graph_name if graph_name.nil?
314
- options[:graph_name] = graph_name unless graph_name.nil?
319
+ @graph_name = graph_name unless graph_name.nil?
315
320
 
316
321
  # Add graph_name to pattern, if necessary
317
- unless graph_name.nil?
322
+ unless @graph_name.nil?
318
323
  if patterns.empty?
319
- patterns = [Pattern.new(nil, nil, nil, graph_name: graph_name)]
324
+ patterns = [Pattern.new(nil, nil, nil, graph_name: @graph_name)]
320
325
  else
321
- apply_graph_name(graph_name)
326
+ apply_graph_name(@graph_name)
322
327
  end
323
328
  end
324
329
 
@@ -326,15 +331,15 @@ module RDF
326
331
 
327
332
  old_solutions, @solutions = @solutions, Query::Solutions()
328
333
 
329
- options[:bindings].each_key do |variable|
334
+ bindings.each_key do |variable|
330
335
  if pattern.variables.include?(variable)
331
336
  unbound_solutions, old_solutions = old_solutions, Query::Solutions()
332
- options[:bindings][variable].each do |binding|
337
+ bindings[variable].each do |binding|
333
338
  unbound_solutions.each do |solution|
334
339
  old_solutions << solution.merge(variable => binding)
335
340
  end
336
341
  end
337
- options[:bindings].delete(variable)
342
+ bindings.delete(variable)
338
343
  end
339
344
  end
340
345
 
@@ -407,38 +412,26 @@ module RDF
407
412
  # Is this query scoped to a named graph?
408
413
  # @return [Boolean]
409
414
  def named?
410
- !!options[:graph_name]
415
+ !!graph_name
411
416
  end
412
417
 
413
418
  # Is this query scoped to the default graph?
414
419
  # @return [Boolean]
415
420
  def default?
416
- options[:graph_name] == false
421
+ graph_name == false
417
422
  end
418
423
 
419
424
  # Is this query unscoped? This indicates that it can return results from
420
425
  # either a named graph or the default graph.
421
426
  # @return [Boolean]
422
427
  def unnamed?
423
- options[:graph_name].nil?
424
- end
425
-
426
- # Scope the query to named graphs matching value
427
- # @param [RDF::IRI, RDF::Query::Variable] value
428
- # @return [RDF::IRI, RDF::Query::Variable]
429
- def graph_name=(value)
430
- options[:graph_name] = value
431
- end
432
-
433
- # Scope of this query, if any
434
- # @return [RDF::IRI, RDF::Query::Variable]
435
- def graph_name
436
- options[:graph_name]
428
+ graph_name.nil?
437
429
  end
438
430
 
439
431
  # Apply the graph name specified (or configured) to all patterns that have no graph name
440
432
  # @param [RDF::IRI, RDF::Query::Variable] graph_name (self.graph_name)
441
- def apply_graph_name(graph_name = options[:graph_name])
433
+ def apply_graph_name(graph_name = nil)
434
+ graph_name ||= self.graph_name
442
435
  patterns.each {|pattern| pattern.graph_name = graph_name if pattern.graph_name.nil?} unless graph_name.nil?
443
436
  end
444
437
 
@@ -515,8 +508,7 @@ module RDF
515
508
  # @return [RDF::Query]
516
509
  def dup
517
510
  patterns = @patterns.map {|p| p.dup}
518
- patterns << @options.merge(solutions: @solutions.dup)
519
- Query.new(*patterns)
511
+ Query.new(patterns, graph_name: graph_name, solutions: @solutions.dup, **options)
520
512
  end
521
513
 
522
514
  ##