rdf 0.3.3 → 0.3.4

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.
@@ -9,20 +9,19 @@ module RDF; class Literal
9
9
  # RDF::Literal(84) / 2 #=> RDF::Literal(42)
10
10
  #
11
11
  # @see http://www.w3.org/TR/xmlschema-2/#integer
12
+ # @see http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#integer
12
13
  # @since 0.2.1
13
14
  class Integer < Decimal
14
15
  DATATYPE = XSD.integer
15
16
  GRAMMAR = /^[\+\-]?\d+$/.freeze
16
17
 
17
- include RDF::Literal::Numeric
18
-
19
18
  ##
20
19
  # @param [Integer, #to_i] value
21
20
  # @option options [String] :lexical (nil)
22
21
  def initialize(value, options = {})
23
- @datatype = RDF::URI(options[:datatype] || DATATYPE)
22
+ @datatype = RDF::URI(options[:datatype] || self.class.const_get(:DATATYPE))
24
23
  @string = options[:lexical] if options.has_key?(:lexical)
25
- @string = value if !defined?(@string) && value.is_a?(String)
24
+ @string ||= value if value.is_a?(String)
26
25
  @object = case
27
26
  when value.is_a?(::String) then Integer(value) rescue nil
28
27
  when value.is_a?(::Integer) then value
@@ -105,65 +104,6 @@ module RDF; class Literal
105
104
  to_i.nonzero? ? self : nil
106
105
  end
107
106
 
108
- ##
109
- # Returns `self`.
110
- #
111
- # @return [RDF::Literal]
112
- # @since 0.2.3
113
- def +@
114
- self # unary plus
115
- end
116
-
117
- ##
118
- # Returns `self` negated.
119
- #
120
- # @return [RDF::Literal]
121
- # @since 0.2.3
122
- def -@
123
- RDF::Literal(-to_i) # unary minus
124
- end
125
-
126
- ##
127
- # Returns the sum of `self` plus `other`.
128
- #
129
- # @param [#to_i] other
130
- # @return [RDF::Literal]
131
- # @since 0.2.3
132
- def +(other)
133
- RDF::Literal(to_i + other.to_i)
134
- end
135
-
136
- ##
137
- # Returns the difference of `self` minus `other`.
138
- #
139
- # @param [#to_i] other
140
- # @return [RDF::Literal]
141
- # @since 0.2.3
142
- def -(other)
143
- RDF::Literal(to_i - other.to_i)
144
- end
145
-
146
- ##
147
- # Returns the product of `self` times `other`.
148
- #
149
- # @param [#to_i] other
150
- # @return [RDF::Literal]
151
- # @since 0.2.3
152
- def *(other)
153
- RDF::Literal(to_i * other.to_i)
154
- end
155
-
156
- ##
157
- # Returns the quotient of `self` divided by `other`.
158
- #
159
- # @param [#to_i] other
160
- # @return [RDF::Literal]
161
- # @raise [ZeroDivisionError] if divided by zero
162
- # @since 0.2.3
163
- def /(other)
164
- RDF::Literal(to_i / other.to_i)
165
- end
166
-
167
107
  ##
168
108
  # Returns the value as a string.
169
109
  #
@@ -172,40 +112,6 @@ module RDF; class Literal
172
112
  @string || @object.to_s
173
113
  end
174
114
 
175
- ##
176
- # Returns the value as an integer.
177
- #
178
- # @return [Integer]
179
- def to_i
180
- @object.to_i
181
- end
182
- alias_method :to_int, :to_i
183
- alias_method :ord, :to_i
184
-
185
- ##
186
- # Returns the value as a floating point number.
187
- #
188
- # @return [Float]
189
- def to_f
190
- @object.to_f
191
- end
192
-
193
- ##
194
- # Returns the value as a decimal number.
195
- #
196
- # @return [BigDecimal]
197
- def to_d
198
- @object.respond_to?(:to_d) ? @object.to_d : BigDecimal(@object.to_s)
199
- end
200
-
201
- ##
202
- # Returns the value as a rational number.
203
- #
204
- # @return [Rational]
205
- def to_r
206
- @object.to_r
207
- end
208
-
209
115
  ##
210
116
  # Returns the value as an `OpenSSL::BN` instance.
211
117
  #
@@ -1,9 +1,184 @@
1
1
  module RDF; class Literal
2
2
  ##
3
- # Shared methods for numeric literal classes.
3
+ # Shared methods and class ancestry for numeric literal classes.
4
4
  #
5
5
  # @since 0.3.0
6
- module Numeric
7
- # TODO
6
+ class Numeric < Literal
7
+ ##
8
+ # Compares this literal to `other` for sorting purposes.
9
+ #
10
+ # @param [Object] other
11
+ # @return [Integer] `-1`, `0`, or `1`
12
+ # @since 0.3.0
13
+ def <=>(other)
14
+ case other
15
+ when ::Numeric
16
+ to_d <=> other
17
+ when Numeric
18
+ to_d <=> other.to_d
19
+ else super
20
+ end
21
+ end
22
+
23
+ ##
24
+ # Returns `true` if this literal is equal to `other`.
25
+ #
26
+ # @param [Object] other
27
+ # @return [Boolean] `true` or `false`
28
+ # @since 0.3.0
29
+ def ==(other)
30
+ # If lexically invalid, use regular literal testing
31
+ return super unless self.valid?
32
+
33
+ case other
34
+ when Literal::Numeric
35
+ return super unless other.valid?
36
+ (cmp = (self <=> other)) ? cmp.zero? : false
37
+ when RDF::URI, RDF::Node
38
+ # Interpreting SPARQL data-r2/expr-equal/eq-2-2, numeric can't be compared with other types
39
+ type_error("unable to determine whether #{self.inspect} and #{other.inspect} are equivalent")
40
+ else
41
+ super
42
+ end
43
+ end
44
+
45
+ ##
46
+ # Returns `self`.
47
+ #
48
+ # @return [RDF::Literal::Numeric]
49
+ # @since 0.2.3
50
+ def +@
51
+ self # unary plus
52
+ end
53
+
54
+ ##
55
+ # Returns `self` negated.
56
+ #
57
+ # @return [RDF::Literal::Numeric]
58
+ # @since 0.2.3
59
+ def -@
60
+ self.class.new(-self.object)
61
+ end
62
+
63
+ ##
64
+ # Returns the sum of `self` plus `other`.
65
+ #
66
+ # For xs:float or xs:double values, if one of the operands is a zero or a finite number
67
+ # and the other is INF or -INF, INF or -INF is returned. If both operands are INF, INF is returned.
68
+ # If both operands are -INF, -INF is returned. If one of the operands is INF
69
+ # and the other is -INF, NaN is returned.
70
+ # @param [Literal::Numeric, #to_i, #to_f, #to_d] other
71
+ # @return [RDF::Literal::Numeric]
72
+ # @since 0.2.3
73
+ # @see http://www.w3.org/TR/xpath-functions/#func-numeric-add
74
+ def +(other)
75
+ if self.class == Double || other.class == Double
76
+ RDF::Literal::Double.new(to_f + other.to_f)
77
+ elsif self.class == Float || other.class == Float
78
+ RDF::Literal::Float.new(to_f + other.to_f)
79
+ elsif self.class == Decimal || other.class == Decimal
80
+ RDF::Literal::Decimal.new(to_d + (other.respond_to?(:to_d) ? other.to_d : BigDecimal(other.to_s)))
81
+ else
82
+ RDF::Literal::Integer.new(to_i + other.to_i)
83
+ end
84
+ end
85
+
86
+ ##
87
+ # Returns the difference of `self` minus `other`.
88
+ #
89
+ # @param [Literal::Numeric, #to_i, #to_f, #to_d] other
90
+ # @return [RDF::Literal::Numeric]
91
+ # @since 0.2.3
92
+ # @see http://www.w3.org/TR/xpath-functions/#func-numeric-subtract
93
+ def -(other)
94
+ if self.class == Double || other.class == Double
95
+ RDF::Literal::Double.new(to_f - other.to_f)
96
+ elsif self.class == Float || other.class == Float
97
+ RDF::Literal::Float.new(to_f - other.to_f)
98
+ elsif self.class == Decimal || other.class == Decimal
99
+ RDF::Literal::Decimal.new(to_d - (other.respond_to?(:to_d) ? other.to_d : BigDecimal(other.to_s)))
100
+ else
101
+ RDF::Literal::Integer.new(to_i - other.to_i)
102
+ end
103
+ end
104
+
105
+ ##
106
+ # Returns the product of `self` times `other`.
107
+ #
108
+ # @param [Literal::Numeric, #to_i, #to_f, #to_d] other
109
+ # @return [RDF::Literal::Numeric]
110
+ # @since 0.2.3
111
+ # @see http://www.w3.org/TR/xpath-functions/#func-numeric-multiply
112
+ def *(other)
113
+ if self.class == Double || other.class == Double
114
+ RDF::Literal::Double.new(to_f * other.to_f)
115
+ elsif self.class == Float || other.class == Float
116
+ RDF::Literal::Float.new(to_f * other.to_f)
117
+ elsif self.class == Decimal || other.class == Decimal
118
+ RDF::Literal::Decimal.new(to_d * (other.respond_to?(:to_d) ? other.to_d : BigDecimal(other.to_s)))
119
+ else
120
+ RDF::Literal::Integer.new(to_i * other.to_i)
121
+ end
122
+ end
123
+
124
+ ##
125
+ # Returns the quotient of `self` divided by `other`.
126
+ #
127
+ # As a special case, if the types of both $arg1 and $arg2 are xs:integer,
128
+ # then the return type is xs:decimal.
129
+ #
130
+ # @param [Literal::Numeric, #to_i, #to_f, #to_d] other
131
+ # @return [RDF::Literal::Numeric]
132
+ # @raise [ZeroDivisionError] if divided by zero
133
+ # @since 0.2.3
134
+ # @see http://www.w3.org/TR/xpath-functions/#func-numeric-divide
135
+ def /(other)
136
+ if self.class == Double || other.class == Double
137
+ RDF::Literal::Double.new(to_f / other.to_f)
138
+ elsif self.class == Float || other.class == Float
139
+ RDF::Literal::Float.new(to_f / other.to_f)
140
+ elsif self.class == Decimal || other.class == Decimal
141
+ RDF::Literal::Decimal.new(to_d / (other.respond_to?(:to_d) ? other.to_d : BigDecimal(other.to_s)))
142
+ else
143
+ RDF::Literal::Integer.new(to_i / other.to_i)
144
+ end
145
+ end
146
+
147
+ ##
148
+ # Returns the value as an integer.
149
+ #
150
+ # @return [Integer]
151
+ def to_i
152
+ @object.to_i
153
+ end
154
+ alias_method :to_int, :to_i
155
+ alias_method :ord, :to_i
156
+
157
+ ##
158
+ # Returns the value as a floating point number.
159
+ #
160
+ # The usual accuracy limits and errors of binary float arithmetic apply.
161
+ #
162
+ # @return [Float]
163
+ # @see BigDecimal#to_f
164
+ def to_f
165
+ @object.to_f
166
+ end
167
+
168
+ ##
169
+ # Returns the value as a decimal number.
170
+ #
171
+ # @return [BigDecimal]
172
+ def to_d
173
+ @object.respond_to?(:to_d) ? @object.to_d : BigDecimal(@object.to_s)
174
+ end
175
+
176
+ ##
177
+ # Returns the value as a rational number.
178
+ #
179
+ # @return [Rational]
180
+ def to_r
181
+ @object.to_r
182
+ end
8
183
  end # Numeric
9
184
  end; end # RDF::Literal
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  module RDF; class Literal
2
3
  ##
3
4
  # A time literal.
@@ -16,14 +17,14 @@ module RDF; class Literal
16
17
  # @param [Time] value
17
18
  # @option options [String] :lexical (nil)
18
19
  def initialize(value, options = {})
19
- @datatype = RDF::URI(options[:datatype] || DATATYPE)
20
+ @datatype = RDF::URI(options[:datatype] || self.class.const_get(:DATATYPE))
20
21
  @string = options[:lexical] if options.has_key?(:lexical)
21
- @string = value if !defined?(@string) && value.is_a?(String)
22
+ @string ||= value if value.is_a?(String)
22
23
  @object = case
23
24
  when value.is_a?(::Time) then value
24
25
  when value.respond_to?(:to_time) then value.to_time # Ruby 1.9+
25
26
  else ::Time.parse(value.to_s)
26
- end
27
+ end rescue nil
27
28
  end
28
29
 
29
30
  ##
@@ -51,5 +52,24 @@ module RDF; class Literal
51
52
  def to_s
52
53
  @string || @object.strftime('%H:%M:%S%Z').sub(/\+00:00|UTC/, 'Z')
53
54
  end
55
+
56
+ ##
57
+ # Equal compares as Time objects
58
+ def ==(other)
59
+ # If lexically invalid, use regular literal testing
60
+ return super unless self.valid?
61
+
62
+ case other
63
+ when Literal::Time
64
+ return super unless other.valid?
65
+ # Compare as strings, as time includes a date portion, and adjusting for UTC
66
+ # can create a mismatch in the date portion.
67
+ self.object.utc.strftime('%H%M%S') == other.object.utc.strftime('%H%M%S')
68
+ when Literal::DateTime, Literal::Date
69
+ false
70
+ else
71
+ super
72
+ end
73
+ end
54
74
  end # Time
55
75
  end; end # RDF::Literal
@@ -12,9 +12,9 @@ module RDF; class Literal
12
12
  # @param [Symbol, #to_s] value
13
13
  # @option options [String] :lexical (nil)
14
14
  def initialize(value, options = {})
15
- @datatype = RDF::URI(options[:datatype] || DATATYPE)
15
+ @datatype = RDF::URI(options[:datatype] || self.class.const_get(:DATATYPE))
16
16
  @string = options[:lexical] if options.has_key?(:lexical)
17
- @string = value if !defined?(@string) && value.is_a?(String)
17
+ @string ||= value if value.is_a?(String)
18
18
  @object = value.is_a?(Symbol) ? value : value.to_s
19
19
  end
20
20
 
@@ -13,7 +13,7 @@ module RDF; class Literal
13
13
  # @param [Object] value
14
14
  # @option options [String] :lexical (nil)
15
15
  def initialize(value, options = {})
16
- @datatype = options[:datatype] || DATATYPE
16
+ @datatype = options[:datatype] || self.class.const_get(:DATATYPE)
17
17
  @string = options[:lexical] if options.has_key?(:lexical)
18
18
  @object = value # TODO: parse XML string using REXML
19
19
  end
@@ -44,6 +44,23 @@ module RDF
44
44
  self.new(id)
45
45
  end
46
46
 
47
+ ##
48
+ # Override #dup to remember original object.
49
+ # This allows .eql? to determine that two nodes
50
+ # are the same thing, and not different nodes
51
+ # instantiated with the same identifier.
52
+ # @return [RDF::Node]
53
+ def dup
54
+ node = super
55
+ node.original = self.original || self
56
+ node
57
+ end
58
+
59
+ ##
60
+ # Originally instantiated node, if any
61
+ # @return [RDF::Node]
62
+ attr_accessor :original
63
+
47
64
  # @return [String]
48
65
  attr_accessor :id
49
66
 
@@ -88,23 +105,36 @@ module RDF
88
105
  end
89
106
 
90
107
  ##
91
- # Checks whether this blank node is equal to `other`.
108
+ # Determins if `self` is the same term as `other`.
109
+ #
110
+ # In this case, nodes must be the same object
92
111
  #
93
112
  # @param [Node] other
94
113
  # @return [Boolean]
95
114
  def eql?(other)
96
- other.is_a?(Node) && self == other
115
+ other.is_a?(RDF::Node) && (self.original || self).equal?(other.original || other)
97
116
  end
98
117
 
99
118
  ##
100
- # Checks whether this blank node is equal to `other`.
119
+ # Checks whether this blank node is equal to `other` (type checking).
120
+ #
121
+ # In this case, different nodes having the same id are considered the same.
122
+ #
123
+ # Per SPARQL data-r2/expr-equal/eq-2-2, numeric can't be compared with other types
101
124
  #
102
125
  # @param [Object] other
103
126
  # @return [Boolean]
127
+ # @see http://www.w3.org/TR/rdf-sparql-query/#func-RDFterm-equal
104
128
  def ==(other)
105
- other.respond_to?(:node?) && other.node? &&
106
- other.respond_to?(:id) && @id == other.id
129
+ case other
130
+ when Literal
131
+ # If other is a Literal, reverse test to consolodate complex type checking logic
132
+ other == self
133
+ else
134
+ other.respond_to?(:node?) && other.node? && other.respond_to?(:id) && @id == other.id
135
+ end
107
136
  end
137
+ alias_method :===, :==
108
138
 
109
139
  ##
110
140
  # Returns a string representation of this blank node.