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
@@ -42,6 +42,11 @@ module RDF
42
42
  @extra = extra
43
43
  end
44
44
 
45
+ # patch to run over loaded vocabulary
46
+ def patch=(patch)
47
+ @patch = patch
48
+ end
49
+
45
50
  # Use StrictVocabulary or Vocabulary
46
51
  def strict=(strict)
47
52
  @strict = strict
@@ -105,10 +110,10 @@ module RDF
105
110
  attributes.keys.sort_by(&:to_s).each do |key|
106
111
  next if key == :vocab
107
112
  value = Array(attributes[key])
108
- component = key.is_a?(Symbol) ? "#{key}: " : "#{key.inspect} => "
113
+ component = key.is_a?(Symbol) ? "#{key}: " : ":#{key.inspect} => "
109
114
  value = value.first if value.length == 1
110
115
  component << if value.is_a?(Array)
111
- '[' + value.map {|v| serialize_value(v, key)}.join(", ") + "]"
116
+ '[' + value.map {|v| serialize_value(v, key)}.sort.join(", ") + "]"
112
117
  else
113
118
  serialize_value(value, key)
114
119
  end
@@ -131,14 +136,19 @@ module RDF
131
136
  # then call #run
132
137
  def run
133
138
  @output.print %(# -*- encoding: utf-8 -*-
139
+ # frozen_string_literal: true
134
140
  # This file generated automatically using vocab-fetch from #{source}
135
141
  require 'rdf'
136
142
  module #{module_name}
143
+ # @!parse
144
+ # # Vocabulary for <#{uri}>
145
+ # class #{class_name} < RDF::#{"Strict" if @strict}Vocabulary
146
+ # end
137
147
  class #{class_name} < RDF::#{"Strict" if @strict}Vocabulary("#{uri}")
138
148
  ).gsub(/^ /, '') if @output_class_file
139
149
 
140
150
  # Extract statements with subjects that have the vocabulary prefix and organize into a hash of properties and values
141
- vocab = RDF::Vocabulary.load(uri, location: source, extra: @extra)
151
+ vocab = RDF::Vocabulary.load(uri, location: source, extra: @extra, patch: @patch)
142
152
 
143
153
  # Split nodes into Class/Property/Datatype/Other
144
154
  term_nodes = {
@@ -56,7 +56,7 @@ module RDF
56
56
  end
57
57
 
58
58
  ##
59
- # Finds an RDF serialization format class based on the given criteria.
59
+ # Finds an RDF serialization format class based on the given criteria. If multiple formats are identified, the last one found is returned; this allows descrimination of equivalent formats based on load order.
60
60
  #
61
61
  # @overload for(format)
62
62
  # Finds an RDF serialization format class based on a symbolic name.
@@ -67,7 +67,7 @@ module RDF
67
67
  # @overload for(filename)
68
68
  # Finds an RDF serialization format class based on a file name.
69
69
  #
70
- # @param [String] filename
70
+ # @param [String, RDF::URI] filename
71
71
  # @return [Class]
72
72
  #
73
73
  # @overload for(options = {})
@@ -83,19 +83,17 @@ module RDF
83
83
  # @option options [Boolean] :has_writer (false)
84
84
  # Only return a format having a writer.
85
85
  # @option options [String] :sample (nil)
86
- # A sample of input used for performing format detection.
87
- # If we find no formats, or we find more than one, and we have a sample, we can
88
- # perform format detection to find a specific format to use, in which case
89
- # we pick the first one we find
86
+ # A sample of input used for performing format detection. If we find no formats, or we find more than one, and we have a sample, we can perform format detection to find a specific format to use, in which case we pick the last one we find
90
87
  # @return [Class]
91
88
  # @yieldreturn [String] another way to provide a sample, allows lazy for retrieving the sample.
92
89
  #
93
90
  # @return [Class]
94
91
  def self.for(options = {})
95
92
  format = case options
96
- when String
93
+ when String, RDF::URI
97
94
  # Find a format based on the file name
98
- self.for(file_name: options) { yield if block_given? }
95
+ fn, options = options, {}
96
+ self.for(file_name: fn) { yield if block_given? }
99
97
 
100
98
  when Hash
101
99
  case
@@ -112,7 +110,7 @@ module RDF
112
110
  content_types[mime_type] unless mime_type == 'text/plain' && (options[:sample] || block_given?)
113
111
  # Find a format based on the file name:
114
112
  when file_name = options[:file_name]
115
- self.for(file_extension: File.extname(file_name.to_s)[1..-1]) { yield if block_given? }
113
+ self.for(file_extension: File.extname(RDF::URI(file_name).path)[1..-1]) { yield if block_given? }
116
114
  # Find a format based on the file extension:
117
115
  when file_ext = options[:file_extension]
118
116
  file_extensions[file_ext.to_sym]
@@ -121,21 +119,23 @@ module RDF
121
119
  when Symbol
122
120
  # Try to find a match based on the full class name
123
121
  # We want this to work even if autoloading fails
124
- format = options
125
- @@subclasses.detect { |klass| klass.to_sym == format } ||
126
- case format
127
- when :ntriples
128
- RDF::NTriples::Format
129
- when :nquads
130
- RDF::NQuads::Format
122
+ fmt, options = options, {}
123
+ classes = @@subclasses.select { |klass| klass.symbols.include?(fmt) }
124
+ if classes.empty?
125
+ classes = case fmt
126
+ when :ntriples then [RDF::NTriples::Format]
127
+ when :nquads then [RDF::NQuads::Format]
128
+ else []
129
+ end
131
130
  end
131
+ classes
132
132
  end
133
133
 
134
134
  if format.is_a?(Array)
135
135
  format = format.select {|f| f.reader} if options[:has_reader]
136
136
  format = format.select {|f| f.writer} if options[:has_writer]
137
137
 
138
- return format.first if format.uniq.length == 1
138
+ return format.last if format.uniq.length == 1
139
139
  elsif !format.nil?
140
140
  return format
141
141
  end
@@ -144,15 +144,14 @@ module RDF
144
144
  if sample = (options[:sample] if options.is_a?(Hash)) || (yield if block_given?)
145
145
  sample = sample.dup.to_s
146
146
  sample.force_encoding(Encoding::ASCII_8BIT) if sample.respond_to?(:force_encoding)
147
- # Given a sample, perform format detection across the appropriate formats, choosing
148
- # the first that matches
147
+ # Given a sample, perform format detection across the appropriate formats, choosing the last that matches
149
148
  format ||= @@subclasses
150
149
 
151
- # Return first format that has a positive detection
152
- format.detect {|f| f.detect(sample)} || format.first
150
+ # Return last format that has a positive detection
151
+ format.reverse.detect {|f| f.detect(sample)} || format.last
153
152
  elsif format.is_a?(Array)
154
- # Otherwise, just return the first matching format
155
- format.first
153
+ # Otherwise, just return the last matching format
154
+ format.last
156
155
  else
157
156
  nil
158
157
  end
@@ -192,7 +191,7 @@ module RDF
192
191
  #
193
192
  # @return [Array<Symbol>]
194
193
  def self.reader_symbols
195
- @@readers.keys.compact.map(&:to_sym).uniq
194
+ @@readers.keys.map(&:symbols).flatten.uniq
196
195
  end
197
196
 
198
197
  ##
@@ -218,7 +217,7 @@ module RDF
218
217
  #
219
218
  # @return [Array<Symbol>]
220
219
  def self.writer_symbols
221
- @@writers.keys.compact.map(&:to_sym).uniq
220
+ @@writers.keys.map(&:symbols).flatten.uniq
222
221
  end
223
222
 
224
223
  ##
@@ -235,7 +234,9 @@ module RDF
235
234
  end
236
235
 
237
236
  ##
238
- # Returns a symbol appropriate to use with RDF::Format.for()
237
+ # Returns a symbol appropriate to use with `RDF::Format.for()`
238
+ #
239
+ # @note Defaults to the last element of the class name before `Format` downcased and made a symbol. Individual formats can override this.
239
240
  # @return [Symbol]
240
241
  def self.to_sym
241
242
  elements = self.to_s.split("::")
@@ -244,6 +245,17 @@ module RDF
244
245
  sym.downcase.to_s.to_sym if sym.is_a?(String)
245
246
  end
246
247
 
248
+ ##
249
+ # Returns the set of symbols for a writer appropriate for use with with `RDF::Format.for()`
250
+ #
251
+ # @note Individual formats can override this to provide an array of symbols; otherwise, it uses `self.to_sym`
252
+ # @return [Array<Symbol>]
253
+ # @see to_sym
254
+ # @since 2.0
255
+ def self.symbols
256
+ [self.to_sym]
257
+ end
258
+
247
259
  ##
248
260
  # Returns a human-readable name for the format.
249
261
  # Subclasses should override this to use something
@@ -347,6 +359,12 @@ module RDF
347
359
  end
348
360
  end
349
361
 
362
+ ##
363
+ # Hash of CLI commands appropriate for this format
364
+ # @return [Hash{Symbol => Lambda(Array, Hash)}]
365
+ def self.cli_commands
366
+ {}
367
+ end
350
368
 
351
369
  ##
352
370
  # Use a text sample to detect the format of an input file. Sub-classes implement
@@ -41,6 +41,7 @@ module RDF
41
41
  # enumerable.each_subject { |term| puts term.inspect }
42
42
  # enumerable.each_predicate { |term| puts term.inspect }
43
43
  # enumerable.each_object { |term| puts term.inspect }
44
+ # enumerable.each_term { |term| puts term.inspect }
44
45
  #
45
46
  # @example Obtaining all statements
46
47
  # enumerable.statements #=> [RDF::Statement(subject1, predicate1, object1), ...]
@@ -62,12 +63,12 @@ module RDF
62
63
  include RDF::Countable # NOTE: must come after ::Enumerable
63
64
 
64
65
  ##
65
- # Returns `true` if this repository supports the given `feature`.
66
+ # Returns `true` if this enumerable supports the given `feature`.
66
67
  #
67
68
  # Supported features include:
68
69
  # * `:graph_name` supports statements with a graph_name, allowing multiple named graphs
69
- # * `:context` supports statements with a context, allowing multiple contexts (DEPRECATED, use graph_name. `context` will be removed in RDF.rb 2.0)
70
70
  # * `:inference` supports RDFS inferrence of queryable contents.
71
+ # * `:literal_equality' preserves [term-equality](https://www.w3.org/TR/rdf11-concepts/#dfn-literal-term-equality) for literals. Literals are equal only if their lexical values and datatypes are equal, character by character. Literals may be "inlined" to value-space for efficiency only if `:literal_equality` is `false`.
71
72
  # * `:validity` allows a concrete Enumerable implementation to indicate that it does or does not support valididty checking. By default implementations are assumed to support validity checking.
72
73
  # * `:skolemize` supports [Skolemization](https://www.w3.org/wiki/BnodeSkolemization) of an `Enumerable`. Implementations supporting this feature must implement a `#skolemize` method, taking a base URI used for minting URIs for BNodes as stable identifiers and a `#deskolemize` method, also taking a base URI used for turning URIs having that prefix back into the same BNodes which were originally skolemized.
73
74
  #
@@ -75,7 +76,7 @@ module RDF
75
76
  # @return [Boolean]
76
77
  # @since 0.3.5
77
78
  def supports?(feature)
78
- feature == :validity
79
+ feature == :validity || feature == :literal_equality
79
80
  end
80
81
 
81
82
  ##
@@ -117,11 +118,11 @@ module RDF
117
118
  # Returns all RDF statements.
118
119
  #
119
120
  # @param [Hash{Symbol => Boolean}] options
120
- # @return [Enumerator<RDF::Statement>]
121
+ # @return [Array<RDF::Statement>]
121
122
  # @see #each_statement
122
123
  # @see #enum_statement
123
124
  def statements(options = {})
124
- enum_statement
125
+ Array(enum_statement)
125
126
  end
126
127
 
127
128
  ##
@@ -149,9 +150,8 @@ module RDF
149
150
  # @return [void]
150
151
  #
151
152
  # @overload each_statement
152
- # @return [Enumerator]
153
+ # @return [Enumerator<RDF::Statement>]
153
154
  #
154
- # @return [void]
155
155
  # @see #enum_statement
156
156
  def each_statement(&block)
157
157
  if block_given?
@@ -166,7 +166,7 @@ module RDF
166
166
  # FIXME: enum_for doesn't seem to be working properly
167
167
  # in JRuby 1.7, so specs are marked pending
168
168
  #
169
- # @return [Enumerator]
169
+ # @return [Enumerator<RDF::Statement>]
170
170
  # @see #each_statement
171
171
  def enum_statement
172
172
  # Ensure that statements are queryable, countable and enumerable
@@ -181,11 +181,11 @@ module RDF
181
181
  # Returns all RDF triples.
182
182
  #
183
183
  # @param [Hash{Symbol => Boolean}] options
184
- # @return [Enumerator<Array(RDF::Resource, RDF::URI, RDF::Term)>]
184
+ # @return [Array<Array(RDF::Resource, RDF::URI, RDF::Term)>]
185
185
  # @see #each_triple
186
186
  # @see #enum_triple
187
187
  def triples(options = {})
188
- enum_statement.map(&:to_triple).to_enum # TODO: optimize
188
+ enum_statement.map(&:to_triple) # TODO: optimize
189
189
  end
190
190
 
191
191
  ##
@@ -214,9 +214,8 @@ module RDF
214
214
  # @return [void]
215
215
  #
216
216
  # @overload each_triple
217
- # @return [Enumerator]
217
+ # @return [Enumerator<Array(RDF::Resource, RDF::URI, RDF::Term)>]
218
218
  #
219
- # @return [void]
220
219
  # @see #enum_triple
221
220
  def each_triple
222
221
  if block_given?
@@ -230,7 +229,7 @@ module RDF
230
229
  ##
231
230
  # Returns an enumerator for {RDF::Enumerable#each_triple}.
232
231
  #
233
- # @return [Enumerator]
232
+ # @return [Enumerator<Array(RDF::Resource, RDF::URI, RDF::Term)>]
234
233
  # @see #each_triple
235
234
  def enum_triple
236
235
  Countable::Enumerator.new do |yielder|
@@ -243,11 +242,11 @@ module RDF
243
242
  # Returns all RDF quads.
244
243
  #
245
244
  # @param [Hash{Symbol => Boolean}] options
246
- # @return [Enumerator<Array(RDF::Resource, RDF::URI, RDF::Term, RDF::Resource)>]
245
+ # @return [Array<Array(RDF::Resource, RDF::URI, RDF::Term, RDF::Resource)>]
247
246
  # @see #each_quad
248
247
  # @see #enum_quad
249
248
  def quads(options = {})
250
- enum_statement.map(&:to_quad).to_enum # TODO: optimize
249
+ enum_statement.map(&:to_quad) # TODO: optimize
251
250
  end
252
251
 
253
252
  ##
@@ -292,7 +291,7 @@ module RDF
292
291
  ##
293
292
  # Returns an enumerator for {RDF::Enumerable#each_quad}.
294
293
  #
295
- # @return [Enumerator]
294
+ # @return [Enumerator<Array(RDF::Resource, RDF::URI, RDF::Term, RDF::Resource)>]
296
295
  # @see #each_quad
297
296
  def enum_quad
298
297
  Countable::Enumerator.new do |yielder|
@@ -304,16 +303,15 @@ module RDF
304
303
  ##
305
304
  # Returns all unique RDF subject terms.
306
305
  #
307
- # @param [Hash{Symbol => Boolean}] options
308
- # @option options [Boolean] :unique (true)
309
- # @return [Enumerator<RDF::Resource>]
306
+ # @param unique (true)
307
+ # @return [Array<RDF::Resource>]
310
308
  # @see #each_subject
311
309
  # @see #enum_subject
312
- def subjects(options = {})
313
- if options[:unique] == false
314
- enum_statement.map(&:subject).to_enum # TODO: optimize
310
+ def subjects(unique: true)
311
+ unless unique
312
+ enum_statement.map(&:subject) # TODO: optimize
315
313
  else
316
- enum_subject
314
+ Array(enum_subject)
317
315
  end
318
316
  end
319
317
 
@@ -370,16 +368,15 @@ module RDF
370
368
  ##
371
369
  # Returns all unique RDF predicate terms.
372
370
  #
373
- # @param [Hash{Symbol => Boolean}] options
374
- # @option options [Boolean] :unique (true)
371
+ # @param unique (true)
375
372
  # @return [Array<RDF::URI>]
376
373
  # @see #each_predicate
377
374
  # @see #enum_predicate
378
- def predicates(options = {})
379
- if options[:unique] == false
380
- enum_statement.map(&:predicate).to_enum # TODO: optimize
375
+ def predicates(unique: true)
376
+ unless unique
377
+ enum_statement.map(&:predicate) # TODO: optimize
381
378
  else
382
- enum_predicate
379
+ Array(enum_predicate)
383
380
  end
384
381
  end
385
382
 
@@ -436,16 +433,15 @@ module RDF
436
433
  ##
437
434
  # Returns all unique RDF object terms.
438
435
  #
439
- # @param [Hash{Symbol => Boolean}] options
440
- # @option options [Boolean] :unique (true)
441
- # @return [Enumerator<RDF::Term>]
436
+ # @param unique (true)
437
+ # @return [Array<RDF::Term>]
442
438
  # @see #each_object
443
439
  # @see #enum_object
444
- def objects(options = {})
445
- if options[:unique] == false
446
- enum_statement.map(&:object).to_enum # TODO: optimize
440
+ def objects(unique: true)
441
+ unless unique
442
+ enum_statement.map(&:object) # TODO: optimize
447
443
  else
448
- enum_object
444
+ Array(enum_object)
449
445
  end
450
446
  end
451
447
 
@@ -501,97 +497,96 @@ module RDF
501
497
  alias_method :enum_objects, :enum_object
502
498
 
503
499
  ##
504
- # Returns all unique RDF contexts, other than the default context.
500
+ # Returns all unique RDF terms (subjects, predicates, objects, and graph_names).
505
501
  #
506
- # @param [Hash{Symbol => Boolean}] options
507
- # @option options [Boolean] :unique (true)
508
- # @return [Enumerator<RDF::Resource>]
509
- # @see #each_context
510
- # @see #enum_context
511
- # @deprecated use {#graph_names} instead.
512
- def contexts(options = {})
513
- warn "[DEPRECATION] Enumerable#contexts is being replaced with Enumerable#graph_names in RDF.rb 2.0. Called from #{Gem.location_of_caller.join(':')}"
514
- if options[:unique] == false
515
- enum_statement.map(&:context).compact.to_enum # TODO: optimize
516
- else
517
- enum_context
518
- end
519
- end
520
-
521
- ##
522
- # Returns all unique RDF graph names, other than the default graph.
502
+ # @example finding all Blank Nodes used within an enumerable
503
+ # enumberable.terms.select(&:node?)
523
504
  #
524
- # @param [Hash{Symbol => Boolean}] options
525
- # @option options [Boolean] :unique (true)
505
+ # @param unique (true)
526
506
  # @return [Array<RDF::Resource>]
527
- # @see #each_graph
528
- # @see #enum_graph
529
507
  # @since 2.0
530
- def graph_names(options = {})
531
- if options[:unique] == false
532
- enum_statement.map(&:graph_name).compact # TODO: optimize
508
+ # @see #each_resource
509
+ # @see #enum_resource
510
+ def terms(unique: true)
511
+ unless unique
512
+ enum_statement.
513
+ map(&:to_quad).
514
+ flatten.
515
+ compact
533
516
  else
534
- enum_graph.map(&:graph_name).compact
517
+ Array(enum_term)
535
518
  end
536
519
  end
537
520
 
538
521
  ##
539
- # Returns `true` if `self` contains the given RDF context.
522
+ # Returns `true` if `self` contains the given RDF subject term.
540
523
  #
541
- # @param [RDF::Resource, false] value
542
- # Use value `false` to query for the default context
524
+ # @param [RDF::Resource] value
543
525
  # @return [Boolean]
544
- # @deprecated Use {#has_graph?} instead.
545
- def has_context?(value)
546
- warn "[DEPRECATION] Enumerable#has_context? is being replaced with Enumerable#has_graph? in RDF.rb 2.0. Called from #{Gem.location_of_caller.join(':')}"
547
- has_graph?(value)
526
+ # @since 2.0
527
+ def has_term?(value)
528
+ enum_term.include?(value)
548
529
  end
549
530
 
550
531
  ##
551
- # Iterates the given block for each unique RDF context, other than the default context.
532
+ # Iterates the given block for each unique RDF term (subject, predicate, object, or graph_name).
552
533
  #
553
534
  # If no block was given, returns an enumerator.
554
535
  #
555
536
  # The order in which values are yielded is undefined.
556
537
  #
557
- # @overload each_context
558
- # @yield [context]
559
- # each context term
560
- # @yieldparam [RDF::Resource] context
538
+ # @overload each_term
539
+ # @yield [term]
540
+ # each term
541
+ # @yieldparam [RDF::Term] term
561
542
  # @yieldreturn [void] ignored
562
543
  # @return [void]
563
544
  #
564
- # @overload each_context
565
- # @return [Enumerator]
566
- #
567
- # @see #enum_context
568
- # @deprecated Use {#each_graph} instead.
569
- def each_context
570
- warn "[DEPRECATION] Enumerable#each_context is being replaced with Enumerable#each_graph in RDF.rb 2.0. Called from #{Gem.location_of_caller.join(':')}"
545
+ # @overload each_term
546
+ # @return [Enumerator<RDF::Term>]
547
+ # @since 2.0
548
+ # @see #enum_term
549
+ def each_term
571
550
  if block_given?
572
551
  values = {}
573
552
  each_statement do |statement|
574
- value = statement.context
575
- unless value.nil? || values.include?(value)
576
- values[value] = true
577
- yield value
553
+ statement.to_quad.each do |value|
554
+ unless value.nil? || values.include?(value.hash)
555
+ values[value.hash] = true
556
+ yield value
557
+ end
578
558
  end
579
559
  end
580
560
  end
581
- enum_context
561
+ enum_term
582
562
  end
583
563
 
584
564
  ##
585
- # Returns an enumerator for {RDF::Enumerable#each_context}.
565
+ # Returns an enumerator for {RDF::Enumerable#each_term}.
586
566
  #
587
- # @return [Enumerator]
588
- # @see #each_context
589
- # @deprecated Use {#enum_graph} instead.
590
- def enum_context
591
- warn "[DEPRECATION] Enumerable#enum_context is being replaced with Enumerable#enum_graph in RDF.rb 2.0. Called from #{Gem.location_of_caller.join(':')}"
592
- enum_for(:each_context)
567
+ # @return [Enumerator<RDF::Term>]
568
+ # @see #each_term
569
+ # @since 2.0
570
+ def enum_term
571
+ enum_for(:each_term)
572
+ end
573
+ alias_method :enum_terms, :enum_term
574
+
575
+ ##
576
+ # Returns all unique RDF graph names, other than the default graph.
577
+ #
578
+ # @param unique (true)
579
+ # @return [Array<RDF::Resource>]
580
+ # @see #each_graph
581
+ # @see #enum_graph
582
+ # @since 2.0
583
+ def graph_names(unique: true)
584
+ unless unique
585
+ enum_statement.map(&:graph_name).compact # TODO: optimize
586
+ else
587
+ enum_graph.map(&:graph_name).compact
588
+ end
593
589
  end
594
- alias_method :enum_contexts, :enum_context
595
590
 
596
591
  ##
597
592
  # Returns `true` if `self` contains the given RDF graph_name.
@@ -603,6 +598,45 @@ module RDF
603
598
  enum_statement.any? {|s| s.graph_name == graph_name}
604
599
  end
605
600
 
601
+ ##
602
+ # Limits statements to be from a specific graph.
603
+ #
604
+ # If no block was given, returns an enumerator.
605
+ #
606
+ # The order in which statements are yielded is undefined.
607
+ #
608
+ # @overload project_graph(graph_name)
609
+ # @param [RDF::Resource, nil] graph_name
610
+ # The name of the graph from which statements are taken.
611
+ # Use `nil` for the default graph.
612
+ # @yield [statement]
613
+ # each statement
614
+ # @yieldparam [RDF::Statement] statement
615
+ # @yieldreturn [void] ignored
616
+ # @return [void]
617
+ #
618
+ # @overload project_graph(graph_name)
619
+ # @param [RDF::Resource, false] graph_name
620
+ # The name of the graph from which statements are taken.
621
+ # Use `false` for the default graph.
622
+ # @return [Enumerable]
623
+ #
624
+ # @see #each_statement
625
+ # @since 3.0
626
+ def project_graph(graph_name)
627
+ if block_given?
628
+ self.each do |statement|
629
+ yield statement if statement.graph_name == graph_name
630
+ end
631
+ else
632
+ # Ensure that statements are queryable, countable and enumerable
633
+ this = self
634
+ Queryable::Enumerator.new do |yielder|
635
+ this.send(:project_graph, graph_name) {|y| yielder << y}
636
+ end
637
+ end
638
+ end
639
+
606
640
  ##
607
641
  # Iterates the given block for each RDF graph in `self`.
608
642
  #
@@ -624,10 +658,12 @@ module RDF
624
658
  # @since 0.1.9
625
659
  def each_graph
626
660
  if block_given?
627
- yield RDF::Graph.new(nil, data: self)
661
+ yield RDF::Graph.new(graph_name: nil, data: self)
628
662
  # FIXME: brute force, repositories should override behavior
629
- enum_statement.map(&:graph_name).uniq.compact do |graph_name|
630
- yield RDF::Graph.new(graph_name, data: self)
663
+ if supports?(:graph_name)
664
+ enum_statement.map(&:graph_name).uniq.compact.each do |graph_name|
665
+ yield RDF::Graph.new(graph_name: graph_name, data: self)
666
+ end
631
667
  end
632
668
  end
633
669
  enum_graph