rdf 3.0.12 → 3.1.3

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 (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
  ##