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

Last change on this file since 250 was 250, checked in by KOBAYASHI, Shinji, 11 years ago

move DvQuantity? test to spec

File size: 11.9 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(numerator, denominator, type, precision=nil,
316                         magnitude_status=nil, accuracy=nil,
317                         accuracy_percent=nil, normal_range=nil,
318                         normal_status = nil, other_reference_ranges=nil)
319            self.type = type
320            self.numerator = numerator
321            self.denominator = denominator
322            self.precision = precision
323            self.magnitude_status = magnitude_status
324            unless accuracy.nil?
325              set_accuracy(accuracy, accuracy_percent)
326            else
327              @accuracy, @accuracy_percent = nil, nil
328            end
329            self.normal_range = normal_range
330            self.normal_status = normal_status
331            self.other_reference_ranges = other_reference_ranges
332          end
333
334          def numerator=(numerator)
335            raise ArgumentError, 'numerator should not be nil' if numerator.nil?
336            if (@type == PK_FRACTION || @type == PK_INTEGER_FRACTION) &&
337                !numerator.integer?
338              raise ArgumentError, 'numerator invalid for type'
339            end
340            @numerator = numerator
341          end
342
343          def denominator=(denominator)
344            if denominator.nil? or denominator == PK_RATIO
345              raise ArgumentError, 'denominator invalid'
346            end
347            if (@type == PK_FRACTION || @type == PK_INTEGER_FRACTION) &&
348                !denominator.integer?
349              raise ArgumentError, 'denominator invalid for type'
350            end
351            if @type == PK_UNITARY && denominator != 1
352              raise ArgumentError, 'denominator invalid for type'
353            end
354            if @type == PK_PERCENT && denominator != 100
355              raise ArgumentError, 'denominator invaild for type'
356            end
357            @denominator = denominator
358          end
359
360          def type=(type)
361            if ProportionKind.valid_proportion_kind?(type)
362              @type = type
363            else
364              raise ArgumentError, 'type invalid'
365            end
366          end
367
368          def magnitude
369            return numerator.to_f/denominator.to_f
370          end
371
372          def precision=(precision)
373            unless precision.nil?
374              unless precision == 0 || self.is_integral?
375                @precision = precision
376              else
377                raise ArgumentError, 'precision invalid'
378              end
379            end
380          end
381
382          def is_integral?
383            return denominator.integer? && numerator.integer?
384          end
385
386          def is_strictly_comparable_to?(other)
387            unless other.instance_of?(DvProportion)
388              return false
389            end
390            if other.type == @type
391              return true
392            else
393              return false
394            end
395          end
396        end # end of DvProportion
397      end # of Quantity
398    end # of Data_Types
399  end # of RM
400end # of OpenEHR
Note: See TracBrowser for help on using the repository browser.