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

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

move DvAbsoluteQuantity test to spec

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