rdf 3.1.5 → 3.1.10

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.
@@ -45,18 +45,27 @@ module RDF
45
45
  # identified by `subject`, but will be invalid.
46
46
  #
47
47
  # @example add constructed list to existing graph
48
- # l = RDF::List(nil, nil (1, 2, 3))
48
+ # l = RDF::List(values: (1, 2, 3))
49
49
  # g = RDF::Graph.new << l
50
50
  # g.count # => l.count
51
51
  #
52
+ # @example use a transaction for block initialization
53
+ # l = RDF::List(graph: graph, wrap_transaction: true) do |list|
54
+ # list << RDF::Literal(1)
55
+ # # list.graph.rollback will rollback all list changes within this block.
56
+ # end
57
+ # list.count #=> 1
58
+ #
52
59
  # @param [RDF::Resource] subject (RDF.nil)
53
60
  # Subject should be an {RDF::Node}, not a {RDF::URI}. A list with an IRI head will not validate, but is commonly used to detect if a list is valid.
54
61
  # @param [RDF::Graph] graph (RDF::Graph.new)
55
62
  # @param [Array<RDF::Term>] values
56
63
  # Any values which are not terms are coerced to `RDF::Literal`.
64
+ # @param [Boolean] wrap_transaction (false)
65
+ # Wraps the callback in a transaction, and replaces the graph with that transaction for the duraction of the callback. This has the effect of allowing any list changes to be made atomically, or rolled back.
57
66
  # @yield [list]
58
67
  # @yieldparam [RDF::List] list
59
- def initialize(subject: nil, graph: nil, values: nil, &block)
68
+ def initialize(subject: nil, graph: nil, values: nil, wrap_transaction: false, &block)
60
69
  @subject = subject || RDF.nil
61
70
  @graph = graph || RDF::Graph.new
62
71
  is_empty = @graph.query({subject: subject, predicate: RDF.first}).empty?
@@ -68,8 +77,8 @@ module RDF
68
77
  if first || values.length > 0
69
78
  # Intantiate the list from values, and insert the first value using subject.
70
79
  values.reverse_each {|value| self.unshift(value)}
71
- graph.insert RDF::Statement(subject, RDF.first, first || RDF.nil)
72
- graph.insert RDF::Statement(subject, RDF.rest, @subject)
80
+ @graph.insert RDF::Statement(subject, RDF.first, first || RDF.nil)
81
+ @graph.insert RDF::Statement(subject, RDF.rest, @subject)
73
82
  end
74
83
  @subject = subject
75
84
  else
@@ -78,9 +87,25 @@ module RDF
78
87
  end
79
88
 
80
89
  if block_given?
81
- case block.arity
82
- when 1 then block.call(self)
83
- else instance_eval(&block)
90
+ if wrap_transaction
91
+ old_graph = @graph
92
+ begin
93
+ Transaction.begin(@graph, graph_name: @graph.graph_name, mutable: @graph.mutable?) do |trans|
94
+ @graph = trans
95
+ case block.arity
96
+ when 1 then block.call(self)
97
+ else instance_eval(&block)
98
+ end
99
+ trans.execute if trans.mutated?
100
+ end
101
+ ensure
102
+ @graph = old_graph
103
+ end
104
+ else
105
+ case block.arity
106
+ when 1 then block.call(self)
107
+ else instance_eval(&block)
108
+ end
84
109
  end
85
110
  end
86
111
  end
@@ -175,7 +200,7 @@ module RDF
175
200
  # @return [RDF::List]
176
201
  # @see http://ruby-doc.org/core-2.2.2/Array.html#method-i-26
177
202
  def &(other)
178
- RDF::List[*(to_a & other.to_a)]
203
+ self.class.new(values: (to_a & other.to_a))
179
204
  end
180
205
 
181
206
  ##
@@ -193,7 +218,7 @@ module RDF
193
218
  # @return [RDF::List]
194
219
  # @see http://ruby-doc.org/core-2.2.2/Array.html#method-i-7C
195
220
  def |(other)
196
- RDF::List[*(to_a | other.to_a)]
221
+ self.class.new(values: (to_a | other.to_a))
197
222
  end
198
223
 
199
224
  ##
@@ -206,7 +231,7 @@ module RDF
206
231
  # @return [RDF::List]
207
232
  # @see http://ruby-doc.org/core-2.2.2/Array.html#method-i-2B
208
233
  def +(other)
209
- RDF::List[*(to_a + other.to_a)]
234
+ self.class.new(values: (to_a + other.to_a))
210
235
  end
211
236
 
212
237
  ##
@@ -220,7 +245,7 @@ module RDF
220
245
  # @return [RDF::List]
221
246
  # @see http://ruby-doc.org/core-2.2.2/Array.html#method-i-2D
222
247
  def -(other)
223
- RDF::List[*(to_a - other.to_a)]
248
+ self.class.new(values: (to_a - other.to_a))
224
249
  end
225
250
 
226
251
  ##
@@ -250,7 +275,7 @@ module RDF
250
275
  # @see http://ruby-doc.org/core-2.2.2/Array.html#method-i-2A
251
276
  def *(int_or_str)
252
277
  case int_or_str
253
- when Integer then RDF::List[*(to_a * int_or_str)]
278
+ when Integer then self.class.new(values: (to_a * int_or_str))
254
279
  else join(int_or_str.to_s)
255
280
  end
256
281
  end
@@ -538,13 +563,13 @@ module RDF
538
563
  ##
539
564
  # @private
540
565
  def slice_with_start_and_length(start, length)
541
- RDF::List[*to_a.slice(start, length)]
566
+ self.class.new(values: to_a.slice(start, length))
542
567
  end
543
568
 
544
569
  ##
545
570
  # @private
546
571
  def slice_with_range(range)
547
- RDF::List[*to_a.slice(range)]
572
+ self.class.new(values: to_a.slice(range))
548
573
  end
549
574
 
550
575
  protected :slice_with_start_and_length
@@ -851,7 +876,7 @@ module RDF
851
876
  # @return [RDF::List]
852
877
  # @see http://ruby-doc.org/core-2.2.2/Array.html#method-i-reverse
853
878
  def reverse
854
- RDF::List[*to_a.reverse]
879
+ self.class.new(values: to_a.reverse)
855
880
  end
856
881
 
857
882
  ##
@@ -863,7 +888,7 @@ module RDF
863
888
  # @return [RDF::List]
864
889
  # @see http://ruby-doc.org/core-2.2.2/Array.html#method-i-sort
865
890
  def sort(&block)
866
- RDF::List[*super]
891
+ self.class.new(values: super)
867
892
  end
868
893
 
869
894
  ##
@@ -875,7 +900,7 @@ module RDF
875
900
  # @return [RDF::List]
876
901
  # @see http://ruby-doc.org/core-2.2.2/Array.html#method-i-sort_by
877
902
  def sort_by(&block)
878
- RDF::List[*super]
903
+ self.class.new(values: super)
879
904
  end
880
905
 
881
906
  ##
@@ -887,7 +912,7 @@ module RDF
887
912
  # @return [RDF::List]
888
913
  # @see http://ruby-doc.org/core-2.2.2/Array.html#method-i-uniq
889
914
  def uniq
890
- RDF::List[*to_a.uniq]
915
+ self.class.new(values: to_a.uniq)
891
916
  end
892
917
 
893
918
  ##
@@ -964,7 +989,7 @@ module RDF
964
989
  case value
965
990
  when nil then RDF.nil
966
991
  when RDF::Value then value
967
- when Array then RDF::List.new(subject: nil, graph: graph, values: value)
992
+ when Array then self.class.new(subject: nil, graph: graph, values: value)
968
993
  else value
969
994
  end
970
995
  end
@@ -25,7 +25,7 @@ module RDF
25
25
  #
26
26
  # @example Creating a language-tagged literal (1)
27
27
  # value = RDF::Literal.new("Hello!", language: :en)
28
- # value.has_language? #=> true
28
+ # value.language? #=> true
29
29
  # value.language #=> :en
30
30
  #
31
31
  # @example Creating a language-tagged literal (2)
@@ -35,12 +35,12 @@ module RDF
35
35
  #
36
36
  # @example Creating an explicitly datatyped literal
37
37
  # value = RDF::Literal.new("2009-12-31", datatype: RDF::XSD.date)
38
- # value.has_datatype? #=> true
38
+ # value.datatype? #=> true
39
39
  # value.datatype #=> RDF::XSD.date
40
40
  #
41
41
  # @example Creating an implicitly datatyped literal
42
42
  # value = RDF::Literal.new(Date.today)
43
- # value.has_datatype? #=> true
43
+ # value.datatype? #=> true
44
44
  # value.datatype #=> RDF::XSD.date
45
45
  #
46
46
  # @example Creating implicitly datatyped literals
@@ -118,6 +118,7 @@ module RDF
118
118
  when ::Integer then RDF::Literal::Integer
119
119
  when ::Float then RDF::Literal::Double
120
120
  when ::BigDecimal then RDF::Literal::Decimal
121
+ when ::Rational then RDF::Literal::Double
121
122
  when ::DateTime then RDF::Literal::DateTime
122
123
  when ::Time then RDF::Literal::DateTime
123
124
  when ::Date then RDF::Literal::Date
@@ -224,7 +225,7 @@ module RDF
224
225
  # * The arguments are simple literals or literals typed as xsd:string
225
226
  # * The arguments are plain literals with identical language tags
226
227
  # * The first argument is a plain literal with language tag and the second argument is a simple literal or literal typed as xsd:string
227
- has_language? ?
228
+ language? ?
228
229
  (language == other.language || other.datatype == RDF::URI("http://www.w3.org/2001/XMLSchema#string")) :
229
230
  other.datatype == RDF::URI("http://www.w3.org/2001/XMLSchema#string")
230
231
  end
@@ -288,7 +289,7 @@ module RDF
288
289
  case
289
290
  when self.eql?(other)
290
291
  true
291
- when self.has_language? && self.language.to_s == other.language.to_s
292
+ when self.language? && self.language.to_s == other.language.to_s
292
293
  # Literals with languages can compare if languages are identical
293
294
  self.value_hash == other.value_hash && self.value == other.value
294
295
  when self.simple? && other.simple?
@@ -334,10 +335,10 @@ module RDF
334
335
  #
335
336
  # @return [Boolean] `true` or `false`
336
337
  # @see http://www.w3.org/TR/rdf-concepts/#dfn-plain-literal
337
- def has_language?
338
+ def language?
338
339
  datatype == RDF.langString
339
340
  end
340
- alias_method :language?, :has_language?
341
+ alias_method :has_language?, :language?
341
342
 
342
343
  ##
343
344
  # Returns `true` if this is a datatyped literal.
@@ -346,12 +347,12 @@ module RDF
346
347
  #
347
348
  # @return [Boolean] `true` or `false`
348
349
  # @see http://www.w3.org/TR/rdf-concepts/#dfn-typed-literal
349
- def has_datatype?
350
+ def datatype?
350
351
  !plain? && !language?
351
352
  end
352
- alias_method :datatype?, :has_datatype?
353
- alias_method :typed?, :has_datatype?
354
- alias_method :datatyped?, :has_datatype?
353
+ alias_method :has_datatype?, :datatype?
354
+ alias_method :typed?, :datatype?
355
+ alias_method :datatyped?, :datatype?
355
356
 
356
357
  ##
357
358
  # Returns `true` if the value adheres to the defined grammar of the
@@ -385,16 +386,16 @@ module RDF
385
386
  # This behavior is intuited from SPARQL data-r2/expr-equal/eq-2-2
386
387
  # @return [Boolean]
387
388
  def comperable_datatype?(other)
388
- return false unless self.plain? || self.has_language?
389
+ return false unless self.plain? || self.language?
389
390
 
390
391
  case other
391
392
  when RDF::Literal::Numeric, RDF::Literal::Boolean,
392
393
  RDF::Literal::Date, RDF::Literal::Time, RDF::Literal::DateTime
393
394
  # Invald types can be compared without raising a TypeError if literal has a language (open-eq-08)
394
- !other.valid? && self.has_language?
395
+ !other.valid? && self.language?
395
396
  else
396
397
  # An unknown datatype may not be used for comparison, unless it has a language? (open-eq-8)
397
- self.has_language?
398
+ self.language?
398
399
  end
399
400
  end
400
401
 
@@ -51,11 +51,13 @@ module RDF; class Literal
51
51
  #
52
52
  # @return [Boolean]
53
53
  # @since 1.1.6
54
- def has_timezone?
54
+ def timezone?
55
55
  md = self.to_s.match(GRAMMAR)
56
56
  md && !!md[2]
57
57
  end
58
- alias_method :has_tz?, :has_timezone?
58
+ alias_method :tz?, :timezone?
59
+ alias_method :has_tz?, :timezone?
60
+ alias_method :has_timezone?, :timezone?
59
61
 
60
62
  ##
61
63
  # Returns the value as a string.
@@ -72,7 +74,7 @@ module RDF; class Literal
72
74
  # @since 1.1.6
73
75
  def humanize(lang = :en)
74
76
  d = object.strftime("%A, %d %B %Y")
75
- if has_timezone?
77
+ if timezone?
76
78
  d += if self.tz == 'Z'
77
79
  " UTC"
78
80
  else
@@ -30,7 +30,7 @@ module RDF; class Literal
30
30
  # @see http://www.w3.org/TR/xmlschema11-2/#dateTime
31
31
  def canonicalize!
32
32
  if self.valid?
33
- @string = if has_timezone?
33
+ @string = if timezone?
34
34
  @object.new_offset.new_offset.strftime(FORMAT[0..-4] + 'Z').sub('.000', '')
35
35
  else
36
36
  @object.strftime(FORMAT[0..-4]).sub('.000', '')
@@ -45,7 +45,7 @@ module RDF; class Literal
45
45
  # @return [RDF::Literal]
46
46
  # @see http://www.w3.org/TR/sparql11-query/#func-tz
47
47
  def tz
48
- zone = has_timezone? ? object.zone : ""
48
+ zone = timezone? ? object.zone : ""
49
49
  zone = "Z" if zone == "+00:00"
50
50
  RDF::Literal(zone)
51
51
  end
@@ -85,21 +85,25 @@ module RDF; class Literal
85
85
  #
86
86
  # @return [Boolean]
87
87
  # @since 1.1.6
88
- def has_milliseconds?
88
+ def milliseconds?
89
89
  self.format("%L").to_i > 0
90
90
  end
91
- alias_method :has_ms?, :has_milliseconds?
91
+ alias_method :has_milliseconds?, :milliseconds?
92
+ alias_method :has_ms?, :milliseconds?
93
+ alias_method :ms?, :milliseconds?
92
94
 
93
95
  ##
94
96
  # Does the literal representation include a timezone? Note that this is only possible if initialized using a string, or `:lexical` option.
95
97
  #
96
98
  # @return [Boolean]
97
99
  # @since 1.1.6
98
- def has_timezone?
100
+ def timezone?
99
101
  md = self.to_s.match(GRAMMAR)
100
102
  md && !!md[2]
101
103
  end
102
- alias_method :has_tz?, :has_timezone?
104
+ alias_method :tz?, :timezone?
105
+ alias_method :has_tz?, :timezone?
106
+ alias_method :has_timezone?, :timezone?
103
107
 
104
108
  ##
105
109
  # Returns the `timezone` of the literal. If the
@@ -118,7 +122,7 @@ module RDF; class Literal
118
122
  # @since 1.1.6
119
123
  def humanize(lang = :en)
120
124
  d = object.strftime("%r on %A, %d %B %Y")
121
- if has_timezone?
125
+ if timezone?
122
126
  zone = if self.tz == 'Z'
123
127
  "UTC"
124
128
  else
@@ -63,9 +63,15 @@ module RDF; class Literal
63
63
  ##
64
64
  # Returns the number with no fractional part that is closest to the argument. If there are two such numbers, then the one that is closest to positive infinity is returned. An error is raised if arg is not a numeric value.
65
65
  #
66
- # @return [RDF::Literal]
66
+ # @return [RDF::Literal::Decimal]
67
67
  def round
68
- self.class.new(to_d.round)
68
+ rounded = to_d.round(half: (to_d < 0 ? :down : :up))
69
+ if rounded == -0.0
70
+ # to avoid -0.0
71
+ self.class.new(0.0)
72
+ else
73
+ self.class.new(rounded)
74
+ end
69
75
  end
70
76
 
71
77
  ##
@@ -74,9 +80,9 @@ module RDF; class Literal
74
80
  # @example
75
81
  # RDF::Literal(1).ceil #=> RDF::Literal(1)
76
82
  #
77
- # @return [RDF::Literal]
83
+ # @return [RDF::Literal::Integer]
78
84
  def ceil
79
- self.class.new(to_d.ceil)
85
+ RDF::Literal::Integer.new(to_d.ceil)
80
86
  end
81
87
 
82
88
  ##
@@ -85,9 +91,9 @@ module RDF; class Literal
85
91
  # @example
86
92
  # RDF::Literal(1).floor #=> RDF::Literal(1)
87
93
  #
88
- # @return [RDF::Literal]
94
+ # @return [RDF::Literal::Integer]
89
95
  def floor
90
- self.class.new(to_d.floor)
96
+ RDF::Literal::Integer.new(to_d.floor)
91
97
  end
92
98
 
93
99
  ##
@@ -142,7 +142,7 @@ module RDF; class Literal
142
142
  end
143
143
 
144
144
  ##
145
- # Returns the smallest number greater than or equal to `self`.
145
+ # Returns the smallest integer greater than or equal to `self`.
146
146
  #
147
147
  # @example
148
148
  # RDF::Literal(1.2).ceil #=> RDF::Literal(2)
@@ -150,14 +150,14 @@ module RDF; class Literal
150
150
  # RDF::Literal(2.0).ceil #=> RDF::Literal(2)
151
151
  # RDF::Literal(-2.0).ceil #=> RDF::Literal(-2)
152
152
  #
153
- # @return [RDF::Literal]
153
+ # @return [RDF::Literal::Integer]
154
154
  # @since 0.2.3
155
155
  def ceil
156
- self.class.new(to_f.ceil)
156
+ RDF::Literal::Integer.new(to_f.ceil)
157
157
  end
158
158
 
159
159
  ##
160
- # Returns the largest number less than or equal to `self`.
160
+ # Returns the largest integer less than or equal to `self`.
161
161
  #
162
162
  # @example
163
163
  # RDF::Literal(1.2).floor #=> RDF::Literal(1)
@@ -165,10 +165,10 @@ module RDF; class Literal
165
165
  # RDF::Literal(2.0).floor #=> RDF::Literal(2)
166
166
  # RDF::Literal(-2.0).floor #=> RDF::Literal(-2)
167
167
  #
168
- # @return [RDF::Literal]
168
+ # @return [RDF::Literal::Integer]
169
169
  # @since 0.2.3
170
170
  def floor
171
- self.class.new(to_f.floor)
171
+ RDF::Literal::Integer.new(to_f.floor)
172
172
  end
173
173
 
174
174
  ##
@@ -183,9 +183,9 @@ module RDF; class Literal
183
183
  ##
184
184
  # Returns the number with no fractional part that is closest to the argument. If there are two such numbers, then the one that is closest to positive infinity is returned. An error is raised if arg is not a numeric value.
185
185
  #
186
- # @return [RDF::Literal]
186
+ # @return [RDF::Literal::Double]
187
187
  def round
188
- self.class.new(to_f.round)
188
+ self.class.new(to_d.round(half: (to_d < 0 ? :down : :up)))
189
189
  end
190
190
 
191
191
  ##
@@ -123,6 +123,40 @@ module RDF; class Literal
123
123
  end
124
124
  end
125
125
 
126
+ ##
127
+ # Exponent − Performs exponential (power) calculation on operators.
128
+ #
129
+ # Promotes values, as necessary, with the result type depending on the input values.
130
+ #
131
+ # @param [Literal::Numeric, #to_i, #to_f, #to_d] other
132
+ # @return [RDF::Literal::Numeric]
133
+ # @since 0.2.3
134
+ # @see https://www.w3.org/TR/xpath-functions/#func-math-pow
135
+ def **(other)
136
+ RDF::Literal(object ** (other.is_a?(RDF::Literal::Numeric) ? other.object : other))
137
+ rescue ZeroDivisionError
138
+ RDF::Literal::Double.new('INF')
139
+ end
140
+
141
+ ##
142
+ # Exponent − Performs remainder of `self` divided by `other`.
143
+ #
144
+ # @param [Literal::Numeric, #to_i, #to_f, #to_d] other
145
+ # @return [RDF::Literal]
146
+ # @since 0.2.3
147
+ # @see https://www.w3.org/TR/xpath-functions/#func-numeric-mod
148
+ def %(other)
149
+ if self.class == Double || [Double, ::Float].include?(other.class)
150
+ self.class.new(to_f % other.to_f)
151
+ elsif ((self.class == RDF::Literal::Float || other.class == RDF::Literal::Float) rescue false)
152
+ self.class.new(to_f % other.to_f)
153
+ elsif self.class == Decimal || other.class == Decimal
154
+ self.class.new(to_d % (other.respond_to?(:to_d) ? other.to_d : BigDecimal(other.to_s)))
155
+ else
156
+ self.class.new(to_i % other.to_i)
157
+ end
158
+ end
159
+
126
160
  ##
127
161
  # Returns the quotient of `self` divided by `other`.
128
162
  #