rdf 2.1.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
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