source: ruby/branches/0.5/lib/open_ehr/rm/data_types/quantity.rb@ 252

Last change on this file since 252 was 252, checked in by KOBAYASHI, Shinji, 15 years ago

DvProportion moved test/unit to rspec

File size: 11.7 KB
Line 
1# This modules are implemented from the UML shown bellow
2# http://www.openehr.org/uml/release-1.0.1/Browsable/_9_0_76d0249_1109599337877_94556_1510Report.html
3# Ticket refs #50
4#require 'assumed_library_types'
5module OpenEHR
6 module RM
7 module DataTypes
8 module Quantity
9 class DvOrdered < OpenEHR::RM::DataTypes::Basic::DataValue
10 include Comparable
11 attr_accessor :normal_range, :other_refference_ranges, :normal_status
12
13 def initialize(args = {})
14 super(args)
15 self.normal_range = args[:normal_range]
16 self.normal_status = args[:normal_status]
17 self.other_reference_ranges = args[:other_reference_ranges]
18 end
19
20 def is_normal?
21 if @normal_range.nil? and @normal_status.nil?
22 return false
23 elsif !@normal_range.nil?
24 return @normal_range.has(@value)
25 elsif !@normal_status.nil?
26 return @normal_status.code_string == 'N'
27 end
28 end
29
30 def is_simple?
31 return @other_reference_ranges.nil?
32 end
33
34 def <=>(other)
35 raise NotImplementedError, 'This method should be implemented'
36 end
37
38 def other_reference_ranges=(other_reference_ranges)
39 if !other_reference_ranges.nil? && other_reference_ranges.empty?
40 raise ArgumentError, "Other reference ranges validity error"
41 end
42 @other_reference_ranges = other_reference_ranges
43 end
44
45 def is_strictly_comparable_to?(others)
46 if others.instance_of? self.class
47 return true
48 else
49 return false
50 end
51 end
52 end
53
54 class DvInterval < OpenEHR::AssumedLibraryTypes::Interval
55
56 end
57
58 class DvQuantified < DvOrdered
59 attr_reader :magnitude, :magnitude_status
60
61 def initialize(args = {})
62 super(args)
63 self.magnitude = args[:magnitude]
64 self.magnitude_status = args[:magnitude_status]
65 end
66
67 def <=>(others)
68 @magnitude <=> others.magnitude
69 end
70
71 def magnitude=(magnitude)
72 raise ArgumentError, 'magnitude should not be nil' if magnitude.nil?
73 @magnitude = magnitude
74 end
75
76 def magnitude_status=(magnitude_status)
77 if magnitude_status.nil?
78 @magnitude_status = '='
79 elsif DvQuantified.valid_magnitude_status?(magnitude_status)
80 @magnitude_status = magnitude_status
81 else
82 raise ArgumentError, 'magnitude_status invalid'
83 end
84 end
85
86 def accuracy_unknown?
87 return @accuracy.nil?
88 end
89
90 def self.valid_magnitude_status?(s)
91 if s == '=' || s == '>' || s == '<' || s == '<=' ||
92 s == '>=' || s == '~'
93 return true
94 else
95 return false
96 end
97 end
98 end
99
100 class DvOrdinal < DvOrdered
101 attr_reader :value, :symbol, :limits
102
103 def initialize(args = {})
104 super(args)
105 self.symbol = args[:symbol]
106 self.limits = args[:limits]
107 end
108
109 def value=(value)
110 raise ArgumentError, 'value should not be nil' if value.nil?
111 @value = value
112 end
113
114 def symbol=(symbol)
115 raise ArgumentError,'symbol should not be nil' if symbol.nil?
116 @symbol = symbol
117 end
118
119 def <=>(other)
120 @value <=> other.value
121 end
122
123 def limits=(limits)
124 unless limits.nil? or limits.meaning.value == 'limits'
125 raise ArgumentError, 'invalid limits'
126 else
127 @limits = limits
128 end
129 end
130 def is_strictly_comparable_to?(others)
131 unless super(others)
132 return false
133 end
134 unless others.symbol.defining_code.terminology_id.value ==
135 @symbol.defining_code.terminology_id.value
136 return false
137 else
138 return true
139 end
140 end
141 end
142
143 class DvAbsoluteQuantity < DvQuantified
144 attr_accessor :accuracy
145
146 def initialize(args = {})
147 super(args)
148 self.accuracy = args[:accuracy]
149 end
150
151 def add(a_diff)
152 type_check(a_diff)
153 return result_builder(DvAbsoluteQuantity,
154 @magnitude+a_diff.magnitude)
155 end
156
157 def diff(other)
158 type_check(other)
159 return result_builder(DvAmount,
160 (@magnitude-other.magnitude).abs)
161 end
162
163 def subtract(a_diff)
164 type_check(a_diff)
165 return result_builder(DvAbsoluteQuantity,
166 @magnitude-a_diff.magnitude)
167 end
168 private
169 def type_check(other)
170 unless self.is_strictly_comparable_to? other
171 raise ArgumentError, 'type mismatch'
172 end
173 end
174
175 def result_builder(klass, magnitude)
176 return klass.new(:magnitude => magnitude,
177 :magnitude_status => @magnitude_status,
178 :accuracy => @accuracy,
179 :accuracy_percent => @accuracy_percent,
180 :normal_range => @normal_range,
181 :normal_status => @normal_status,
182 :other_reference_ranges => @other_reference_ranges)
183 end
184 end
185
186 class DvAmount < DvQuantified
187 attr_reader :accuracy, :accuracy_percent
188
189 def initialize(args = {})
190 super(args)
191 unless args[:accuracy].nil?
192 set_accuracy(args[:accuracy], args[:accuracy_percent])
193 else
194 @accuracy, @accuracy_percent = nil, nil
195 end
196 end
197
198 def +(other)
199 unless self.is_strictly_comparable_to? other
200 raise ArgumentError, 'type mismatch'
201 end
202 result = self.dup
203 result.magnitude = @magnitude + other.magnitude
204 return result
205 end
206
207 def -(other)
208 other.magnitude = - other.magnitude
209 self+(other)
210 end
211
212 def set_accuracy(accuracy, accuracy_percent)
213 if accuracy_percent
214 raise ArgumentError, 'accuracy invalid' if accuracy < 0.0 || accuracy > 100.0
215 else
216 raise ArgumentError, 'accuracy invaild' if accuracy < 0.0 || accuracy > 1.0
217 end
218 @accuracy, @accuracy_percent = accuracy, accuracy_percent
219 end
220
221 def accuracy_is_percent?
222 return @accuracy_percent
223 end
224 end
225
226 class DvQuantity < DvAmount
227 attr_reader :units, :precision
228
229 def initialize(args = {})
230 super(args)
231 self.units = args[:units]
232 self.precision = args[:precision]
233 end
234
235 def units=(units)
236 raise ArgumentError, 'units should not be nil' if units.nil?
237 @units = units
238 end
239
240 def precision=(precision)
241 unless precision.nil? || precision >= -1
242 raise ArgumentError, 'precision invalid'
243 end
244 @precision = precision
245 end
246
247 def is_strictly_comparable_to?(others)
248 unless super(others)
249 return false
250 end
251 if others.units == @units
252 return true
253 else
254 return false
255 end
256 end
257
258 def is_integral?
259 if @precision.nil? || precision != 0
260 return false
261 else
262 return true
263 end
264 end
265 end
266
267 class DvCount < DvAmount
268
269 end
270
271 class ReferenceRange
272 attr_reader :meaning, :range
273
274 def initialize(args = {})
275 self.meaning = args[:meaning]
276 self.range = args[:range]
277 end
278
279 def meaning=(meaning)
280 if meaning.nil?
281 raise ArgumentError, 'meaning should not be nil'
282 end
283 @meaning = meaning
284 end
285
286 def range=(range)
287 if range.nil?
288 raise ArgumentError, 'range should not be nil'
289 end
290 @range = range
291 end
292
293 def is_in_range?(val)
294 return @range.has?(val)
295 end
296 end
297
298 module ProportionKind
299 PK_RATIO = 0
300 PK_UNITARY = 1
301 PK_PERCENT = 2
302 PK_FRACTION = 3
303 PK_INTEGER_FRACTION = 4
304
305 def ProportionKind.valid_proportion_kind?(kind)
306 return true if kind >= 0 && kind <= 4
307 return false
308 end
309 end # end of ProportionKind
310
311 class DvProportion < DvAmount
312 include ProportionKind
313 attr_reader :numerator, :denominator, :type, :precision
314
315 def initialize(args = {})
316 self.type = args[:type]
317 self.numerator = args[:numerator]
318 self.denominator = args[:denominator]
319 self.precision = args[:precision]
320 self.magnitude_status =args[:magnitude_status]
321 unless args[:accuracy].nil?
322 set_accuracy(args[:accuracy], args[:accuracy_percent])
323 else
324 @accuracy, @accuracy_percent = nil, nil
325 end
326 self.normal_range = args[:normal_range]
327 self.normal_status = args[:normal_status]
328 self.other_reference_ranges = args[:other_reference_ranges]
329 end
330
331 def numerator=(numerator)
332 raise ArgumentError, 'numerator should not be nil' if numerator.nil?
333 if (@type == PK_FRACTION || @type == PK_INTEGER_FRACTION) &&
334 !numerator.integer?
335 raise ArgumentError, 'numerator invalid for type'
336 end
337 @numerator = numerator
338 end
339
340 def denominator=(denominator)
341 case @type
342 when PK_UNITARY
343 unless denominator == 1
344 raise ArgumentError, 'Unitary denominator must be 1'
345 end
346 when PK_PERCENT
347 unless denominator == 100
348 raise ArgumentError, 'Percent denominator must be 100'
349 end
350 when PK_FRACTION, PK_INTEGER_FRACTION
351 unless denominator.integer? and @numerator.integer?
352 raise ArgumentError, 'Fraction numerator/denominator must be integer'
353 end
354 end
355 @denominator = denominator
356 end
357
358 def type=(type)
359 if ProportionKind.valid_proportion_kind?(type)
360 @type = type
361 else
362 raise ArgumentError, 'type invalid'
363 end
364 end
365
366 def magnitude
367 return numerator.to_f/denominator.to_f
368 end
369
370 def precision=(precision)
371 unless precision.nil?
372 if (self.is_integral? && precision !=0)
373 raise ArgumentError, 'precision invalid'
374 end
375 end
376 @precision = precision
377 end
378
379 def is_integral?
380 return denominator.integer? && numerator.integer?
381 end
382
383 def is_strictly_comparable_to?(other)
384 unless super(other)
385 return false
386 end
387 if other.type == @type
388 return true
389 else
390 return false
391 end
392 end
393 end # end of DvProportion
394 end # of Quantity
395 end # of Data_Types
396 end # of RM
397end # of OpenEHR
Note: See TracBrowser for help on using the repository browser.