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
@@ -7,6 +7,10 @@ module RDF
7
7
  include Queryable
8
8
  include Enumerable
9
9
 
10
+ def method_missing(method, *args)
11
+ self.to_a if method.to_sym == :to_ary
12
+ end
13
+
10
14
  # Make sure returned arrays are also queryable
11
15
  def to_a
12
16
  return super.to_a.extend(RDF::Queryable, RDF::Enumerable)
@@ -27,6 +31,10 @@ module RDF
27
31
  include Queryable
28
32
  include Enumerable
29
33
 
34
+ def method_missing(method, *args)
35
+ self.to_a if method.to_sym == :to_ary
36
+ end
37
+
30
38
  # Make sure returned arrays are also queryable
31
39
  def to_a
32
40
  return super.to_a.extend(RDF::Queryable, RDF::Enumerable)
@@ -18,7 +18,7 @@ module RDF
18
18
  # Indexes `self`.
19
19
  #
20
20
  # @abstract
21
- # @return [void]
21
+ # @return [self]
22
22
  def index!
23
23
  raise NotImplementedError, "#{self.class}#index!"
24
24
  end
@@ -31,26 +31,20 @@ module RDF
31
31
  ##
32
32
  # Loads RDF statements from the given file or URL into `self`.
33
33
  #
34
- # @param [String, #to_s] filename
34
+ # @param [String, #to_s] url
35
35
  # @param [Hash{Symbol => Object}] options
36
36
  # Options from {RDF::Reader.open}
37
- # @option options [RDF::Resource] :context
38
- # Set set context of each loaded statement. This option is deprecated in RDF.rb 2.0.
39
37
  # @option options [RDF::Resource] :graph_name
40
38
  # Set set graph name of each loaded statement
41
39
  # @return [void]
42
- def load(filename, options = {})
43
- if options.has_key?(:context)
44
- warn "[DEPRECATION] the :contexts option to Mutable#load is deprecated in RDF.rb 2.0, use :graph_name instead. Called from #{Gem.location_of_caller.join(':')}"
45
- options[:graph_name] ||= options.delete(:context)
46
- end
40
+ def load(url, graph_name: nil, **options)
47
41
  raise TypeError.new("#{self} is immutable") if immutable?
48
42
 
49
- Reader.open(filename, {base_uri: filename}.merge(options)) do |reader|
50
- if options[:graph_name]
43
+ Reader.open(url, {base_uri: url}.merge(options)) do |reader|
44
+ if graph_name
51
45
  statements = []
52
46
  reader.each_statement do |statement|
53
- statement.graph_name = options[:graph_name]
47
+ statement.graph_name = graph_name
54
48
  statements << statement
55
49
  end
56
50
  insert_statements(statements)
@@ -80,9 +74,20 @@ module RDF
80
74
  ##
81
75
  # Inserts RDF statements into `self`.
82
76
  #
83
- # @param [Array<RDF::Statement>] statements
84
- # @raise [TypeError] if `self` is immutable
85
- # @return [Mutable]
77
+ # @note using splat argument syntax with excessive arguments provided
78
+ # significantly affects performance. Use Enumerator form for large
79
+ # numbers of statements.
80
+ #
81
+ # @overload insert(*statements)
82
+ # @param [Array<RDF::Statement>] statements
83
+ # @raise [TypeError] if `self` is immutable
84
+ # @return [self]
85
+ #
86
+ # @overload insert(statements)
87
+ # @param [Enumerable<RDF::Statement>] statements
88
+ # @raise [TypeError] if `self` is immutable
89
+ # @return [self]
90
+ #
86
91
  # @see RDF::Writable#insert
87
92
  def insert(*statements)
88
93
  raise TypeError.new("#{self} is immutable") if immutable?
@@ -97,16 +102,30 @@ module RDF
97
102
  # `#delete([subject, predicate, nil])` followed by
98
103
  # `#insert([subject, predicate, object])` unless `object` is `nil`.
99
104
  #
100
- # @param [Enumerable<RDF::Statement>] statements
101
- # @raise [TypeError] if `self` is immutable
102
- # @return [Mutable]
105
+ # @note using splat argument syntax with excessive arguments provided
106
+ # significantly affects performance. Use Enumerator form for large
107
+ # numbers of statements.
108
+ #
109
+ # @overload update(*statements)
110
+ # @param [Array<RDF::Statement>] statements
111
+ # @raise [TypeError] if `self` is immutable
112
+ # @return [self]
113
+ #
114
+ # @overload update(statements)
115
+ # @param [Enumerable<RDF::Statement>] statements
116
+ # @raise [TypeError] if `self` is immutable
117
+ # @return [self]
103
118
  def update(*statements)
104
119
  raise TypeError.new("#{self} is immutable") if immutable?
120
+ statements = statements[0] if statements.length == 1 && statements[0].is_a?(Enumerable)
105
121
 
106
122
  statements.each do |statement|
107
123
  if (statement = Statement.from(statement))
108
- delete([statement.subject, statement.predicate, nil])
109
- insert(statement) if statement.has_object?
124
+ if statement.has_object?
125
+ delete_insert([[statement.subject, statement.predicate, nil]], [statement])
126
+ else
127
+ delete([statement.subject, statement.predicate, nil])
128
+ end
110
129
  end
111
130
  end
112
131
  end
@@ -119,9 +138,19 @@ module RDF
119
138
  # considered to be a pattern, and used to query
120
139
  # self to find matching statements to delete.
121
140
  #
122
- # @param [Enumerable<RDF::Statement>] statements
123
- # @raise [TypeError] if `self` is immutable
124
- # @return [Mutable]
141
+ # @note using splat argument syntax with excessive arguments provided
142
+ # significantly affects performance. Use Enumerator form for large
143
+ # numbers of statements.
144
+ #
145
+ # @overload delete(*statements)
146
+ # @param [Array<RDF::Statement>] statements
147
+ # @raise [TypeError] if `self` is immutable
148
+ # @return [self]
149
+ #
150
+ # @overload delete(statements)
151
+ # @param [Enumerable<RDF::Statement>] statements
152
+ # @raise [TypeError] if `self` is immutable
153
+ # @return [self]
125
154
  def delete(*statements)
126
155
  raise TypeError.new("#{self} is immutable") if immutable?
127
156
 
@@ -145,6 +174,56 @@ module RDF
145
174
 
146
175
  alias_method :delete!, :delete
147
176
 
177
+ ##
178
+ # Performs a set of deletes and inserts as a combined operation.
179
+ #
180
+ # @note in the base implementation, this is equivalent to calling `#delete`
181
+ # and `#insert` sequentially. This method is preferred to take advantage
182
+ # of (e.g.) `RDF::Repositories` that can execute the operation in a single
183
+ # request.
184
+ #
185
+ # @param [Enumerable<RDF::Statement>, Array<RDF::Statement>] deletes
186
+ # @param [Enumerable<RDF::Statement>, Array<RDF::Statement>] inserts
187
+ # @raise [TypeError] if `self` is immutable
188
+ # @return [Mutable] self
189
+ #
190
+ # @see #delete
191
+ # @see #insert
192
+ def delete_insert(deletes, inserts)
193
+ deletes.respond_to?(:each_statement) ? delete(deletes) : delete(*deletes)
194
+ inserts.respond_to?(:each_statement) ? insert(inserts) : insert(*inserts)
195
+
196
+ self
197
+ end
198
+
199
+ alias_method :delete_insert!, :delete_insert
200
+
201
+ ##
202
+ # Applies the given changeset
203
+ #
204
+ # If `#supports?(:atomic_write)` is `true`, this must apply the changeset
205
+ # atomically. Otherwise, it should offer an efficient implementation of a
206
+ # combined delete/insert of the changeset.
207
+ #
208
+ # @param changeset [RDF::Changeset] the changeset to apply
209
+ # @return [Boolean] true if the changeset has been applied
210
+ def apply_changeset(changeset)
211
+ delete_insert(changeset.deletes, changeset.inserts)
212
+ end
213
+
214
+ ##
215
+ # A readable & queryable snapshot of the repository for isolated reads.
216
+ #
217
+ # This method must be implemented when `#supports(:snapshots)` is `true`.
218
+ #
219
+ # @return [Dataset] an immutable Dataset containing a current snapshot of
220
+ # the Repository contents.
221
+ # @raise [NotImplementederror] when snapshots aren't implemented for the
222
+ # class
223
+ def snapshot
224
+ raise NotImplementedError, "#{self.class} does not implement snapshots"
225
+ end
226
+
148
227
  ##
149
228
  # Deletes all RDF statements from `self`.
150
229
  #
@@ -15,8 +15,7 @@ module RDF
15
15
  ##
16
16
  # Queries `self` for RDF statements matching the given `pattern`.
17
17
  #
18
- # This method delegates to the protected {RDF::Queryable#query_pattern} method for the
19
- # actual lower-level query pattern matching implementation.
18
+ # This method delegates to the protected {RDF::Queryable#query_pattern} method for the actual lower-level query pattern matching implementation.
20
19
  #
21
20
  # @example Querying for statements having a given predicate
22
21
  # queryable.query([nil, RDF::Vocab::DOAP.developer, nil])
@@ -38,9 +37,10 @@ module RDF
38
37
  # @yieldparam [RDF::Statement, RDF::Query::Solution] statement
39
38
  # Statement or Solution
40
39
  # @yieldreturn [void] ignored
41
- # @return [Enumerator, Query::Solutions]
42
- # Returns an enumerator over statements or query solutions, if passed an {RDF::Query}
40
+ # @return [Enumerator<RDF::Statement>, RDF::Enumerable, Query::Solutions]
41
+ # Returns an enumerable of statements (may be an enumerator) or query solutions, if passed an {RDF::Query}
43
42
  # @see RDF::Queryable#query_pattern
43
+ # @note Since 2.0, this may return an Enumerable or an Enumerator in addition to Solutions
44
44
  def query(pattern, options = {}, &block)
45
45
  raise TypeError, "#{self} is not readable" if respond_to?(:readable?) && !readable?
46
46
 
@@ -50,11 +50,7 @@ module RDF
50
50
  solutions = RDF::Query::Solutions.new
51
51
  block = lambda {|solution| solutions << solution} unless block_given?
52
52
  before_query(pattern) if respond_to?(:before_query)
53
- if method(:query_execute).arity == 1
54
- query_execute(pattern, &block)
55
- else
56
- query_execute(pattern, options, &block)
57
- end
53
+ query_execute(pattern, options, &block)
58
54
  after_query(pattern) if respond_to?(:after_query)
59
55
  # Returns the solutions, not an enumerator
60
56
  solutions
@@ -62,35 +58,36 @@ module RDF
62
58
  # A simple triple/quad pattern query:
63
59
  else
64
60
  pattern = Query::Pattern.from(pattern)
65
- before_query(pattern) if block_given? && respond_to?(:before_query)
61
+ before_query(pattern) if respond_to?(:before_query)
66
62
  enum = case
67
63
  # Blank triple/quad patterns are equivalent to iterating over
68
64
  # every statement, so as a minor optimization we'll just do that
69
65
  # directly instead of bothering with `#query_pattern`:
70
66
  when pattern.blank?
71
- each(&block) if block_given?
72
- enum_for(:each)
67
+ if block_given?
68
+ each(&block)
69
+ else
70
+ to_a.extend(Queryable)
71
+ end
73
72
 
74
73
  # Constant triple/quad patterns are equivalent to looking up a
75
74
  # particular statement, so as a minor optimization we'll just do
76
75
  # that directly instead of bothering with `#query_pattern`:
77
76
  when pattern.constant?
78
77
  statement = Statement.from(pattern)
79
- block.call(statement) if block_given? && include?(statement)
80
- enum_for(:query, pattern)
81
-
82
- # Otherwise, we delegate to `#query_pattern`:
83
- else # pattern.variable?
84
- if block_given?
85
- if self.method(:query_pattern).arity == 1
86
- query_pattern(pattern, &block)
78
+ if include?(statement)
79
+ if block_given?
80
+ yield statement
87
81
  else
88
- query_pattern(pattern, options, &block)
82
+ [statement]
89
83
  end
90
84
  end
91
- enum_for(:query_pattern, pattern)
85
+
86
+ # Otherwise, we delegate to `#query_pattern`:
87
+ else # pattern.variable?
88
+ query_pattern(pattern, options, &block)
92
89
  end
93
- after_query(pattern) if block_given? && respond_to?(:after_query)
90
+ after_query(pattern) if respond_to?(:after_query)
94
91
  enum
95
92
  end
96
93
  end
@@ -193,8 +190,6 @@ module RDF
193
190
  # @overload first_subject(pattern)
194
191
  # @param [RDF::Query, RDF::Statement, Array(RDF::Term), Hash] pattern
195
192
  # @return [RDF::Resource]
196
- #
197
- # @return [RDF::Resource]
198
193
  # @since 0.1.9
199
194
  def first_subject(pattern = nil)
200
195
  __send__(*(pattern ? [:query, pattern] : [:each])) do |statement|
@@ -215,8 +210,6 @@ module RDF
215
210
  # @overload first_predicate(pattern)
216
211
  # @param [RDF::Query, RDF::Statement, Array(RDF::Term), Hash] pattern
217
212
  # @return [RDF::URI]
218
- #
219
- # @return [RDF::URI]
220
213
  # @since 0.1.9
221
214
  def first_predicate(pattern = nil)
222
215
  __send__(*(pattern ? [:query, pattern] : [:each])) do |statement|
@@ -237,8 +230,6 @@ module RDF
237
230
  # @overload first_object(pattern)
238
231
  # @param [RDF::Query, RDF::Statement, Array(RDF::Term), Hash] pattern
239
232
  # @return [RDF::Term]
240
- #
241
- # @return [RDF::Term]
242
233
  # @since 0.1.9
243
234
  def first_object(pattern = nil)
244
235
  __send__(*(pattern ? [:query, pattern] : [:each])) do |statement|
@@ -283,8 +274,6 @@ module RDF
283
274
  # @overload first_value(pattern)
284
275
  # @param [RDF::Query, RDF::Statement, Array(RDF::Term), Hash] pattern
285
276
  # @return [Object]
286
- #
287
- # @return [Object]
288
277
  # @since 0.1.9
289
278
  def first_value(pattern = nil)
290
279
  (literal = first_literal(pattern)) ? literal.value : nil
@@ -293,7 +282,7 @@ module RDF
293
282
  ##
294
283
  # @private
295
284
  # @param [Symbol, #to_sym] method
296
- # @return [Enumerator]
285
+ # @return [Enumerator<RDF::Statement, RDF::Query::Pattern>]
297
286
  # @see Object#enum_for
298
287
  def enum_for(method = :each, *args)
299
288
  # Ensure that enumerators are, themselves, queryable
@@ -0,0 +1,94 @@
1
+ module RDF
2
+ ##
3
+ # A transaction application mixin.
4
+ #
5
+ # Classes that include this module must provide a `#begin_transaction` method
6
+ # returning an {RDF::Transaction}.
7
+ #
8
+ # @example running a read/write transaction with block syntax
9
+ # repository = RDF::Repository.new # or other transactable
10
+ #
11
+ # repository.transaction(mutable: true) do |tx|
12
+ # tx.insert [:node, RDF.type, RDF::OWL.Thing]
13
+ # # ...
14
+ # end
15
+ #
16
+ # @see RDF::Transaction
17
+ # @since 2.0.0
18
+ module Transactable
19
+ ##
20
+ # Executes the given block in a transaction.
21
+ #
22
+ # @example running a transaction
23
+ # repository.transaction do |tx|
24
+ # tx.insert [RDF::URI("http://rubygems.org/gems/rdf"), RDF::RDFS.label, "RDF.rb"]
25
+ # end
26
+ #
27
+ # Raising an error within the transaction block causes automatic rollback.
28
+ #
29
+ # @param mutable [Boolean]
30
+ # allows changes to the transaction, otherwise it is a read-only snapshot of the underlying repository.
31
+ # @yield [tx]
32
+ # @yieldparam [RDF::Transaction] tx
33
+ # @yieldreturn [void] ignored
34
+ # @return [self]
35
+ # @see RDF::Transaction
36
+ # @since 0.3.0
37
+ def transaction(mutable: false, &block)
38
+ tx = begin_transaction(mutable: mutable)
39
+ begin
40
+ case block.arity
41
+ when 1 then block.call(tx)
42
+ else tx.instance_eval(&block)
43
+ end
44
+ rescue => error
45
+ rollback_transaction(tx)
46
+ raise error
47
+ end
48
+ commit_transaction(tx)
49
+ self
50
+ end
51
+ alias_method :transact, :transaction
52
+
53
+ protected
54
+
55
+ ##
56
+ # Begins a new transaction.
57
+ #
58
+ # Subclasses implementing transaction-capable storage adapters may wish
59
+ # to override this method in order to begin a transaction against the
60
+ # underlying storage.
61
+ #
62
+ # @param mutable [Boolean] Create a mutable or immutable transaction.
63
+ # @param graph_name [Boolean] A default graph name for statements inserted
64
+ # or deleted (default: nil)
65
+ # @return [RDF::Transaction]
66
+ def begin_transaction(mutable: false, graph_name: nil)
67
+ raise NotImplementedError
68
+ end
69
+
70
+ ##
71
+ # Rolls back the given transaction.
72
+ #
73
+ # @param [RDF::Transaction] tx
74
+ # @return [void] ignored
75
+ # @since 0.3.0
76
+ def rollback_transaction(tx)
77
+ tx.rollback
78
+ end
79
+
80
+ ##
81
+ # Commits the given transaction.
82
+ #
83
+ # Subclasses implementing transaction-capable storage adapters may wish
84
+ # to override this method in order to commit the given transaction to
85
+ # the underlying storage.
86
+ #
87
+ # @param [RDF::Transaction] tx
88
+ # @return [void] ignored
89
+ # @since 0.3.0
90
+ def commit_transaction(tx)
91
+ tx.execute
92
+ end
93
+ end
94
+ end
@@ -21,7 +21,7 @@ module RDF
21
21
  # Inserts RDF data into `self`.
22
22
  #
23
23
  # @param [RDF::Enumerable, RDF::Statement, #to_rdf] data
24
- # @return [RDF::Writable] `self`
24
+ # @return [self]
25
25
  def <<(data)
26
26
  case data
27
27
  when RDF::Reader
@@ -46,8 +46,17 @@ module RDF
46
46
  ##
47
47
  # Inserts RDF statements into `self`.
48
48
  #
49
- # @param [Array<RDF::Statement>] statements
50
- # @return [RDF::Writable] `self`
49
+ # @note using splat argument syntax with excessive arguments provided
50
+ # significantly affects performance. Use Enumerator form for large
51
+ # numbers of statements.
52
+ #
53
+ # @overload insert(*statements)
54
+ # @param [Array<RDF::Statement>] statements
55
+ # @return [self]
56
+ #
57
+ # @overload insert(statements)
58
+ # @param [Enumerable<RDF::Statement>] statements
59
+ # @return [self]
51
60
  def insert(*statements)
52
61
  statements.map! do |value|
53
62
  case