rdf 0.3.3 → 0.3.4

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