rdf 2.1.0 → 2.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2751c96a0ba8f1a51fe00c0b58f3ce4a7f11391c
4
- data.tar.gz: 47e64925efb02489826099373e75215d81c06f59
3
+ metadata.gz: 27bb98ac53c34487b7b019cec8348e4d1c1b0248
4
+ data.tar.gz: 02531a71cfeae374e921994416c23be579147b25
5
5
  SHA512:
6
- metadata.gz: e4b2cab8b9e984b9b9c2895a3c283523f039e31fc95cb75d7dee81f63baf6a419c45153f8143f61b9f34c11ea9b0e47cdb82f887ce8bfea58f47ff7d273c0696
7
- data.tar.gz: '09b142a596e81f4a38e345fde610d0f9ff7b22060540ede70045213693e2e2fc43ec15d7014595bced01e6e8ff86767b215f71be7241f3a37c4728df2b231fda'
6
+ metadata.gz: d50dc7d520c49ec465bbc83c6d0a0df1348a921e77b0c1df19ab6286a14598a5a11bf1ff5460a753f851411df6d2e743bbc092e3b93cef2ed7784e09b96db46e
7
+ data.tar.gz: 44d24ae43fc15dcfff3421c8a86e3a8cc6a4878f74b18077e30791d2284ccf99ce6a2556febce3dc94c0d1c5a220812da235e17f6c7ae27648195c1f630709e9
data/README.md CHANGED
@@ -11,7 +11,6 @@ This is a pure-Ruby library for working with [Resource Description Framework
11
11
 
12
12
  [![Gem Version](https://badge.fury.io/rb/rdf.png)](http://badge.fury.io/rb/rdf)
13
13
  [![Build Status](https://travis-ci.org/ruby-rdf/rdf.png?branch=master)](http://travis-ci.org/ruby-rdf/rdf)
14
- [![Code Climate](https://codeclimate.com/github/ruby-rdf/rdf/badges/gpa.svg)](https://codeclimate.com/github/ruby-rdf/rdf)
15
14
  [![Coverage Status](https://coveralls.io/repos/ruby-rdf/rdf/badge.svg)](https://coveralls.io/r/ruby-rdf/rdf)
16
15
  [![Join the chat at https://gitter.im/ruby-rdf/rdf](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ruby-rdf/rdf?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
17
16
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.0
1
+ 2.1.1
data/lib/rdf.rb CHANGED
@@ -206,6 +206,20 @@ module RDF
206
206
  property.to_s =~ %r{_\d+} ? RDF::URI("#{to_uri}#{property}") : RDF::RDFV[property]
207
207
  end
208
208
 
209
+ ##
210
+ # Return an enumerator over {RDF::Statement} defined for this vocabulary.
211
+ # @return [RDF::Enumerable::Enumerator]
212
+ # @see Object#enum_for
213
+ def self.enum_for(method = :each_statement, *args)
214
+ # Ensure that enumerators are, themselves, queryable
215
+ Enumerable::Enumerator.new do |yielder|
216
+ RDF::RDFV.send(method, *args) {|*y| yielder << (y.length > 1 ? y : y.first)}
217
+ end
218
+ end
219
+ class << self
220
+ alias_method :to_enum, :enum_for
221
+ end
222
+
209
223
  ##
210
224
  # respond to module or RDFV
211
225
  def self.respond_to?(method, include_all = false)
@@ -439,7 +439,9 @@ module RDF
439
439
  # If files are empty, either use options[:execute]
440
440
  input = options[:evaluate] ? StringIO.new(options[:evaluate]) : $stdin
441
441
  input.set_encoding(options.fetch(:encoding, Encoding::UTF_8))
442
- RDF::Reader.for(options[:format] || :ntriples).new(input, options) do |reader|
442
+ r = RDF::Reader.for(options[:format] || :ntriples)
443
+ (@readers ||= []) << r
444
+ r.new(input, options) do |reader|
443
445
  yield(reader)
444
446
  end
445
447
  else
@@ -207,6 +207,19 @@ module RDF
207
207
  reader_symbols.flat_map {|s| RDF::Format.for(s).content_type}.uniq
208
208
  end
209
209
 
210
+ ##
211
+ # Returns the set of content types with quality for available RDF::Reader subclasses.
212
+ #
213
+ # @example
214
+ #
215
+ # accept_types = RDF::Format.accept_types
216
+ # # => %w(text/html;q=0.5 text/turtle ...)
217
+ #
218
+ # @return [Array<String>]
219
+ def self.accept_types
220
+ reader_symbols.flat_map {|s| RDF::Format.for(s).accept_type}.uniq
221
+ end
222
+
210
223
  ##
211
224
  # Returns the set of format symbols for available RDF::Writer subclasses.
212
225
  #
@@ -400,6 +413,11 @@ module RDF
400
413
  # extensions, that should be mapped to the given MIME type and handled
401
414
  # by this class.
402
415
  #
416
+ # Optionally, both `type`, `alias`, and `aliases`, may be parameterized
417
+ # for expressing quality.
418
+ #
419
+ # content_type "text/html;q=0.4"
420
+ #
403
421
  # @param [String] type
404
422
  # @param [Hash{Symbol => Object}] options
405
423
  # @option options [String] :alias (nil)
@@ -420,10 +438,14 @@ module RDF
420
438
  [@@content_type[self], @@content_types.map {
421
439
  |ct, cl| (cl.include?(self) && ct != @@content_type[self]) ? ct : nil }].flatten.compact
422
440
  else
441
+ accept_type, type = type, type.split(';').first
423
442
  @@content_type[self] = type
424
443
  @@content_types[type] ||= []
425
444
  @@content_types[type] << self unless @@content_types[type].include?(self)
426
445
 
446
+ @@accept_types[accept_type] ||= []
447
+ @@accept_types[accept_type] << self unless @@accept_types[accept_type].include?(self)
448
+
427
449
  if extensions = (options[:extension] || options[:extensions])
428
450
  extensions = Array(extensions).map(&:to_sym)
429
451
  extensions.each do |ext|
@@ -433,13 +455,26 @@ module RDF
433
455
  end
434
456
  if aliases = (options[:alias] || options[:aliases])
435
457
  aliases = Array(aliases).each do |a|
436
- @@content_types[a] ||= []
437
- @@content_types[a] << self unless @@content_types[a].include?(self)
458
+ aa = a.split(';').first
459
+ @@accept_types[a] ||= []
460
+ @@accept_types[a] << self unless @@accept_types[a].include?(self)
461
+
462
+ @@content_types[aa] ||= []
463
+ @@content_types[aa] << self unless @@content_types[aa].include?(self)
438
464
  end
439
465
  end
440
466
  end
441
467
  end
442
468
 
469
+ ##
470
+ # Returns an array of values appropriate for an Accept header.
471
+ # Same as `self.content_type`, if no parameter is given when defined.
472
+ #
473
+ # @return [Array<String>]
474
+ def self.accept_type
475
+ @@accept_types.map {|t, formats| t if formats.include?(self)}.compact
476
+ end
477
+
443
478
  ##
444
479
  # Retrieves or defines file extensions for this RDF serialization format.
445
480
  #
@@ -488,6 +523,7 @@ module RDF
488
523
  @@content_type = {} # @private
489
524
  @@content_types = {} # @private
490
525
  @@content_encoding = {} # @private
526
+ @@accept_types = {} # @private
491
527
  @@readers = {} # @private
492
528
  @@writers = {} # @private
493
529
  @@subclasses = [] # @private
@@ -7,14 +7,11 @@ 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
-
14
10
  # Make sure returned arrays are also queryable
15
11
  def to_a
16
12
  return super.to_a.extend(RDF::Queryable, RDF::Enumerable)
17
13
  end
14
+ alias_method :to_ary, :to_a
18
15
  end
19
16
  end
20
17
 
@@ -2,22 +2,83 @@ module RDF
2
2
  ##
3
3
  # An RDF Dataset
4
4
  #
5
- # Datasets are immutable by default. {RDF::Repository} provides an interface
5
+ # Datasets are immutable by default. {RDF::Repository} provides an interface
6
6
  # for mutable Datasets.
7
- #
7
+ #
8
+ # A Dataset functions as an a set of named RDF graphs with a default graph.
9
+ # It implements {RDF::Enumerable} and {RDF::Queryable} over the whole set;
10
+ # if no specific graph name is queried, enumerating and querying takes place
11
+ # over the intersection of all the graphs in the Dataset.
12
+ #
13
+ # The default graph is named with a constant `DEFAULT_GRAPH`.
14
+ #
15
+ # @example initializing an RDF::Dataset with existing data
16
+ # statements = [RDF::Statement.new(RDF::URI(:s), RDF::URI(:p), :o)]
17
+ # dataset = RDF::Dataset.new(statements: statements)
18
+ # dataset.count # => 1
19
+ #
8
20
  # @see https://www.w3.org/TR/rdf11-concepts/#section-dataset
9
21
  # @see https://www.w3.org/TR/rdf11-datasets/
10
22
  class Dataset
11
- include RDF::Countable
12
23
  include RDF::Enumerable
13
24
  include RDF::Durable
14
25
  include RDF::Queryable
15
26
 
16
- ISOLATION_LEVELS = [ :read_uncommitted,
17
- :read_committed,
18
- :repeatable_read,
19
- :snapshot,
20
- :serializable].freeze
27
+ DEFAULT_GRAPH = false
28
+
29
+ ISOLATION_LEVELS = [ :read_uncommitted,
30
+ :read_committed,
31
+ :repeatable_read,
32
+ :snapshot,
33
+ :serializable ].freeze
34
+
35
+ ##
36
+ # @param [RDF::Enumerable, Array<RDF::Statement>] statements the initial
37
+ # contents of the dataset
38
+ # @yield [dataset] yields itself when a block is given
39
+ # @yieldparam [RDF::Dataset] dataset
40
+ def initialize(statements: [], **options, &block)
41
+ @statements = statements.map do |s|
42
+ s = s.dup
43
+ s.graph_name ||= DEFAULT_GRAPH
44
+ s.freeze
45
+ end.freeze
46
+
47
+ if block_given?
48
+ case block.arity
49
+ when 1 then yield self
50
+ else instance_eval(&block)
51
+ end
52
+ end
53
+ end
54
+
55
+ ##
56
+ # @private
57
+ # @see RDF::Durable#durable?
58
+ def durable?
59
+ false
60
+ end
61
+
62
+ ##
63
+ # @private
64
+ # @see RDF::Enumerable#each_statement
65
+ def each_statement
66
+ if block_given?
67
+ @statements.each do |st|
68
+ if st.graph_name.equal?(DEFAULT_GRAPH)
69
+ st = st.dup
70
+ st.graph_name = nil
71
+ end
72
+
73
+ yield st
74
+ end
75
+
76
+ self
77
+ end
78
+
79
+ enum_statement
80
+ end
81
+ alias_method :each, :each_statement
21
82
 
22
83
  ##
23
84
  # Returns a developer-friendly representation of this object.
@@ -36,13 +97,42 @@ module RDF
36
97
  each_statement { |statement| statement.inspect! }
37
98
  nil
38
99
  end
39
-
100
+
40
101
  ##
41
102
  # @return [Symbol] a representation of the isolation level for reads of this
42
- # Dataset. One of `:read_uncommitted`, `:read_committed`, `:repeatable_read`,
103
+ # Dataset. One of `:read_uncommitted`, `:read_committed`, `:repeatable_read`,
43
104
  # `:snapshot`, or `:serializable`.
44
105
  def isolation_level
45
106
  :read_committed
46
107
  end
108
+
109
+ ##
110
+ # @private
111
+ # @see RDF::Enumerable#supports?
112
+ def supports?(feature)
113
+ return true if feature == :graph_name
114
+ super
115
+ end
116
+
117
+ protected
118
+
119
+ ##
120
+ # Implements basic query pattern matching over the Dataset, with handling
121
+ # for a default graph.
122
+ def query_pattern(pattern, options = {}, &block)
123
+ return super unless pattern.graph_name == DEFAULT_GRAPH
124
+
125
+ if block_given?
126
+ pattern = pattern.dup
127
+ pattern.graph_name = nil
128
+
129
+ each_statement do |statement|
130
+ yield statement if (statement.graph_name == DEFAULT_GRAPH ||
131
+ statement.graph_name.nil?) && pattern === statement
132
+ end
133
+ else
134
+ enum_for(:query_pattern, pattern, options)
135
+ end
136
+ end
47
137
  end
48
138
  end
@@ -408,6 +408,30 @@ module RDF
408
408
  self
409
409
  end
410
410
 
411
+ ##
412
+ # Returns the literal, first removing all whitespace on both ends of the value, and then changing remaining consecutive whitespace groups into one space each.
413
+ #
414
+ # Note that it handles both ASCII and Unicode whitespace.
415
+ #
416
+ # @see [String#squish](http://apidock.com/rails/String/squish)
417
+ # @return [RDF::Literal] a new literal based on `self`.
418
+ def squish(*other_string)
419
+ self.dup.squish!
420
+ end
421
+
422
+ ##
423
+ # Performs a destructive {#squish}.
424
+ #
425
+ # @see [String#squish!](http://apidock.com/rails/String/squish%21)
426
+ # @return self
427
+ def squish!
428
+ @string = value.
429
+ gsub(/\A[[:space:]]+/, '').
430
+ gsub(/[[:space:]]+\z/, '').
431
+ gsub(/[[:space:]]+/, ' ')
432
+ self
433
+ end
434
+
411
435
  ##
412
436
  # Escape a literal using ECHAR escapes.
413
437
  #
@@ -12,7 +12,7 @@ module RDF; class Literal
12
12
  # @since 0.2.1
13
13
  class Double < Numeric
14
14
  DATATYPE = RDF::XSD.double
15
- GRAMMAR = /^(?:NaN|(?:[\+\-]?(?:INF|(?:\d+(\.\d*)?([eE][\+\-]?\d+)?))))$/.freeze
15
+ GRAMMAR = /^(?:NaN|(?:[\+\-]?(?:INF|(?:\d+(\.\d*)?(e[\+\-]?\d+)?))))$/i.freeze
16
16
 
17
17
  ##
18
18
  # @param [Float, #to_f] value
@@ -23,9 +23,8 @@ module RDF; class Literal
23
23
  @string = options[:lexical] if options.has_key?(:lexical)
24
24
  @string ||= value if value.is_a?(String)
25
25
  @object = case
26
- when value.is_a?(::String) then Integer(value) rescue nil
27
- when value.is_a?(::Integer) then value
28
26
  when value.respond_to?(:to_i) then value.to_i
27
+ when value.is_a?(::Integer) then value
29
28
  else Integer(value.to_s) rescue nil
30
29
  end
31
30
  end
@@ -67,6 +67,7 @@ module RDF
67
67
  # if not a {Resource}, it is coerced to {Literal} or {Node} depending on if it is a symbol or something other than a {Term}.
68
68
  # @option options [RDF::Term] :graph_name (nil)
69
69
  # Note, in RDF 1.1, a graph name MUST be an {Resource}.
70
+ # @option options [Boolean] :inferred used as a marker to record that this statement was inferred based on semantic relationships (T-Box).
70
71
  # @return [RDF::Statement]
71
72
  #
72
73
  # @overload initialize(subject, predicate, object, options = {})
@@ -78,6 +79,7 @@ module RDF
78
79
  # @param [Hash{Symbol => Object}] options
79
80
  # @option options [RDF::Term] :graph_name (nil)
80
81
  # Note, in RDF 1.1, a graph name MUST be an {Resource}.
82
+ # @option options [Boolean] :inferred used as a marker to record that this statement was inferred based on semantic relationships (T-Box).
81
83
  # @return [RDF::Statement]
82
84
  def initialize(subject = nil, predicate = nil, object = nil, options = {})
83
85
  if subject.is_a?(Hash)
@@ -138,7 +140,7 @@ module RDF
138
140
  !(has_subject? && subject.resource? &&
139
141
  has_predicate? && predicate.resource? &&
140
142
  has_object? && (object.resource? || object.literal?) &&
141
- (has_graph? ? graph_name.resource? : true ))
143
+ (has_graph? ? graph_name.resource? : true))
142
144
  end
143
145
 
144
146
  ##
@@ -153,7 +155,7 @@ module RDF
153
155
  has_subject? && subject.resource? && subject.valid? &&
154
156
  has_predicate? && predicate.uri? && predicate.valid? &&
155
157
  has_object? && object.term? && object.valid? &&
156
- (has_graph? ? graph_name.resource? && graph_name.valid? : true )
158
+ (has_graph? ? (graph_name.resource? && graph_name.valid?) : true)
157
159
  end
158
160
 
159
161
  ##
@@ -171,7 +173,7 @@ module RDF
171
173
  ##
172
174
  # @return [Boolean]
173
175
  def inferred?
174
- false
176
+ !!@options[:inferred]
175
177
  end
176
178
 
177
179
  ##
@@ -241,6 +243,12 @@ module RDF
241
243
  other.is_a?(Statement) && self == other && (self.graph_name || false) == (other.graph_name || false)
242
244
  end
243
245
 
246
+ ##
247
+ # Generates a Fixnum hash value as a quad.
248
+ def hash
249
+ @hash ||= to_quad.hash
250
+ end
251
+
244
252
  ##
245
253
  # Checks statement equality as a triple.
246
254
  #
@@ -345,6 +353,7 @@ module RDF
345
353
  self.object.canonicalize! if has_object? && !self.object.frozen?
346
354
  self.graph_name.canonicalize! if has_graph? && !self.graph_name.frozen?
347
355
  self.validate!
356
+ @hash = nil
348
357
  self
349
358
  end
350
359
 
@@ -42,7 +42,7 @@ module RDF
42
42
  [\\u{D0000}-\\u{DFFFD}]|[\\u{E1000}-\\u{EFFFD}]
43
43
  EOS
44
44
  IPRIVATE = Regexp.compile("[\\uE000-\\uF8FF]|[\\u{F0000}-\\u{FFFFD}]|[\\u100000-\\u10FFFD]").freeze
45
- SCHEME = Regexp.compile("[A-za-z](?:[A-Za-z0-9+-\.])*").freeze
45
+ SCHEME = Regexp.compile("[A-Za-z](?:[A-Za-z0-9+-\.])*").freeze
46
46
  PORT = Regexp.compile("[0-9]*").freeze
47
47
  IP_literal = Regexp.compile("\\[[0-9A-Fa-f:\\.]*\\]").freeze # Simplified, no IPvFuture
48
48
  PCT_ENCODED = Regexp.compile("%[0-9A-Fa-f][0-9A-Fa-f]").freeze
@@ -382,6 +382,7 @@ module RDF
382
382
  fragment: normalized_fragment
383
383
  }
384
384
  @value = nil
385
+ @hash = nil
385
386
  self
386
387
  end
387
388
  alias_method :normalize!, :canonicalize!
@@ -672,22 +673,6 @@ module RDF
672
673
  self
673
674
  end
674
675
 
675
- ##
676
- # Returns `true` if this URI starts with the given `string`.
677
- #
678
- # @example
679
- # RDF::URI('http://example.org/').start_with?('http') #=> true
680
- # RDF::URI('http://example.org/').start_with?('ftp') #=> false
681
- #
682
- # @param [String, #to_s] string
683
- # @return [Boolean] `true` or `false`
684
- # @see String#start_with?
685
- # @since 0.3.0
686
- def start_with?(string)
687
- to_s.start_with?(string.to_s)
688
- end
689
- alias_method :starts_with?, :start_with?
690
-
691
676
  ##
692
677
  # Returns `true` if this URI ends with the given `string`.
693
678
  #
@@ -159,6 +159,23 @@ module RDF
159
159
  end
160
160
  alias_method :validate, :validate!
161
161
 
162
+ ##
163
+ # Returns `true` if this Value starts with the given `string`.
164
+ #
165
+ # @example
166
+ # RDF::URI('http://example.org/').start_with?('http') #=> true
167
+ # RDF::Node('_:foo').start_with?('_:bar') #=> false
168
+ # RDF::Litera('Apple').start_with?('Orange') #=> false
169
+ #
170
+ # @param [String, #to_s] string
171
+ # @return [Boolean] `true` or `false`
172
+ # @see String#start_with?
173
+ # @since 0.3.0
174
+ def start_with?(string)
175
+ to_s.start_with?(string.to_s)
176
+ end
177
+ alias_method :starts_with?, :start_with?
178
+
162
179
  ##
163
180
  # Returns a copy of this value converted into its canonical
164
181
  # representation.
@@ -20,7 +20,7 @@ module RDF
20
20
  # @see http://www.w3.org/TR/n-quads/
21
21
  # @since 0.4.0
22
22
  class Format < RDF::Format
23
- content_type 'application/n-quads', extension: :nq, alias: ['text/x-nquads']
23
+ content_type 'application/n-quads', extension: :nq, alias: 'text/x-nquads;q=0.2'
24
24
  content_encoding 'utf-8'
25
25
 
26
26
  reader { RDF::NQuads::Reader }
@@ -16,7 +16,7 @@ module RDF::NTriples
16
16
  # @see http://www.w3.org/TR/rdf-testcases/#ntriples
17
17
  # @see http://www.w3.org/TR/n-triples/
18
18
  class Format < RDF::Format
19
- content_type 'application/n-triples', extension: :nt, alias: ['text/plain']
19
+ content_type 'application/n-triples', extension: :nt, alias: 'text/plain;q=0.2'
20
20
  content_encoding 'utf-8'
21
21
 
22
22
  reader { RDF::NTriples::Reader }
@@ -104,7 +104,7 @@ module RDF; class Query
104
104
  (has_subject? ? (subject.resource? || subject.variable?) && subject.valid? : true) &&
105
105
  (has_predicate? ? (predicate.uri? || predicate.variable?) && predicate.valid? : true) &&
106
106
  (has_object? ? (object.term? || object.variable?) && object.valid? : true) &&
107
- (has_graph? ? (graph_name.resource? || graph_name.variable?) && graph_name.valid? : true )
107
+ (has_graph? ? (graph_name.resource? || graph_name.variable?) && graph_name.valid? : true)
108
108
  rescue NoMethodError
109
109
  false
110
110
  end
@@ -177,11 +177,12 @@ module RDF
177
177
  # @see RDF::Enumerable#supports?
178
178
  def supports?(feature)
179
179
  case feature.to_sym
180
- when :graph_name then @options[:with_graph_name]
181
- when :inference then false # forward-chaining inference
182
- when :validity then @options.fetch(:with_validity, true)
183
- when :atomic_write then false
184
- when :snapshots then false
180
+ when :graph_name then @options[:with_graph_name]
181
+ when :inference then false # forward-chaining inference
182
+ when :validity then @options.fetch(:with_validity, true)
183
+ when :literal_equality then true
184
+ when :atomic_write then false
185
+ when :snapshots then false
185
186
  else false
186
187
  end
187
188
  end
@@ -212,7 +213,7 @@ module RDF
212
213
  ##
213
214
  # @see RDF::Dataset#isolation_level
214
215
  def isolation_level
215
- supports?(:snapshot) ? :repeatable_read : super
216
+ supports?(:snapshots) ? :repeatable_read : super
216
217
  end
217
218
 
218
219
  ##
@@ -259,11 +260,12 @@ module RDF
259
260
  # @see RDF::Enumerable#supports?
260
261
  def supports?(feature)
261
262
  case feature.to_sym
262
- when :graph_name then @options[:with_graph_name]
263
- when :inference then false # forward-chaining inference
264
- when :validity then @options.fetch(:with_validity, true)
265
- when :atomic_write then true
266
- when :snapshots then true
263
+ when :graph_name then @options[:with_graph_name]
264
+ when :inference then false # forward-chaining inference
265
+ when :validity then @options.fetch(:with_validity, true)
266
+ when :literal_equality then true
267
+ when :atomic_write then true
268
+ when :snapshots then true
267
269
  else false
268
270
  end
269
271
  end
@@ -281,13 +283,6 @@ module RDF
281
283
  count
282
284
  end
283
285
 
284
- ##
285
- # @private
286
- # @see RDF::Durable#durable?
287
- def durable?
288
- false
289
- end
290
-
291
286
  ##
292
287
  # @private
293
288
  # @see RDF::Enumerable#has_graph?
@@ -388,7 +383,7 @@ module RDF
388
383
 
389
384
  cs.each do |c, ss|
390
385
  next unless graph_name.nil? ||
391
- graph_name == false && !c ||
386
+ graph_name == DEFAULT_GRAPH && !c ||
392
387
  graph_name.eql?(c)
393
388
 
394
389
  ss = if subject.nil? || subject.is_a?(RDF::Query::Variable)
@@ -549,6 +544,14 @@ module RDF
549
544
  :serializable
550
545
  end
551
546
 
547
+ ##
548
+ # @note this is a simple object equality check.
549
+ #
550
+ # @see RDF::Transaction#mutated?
551
+ def mutated?
552
+ !@snapshot.send(:data).equal?(repository.send(:data))
553
+ end
554
+
552
555
  ##
553
556
  # Replaces repository data with the transaction's snapshot in a safely
554
557
  # serializable fashion.
@@ -566,11 +569,9 @@ module RDF
566
569
  raise TransactionError, 'Cannot execute a rolled back transaction. ' \
567
570
  'Open a new one instead.' if @rolledback
568
571
 
569
- # `Hamster::Hash#==` will use a cheap `#equal?` check first, but fall
570
- # back on a full Ruby Hash comparison if required.
571
572
  raise TransactionError, 'Error merging transaction. Repository' \
572
573
  'has changed during transaction time.' unless
573
- repository.send(:data) == @base_snapshot.send(:data)
574
+ repository.send(:data).equal? @base_snapshot.send(:data)
574
575
 
575
576
  repository.send(:data=, @snapshot.send(:data))
576
577
  end
@@ -156,6 +156,29 @@ module RDF
156
156
  :read_committed
157
157
  end
158
158
 
159
+ ##
160
+ # Indicates whether the transaction includes changes relative to the target
161
+ # repository's state at transaction start time.
162
+ #
163
+ # The response is guaranteed to be `true` if executing the transaction
164
+ # against the original repository state would cause a change. It may also
165
+ # return `true` in cases where the repository would not change (e.g.
166
+ # because the transaction would insert statements already present).
167
+ #
168
+ # @note `Transaction` implementers may choose to `NotImplementedError`
169
+ # if the transaction implementation cannot be implemented efficiently.
170
+ #
171
+ # @return [Boolean] true if the transaction has mutated (insert/delete)
172
+ # since transaction start time
173
+ #
174
+ # @raise [NotImplementedError] if a mutation check is not implemented
175
+ def mutated?
176
+ return !changes.empty? if self.class == Transaction
177
+
178
+ raise NotImplementedError,
179
+ '#mutated? is not implemented for #{self.class}'
180
+ end
181
+
159
182
  ##
160
183
  # Returns `true` if this is a read/write transaction, `false` otherwise.
161
184
  #
@@ -39,19 +39,7 @@ module RDF; module Util
39
39
  ##
40
40
  # @return [String] the value for an Accept header
41
41
  def self.default_accept_header
42
- # Receive text/html and text/plain at a lower priority than other formats
43
- reader_types = RDF::Format.reader_types.map do |t|
44
- case t.to_s
45
- when /text\/(?:plain|html)/
46
- "#{t};q=0.5"
47
- when /application\/xhtml\+xml/
48
- "#{t};q=0.7"
49
- else
50
- t
51
- end
52
- end
53
-
54
- (reader_types + %w(*/*;q=0.1)).join(", ")
42
+ (RDF::Format.accept_types + %w(*/*;q=0.1)).join(", ")
55
43
  end
56
44
 
57
45
  ##
@@ -109,7 +97,7 @@ module RDF; module Util
109
97
  # Document base is redirected location
110
98
  # Location may be relative
111
99
  base_uri = ::URI.join(base_uri, response.headers[:location].to_s).to_s
112
- response.follow_redirection(request, res, &blk)
100
+ response.follow_redirection(&blk)
113
101
  else
114
102
  raise IOError, "<#{base_uri}>: #{response.code}"
115
103
  end
@@ -1,6 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  # frozen_string_literal: true
3
- # This file generated automatically using vocab-fetch from http://www.w3.org/2002/07/owl#
3
+ # This file generated automatically using rdf vocabulary format from http://www.w3.org/2002/07/owl#
4
4
  require 'rdf'
5
5
  module RDF
6
6
  # @!parse
@@ -9,6 +9,35 @@ module RDF
9
9
  # end
10
10
  class OWL < RDF::StrictVocabulary("http://www.w3.org/2002/07/owl#")
11
11
 
12
+ # Ontology definition
13
+ ontology :"http://www.w3.org/2002/07/owl",
14
+ comment: %(
15
+ This ontology partially describes the built-in classes and
16
+ properties that together form the basis of the RDF/XML syntax of OWL 2.
17
+ The content of this ontology is based on Tables 6.1 and 6.2
18
+ in Section 6.4 of the OWL 2 RDF-Based Semantics specification,
19
+ available at http://www.w3.org/TR/owl2-rdf-based-semantics/.
20
+ Please note that those tables do not include the different annotations
21
+ \(labels, comments and rdfs:isDefinedBy links\) used in this file.
22
+ Also note that the descriptions provided in this ontology do not
23
+ provide a complete and correct formal description of either the syntax
24
+ or the semantics of the introduced terms \(please see the OWL 2
25
+ recommendations for the complete and normative specifications\).
26
+ Furthermore, the information provided by this ontology may be
27
+ misleading if not used with care. This ontology SHOULD NOT be imported
28
+ into OWL ontologies. Importing this file into an OWL 2 DL ontology
29
+ will cause it to become an OWL 2 Full ontology and may have other,
30
+ unexpected, consequences.
31
+ ).freeze,
32
+ :"dc11:title" => %(The OWL 2 Schema vocabulary \(OWL 2\)).freeze,
33
+ :"http://www.w3.org/2003/g/data-view#namespaceTransformation" => %(http://dev.w3.org/cvsweb/2009/owl-grddl/owx2rdf.xsl).freeze,
34
+ :"owl:imports" => %(http://www.w3.org/2000/01/rdf-schema).freeze,
35
+ :"owl:versionIRI" => %(http://www.w3.org/2002/07/owl).freeze,
36
+ :"owl:versionInfo" => %($Date: 2009/11/15 10:54:12 $).freeze,
37
+ :"rdfs:isDefinedBy" => [%(http://www.w3.org/TR/owl2-mapping-to-rdf/).freeze, %(http://www.w3.org/TR/owl2-rdf-based-semantics/).freeze, %(http://www.w3.org/TR/owl2-syntax/).freeze],
38
+ :"rdfs:seeAlso" => [%(http://www.w3.org/TR/owl2-rdf-based-semantics/#table-axiomatic-classes).freeze, %(http://www.w3.org/TR/owl2-rdf-based-semantics/#table-axiomatic-properties).freeze],
39
+ type: "owl:Ontology".freeze
40
+
12
41
  # Class definitions
13
42
  term :AllDifferent,
14
43
  comment: %(The class of collections of pairwise different individuals.).freeze,
@@ -1,6 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  # frozen_string_literal: true
3
- # This file generated automatically using vocab-fetch from http://www.w3.org/2000/01/rdf-schema#
3
+ # This file generated automatically using rdf vocabulary format from http://www.w3.org/2000/01/rdf-schema#
4
4
  require 'rdf'
5
5
  module RDF
6
6
  # @!parse
@@ -9,6 +9,12 @@ module RDF
9
9
  # end
10
10
  class RDFS < RDF::StrictVocabulary("http://www.w3.org/2000/01/rdf-schema#")
11
11
 
12
+ # Ontology definition
13
+ ontology :"http://www.w3.org/2000/01/rdf-schema#",
14
+ :"dc11:title" => %(The RDF Schema vocabulary \(RDFS\)).freeze,
15
+ :"rdfs:seeAlso" => %(http://www.w3.org/2000/01/rdf-schema-more).freeze,
16
+ type: "owl:Ontology".freeze
17
+
12
18
  # Class definitions
13
19
  term :Class,
14
20
  comment: %(The class of classes.).freeze,
@@ -112,12 +118,5 @@ module RDF
112
118
  range: "rdf:Property".freeze,
113
119
  :"rdfs:isDefinedBy" => %(rdfs:).freeze,
114
120
  type: "rdf:Property".freeze
115
-
116
- # Extra definitions
117
- term :"",
118
- :"dc11:title" => %(The RDF Schema vocabulary \(RDFS\)).freeze,
119
- label: "".freeze,
120
- :"rdfs:seeAlso" => %(http://www.w3.org/2000/01/rdf-schema-more).freeze,
121
- type: "owl:Ontology".freeze
122
121
  end
123
122
  end
@@ -1,14 +1,25 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # This file generated automatically using vocab-fetch from http://www.w3.org/1999/02/22-rdf-syntax-ns#
2
+ # frozen_string_literal: true
3
+ # This file generated automatically using rdf vocabulary format from http://www.w3.org/1999/02/22-rdf-syntax-ns#
3
4
  require 'rdf'
4
5
  module RDF
5
- class RDFV < StrictVocabulary("http://www.w3.org/1999/02/22-rdf-syntax-ns#")
6
+ # @!parse
7
+ # # Vocabulary for <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
8
+ # class RDFV < RDF::StrictVocabulary
9
+ # end
10
+ class RDFV < RDF::StrictVocabulary("http://www.w3.org/1999/02/22-rdf-syntax-ns#")
6
11
 
7
12
  class << self
8
13
  def name; "RDF"; end
9
14
  alias_method :__name__, :name
10
15
  end
11
16
 
17
+ # Ontology definition
18
+ ontology :"http://www.w3.org/1999/02/22-rdf-syntax-ns#",
19
+ :"dc11:description" => %(This is the RDF Schema for the RDF vocabulary terms in the RDF Namespace, defined in RDF 1.1 Concepts.).freeze,
20
+ :"dc11:title" => %(The RDF Concepts Vocabulary \(RDF\)).freeze,
21
+ type: "owl:Ontology".freeze
22
+
12
23
  # Class definitions
13
24
  term :Alt,
14
25
  comment: %(The class of containers of alternatives.).freeze,
@@ -128,11 +139,7 @@ module RDF
128
139
  type: "rdfs:Datatype".freeze
129
140
 
130
141
  # Extra definitions
131
- term :"",
132
- :"dc11:description" => %(This is the RDF Schema for the RDF vocabulary terms in the RDF Namespace, defined in RDF 1.1 Concepts.).freeze,
133
- :"dc11:title" => %(The RDF Concepts Vocabulary \(RDF\)).freeze,
134
- type: "owl:Ontology".freeze
135
- term :Description,
142
+ term :Description,
136
143
  comment: %(RDF/XML node element).freeze,
137
144
  label: "Description".freeze
138
145
  term :ID,
@@ -40,7 +40,12 @@ module RDF
40
40
  datatype: String,
41
41
  on: ["--extra URIEncodedJSON"],
42
42
  description: "URI Encoded JSON representation of extra data"
43
- ) {|arg| ::JSON.parse(::URI.decode(arg))},
43
+ ) do |arg|
44
+ ::JSON.parse(::URI.decode(arg)).inject({}) do |m1, (term, defs)|
45
+ d1 = defs.inject({}) {|m, (k,v)| m.merge(k.to_sym => v)}
46
+ m1.merge(term.to_sym => d1)
47
+ end
48
+ end,
44
49
  ]
45
50
  end
46
51
 
@@ -104,14 +109,21 @@ module RDF
104
109
 
105
110
  # Split nodes into Class/Property/Datatype/Other
106
111
  term_nodes = {
112
+ ontology: {},
107
113
  class: {},
108
114
  property: {},
109
115
  datatype: {},
110
116
  other: {}
111
117
  }
112
118
 
119
+ # Generate Ontology first
120
+ if vocab.ontology
121
+ term_nodes[:ontology][vocab.ontology.to_s] = vocab.ontology.attributes
122
+ end
123
+
113
124
  vocab.each.to_a.sort.each do |term|
114
125
  name = term.to_s[base_uri.length..-1].to_sym
126
+ next if name.to_s.empty? # Ontology serialized separately
115
127
  kind = begin
116
128
  case term.type.to_s
117
129
  when /Class/ then :class
@@ -127,6 +139,7 @@ module RDF
127
139
  end
128
140
 
129
141
  {
142
+ ontology: "Ontology definition",
130
143
  class: "Class definitions",
131
144
  property: "Property definitions",
132
145
  datatype: "Datatype definitions",
@@ -145,7 +158,11 @@ module RDF
145
158
  ##
146
159
  # Turn a node definition into a property/term expression
147
160
  def from_node(name, attributes, term_type)
148
- op = term_type == :property ? "property" : "term"
161
+ op = case term_type
162
+ when :property then "property"
163
+ when :ontology then "ontology"
164
+ else "term"
165
+ end
149
166
 
150
167
  components = [" #{op} #{name.to_sym.inspect}"]
151
168
  attributes.keys.sort_by(&:to_s).map(&:to_sym).each do |key|
@@ -1,6 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  # frozen_string_literal: true
3
- # This file generated automatically using vocab-fetch from etc/xsd.ttl
3
+ # This file generated automatically using rdf vocabulary format from http://www.w3.org/2001/XMLSchema#
4
4
  require 'rdf'
5
5
  module RDF
6
6
  # @!parse
@@ -120,6 +120,10 @@ module RDF
120
120
  Term.cache.delete(uri_str.to_sym) # Clear any previous entry
121
121
  prop = Term.intern(uri_str, attributes: options)
122
122
  props[name.to_sym] = prop
123
+
124
+ # If name is empty, also treat it as the ontology
125
+ @ontology ||= prop if name.to_s.empty?
126
+
123
127
  # Define an accessor, except for problematic properties
124
128
  (class << self; self; end).send(:define_method, name) { prop } unless %w(property hash).include?(name.to_s)
125
129
  prop
@@ -130,6 +134,45 @@ module RDF
130
134
  alias_method :term, :property
131
135
  alias_method :__property__, :property
132
136
 
137
+ ##
138
+ # @overload ontology
139
+ # Returns the ontology definition of the current vocabulary as a term.
140
+ # @return [RDF::Vocabulary::Term]
141
+ #
142
+ # @overload ontology(name, options)
143
+ # Defines the vocabulary ontology.
144
+ #
145
+ # @param [String, #to_s] uri
146
+ # The URI of the ontology.
147
+ # @param [Hash{Symbol => Object}] options
148
+ # Any other values are expected to be String which expands to a {URI} using built-in vocabulary prefixes. The value is a `String` or `Array<String>` which is interpreted according to the `range` of the associated property.
149
+ # @option options [String, Array<String>] :label
150
+ # Shortcut for `rdfs:label`, values are String interpreted as a {Literal}.
151
+ # @option options [String, Array<String>] :comment
152
+ # Shortcut for `rdfs:comment`, values are String interpreted as a {Literal}.
153
+ # @option options [String, Array<String>] :type
154
+ # Shortcut for `rdf:type`, values are String interpreted as a {URI}.
155
+ # @return [RDF::Vocabulary::Term]
156
+ #
157
+ # @note If the ontology URI has the vocabulary namespace URI as a prefix, it may also be defined using {#property} or {#term}
158
+ def ontology(*args)
159
+ case args.length
160
+ when 0
161
+ @ontology
162
+ else
163
+ uri, options = args
164
+ options = {vocab: self}.merge(options || {})
165
+ Term.cache.delete(uri.to_s.to_sym) # Clear any previous entry
166
+ @ontology = Term.intern(uri.to_s, attributes: options)
167
+
168
+ # If the URI is the same as the vocabulary namespace, also define it as a term
169
+ props[:""] ||= @ontology if self.to_s == uri.to_s
170
+
171
+ @ontology
172
+ end
173
+ end
174
+ alias_method :__ontology__, :ontology
175
+
133
176
  ##
134
177
  # @return [Array<RDF::URI>] a list of properties in the current vocabulary
135
178
  def properties
@@ -150,7 +193,7 @@ module RDF
150
193
  elsif vocab = RDF::Vocabulary.each.detect {|v| v.__name__ && v.__prefix__ == prefix.to_sym}
151
194
  suffix.to_s.empty? ? vocab.to_uri : vocab[suffix]
152
195
  else
153
- RDF::Vocabulary.find_term(pname) || RDF::URI(pname)
196
+ (RDF::Vocabulary.find_term(pname) rescue nil) || RDF::URI(pname)
154
197
  end
155
198
  end
156
199
 
@@ -177,8 +220,13 @@ module RDF
177
220
  def find_term(uri)
178
221
  uri = RDF::URI(uri)
179
222
  return uri if uri.is_a?(Vocabulary::Term)
180
- vocab = RDF::Vocabulary.detect {|v| uri.start_with?(v.to_uri)}
181
- vocab[uri.to_s[vocab.to_uri.to_s.length..-1]] if vocab
223
+ if vocab = find(uri)
224
+ if vocab.ontology == uri
225
+ vocab.ontology
226
+ else
227
+ vocab[uri.to_s[vocab.to_uri.to_s.length..-1].to_s]
228
+ end
229
+ end
182
230
  end
183
231
 
184
232
  ##
@@ -200,8 +248,11 @@ module RDF
200
248
  # @note the alias {__imports__} guards against `RDF::OWL.imports` returning a term, rather than an array of vocabularies
201
249
  # @return [Array<RDF::Vocabulary>]
202
250
  def imports
251
+ return [] unless self.ontology
203
252
  @imports ||= begin
204
- Array(self[""].attributes[:"owl:imports"]).map {|pn|find(expand_pname(pn)) rescue nil}.compact
253
+ Array(self.ontology.attributes[:"owl:imports"]).map do |pn|
254
+ find(expand_pname(pn)) rescue nil
255
+ end.compact
205
256
  rescue KeyError
206
257
  []
207
258
  end
@@ -252,6 +303,9 @@ module RDF
252
303
  props.each do |name, subject|
253
304
  subject.each_statement(&block)
254
305
  end
306
+
307
+ # Also include the ontology, if it's not also a property
308
+ @ontology.each_statement(&block) if @ontology && @ontology != self
255
309
  end
256
310
 
257
311
  ##
@@ -267,23 +321,32 @@ module RDF
267
321
  #
268
322
  # @param [RDF::Enumerable] graph
269
323
  # @param [URI, #to_s] url
270
- # @param [String] class_name
271
- # The class_name associated with the vocabulary, used for creating the class name of the vocabulary. This will create a new class named with a top-level constant based on `class_name`.
324
+ # @param [RDF::Vocabulary, String] class_name
325
+ # The class_name associated with the vocabulary, used for creating the class name of the vocabulary. This will create a new class named with a top-level constant based on `class_name`. If given an existing vocabulary, it replaces the existing definitions for that vocabulary with those from the graph.
272
326
  # @param [Array<Symbol>, Hash{Symbol => Hash}] extra
273
327
  # Extra terms to add to the vocabulary. In the first form, it is an array of symbols, for which terms are created. In the second, it is a Hash mapping symbols to property attributes, as described in {RDF::Vocabulary.property}.
274
328
  # @return [RDF::Vocabulary] the loaded vocabulary
275
329
  def from_graph(graph, url: nil, class_name: nil, extra: nil)
276
- vocab = if class_name
330
+ vocab = case class_name
331
+ when RDF::Vocabulary
332
+ class_name.instance_variable_set(:@ontology, nil)
333
+ class_name.instance_variable_set(:@properties, nil)
334
+ class_name
335
+ when String
277
336
  Object.const_set(class_name, Class.new(self.create(url)))
278
337
  else
279
338
  Class.new(self.create(url))
280
339
  end
281
340
 
341
+ ont_url = url.to_s.sub(%r([/#]$), '')
282
342
  term_defs = {}
283
343
  graph.each do |statement|
284
- next unless statement.subject.uri? && statement.subject.start_with?(url)
285
- name = statement.subject.to_s[url.to_s.length..-1]
344
+ next unless statement.subject.uri?
345
+ next unless statement.subject.start_with?(url) || statement.subject == ont_url
346
+ name = statement.subject.to_s[url.to_s.length..-1].to_s
286
347
  term = (term_defs[name.to_sym] ||= {})
348
+ term[:uri] = statement.subject if name.empty?
349
+
287
350
  key = case statement.predicate
288
351
  when RDF.type then :type
289
352
  when RDF::RDFS.subClassOf then :subClassOf
@@ -318,7 +381,12 @@ module RDF
318
381
  end
319
382
 
320
383
  term_defs.each do |term, attributes|
321
- vocab.__property__ term, attributes
384
+ if term == :""
385
+ uri = attributes.delete(:uri)
386
+ vocab.__ontology__ uri, attributes
387
+ else
388
+ vocab.__property__ term, attributes
389
+ end
322
390
  end
323
391
 
324
392
  vocab
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arto Bendiken
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-08-14 00:00:00.000000000 Z
13
+ date: 2016-12-11 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: link_header
@@ -60,6 +60,20 @@ dependencies:
60
60
  - - "~>"
61
61
  - !ruby/object:Gem::Version
62
62
  version: '2.0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: rdf-turtle
65
+ requirement: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '2.0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '2.0'
63
77
  - !ruby/object:Gem::Dependency
64
78
  name: rdf-vocab
65
79
  requirement: !ruby/object:Gem::Requirement
@@ -94,14 +108,14 @@ dependencies:
94
108
  requirements:
95
109
  - - "~>"
96
110
  - !ruby/object:Gem::Version
97
- version: '1.7'
111
+ version: '2.0'
98
112
  type: :development
99
113
  prerelease: false
100
114
  version_requirements: !ruby/object:Gem::Requirement
101
115
  requirements:
102
116
  - - "~>"
103
117
  - !ruby/object:Gem::Version
104
- version: '1.7'
118
+ version: '2.0'
105
119
  - !ruby/object:Gem::Dependency
106
120
  name: rspec
107
121
  requirement: !ruby/object:Gem::Requirement
@@ -284,9 +298,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
284
298
  version: '0'
285
299
  requirements: []
286
300
  rubyforge_project: rdf
287
- rubygems_version: 2.5.1
301
+ rubygems_version: 2.6.8
288
302
  signing_key:
289
303
  specification_version: 4
290
304
  summary: A Ruby library for working with Resource Description Framework (RDF) data.
291
305
  test_files: []
292
- has_rdoc: false