rdf 3.0.11 → 3.1.2

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHORS +1 -1
  3. data/README.md +127 -95
  4. data/UNLICENSE +1 -1
  5. data/VERSION +1 -1
  6. data/etc/doap.nt +79 -85
  7. data/lib/rdf.rb +35 -23
  8. data/lib/rdf/changeset.rb +80 -19
  9. data/lib/rdf/cli.rb +7 -7
  10. data/lib/rdf/format.rb +17 -10
  11. data/lib/rdf/mixin/enumerable.rb +4 -3
  12. data/lib/rdf/mixin/mutable.rb +5 -15
  13. data/lib/rdf/mixin/queryable.rb +12 -4
  14. data/lib/rdf/mixin/transactable.rb +2 -2
  15. data/lib/rdf/mixin/writable.rb +9 -14
  16. data/lib/rdf/model/dataset.rb +1 -1
  17. data/lib/rdf/model/graph.rb +7 -4
  18. data/lib/rdf/model/list.rb +5 -5
  19. data/lib/rdf/model/literal.rb +3 -3
  20. data/lib/rdf/model/statement.rb +32 -9
  21. data/lib/rdf/model/uri.rb +53 -32
  22. data/lib/rdf/nquads.rb +6 -6
  23. data/lib/rdf/ntriples.rb +7 -5
  24. data/lib/rdf/ntriples/reader.rb +29 -7
  25. data/lib/rdf/ntriples/writer.rb +10 -1
  26. data/lib/rdf/query.rb +27 -35
  27. data/lib/rdf/query/hash_pattern_normalizer.rb +14 -12
  28. data/lib/rdf/query/pattern.rb +51 -18
  29. data/lib/rdf/query/solution.rb +20 -1
  30. data/lib/rdf/query/solutions.rb +15 -5
  31. data/lib/rdf/query/variable.rb +17 -5
  32. data/lib/rdf/reader.rb +76 -25
  33. data/lib/rdf/repository.rb +32 -18
  34. data/lib/rdf/transaction.rb +1 -1
  35. data/lib/rdf/util.rb +6 -5
  36. data/lib/rdf/util/cache.rb +2 -2
  37. data/lib/rdf/util/coercions.rb +60 -0
  38. data/lib/rdf/util/file.rb +20 -10
  39. data/lib/rdf/util/logger.rb +6 -6
  40. data/lib/rdf/util/uuid.rb +4 -4
  41. data/lib/rdf/vocab/owl.rb +401 -86
  42. data/lib/rdf/vocab/rdfs.rb +81 -18
  43. data/lib/rdf/vocab/rdfv.rb +147 -1
  44. data/lib/rdf/vocab/writer.rb +41 -3
  45. data/lib/rdf/vocab/xsd.rb +203 -2
  46. data/lib/rdf/vocabulary.rb +73 -15
  47. data/lib/rdf/writer.rb +33 -11
  48. metadata +34 -28
data/lib/rdf.rb CHANGED
@@ -6,6 +6,9 @@ require 'time'
6
6
  require 'rdf/version'
7
7
  require 'rdf/extensions'
8
8
 
9
+ # When loading, issue deprecation warning on forthcoming unsupported versions of Ruby
10
+ warn "[DEPRECATION] Ruby 2.4+ required in next version 3.1 of RDF.rb" if RUBY_VERSION < "2.4"
11
+
9
12
  module RDF
10
13
  # RDF mixins
11
14
  autoload :Countable, 'rdf/mixin/countable'
@@ -56,16 +59,18 @@ module RDF
56
59
  # RDF vocabularies
57
60
  autoload :Vocabulary, 'rdf/vocabulary'
58
61
  autoload :StrictVocabulary, 'rdf/vocabulary'
59
- VOCABS = Dir.glob(File.expand_path("../rdf/vocab/*.rb", __FILE__)).map { |f| File.basename(f)[0...-(File.extname(f).size)].to_sym } rescue []
60
62
 
61
- # Use const_missing instead of autoload to load most vocabularies so we can provide deprecation messages
62
- def self.const_missing(constant)
63
- if VOCABS.include?(constant.to_s.downcase.to_sym)
64
- require "rdf/vocab/#{constant.to_s.downcase}"
65
- const_get(constant)
66
- else
67
- super
68
- end
63
+ VOCABS = {
64
+ owl: {uri: "http://www.w3.org/2002/07/owl#", class_name: "OWL"},
65
+ rdfs: {uri: "http://www.w3.org/2000/01/rdf-schema#", class_name: "RDFS"},
66
+ rdfv: {uri: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", class_name: "RDFV"},
67
+ xsd: {uri: "http://www.w3.org/2001/XMLSchema#", class_name: "XSD"},
68
+ }
69
+
70
+ # Autoload vocabularies
71
+ VOCABS.each do |id, params|
72
+ v = (params[:class_name] ||= id.to_s.upcase).to_sym
73
+ autoload v, File.expand_path("../rdf/vocab/#{id}", __FILE__)
69
74
  end
70
75
 
71
76
  # Utilities
@@ -76,8 +81,8 @@ module RDF
76
81
  #
77
82
  # @param (see RDF::Resource#initialize)
78
83
  # @return [RDF::Resource]
79
- def self.Resource(*args, &block)
80
- Resource.new(*args, &block)
84
+ def self.Resource(*args)
85
+ Resource.new(*args)
81
86
  end
82
87
 
83
88
  ##
@@ -85,8 +90,8 @@ module RDF
85
90
  #
86
91
  # @param (see RDF::Node#initialize)
87
92
  # @return [RDF::Node]
88
- def self.Node(*args, &block)
89
- Node.new(*args, &block)
93
+ def self.Node(*args)
94
+ Node.new(*args)
90
95
  end
91
96
 
92
97
  ##
@@ -94,8 +99,15 @@ module RDF
94
99
  #
95
100
  # @param (see RDF::URI#initialize)
96
101
  # @return [RDF::URI]
97
- def self.URI(uri, *args, &block)
98
- uri.respond_to?(:to_uri) ? uri.to_uri : URI.new(uri, *args, &block)
102
+ def self.URI(*args)
103
+ if args.first.respond_to?(:to_uri)
104
+ args.first.to_uri
105
+ elsif args.first.is_a?(Hash)
106
+ URI.new(**args.first)
107
+ else
108
+ opts = args.last.is_a?(Hash) ? args.pop : {}
109
+ URI.new(*args, **opts)
110
+ end
99
111
  end
100
112
 
101
113
  ##
@@ -103,10 +115,10 @@ module RDF
103
115
  #
104
116
  # @param (see RDF::Literal#initialize)
105
117
  # @return [RDF::Literal]
106
- def self.Literal(literal, *args, &block)
118
+ def self.Literal(literal, **options)
107
119
  case literal
108
120
  when RDF::Literal then literal
109
- else Literal.new(literal, *args, &block)
121
+ else Literal.new(literal, **options)
110
122
  end
111
123
  end
112
124
 
@@ -116,7 +128,7 @@ module RDF
116
128
  # @param (see RDF::Graph#initialize)
117
129
  # @return [RDF::Graph]
118
130
  def self.Graph(**options, &block)
119
- Graph.new(options, &block)
131
+ Graph.new(**options, &block)
120
132
  end
121
133
 
122
134
  ##
@@ -168,11 +180,11 @@ module RDF
168
180
  # @option options [RDF::Resource] :graph_name (nil)
169
181
  # @return [RDF::Statement]
170
182
  #
171
- def self.Statement(*args)
172
- if args.empty?
183
+ def self.Statement(*args, **options)
184
+ if args.empty? && options.empty?
173
185
  RDF[:Statement]
174
186
  else
175
- Statement.new(*args)
187
+ Statement.new(*args, **options)
176
188
  end
177
189
  end
178
190
 
@@ -190,8 +202,8 @@ module RDF
190
202
  #
191
203
  # @param (see RDF::Vocabulary#initialize)
192
204
  # @return [Class]
193
- def self.StrictVocabulary(prefix)
194
- StrictVocabulary.create(prefix)
205
+ def self.StrictVocabulary(uri)
206
+ StrictVocabulary.create(uri)
195
207
  end
196
208
 
197
209
  ##
@@ -31,10 +31,11 @@ module RDF
31
31
  #
32
32
  # @since 2.0.0
33
33
  class Changeset
34
- include RDF::Mutable
34
+ # include RDF::Mutable
35
+ include RDF::Util::Coercions
35
36
 
36
37
  ##
37
- # Applies a changeset to the given mutable RDF::Enumerable .
38
+ # Applies a changeset to the given {RDF::Mutable} object.
38
39
  #
39
40
  # @param [RDF::Mutable] mutable
40
41
  # @param [Hash{Symbol => Object}] options
@@ -42,7 +43,7 @@ module RDF
42
43
  # @yieldparam [RDF::Changeset] changes
43
44
  # @return [void]
44
45
  def self.apply(mutable, **options, &block)
45
- self.new(&block).apply(mutable, options)
46
+ self.new(&block).apply(mutable, **options)
46
47
  end
47
48
 
48
49
  ##
@@ -98,6 +99,24 @@ module RDF
98
99
  false
99
100
  end
100
101
 
102
+ ##
103
+ # Returns `false` as changesets are not {RDF::Writable}.
104
+ #
105
+ # @return [Boolean]
106
+ # @see RDF::Writable#writable?
107
+ def writable?
108
+ false
109
+ end
110
+
111
+ ##
112
+ # Returns `false` as changesets are not {RDF::Mutable}.
113
+ #
114
+ # @return [Boolean]
115
+ # @see RDF::Mutable#mutable?
116
+ def mutable?
117
+ false
118
+ end
119
+
101
120
  ##
102
121
  # Applies this changeset to the given mutable RDF::Enumerable.
103
122
  #
@@ -127,35 +146,77 @@ module RDF
127
146
 
128
147
  ##
129
148
  # Outputs a developer-friendly representation of this changeset to
130
- # `stderr`.
149
+ # `$stderr`.
131
150
  #
132
151
  # @return [void]
133
152
  def inspect!
134
153
  $stderr.puts(self.inspect)
135
154
  end
136
155
 
137
- protected
138
-
139
156
  ##
140
- # Appends an RDF statement to the sequence to insert when applied.
157
+ # Returns the sum of both the `inserts` and `deletes` counts.
141
158
  #
142
- # @param [RDF::Statement] statement
143
- # @return [void]
144
- # @see RDF::Writable#insert_statement
145
- def insert_statement(statement)
146
- self.inserts << statement
159
+ # @return [Integer]
160
+ def count
161
+ inserts.count + deletes.count
147
162
  end
148
163
 
164
+ # Append statements to `inserts`. Statements _should_ be constant
165
+ # as variable statements will at best be ignored or at worst raise
166
+ # an error when applied.
167
+ #
168
+ # @param statements [Enumerable, RDF::Statement] Some statements
169
+ # @return [self]
170
+ def insert(*statements)
171
+ coerce_statements(statements) do |stmts|
172
+ append_statements :inserts, stmts
173
+ end
174
+
175
+ self
176
+ end
177
+ alias_method :insert!, :insert
178
+ alias_method :<<, :insert
179
+
180
+ # Append statements to `deletes`. Statements _may_ contain
181
+ # variables, although support will depend on the {RDF::Mutable}
182
+ # target.
183
+ #
184
+ # @param statements [Enumerable, RDF::Statement] Some statements
185
+ # @return [self]
186
+ def delete(*statements)
187
+ coerce_statements(statements) do |stmts|
188
+ append_statements :deletes, stmts
189
+ end
190
+
191
+ self
192
+ end
193
+ alias_method :delete!, :delete
194
+ alias_method :>>, :delete
195
+
196
+ private
197
+
149
198
  ##
150
- # Appends an RDF statement to the sequence to delete when applied.
199
+ # Append statements to the appropriate target. This is a little
200
+ # shim to go in between the other shim and the target.
151
201
  #
152
- # @param [RDF::Statement] statement
153
- # @return [void]
154
- # @see RDF::Mutable#delete_statement
155
- def delete_statement(statement)
156
- self.deletes << statement
202
+ # @param target [Symbol] the method to send
203
+ # @param arg [Enumerable, RDF::Statement]
204
+ #
205
+ def append_statements(target, arg)
206
+ # coerce to an enumerator
207
+ stmts = case
208
+ when arg.is_a?(RDF::Statement)
209
+ [arg]
210
+ when arg.respond_to?(:each_statement)
211
+ arg.each_statement
212
+ when arg.respond_to?(:each)
213
+ arg
214
+ else
215
+ raise ArgumentError, "Invalid statement: #{arg.class}"
216
+ end
217
+
218
+ stmts.each { |s| send(target) << s }
157
219
  end
158
220
 
159
- undef_method :load, :update, :clear
160
221
  end # Changeset
161
222
  end # RDF
@@ -175,7 +175,7 @@ module RDF
175
175
  unless repository.count > 0
176
176
  start = Time.new
177
177
  count = 0
178
- self.parse(argv, opts) do |reader|
178
+ self.parse(argv, **opts) do |reader|
179
179
  reader.each_statement do |statement|
180
180
  count += 1
181
181
  end
@@ -240,7 +240,7 @@ module RDF
240
240
  out = opts[:output]
241
241
  opts = opts.merge(prefixes: {})
242
242
  writer_opts = opts.merge(standard_prefixes: true)
243
- writer_class.new(out, writer_opts) do |writer|
243
+ writer_class.new(out, **writer_opts) do |writer|
244
244
  writer << repository
245
245
  end
246
246
  end
@@ -262,7 +262,7 @@ module RDF
262
262
  description: "Validate parsed input",
263
263
  control: :none,
264
264
  parse: true,
265
- help: "validate [options] [args...]\nvalidates parsed input (may also be used with --validate)",
265
+ help: "validate [options] [args...]\nvalidates resulting repository (may also be used with --validate to check for parse-time errors)",
266
266
  lambda: ->(argv, opts) do
267
267
  opts[:output].puts "Input is " + (repository.valid? ? "" : "in") + "valid"
268
268
  end,
@@ -501,7 +501,7 @@ module RDF
501
501
  if cmds.any? {|c| COMMANDS[c.to_sym][:parse]}
502
502
  start = Time.new
503
503
  count = 0
504
- self.parse(args, options) do |reader|
504
+ self.parse(args, **options) do |reader|
505
505
  @repository << reader
506
506
  end
507
507
  secs = Time.new - start
@@ -575,7 +575,7 @@ module RDF
575
575
  RDF::Format.each do |format|
576
576
  format.cli_commands.each do |command, options|
577
577
  options = {lambda: options} unless options.is_a?(Hash)
578
- add_command(command, options)
578
+ add_command(command, **options)
579
579
  end
580
580
  end
581
581
  @commands_loaded = true
@@ -637,13 +637,13 @@ module RDF
637
637
  r = RDF::Reader.for(format|| {sample: sample})
638
638
  raise ArgumentError, "Unknown format for evaluated input" unless r
639
639
  (@readers ||= []) << r
640
- r.new(input, options) do |reader|
640
+ r.new(input, **options) do |reader|
641
641
  yield(reader)
642
642
  end
643
643
  else
644
644
  options[:format] = format if format
645
645
  files.each do |file|
646
- RDF::Reader.open(file, options) do |reader|
646
+ RDF::Reader.open(file, **options) do |reader|
647
647
  (@readers ||= []) << reader.class.to_s
648
648
  yield(reader)
649
649
  end
@@ -122,7 +122,7 @@ module RDF
122
122
  sample = case sample
123
123
  when Proc then sample.call.to_s
124
124
  else sample.dup.to_s
125
- end.force_encoding(Encoding::ASCII_8BIT)
125
+ end.dup.force_encoding(Encoding::ASCII_8BIT)
126
126
  # Given a sample, perform format detection across the appropriate formats, choosing the last that matches
127
127
  # Return last format that has a positive detection
128
128
  formats = formats.select {|f| f.detect(sample)}
@@ -145,10 +145,10 @@ module RDF
145
145
  # @param [String, RDF::URI] filename
146
146
  # @return [Class]
147
147
  #
148
- # @overload for(**options)
148
+ # @overload for(options)
149
149
  # Finds an RDF serialization format class based on various options.
150
150
  #
151
- # @param [Hash{Symbol => Object}] options
151
+ # @param [Hash{Symbol => Object}] options ({})
152
152
  # @option options [String, #to_s] :file_name (nil)
153
153
  # @option options [Symbol, #to_sym] :file_extension (nil)
154
154
  # @option options [String, #to_s] :content_type (nil)
@@ -164,19 +164,26 @@ module RDF
164
164
  # @yieldreturn [String] another way to provide a sample, allows lazy for retrieving the sample.
165
165
  #
166
166
  # @return [Class]
167
- def self.for(*args, **options, &block)
167
+ def self.for(*arg, &block)
168
+ case arg.length
169
+ when 0 then arg = nil
170
+ when 1 then arg = arg.first
171
+ else
172
+ raise ArgumentError, "Format.for accepts zero or one argument, got #{arg.length}."
173
+ end
174
+
175
+ options = arg.is_a?(Hash) ? arg : {}
168
176
  options = {sample: block}.merge(options) if block_given?
169
- formats = case args.first
177
+ formats = case arg
170
178
  when String, RDF::URI
171
179
  # Find a format based on the file name
172
- self.each(file_name: args.first, **options).to_a
180
+ self.each(file_name: arg, **options).to_a
173
181
  when Symbol
174
182
  # Try to find a match based on the full class name
175
183
  # We want this to work even if autoloading fails
176
- fmt = args.first
177
- classes = self.each(options).select {|f| f.symbols.include?(fmt)}
184
+ classes = self.each(**options).select {|f| f.symbols.include?(arg)}
178
185
  if classes.empty?
179
- classes = case fmt
186
+ classes = case arg
180
187
  when :ntriples then [RDF::NTriples::Format]
181
188
  when :nquads then [RDF::NQuads::Format]
182
189
  else []
@@ -184,7 +191,7 @@ module RDF
184
191
  end
185
192
  classes
186
193
  else
187
- self.each(options.merge(all_if_none: false)).to_a
194
+ self.each(**options.merge(all_if_none: false)).to_a
188
195
  end
189
196
 
190
197
  # Return the last detected format
@@ -17,7 +17,7 @@ module RDF
17
17
  # enumerable.has_quad?([subject, predicate, object, graph_name])
18
18
  #
19
19
  # @example Checking whether a specific value exists
20
- # enumerable.has_subject?(RDF::URI("http://rubygems.org/gems/rdf"))
20
+ # enumerable.has_subject?(RDF::URI("https://rubygems.org/gems/rdf"))
21
21
  # enumerable.has_predicate?(RDF::RDFS.label)
22
22
  # enumerable.has_object?(RDF::Literal("A Ruby library for working with Resource Description Framework (RDF) data.", language: :en))
23
23
  # enumerable.has_graph?(RDF::URI("http://ar.to/#self"))
@@ -71,6 +71,7 @@ module RDF
71
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`.
72
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.
73
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.
74
+ # * `:rdfstar` supports RDF* where statements may be subjects or objects of other statements.
74
75
  #
75
76
  # @param [Symbol, #to_sym] feature
76
77
  # @return [Boolean]
@@ -220,7 +221,7 @@ module RDF
220
221
  def each_triple
221
222
  if block_given?
222
223
  each_statement do |statement|
223
- yield *statement.to_triple
224
+ yield(*statement.to_triple)
224
225
  end
225
226
  end
226
227
  enum_triple
@@ -282,7 +283,7 @@ module RDF
282
283
  def each_quad
283
284
  if block_given?
284
285
  each_statement do |statement|
285
- yield *statement.to_quad
286
+ yield(*statement.to_quad)
286
287
  end
287
288
  end
288
289
  enum_quad
@@ -9,6 +9,7 @@ module RDF
9
9
  extend RDF::Util::Aliasing::LateBound
10
10
  include RDF::Readable
11
11
  include RDF::Writable
12
+ include RDF::Util::Coercions
12
13
 
13
14
  ##
14
15
  # Returns `true` if `self` is mutable.
@@ -37,10 +38,10 @@ module RDF
37
38
  # @option options [RDF::Resource] :graph_name
38
39
  # Set set graph name of each loaded statement
39
40
  # @return [void]
40
- def load(url, graph_name: nil, **options)
41
+ def load(url, graph_name: nil, **options)
41
42
  raise TypeError.new("#{self} is immutable") if immutable?
42
43
 
43
- Reader.open(url, {base_uri: url}.merge(options)) do |reader|
44
+ Reader.open(url, base_uri: url, **options) do |reader|
44
45
  if graph_name
45
46
  statements = []
46
47
  reader.each_statement do |statement|
@@ -154,20 +155,9 @@ module RDF
154
155
  def delete(*statements)
155
156
  raise TypeError.new("#{self} is immutable") if immutable?
156
157
 
157
- statements.map! do |value|
158
- case
159
- when value.respond_to?(:each_statement)
160
- delete_statements(value)
161
- nil
162
- when (statement = Statement.from(value)).constant?
163
- statement
164
- else
165
- delete_statements(query(value))
166
- nil
167
- end
158
+ coerce_statements(statements, query: true, constant: true) do |value|
159
+ delete_statements(value)
168
160
  end
169
- statements.compact!
170
- delete_statements(statements) unless statements.empty?
171
161
 
172
162
  return self
173
163
  end