rdf 3.1.13 → 3.2.3

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
  SHA256:
3
- metadata.gz: 0a8a5a69a203cf83628099c927675bbc4abe122bd8568bb69fa06bae0cbcb94b
4
- data.tar.gz: eba5377c635a6b05c25cd2b88107521c494d557dbfde6c0de5dbe52646ee1401
3
+ metadata.gz: 4482866c0eb2c223af0f3a88f1eba8e1e2126c238c1136ff992a795de5047699
4
+ data.tar.gz: 38e58d5e2bab26f76b55affe2cb362aff85afb49c7692056837b69d34cad6081
5
5
  SHA512:
6
- metadata.gz: 51af08617cb541333344b88a968c2d5699439baa7a4263154f7ccbdce06b635491b1cb93b9fb0e4dbca8711d9b71926ff22b60ab92f3f0cad9e205f86d1a3177
7
- data.tar.gz: 8abc461f8937d46d3e75634764bc8bbaaf6f54ba07e39fa94c1400b62a59f20436ffd07c50a428aea7c2a01e292acbedb8f94bd5d07560e2523a00fef19174d1
6
+ metadata.gz: 464c0043d3238fc3c4b077dfe6144a145b2c636b0e7de53ea6e8ce7ea96d2fd196b88053b1974d939650295416a2e4f07d298009d06d3a0320c297caf7883309
7
+ data.tar.gz: 0b27d632fe51c621bd50c27c2b7ecf5da91cd615e4e39ddf82e9f65517bddadcba4adb387a33807f8f2f0851b3a1d3c0429ccf41f4ec1610371c57fe28bd0709
data/README.md CHANGED
@@ -398,16 +398,16 @@ from BNode identity (i.e., they each entail the other)
398
398
 
399
399
  ## Dependencies
400
400
 
401
- * [Ruby](https://ruby-lang.org/) (>= 2.2)
401
+ * [Ruby](https://ruby-lang.org/) (>= 2.6)
402
402
  * [LinkHeader][] (>= 0.0.8)
403
- * Soft dependency on [RestClient][] (>= 1.7)
403
+ * Soft dependency on [RestClient][] (>= 2.1)
404
404
 
405
405
  ## Installation
406
406
 
407
407
  The recommended installation method is via [RubyGems](https://rubygems.org/).
408
408
  To install the latest official release of RDF.rb, do:
409
409
 
410
- % [sudo] gem install rdf # Ruby 2+
410
+ % [sudo] gem install rdf # Ruby 2.6+
411
411
 
412
412
  ## Download
413
413
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.1.13
1
+ 3.2.3
@@ -43,6 +43,7 @@ module RDF; class Literal
43
43
  # Can't use simple %f transformation due to special requirements from
44
44
  # N3 tests in representation
45
45
  @string = case
46
+ when @object.nil? then 'NaN'
46
47
  when @object.nan? then 'NaN'
47
48
  when @object.infinite? then @object.to_s[0...-'inity'.length].upcase
48
49
  when @object.zero? then '0.0E0'
@@ -11,6 +11,9 @@ module RDF; class Literal
11
11
  # @return [Integer] `-1`, `0`, or `1`
12
12
  # @since 0.3.0
13
13
  def <=>(other)
14
+ # If lexically invalid, use regular literal testing
15
+ return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?)
16
+
14
17
  case other
15
18
  when ::Numeric
16
19
  to_d <=> other
@@ -30,11 +33,10 @@ module RDF; class Literal
30
33
  # @since 0.3.0
31
34
  def ==(other)
32
35
  # If lexically invalid, use regular literal testing
33
- return super unless self.valid?
36
+ return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?)
34
37
 
35
38
  case other
36
39
  when Literal::Numeric
37
- return super unless other.valid?
38
40
  (cmp = (self <=> other)) ? cmp.zero? : false
39
41
  when RDF::URI, RDF::Node
40
42
  # Interpreting SPARQL data-r2/expr-equal/eq-2-2, numeric can't be compared with other types
@@ -166,12 +166,12 @@ module RDF
166
166
  @object = value.freeze
167
167
  @string = lexical if lexical
168
168
  @string = value if !defined?(@string) && value.is_a?(String)
169
- @string = @string.encode(Encoding::UTF_8).freeze if @string
170
- @object = @string if @string && @object.is_a?(String)
169
+ @string = @string.encode(Encoding::UTF_8).freeze if instance_variable_defined?(:@string)
170
+ @object = @string if instance_variable_defined?(:@string) && @object.is_a?(String)
171
171
  @language = language.to_s.downcase.to_sym if language
172
172
  @datatype = RDF::URI(datatype).freeze if datatype
173
173
  @datatype ||= self.class.const_get(:DATATYPE) if self.class.const_defined?(:DATATYPE)
174
- @datatype ||= @language ? RDF.langString : RDF::URI("http://www.w3.org/2001/XMLSchema#string")
174
+ @datatype ||= instance_variable_defined?(:@language) && @language ? RDF.langString : RDF::URI("http://www.w3.org/2001/XMLSchema#string")
175
175
  end
176
176
 
177
177
  ##
@@ -179,7 +179,7 @@ module RDF
179
179
  #
180
180
  # @return [String]
181
181
  def value
182
- @string || to_s
182
+ instance_variable_defined?(:@string) && @string || to_s
183
183
  end
184
184
 
185
185
  ##
@@ -308,6 +308,37 @@ module RDF
308
308
  end
309
309
  alias_method :===, :==
310
310
 
311
+ ##
312
+ # Compares `self` to `other` for sorting purposes (with type check).
313
+ #
314
+ # @param [Object] other
315
+ # @return [Integer] `-1`, `0`, or `1`
316
+ def <=>(other)
317
+ case other
318
+ when Literal
319
+ case
320
+ when self.eql?(other)
321
+ 0
322
+ when self.language? && other.language?
323
+ # Literals with languages can compare if languages are identical
324
+ self.to_s <=> other.to_s
325
+ when self.simple? && other.simple?
326
+ self.to_s <=> other.to_s
327
+ when !self.valid?
328
+ type_error("#{self.inspect} is invalid") || 0
329
+ when !other.valid?
330
+ type_error("#{other.inspect} is invalid") || 0
331
+ when self.comperable_datatype2?(other)
332
+ self.object <=> other.object
333
+ else
334
+ type_error("#{self.inspect} and #{other.inspect} are not comperable") || 0
335
+ end
336
+ when String
337
+ self.simple? && self.value <=> other
338
+ else 1
339
+ end
340
+ end
341
+
311
342
  ##
312
343
  # Returns `true` if this is a plain literal. A plain literal
313
344
  # may have a language, but may not have a datatype. For
@@ -399,6 +430,26 @@ module RDF
399
430
  end
400
431
  end
401
432
 
433
+ ##
434
+ # Returns `true` if the literals are comperable.
435
+ #
436
+ # Used for <=> operator.
437
+ #
438
+ # @return [Boolean]
439
+ def comperable_datatype2?(other)
440
+ case self
441
+ when RDF::Literal::Numeric, RDF::Literal::Boolean
442
+ case other
443
+ when RDF::Literal::Numeric, RDF::Literal::Boolean
444
+ true
445
+ else
446
+ false
447
+ end
448
+ else
449
+ self.datatype == other.datatype
450
+ end
451
+ end
452
+
402
453
  ##
403
454
  # Converts this literal into its canonical lexical representation.
404
455
  #
@@ -301,7 +301,7 @@ module RDF
301
301
  # @see RDF::Literal#==
302
302
  # @see RDF::Query::Variable#==
303
303
  def eql?(other)
304
- other.is_a?(Statement) && self == other && (self.graph_name || false) == (other.graph_name || false)
304
+ other.is_a?(Statement) && self.to_a.eql?(other.to_a) && (self.graph_name || false) == (other.graph_name || false)
305
305
  end
306
306
 
307
307
  ##
data/lib/rdf/model/uri.rb CHANGED
@@ -111,6 +111,10 @@ module RDF
111
111
  tag tel turn turns tv urn javascript
112
112
  ).freeze
113
113
 
114
+ # Characters in a PName which must be escaped
115
+ PN_ESCAPE_CHARS = /[~\.\-!\$&'\(\)\*\+,;=\/\?\#@%_]/.freeze
116
+ PN_ESCAPES = /\\#{PN_ESCAPE_CHARS}/.freeze
117
+
114
118
  ##
115
119
  # Cache size may be set through {RDF.config} using `uri_cache_size`.
116
120
  #
@@ -621,16 +625,26 @@ module RDF
621
625
  end
622
626
 
623
627
  ##
624
- # Returns a qualified name (QName) for this URI based on available vocabularies, if possible.
628
+ # Returns a qualified name (QName) as a tuple of `[prefix, suffix]` for this URI based on available vocabularies, if possible.
625
629
  #
626
630
  # @example
627
631
  # RDF::URI('http://www.w3.org/2000/01/rdf-schema#').qname #=> [:rdfs, nil]
628
632
  # RDF::URI('http://www.w3.org/2000/01/rdf-schema#label').qname #=> [:rdfs, :label]
629
633
  # RDF::RDFS.label.qname #=> [:rdfs, :label]
630
- #
631
- # @return [Array(Symbol, Symbol)] or `nil` if no QName found
632
- def qname
633
- if self.to_s =~ %r([:/#]([^:/#]*)$)
634
+ # RDF::Vocab::DC.title.qname(
635
+ # prefixes: {dcterms: 'http://purl.org/dc/terms/'}) #=> [:dcterms, :title]
636
+ #
637
+ # @note within this software, the term QName is used to describe the tuple of prefix and suffix for a given IRI, where the prefix identifies some defined vocabulary. This somewhat contrasts with the notion of a [Qualified Name](https://www.w3.org/TR/2006/REC-xml-names11-20060816/#ns-qualnames) from XML, which are a subset of Prefixed Names.
638
+ #
639
+ # @param [Hash{Symbol => String}] prefixes
640
+ # Explicit set of prefixes to look for matches, defaults to loaded vocabularies.
641
+ # @return [Array(Symbol, Symbol)] or `nil` if no QName found. The suffix component will not have [reserved characters](https://www.w3.org/TR/turtle/#reserved) escaped.
642
+ def qname(prefixes: nil)
643
+ if prefixes
644
+ prefixes.each do |prefix, uri|
645
+ return [prefix, self.to_s[uri.length..-1].to_sym] if self.start_with?(uri)
646
+ end
647
+ elsif self.to_s =~ %r([:/#]([^:/#]*)$)
634
648
  local_name = $1
635
649
  vocab_uri = local_name.empty? ? self.to_s : self.to_s[0...-(local_name.length)]
636
650
  Vocabulary.each do |vocab|
@@ -653,11 +667,25 @@ module RDF
653
667
  end
654
668
 
655
669
  ##
656
- # Returns a string version of the QName or the full IRI
670
+ # Returns a Prefixed Name (PName) or the full IRI with any [reserved characters](https://www.w3.org/TR/turtle/#reserved) in the suffix escaped.
671
+ #
672
+ # @example Using a custom prefix for creating a PNname.
673
+ # RDF::URI('http://purl.org/dc/terms/creator').
674
+ # pname(prefixes: {dcterms: 'http://purl.org/dc/terms/'})
675
+ # #=> "dcterms:creator"
657
676
  #
677
+ # @param [Hash{Symbol => String}] prefixes
678
+ # Explicit set of prefixes to look for matches, defaults to loaded vocabularies.
658
679
  # @return [String] or `nil`
659
- def pname
660
- (q = self.qname) ? q.join(":") : to_s
680
+ # @see #qname
681
+ # @see https://www.w3.org/TR/rdf-sparql-query/#prefNames
682
+ def pname(prefixes: nil)
683
+ q = self.qname(prefixes: prefixes)
684
+ return self.to_s unless q
685
+ prefix, suffix = q
686
+ suffix = suffix.to_s.gsub(PN_ESCAPE_CHARS) {|c| "\\#{c}"} if
687
+ suffix.to_s.match?(PN_ESCAPE_CHARS)
688
+ [prefix, suffix].join(":")
661
689
  end
662
690
 
663
691
  ##
data/lib/rdf/nquads.rb CHANGED
@@ -69,9 +69,9 @@ module RDF
69
69
 
70
70
  begin
71
71
  unless blank? || read_comment
72
- subject = read_uriref || read_node || read_embTriple || fail_subject
72
+ subject = read_uriref || read_node || read_quotedTriple || fail_subject
73
73
  predicate = read_uriref(intern: true) || fail_predicate
74
- object = read_uriref || read_node || read_literal || read_embTriple || fail_object
74
+ object = read_uriref || read_node || read_literal || read_quotedTriple || fail_object
75
75
  graph_name = read_uriref || read_node
76
76
  if validate? && !read_eos
77
77
  log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
@@ -213,7 +213,7 @@ module RDF::NTriples
213
213
  begin
214
214
  read_statement
215
215
  rescue RDF::ReaderError
216
- value = read_uriref || read_node || read_literal || read_embTriple
216
+ value = read_uriref || read_node || read_literal || read_quotedTriple
217
217
  log_recover
218
218
  value
219
219
  end
@@ -229,9 +229,9 @@ module RDF::NTriples
229
229
 
230
230
  begin
231
231
  unless blank? || read_comment
232
- subject = read_uriref || read_node || read_embTriple || fail_subject
232
+ subject = read_uriref || read_node || read_quotedTriple || fail_subject
233
233
  predicate = read_uriref(intern: true) || fail_predicate
234
- object = read_uriref || read_node || read_literal || read_embTriple || fail_object
234
+ object = read_uriref || read_node || read_literal || read_quotedTriple || fail_object
235
235
 
236
236
  if validate? && !read_eos
237
237
  log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
@@ -247,11 +247,11 @@ module RDF::NTriples
247
247
 
248
248
  ##
249
249
  # @return [RDF::Statement]
250
- def read_embTriple
250
+ def read_quotedTriple
251
251
  if @options[:rdfstar] && match(ST_START)
252
- subject = read_uriref || read_node || read_embTriple || fail_subject
252
+ subject = read_uriref || read_node || read_quotedTriple || fail_subject
253
253
  predicate = read_uriref(intern: true) || fail_predicate
254
- object = read_uriref || read_node || read_literal || read_embTriple || fail_object
254
+ object = read_uriref || read_node || read_literal || read_quotedTriple || fail_object
255
255
  if !match(ST_END)
256
256
  log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
257
257
  end
@@ -227,7 +227,7 @@ module RDF::NTriples
227
227
  # @param [RDF::Statement] statement
228
228
  # @param [Hash{Symbol => Object}] options ({})
229
229
  # @return [String]
230
- def format_embTriple(statement, **options)
230
+ def format_quotedTriple(statement, **options)
231
231
  "<<%s %s %s>>" % statement.to_a.map { |value| format_term(value, **options) }
232
232
  end
233
233
  ##
@@ -59,6 +59,12 @@ module RDF; class Query
59
59
  super
60
60
  end
61
61
 
62
+ ##
63
+ # Create a new pattern from the quads, recursivly dupping sub-patterns.
64
+ def dup
65
+ self.class.from(self.to_quad.map {|t| t.is_a?(RDF::Query::Pattern) ? t.dup : t})
66
+ end
67
+
62
68
  ##
63
69
  # Any additional options for this pattern.
64
70
  #
data/lib/rdf/reader.rb CHANGED
@@ -647,7 +647,7 @@ module RDF
647
647
  ##
648
648
  # @return [String]
649
649
  def readline
650
- @line = @line_rest || @input.readline
650
+ @line = instance_variable_defined?(:@line_rest) && @line_rest || @input.readline
651
651
  @line, @line_rest = @line.split("\r", 2)
652
652
  @line = String.new if @line.nil? # not frozen
653
653
  @line.chomp!
@@ -243,17 +243,20 @@ module RDF
243
243
  #
244
244
  # @see RDF::Repository
245
245
  module Implementation
246
- require 'hamster'
247
246
  DEFAULT_GRAPH = false
247
+
248
+ ##
249
+ # @deprecated moved to {RDF::Transaction::SerializedTransaction}
250
+ SerializedTransaction = RDF::Transaction::SerializedTransaction
248
251
 
249
252
  ##
250
253
  # @private
251
254
  def self.extend_object(obj)
252
255
  obj.instance_variable_set(:@data, obj.options.delete(:data) ||
253
- Hamster::Hash.new)
256
+ Hash.new)
254
257
  obj.instance_variable_set(:@tx_class,
255
258
  obj.options.delete(:transaction_class) ||
256
- SerializedTransaction)
259
+ RDF::Transaction::SerializedTransaction)
257
260
  super
258
261
  end
259
262
 
@@ -263,7 +266,6 @@ module RDF
263
266
  def supports?(feature)
264
267
  case feature.to_sym
265
268
  when :graph_name then @options[:with_graph_name]
266
- when :inference then false # forward-chaining inference
267
269
  when :validity then @options.fetch(:with_validity, true)
268
270
  when :literal_equality then true
269
271
  when :atomic_write then true
@@ -381,7 +383,7 @@ module RDF
381
383
  ##
382
384
  # @see RDF::Dataset#isolation_level
383
385
  def isolation_level
384
- :serializable
386
+ :snapshot
385
387
  end
386
388
 
387
389
  ##
@@ -471,7 +473,7 @@ module RDF
471
473
  # @private
472
474
  # @see RDF::Mutable#clear
473
475
  def clear_statements
474
- @data = @data.clear
476
+ @data = @data.class.new
475
477
  end
476
478
 
477
479
  ##
@@ -513,14 +515,11 @@ module RDF
513
515
  unless statement_in?(data, statement)
514
516
  s, p, o, c = statement.to_quad
515
517
  c ||= DEFAULT_GRAPH
516
-
517
- return data.put(c) do |subs|
518
- (subs || Hamster::Hash.new).put(s) do |preds|
519
- (preds || Hamster::Hash.new).put(p) do |objs|
520
- (objs || Hamster::Hash.new).put(o, statement.options)
521
- end
522
- end
523
- end
518
+
519
+ data = data.has_key?(c) ? data.dup : data.merge(c => {})
520
+ data[c] = data[c].has_key?(s) ? data[c].dup : data[c].merge(s => {})
521
+ data[c][s] = data[c][s].has_key?(p) ? data[c][s].dup : data[c][s].merge(p => {})
522
+ data[c][s][p] = data[c][s][p].merge(o => statement.options)
524
523
  end
525
524
  data
526
525
  end
@@ -529,93 +528,18 @@ module RDF
529
528
  # @private
530
529
  # @return [Hamster::Hash] a new, updated hamster hash
531
530
  def delete_from(data, statement)
532
- if statement_in?(data, statement)
531
+ if has_statement_in?(data, statement)
533
532
  s, p, o, g = statement.to_quad
534
533
  g = DEFAULT_GRAPH unless supports?(:graph_name)
535
534
  g ||= DEFAULT_GRAPH
536
535
 
537
- os = data[g][s][p].delete(o)
538
- ps = os.empty? ? data[g][s].delete(p) : data[g][s].put(p, os)
539
- ss = ps.empty? ? data[g].delete(s) : data[g].put(s, ps)
540
- return ss.empty? ? data.delete(g) : data.put(g, ss)
536
+ os = data[g][s][p].dup.delete_if {|k,v| k == o}
537
+ ps = os.empty? ? data[g][s].dup.delete_if {|k,v| k == p} : data[g][s].merge(p => os)
538
+ ss = ps.empty? ? data[g].dup.delete_if {|k,v| k == s} : data[g].merge(s => ps)
539
+ return ss.empty? ? data.dup.delete_if {|k,v| k == g} : data.merge(g => ss)
541
540
  end
542
541
  data
543
542
  end
544
-
545
- ##
546
- # A transaction for the Hamster-based `RDF::Repository::Implementation`
547
- # with full serializability.
548
- #
549
- # @todo refactor me!
550
- # @see RDF::Transaction
551
- class SerializedTransaction < Transaction
552
- ##
553
- # @see Transaction#initialize
554
- def initialize(*args, **options, &block)
555
- super(*args, **options, &block)
556
- @base_snapshot = @snapshot
557
- end
558
-
559
- ##
560
- # Inserts the statement to the transaction's working snapshot.
561
- #
562
- # @see Transaction#insert_statement
563
- def insert_statement(statement)
564
- @snapshot = @snapshot.class
565
- .new(data: @snapshot.send(:insert_to,
566
- @snapshot.send(:data),
567
- process_statement(statement)))
568
- end
569
-
570
- ##
571
- # Deletes the statement from the transaction's working snapshot.
572
- #
573
- # @see Transaction#insert_statement
574
- def delete_statement(statement)
575
- @snapshot = @snapshot.class
576
- .new(data: @snapshot.send(:delete_from,
577
- @snapshot.send(:data),
578
- process_statement(statement)))
579
- end
580
-
581
- ##
582
- # @see RDF::Dataset#isolation_level
583
- def isolation_level
584
- :serializable
585
- end
586
-
587
- ##
588
- # @note this is a simple object equality check.
589
- #
590
- # @see RDF::Transaction#mutated?
591
- def mutated?
592
- !@snapshot.send(:data).equal?(repository.send(:data))
593
- end
594
-
595
- ##
596
- # Replaces repository data with the transaction's snapshot in a safely
597
- # serializable fashion.
598
- #
599
- # @note this transaction uses a pessimistic merge strategy which
600
- # fails the transaction if any data has changed in the repository
601
- # since transaction start time. However, the specific guarantee is
602
- # softer: multiple concurrent conflicting transactions will not
603
- # succeed. We may choose to implement a less pessimistic merge
604
- # strategy as a non-breaking change.
605
- #
606
- # @raise [TransactionError] when the transaction can't be merged.
607
- # @see Transaction#execute
608
- def execute
609
- raise TransactionError, 'Cannot execute a rolled back transaction. ' \
610
- 'Open a new one instead.' if @rolledback
611
-
612
- raise TransactionError, 'Error merging transaction. Repository' \
613
- 'has changed during transaction time.' unless
614
- repository.send(:data).equal? @base_snapshot.send(:data)
615
-
616
- repository.send(:data=, @snapshot.send(:data))
617
- end
618
- end
619
543
  end # Implementation
620
544
  end # Repository
621
545
  end # RDF
@@ -247,7 +247,7 @@ module RDF
247
247
  # @raise [TransactionError] if the transaction can't be applied
248
248
  def execute
249
249
  raise TransactionError, 'Cannot execute a rolled back transaction. ' \
250
- 'Open a new one instead.' if @rolledback
250
+ 'Open a new one instead.' if instance_variable_defined?(:@rolledback) && @rolledback
251
251
  @changes.apply(@repository)
252
252
  end
253
253
 
@@ -322,7 +322,81 @@ module RDF
322
322
  end
323
323
 
324
324
  public
325
-
325
+
326
+ ##
327
+ # A transaction with full serializability.
328
+ #
329
+ # @todo refactor me!
330
+ # @see RDF::Transaction
331
+ class SerializedTransaction < Transaction
332
+ ##
333
+ # @see Transaction#initialize
334
+ def initialize(*args, **options, &block)
335
+ super(*args, **options, &block)
336
+ @base_snapshot = @snapshot
337
+ end
338
+
339
+ ##
340
+ # Inserts the statement to the transaction's working snapshot.
341
+ #
342
+ # @see Transaction#insert_statement
343
+ def insert_statement(statement)
344
+ @snapshot = @snapshot.class
345
+ .new(data: @snapshot.send(:insert_to,
346
+ @snapshot.send(:data),
347
+ process_statement(statement)))
348
+ end
349
+
350
+ ##
351
+ # Deletes the statement from the transaction's working snapshot.
352
+ #
353
+ # @see Transaction#insert_statement
354
+ def delete_statement(statement)
355
+ @snapshot = @snapshot.class
356
+ .new(data: @snapshot.send(:delete_from,
357
+ @snapshot.send(:data),
358
+ process_statement(statement)))
359
+ end
360
+
361
+ ##
362
+ # @see RDF::Dataset#isolation_level
363
+ def isolation_level
364
+ :serializable
365
+ end
366
+
367
+ ##
368
+ # @note this is a simple object equality check.
369
+ #
370
+ # @see RDF::Transaction#mutated?
371
+ def mutated?
372
+ !@snapshot.send(:data).equal?(repository.send(:data))
373
+ end
374
+
375
+ ##
376
+ # Replaces repository data with the transaction's snapshot in a safely
377
+ # serializable fashion.
378
+ #
379
+ # @note this transaction uses a pessimistic merge strategy which
380
+ # fails the transaction if any data has changed in the repository
381
+ # since transaction start time. However, the specific guarantee is
382
+ # softer: multiple concurrent conflicting transactions will not
383
+ # succeed. We may choose to implement a less pessimistic merge
384
+ # strategy as a non-breaking change.
385
+ #
386
+ # @raise [TransactionError] when the transaction can't be merged.
387
+ # @see Transaction#execute
388
+ def execute
389
+ raise TransactionError, 'Cannot execute a rolled back transaction. ' \
390
+ 'Open a new one instead.' if instance_variable_defined?(:@rolledback) && @rolledback
391
+
392
+ raise TransactionError, 'Error merging transaction. Repository' \
393
+ 'has changed during transaction time.' unless
394
+ repository.send(:data).equal? @base_snapshot.send(:data)
395
+
396
+ repository.send(:data=, @snapshot.send(:data))
397
+ end
398
+ end # SerializedTransaction
399
+
326
400
  ##
327
401
  # An error class for transaction failures.
328
402
  #
data/lib/rdf/util/file.rb CHANGED
@@ -98,7 +98,7 @@ module RDF; module Util
98
98
  headers: response.headers
99
99
  }
100
100
 
101
- remote_document = RemoteDocument.new(response.body, document_options)
101
+ RemoteDocument.new(response.body, document_options)
102
102
  when 300..399
103
103
  # Document base is redirected location
104
104
  # Location may be relative
@@ -215,7 +215,7 @@ module RDF; module Util
215
215
  headers: response.headers
216
216
  }
217
217
 
218
- remote_document = RemoteDocument.new(response.body, document_options)
218
+ RemoteDocument.new(response.body, document_options)
219
219
  else
220
220
  raise IOError, "<#{base_uri}>: #{response.status}"
221
221
  end
@@ -17,17 +17,20 @@ module RDF; module Util
17
17
  # @param [Hash{Symbol => Object}] options
18
18
  # @option options [Logger, #<<] :logger
19
19
  # @return [Logger, #write, #<<]
20
- def logger(**options)
21
- logger = options.fetch(:logger, @logger)
22
- logger = @options[:logger] if logger.nil? && @options
20
+ def logger(logger: nil, **options)
21
+ # Guard against undefined instance variables, which may be a warning if used.
22
+ @options = {} unless instance_variable_defined?(:@options) || frozen?
23
+ logger ||= @logger if instance_variable_defined?(:@logger)
24
+ logger = @options[:logger] if logger.nil? && instance_variable_defined?(:@options) && @options
23
25
  if logger.nil?
24
26
  # Unless otherwise specified, use $stderr
25
- logger = (@options || options)[:logger] = IOWrapper.new($stderr)
27
+ logger = IOWrapper.new($stderr)
26
28
 
27
29
  # Reset log_statistics so that it's not inherited across different instances
28
30
  logger.log_statistics.clear if logger.respond_to?(:log_statistics)
29
31
  end
30
- logger = (@options || options)[:logger] = ::Logger.new(::File.open(::File::NULL, "w")) unless logger # Incase false was used, which is frozen
32
+ logger = ::Logger.new(::File.open(::File::NULL, "w")) unless logger # Incase false was used, which is frozen
33
+ @options[:logger] ||= logger if instance_variable_defined?(:@options)
31
34
  logger.extend(LoggerBehavior) unless logger.is_a?(LoggerBehavior)
32
35
  logger
33
36
  end
@@ -53,8 +53,7 @@ module RDF
53
53
  # "rdfs:subClassOf" => "http://example/SuperClass"
54
54
  # end
55
55
  #
56
- # @see http://www.w3.org/TR/curie/
57
- # @see http://en.wikipedia.org/wiki/QName
56
+ # @see https://www.w3.org/TR/rdf-sparql-query/#prefNames
58
57
  class Vocabulary
59
58
  extend ::Enumerable
60
59
 
@@ -70,7 +69,7 @@ module RDF
70
69
  # @return [Enumerator]
71
70
  def each(&block)
72
71
  if self.equal?(Vocabulary)
73
- if @vocabs
72
+ if instance_variable_defined?(:@vocabs) && @vocabs
74
73
  @vocabs.select(&:name).each(&block)
75
74
  else
76
75
  # This is needed since all vocabulary classes are defined using
@@ -356,7 +355,7 @@ module RDF
356
355
  def ontology(*args)
357
356
  case args.length
358
357
  when 0
359
- @ontology
358
+ @ontology if instance_variable_defined?(:@ontology)
360
359
  else
361
360
  uri, options = args
362
361
  URI.cache.delete(uri.to_s.to_sym) # Clear any previous entry
@@ -379,15 +378,20 @@ module RDF
379
378
  alias_method :__properties__, :properties
380
379
 
381
380
  ##
382
- # Attempt to expand a Compact IRI/PName/QName using loaded vocabularies
381
+ # Attempt to expand a Compact IRI/PName using loaded vocabularies
383
382
  #
384
383
  # @param [String, #to_s] pname
384
+ # The local-part of the PName will will have [reserved character escapes](https://www.w3.org/TR/turtle/#reserved) unescaped.
385
385
  # @return [Term]
386
- # @raise [KeyError] if pname suffix not found in identified vocabulary
386
+ # @raise [KeyError] if pname suffix not found in identified vocabulary.
387
387
  # @raise [ArgumentError] if resulting URI is not valid
388
388
  def expand_pname(pname)
389
389
  return pname unless pname.is_a?(String) || pname.is_a?(Symbol)
390
390
  prefix, suffix = pname.to_s.split(":", 2)
391
+ # Unescape escaped PN_ESCAPE_CHARS
392
+ if suffix.match?(/\\#{RDF::URI::PN_ESCAPE_CHARS}/)
393
+ suffix = suffix.gsub(RDF::URI::PN_ESCAPES) {|matched| matched[1..-1]}
394
+ end
391
395
  if prefix == "rdf"
392
396
  RDF[suffix]
393
397
  elsif vocab_detail = RDF::Vocabulary.vocab_map[prefix.to_sym]
@@ -417,9 +421,10 @@ module RDF
417
421
  end
418
422
 
419
423
  ##
420
- # Return the Vocabulary term associated with a URI
424
+ # Return the Vocabulary term associated with a URI
421
425
  #
422
- # @param [RDF::URI] uri
426
+ # @param [RDF::URI, String] uri
427
+ # If `uri` has is a pname in a locded vocabulary, the suffix portion of the PName will have escape characters unescaped before resolving against the vocabulary.
423
428
  # @return [Vocabulary::Term]
424
429
  def find_term(uri)
425
430
  uri = RDF::URI(uri)
@@ -428,7 +433,8 @@ module RDF
428
433
  if vocab.ontology == uri
429
434
  vocab.ontology
430
435
  else
431
- vocab[uri.to_s[vocab.to_uri.to_s.length..-1].to_s]
436
+ suffix = uri.to_s[vocab.to_uri.to_s.length..-1].to_s
437
+ vocab[suffix]
432
438
  end
433
439
  end
434
440
  end
@@ -507,7 +513,7 @@ module RDF
507
513
  end
508
514
 
509
515
  # Also include the ontology, if it's not also a property
510
- @ontology.each_statement(&block) if @ontology && @ontology != self
516
+ @ontology.each_statement(&block) if self.ontology && self.ontology != self
511
517
  end
512
518
 
513
519
  ##
@@ -574,6 +580,7 @@ module RDF
574
580
  term_defs
575
581
  end
576
582
 
583
+ #require 'byebug'; byebug
577
584
  # Pass over embedded_defs with anonymous references, once
578
585
  embedded_defs.each do |term, attributes|
579
586
  attributes.each do |ak, avs|
@@ -642,12 +649,31 @@ module RDF
642
649
  alias_method :__name__, :name
643
650
 
644
651
  ##
645
- # Returns a suggested CURIE/PName prefix for this vocabulary class.
652
+ # Returns a suggested vocabulary prefix for this vocabulary class.
646
653
  #
647
654
  # @return [Symbol]
648
655
  # @since 0.3.0
649
656
  def __prefix__
650
- __name__.split('::').last.downcase.to_sym
657
+ instance_variable_defined?(:@__prefix__) ?
658
+ @__prefix__ :
659
+ __name__.split('::').last.downcase.to_sym
660
+ end
661
+
662
+ ##
663
+ # Sets the vocabulary prefix to use for this vocabulary..
664
+ #
665
+ # @example Overriding a standard vocabulary prefix.
666
+ # RDF::Vocab::DC.__prefix__ = :dcterms
667
+ # RDF::Vocab::DC.title.pname #=> 'dcterms:title'
668
+ #
669
+ # @param [Symbol] prefix
670
+ # @return [Symbol]
671
+ # @since 3.2.3
672
+ def __prefix__=(prefix)
673
+ params = RDF::Vocabulary.vocab_map[__prefix__]
674
+ @__prefix__ = prefix.to_sym
675
+ RDF::Vocabulary.register(@__prefix__, self, **params)
676
+ @__prefix__
651
677
  end
652
678
 
653
679
  protected
@@ -1234,16 +1260,16 @@ module RDF
1234
1260
  values = values.map do |value|
1235
1261
  if value.is_a?(Literal) && %w(: comment definition notation note editorialNote).include?(k.to_s)
1236
1262
  "%(#{value.to_s.gsub('(', '\(').gsub(')', '\)')}).freeze"
1237
- # elsif value.is_a?(RDF::Vocabulary::Term)
1238
- # value.to_ruby(indent: indent + " ")
1263
+ elsif value.node? && value.is_a?(RDF::Vocabulary::Term)
1264
+ "#{value.to_ruby(indent: indent + " ")}.freeze"
1239
1265
  elsif value.is_a?(RDF::Term)
1240
1266
  "#{value.to_s.inspect}.freeze"
1241
1267
  elsif value.is_a?(RDF::List)
1242
1268
  list_elements = value.map do |u|
1243
1269
  if u.uri?
1244
1270
  "#{u.to_s.inspect}.freeze"
1245
- # elsif u.respond_to?(:to_ruby)
1246
- # u.to_ruby(indent: indent + " ")
1271
+ elsif u.node? && u.respond_to?(:to_ruby)
1272
+ u.to_ruby(indent: indent + " ")
1247
1273
  else
1248
1274
  "#{u.to_s.inspect}.freeze"
1249
1275
  end
data/lib/rdf/writer.rb CHANGED
@@ -516,7 +516,7 @@ module RDF
516
516
  when RDF::Literal then format_literal(term, **options)
517
517
  when RDF::URI then format_uri(term, **options)
518
518
  when RDF::Node then format_node(term, **options)
519
- when RDF::Statement then format_embTriple(term, **options)
519
+ when RDF::Statement then format_quotedTriple(term, **options)
520
520
  else nil
521
521
  end
522
522
  end
@@ -574,7 +574,7 @@ module RDF
574
574
  # @return [String]
575
575
  # @raise [NotImplementedError] unless implemented in subclass
576
576
  # @abstract
577
- def format_embTriple(value, **options)
577
+ def format_quotedTriple(value, **options)
578
578
  raise NotImplementedError.new("#{self.class}#format_statement") # override in subclasses
579
579
  end
580
580
 
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: 3.1.13
4
+ version: 3.2.3
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: 2021-03-06 00:00:00.000000000 Z
13
+ date: 2022-01-16 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: link_header
@@ -32,76 +32,62 @@ dependencies:
32
32
  - - ">="
33
33
  - !ruby/object:Gem::Version
34
34
  version: 0.0.8
35
- - !ruby/object:Gem::Dependency
36
- name: hamster
37
- requirement: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - "~>"
40
- - !ruby/object:Gem::Version
41
- version: '3.0'
42
- type: :runtime
43
- prerelease: false
44
- version_requirements: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - "~>"
47
- - !ruby/object:Gem::Version
48
- version: '3.0'
49
35
  - !ruby/object:Gem::Dependency
50
36
  name: rdf-spec
51
37
  requirement: !ruby/object:Gem::Requirement
52
38
  requirements:
53
39
  - - "~>"
54
40
  - !ruby/object:Gem::Version
55
- version: '3.1'
41
+ version: '3.2'
56
42
  type: :development
57
43
  prerelease: false
58
44
  version_requirements: !ruby/object:Gem::Requirement
59
45
  requirements:
60
46
  - - "~>"
61
47
  - !ruby/object:Gem::Version
62
- version: '3.1'
48
+ version: '3.2'
63
49
  - !ruby/object:Gem::Dependency
64
50
  name: rdf-turtle
65
51
  requirement: !ruby/object:Gem::Requirement
66
52
  requirements:
67
53
  - - "~>"
68
54
  - !ruby/object:Gem::Version
69
- version: '3.1'
55
+ version: '3.2'
70
56
  type: :development
71
57
  prerelease: false
72
58
  version_requirements: !ruby/object:Gem::Requirement
73
59
  requirements:
74
60
  - - "~>"
75
61
  - !ruby/object:Gem::Version
76
- version: '3.1'
62
+ version: '3.2'
77
63
  - !ruby/object:Gem::Dependency
78
64
  name: rdf-vocab
79
65
  requirement: !ruby/object:Gem::Requirement
80
66
  requirements:
81
67
  - - "~>"
82
68
  - !ruby/object:Gem::Version
83
- version: '3.1'
69
+ version: '3.2'
84
70
  type: :development
85
71
  prerelease: false
86
72
  version_requirements: !ruby/object:Gem::Requirement
87
73
  requirements:
88
74
  - - "~>"
89
75
  - !ruby/object:Gem::Version
90
- version: '3.1'
76
+ version: '3.2'
91
77
  - !ruby/object:Gem::Dependency
92
78
  name: rdf-xsd
93
79
  requirement: !ruby/object:Gem::Requirement
94
80
  requirements:
95
81
  - - "~>"
96
82
  - !ruby/object:Gem::Version
97
- version: '3.1'
83
+ version: '3.2'
98
84
  type: :development
99
85
  prerelease: false
100
86
  version_requirements: !ruby/object:Gem::Requirement
101
87
  requirements:
102
88
  - - "~>"
103
89
  - !ruby/object:Gem::Version
104
- version: '3.1'
90
+ version: '3.2'
105
91
  - !ruby/object:Gem::Dependency
106
92
  name: rest-client
107
93
  requirement: !ruby/object:Gem::Requirement
@@ -122,14 +108,14 @@ dependencies:
122
108
  requirements:
123
109
  - - "~>"
124
110
  - !ruby/object:Gem::Version
125
- version: '3.9'
111
+ version: '3.10'
126
112
  type: :development
127
113
  prerelease: false
128
114
  version_requirements: !ruby/object:Gem::Requirement
129
115
  requirements:
130
116
  - - "~>"
131
117
  - !ruby/object:Gem::Version
132
- version: '3.9'
118
+ version: '3.10'
133
119
  - !ruby/object:Gem::Dependency
134
120
  name: rspec-its
135
121
  requirement: !ruby/object:Gem::Requirement
@@ -150,14 +136,14 @@ dependencies:
150
136
  requirements:
151
137
  - - "~>"
152
138
  - !ruby/object:Gem::Version
153
- version: '3.7'
139
+ version: '3.14'
154
140
  type: :development
155
141
  prerelease: false
156
142
  version_requirements: !ruby/object:Gem::Requirement
157
143
  requirements:
158
144
  - - "~>"
159
145
  - !ruby/object:Gem::Version
160
- version: '3.7'
146
+ version: '3.14'
161
147
  - !ruby/object:Gem::Dependency
162
148
  name: yard
163
149
  requirement: !ruby/object:Gem::Requirement
@@ -178,28 +164,28 @@ dependencies:
178
164
  requirements:
179
165
  - - "~>"
180
166
  - !ruby/object:Gem::Version
181
- version: '1.2'
167
+ version: '1.8'
182
168
  type: :development
183
169
  prerelease: false
184
170
  version_requirements: !ruby/object:Gem::Requirement
185
171
  requirements:
186
172
  - - "~>"
187
173
  - !ruby/object:Gem::Version
188
- version: '1.2'
174
+ version: '1.8'
189
175
  - !ruby/object:Gem::Dependency
190
176
  name: faraday_middleware
191
177
  requirement: !ruby/object:Gem::Requirement
192
178
  requirements:
193
179
  - - "~>"
194
180
  - !ruby/object:Gem::Version
195
- version: '1.0'
181
+ version: '1.2'
196
182
  type: :development
197
183
  prerelease: false
198
184
  version_requirements: !ruby/object:Gem::Requirement
199
185
  requirements:
200
186
  - - "~>"
201
187
  - !ruby/object:Gem::Version
202
- version: '1.0'
188
+ version: '1.2'
203
189
  description: RDF.rb is a pure-Ruby library for working with Resource Description Framework
204
190
  (RDF) data.
205
191
  email: public-rdf-ruby@w3.org
@@ -296,14 +282,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
296
282
  requirements:
297
283
  - - ">="
298
284
  - !ruby/object:Gem::Version
299
- version: '2.4'
285
+ version: '2.6'
300
286
  required_rubygems_version: !ruby/object:Gem::Requirement
301
287
  requirements:
302
288
  - - ">="
303
289
  - !ruby/object:Gem::Version
304
290
  version: '0'
305
291
  requirements: []
306
- rubygems_version: 3.2.3
292
+ rubygems_version: 3.3.3
307
293
  signing_key:
308
294
  specification_version: 4
309
295
  summary: A Ruby library for working with Resource Description Framework (RDF) data.