rdf 3.0.12 → 3.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHORS +1 -1
  3. data/README.md +46 -11
  4. data/VERSION +1 -1
  5. data/etc/doap.nt +74 -80
  6. data/lib/rdf.rb +35 -23
  7. data/lib/rdf/changeset.rb +87 -19
  8. data/lib/rdf/cli.rb +7 -7
  9. data/lib/rdf/format.rb +17 -10
  10. data/lib/rdf/mixin/enumerable.rb +3 -2
  11. data/lib/rdf/mixin/mutable.rb +5 -15
  12. data/lib/rdf/mixin/queryable.rb +12 -4
  13. data/lib/rdf/mixin/writable.rb +9 -14
  14. data/lib/rdf/model/dataset.rb +1 -1
  15. data/lib/rdf/model/graph.rb +5 -2
  16. data/lib/rdf/model/list.rb +5 -5
  17. data/lib/rdf/model/literal.rb +3 -3
  18. data/lib/rdf/model/statement.rb +30 -7
  19. data/lib/rdf/model/uri.rb +44 -23
  20. data/lib/rdf/nquads.rb +6 -6
  21. data/lib/rdf/ntriples.rb +6 -4
  22. data/lib/rdf/ntriples/reader.rb +29 -7
  23. data/lib/rdf/ntriples/writer.rb +10 -1
  24. data/lib/rdf/query.rb +27 -35
  25. data/lib/rdf/query/hash_pattern_normalizer.rb +14 -12
  26. data/lib/rdf/query/pattern.rb +51 -18
  27. data/lib/rdf/query/solution.rb +20 -1
  28. data/lib/rdf/query/solutions.rb +15 -5
  29. data/lib/rdf/query/variable.rb +17 -5
  30. data/lib/rdf/reader.rb +76 -25
  31. data/lib/rdf/repository.rb +32 -18
  32. data/lib/rdf/transaction.rb +1 -1
  33. data/lib/rdf/util.rb +6 -5
  34. data/lib/rdf/util/cache.rb +2 -2
  35. data/lib/rdf/util/coercions.rb +60 -0
  36. data/lib/rdf/util/file.rb +20 -10
  37. data/lib/rdf/util/logger.rb +6 -6
  38. data/lib/rdf/vocab/owl.rb +401 -86
  39. data/lib/rdf/vocab/rdfs.rb +81 -18
  40. data/lib/rdf/vocab/rdfv.rb +147 -1
  41. data/lib/rdf/vocab/writer.rb +41 -3
  42. data/lib/rdf/vocab/xsd.rb +203 -2
  43. data/lib/rdf/vocabulary.rb +108 -14
  44. data/lib/rdf/writer.rb +32 -10
  45. metadata +32 -27
@@ -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
@@ -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}
@@ -25,6 +25,10 @@ module RDF::NTriples
25
25
  # end
26
26
  # end
27
27
  #
28
+ # ** RDFStar (RDF*)
29
+ #
30
+ # Supports statements as resources using `<<s p o>>`.
31
+ #
28
32
  # @see http://www.w3.org/TR/rdf-testcases/#ntriples
29
33
  # @see http://www.w3.org/TR/n-triples/
30
34
  class Reader < RDF::Reader
@@ -70,6 +74,10 @@ module RDF::NTriples
70
74
  # 22
71
75
  STRING_LITERAL_QUOTE = /"((?:[^\"\\\n\r]|#{ECHAR}|#{UCHAR})*)"/.freeze
72
76
 
77
+ # RDF*
78
+ ST_START = /^<</.freeze
79
+ ST_END = /^\s*>>/.freeze
80
+
73
81
  # @see http://www.w3.org/TR/rdf-testcases/#ntrip_grammar
74
82
  COMMENT = /^#\s*(.*)$/.freeze
75
83
  NODEID = /^#{BLANK_NODE_LABEL}/.freeze
@@ -96,7 +104,7 @@ module RDF::NTriples
96
104
  def self.unserialize(input, **options)
97
105
  case input
98
106
  when nil then nil
99
- else self.new(input, {logger: []}.merge(options)).read_value
107
+ else self.new(input, logger: [], **options).read_value
100
108
  end
101
109
  end
102
110
 
@@ -104,20 +112,20 @@ module RDF::NTriples
104
112
  # (see unserialize)
105
113
  # @return [RDF::Resource]
106
114
  def self.parse_subject(input, **options)
107
- parse_uri(input, options) || parse_node(input, options)
115
+ parse_uri(input, **options) || parse_node(input, **options)
108
116
  end
109
117
 
110
118
  ##
111
119
  # (see unserialize)
112
120
  # @return [RDF::URI]
113
- def self.parse_predicate(input, *options)
121
+ def self.parse_predicate(input, **options)
114
122
  parse_uri(input, intern: true)
115
123
  end
116
124
 
117
125
  ##
118
126
  # (see unserialize)
119
127
  def self.parse_object(input, **options)
120
- parse_uri(input, options) || parse_node(input, options) || parse_literal(input, options)
128
+ parse_uri(input, **options) || parse_node(input, **options) || parse_literal(input, **options)
121
129
  end
122
130
 
123
131
  ##
@@ -202,7 +210,7 @@ module RDF::NTriples
202
210
  begin
203
211
  read_statement
204
212
  rescue RDF::ReaderError
205
- value = read_uriref || read_node || read_literal
213
+ value = read_uriref || read_node || read_literal || read_rdfstar
206
214
  log_recover
207
215
  value
208
216
  end
@@ -218,9 +226,9 @@ module RDF::NTriples
218
226
 
219
227
  begin
220
228
  unless blank? || read_comment
221
- subject = read_uriref || read_node || fail_subject
229
+ subject = read_uriref || read_node || read_rdfstar || fail_subject
222
230
  predicate = read_uriref(intern: true) || fail_predicate
223
- object = read_uriref || read_node || read_literal || fail_object
231
+ object = read_uriref || read_node || read_literal || read_rdfstar || fail_object
224
232
 
225
233
  if validate? && !read_eos
226
234
  log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
@@ -234,6 +242,20 @@ module RDF::NTriples
234
242
  end
235
243
  end
236
244
 
245
+ ##
246
+ # @return [RDF::Statement]
247
+ def read_rdfstar
248
+ if @options[:rdfstar] && match(ST_START)
249
+ subject = read_uriref || read_node || read_rdfstar || fail_subject
250
+ predicate = read_uriref(intern: true) || fail_predicate
251
+ object = read_uriref || read_node || read_literal || read_rdfstar || fail_object
252
+ if !match(ST_END)
253
+ log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
254
+ end
255
+ RDF::Statement.new(subject, predicate, object)
256
+ end
257
+ end
258
+
237
259
  ##
238
260
  # @return [Boolean]
239
261
  # @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
  ##