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

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

move DvAmount?, DvCount? 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            super
132            unless others.instance_of? self.class
133              return false
134            end
135            unless others.symbol.defining_code.terminology_id.value ==
136                @symbol.defining_code.terminology_id.value
137              return false
138            else
139              return true
140            end
141          end
142        end
143
144        class DvAbsoluteQuantity < DvQuantified
145          attr_accessor :accuracy
146
147          def initialize(magnitude, magnitude_status=nil, accuracy=nil,
148                         normal_range=nil, normal_status = nil,
149                         other_reference_ranges=nil)
150            super(magnitude, magnitude_status, normal_range,
151                   normal_status, other_reference_ranges)
152            self.accuracy = accuracy
153          end
154
155          def add(a_diff)
156            raise NotImplementedError, 'add must be implemented'
157          end
158
159          def diff(other)
160            raise NotImplementedError, 'diff must be implemented'
161          end
162
163          def subtract(a_diff)
164            raise NotImplementedError, 'subtract must be implemented'
165          end
166        end
167
168        class DvAmount < DvQuantified
169          attr_reader :accuracy, :accuracy_percent
170
171          def initialize(args = {})
172            super(args)
173            unless args[:accuracy].nil?
174              set_accuracy(args[:accuracy], args[:accuracy_percent])
175            else
176              @accuracy, @accuracy_percent = nil, nil
177            end
178          end
179
180          def +(other)
181            unless self.is_strictly_comparable_to? other
182              raise ArgumentError, 'type mismatch'
183            end
184            result = self.dup
185            result.magnitude = @magnitude + other.magnitude
186            return result
187          end
188
189          def -(other)           
190            other.magnitude = - other.magnitude
191            self+(other)
192          end
193
194          def set_accuracy(accuracy, accuracy_percent)
195            if accuracy_percent
196              raise ArgumentError, 'accuracy invalid' if accuracy < 0.0 || accuracy > 100.0
197            else
198              raise ArgumentError, 'accuracy invaild' if accuracy < 0.0 || accuracy > 1.0
199            end
200            @accuracy, @accuracy_percent = accuracy, accuracy_percent
201          end
202
203          def accuracy_is_percent?
204            return @accuracy_percent
205          end
206        end
207
208        class DvQuantity < DvAmount
209          attr_reader :units, :precision
210          def initialize(magnitude, units, magnitude_status=nil, precision=nil,
211                         accuracy=nil, accuracy_percent=nil, normal_range=nil,
212                         normal_status = nil, other_reference_ranges=nil)
213            super(magnitude, magnitude_status, accuracy, accuracy_percent,
214                  normal_range, normal_status, other_reference_ranges)
215            self.units = units
216            self.precision = precision
217          end
218
219          def units=(units)
220            raise ArgumentError, 'units should not be nil' if units.nil?
221            @units = units
222          end
223
224          def precision=(precision)
225            unless precision.nil? || precision >= -1
226              raise ArgumentError, 'precision invalid'
227            end
228            @precision = precision
229          end
230
231          def is_strictly_comparable_to?(others)
232            return false if others.nil?
233            if others.instance_of?(DvQuantity) && others.units == @units
234              return true
235            else
236              return false
237            end
238          end
239
240          def is_integral?
241            if @precision.nil? || precision != 0
242              return false
243            else
244              return true
245            end
246          end
247# accuracy???
248          def +(other)
249            dv_amount = super(other)
250            return DvQuantity.new(dv_amount.magnitude, @units,
251                                   @magnitude_status, @precision,
252                                   @accuracy, @accuracy_percent, @normal_range,
253                                   @normal_status, @other_reference_ranges)
254          end
255        end
256
257        class DvCount < DvAmount
258
259        end
260
261        class ReferenceRange
262          attr_reader :meaning, :range
263
264          def initialize(args = {})
265            self.meaning = args[:meaning]
266            self.range = args[:range]
267          end
268
269          def meaning=(meaning)
270            if meaning.nil?
271              raise ArgumentError, 'meaning should not be nil'
272            end
273            @meaning = meaning
274          end
275
276          def range=(range)
277            if range.nil?
278              raise ArgumentError, 'range should not be nil'
279            end
280            @range = range
281          end
282
283          def is_in_range?(val)
284            return @range.has?(val)
285          end
286        end
287
288        module ProportionKind
289          PK_RATIO = 0
290          PK_UNITARY = 1
291          PK_PERCENT = 2
292          PK_FRACTION = 3
293          PK_INTEGER_FRACTION = 4
294
295          def ProportionKind.valid_proportion_kind?(kind)
296            return true if kind >= 0 && kind <= 4
297            return false
298          end
299        end # end of ProportionKind
300
301        class DvProportion < DvAmount
302          include ProportionKind
303          attr_reader :numerator, :denominator, :type, :precision
304
305          def initialize(numerator, denominator, type, precision=nil,
306                         magnitude_status=nil, accuracy=nil,
307                         accuracy_percent=nil, normal_range=nil,
308                         normal_status = nil, other_reference_ranges=nil)
309            self.type = type
310            self.numerator = numerator
311            self.denominator = denominator
312            self.precision = precision
313            self.magnitude_status = magnitude_status
314            unless accuracy.nil?
315              set_accuracy(accuracy, accuracy_percent)
316            else
317              @accuracy, @accuracy_percent = nil, nil
318            end
319            self.normal_range = normal_range
320            self.normal_status = normal_status
321            self.other_reference_ranges = other_reference_ranges
322          end
323
324          def numerator=(numerator)
325            raise ArgumentError, 'numerator should not be nil' if numerator.nil?
326            if (@type == PK_FRACTION || @type == PK_INTEGER_FRACTION) &&
327                !numerator.integer?
328              raise ArgumentError, 'numerator invalid for type'
329            end
330            @numerator = numerator
331          end
332
333          def denominator=(denominator)
334            if denominator.nil? or denominator == PK_RATIO
335              raise ArgumentError, 'denominator invalid'
336            end
337            if (@type == PK_FRACTION || @type == PK_INTEGER_FRACTION) &&
338                !denominator.integer?
339              raise ArgumentError, 'denominator invalid for type'
340            end
341            if @type == PK_UNITARY && denominator != 1
342              raise ArgumentError, 'denominator invalid for type'
343            end
344            if @type == PK_PERCENT && denominator != 100
345              raise ArgumentError, 'denominator invaild for type'
346            end
347            @denominator = denominator
348          end
349
350          def type=(type)
351            if ProportionKind.valid_proportion_kind?(type)
352              @type = type
353            else
354              raise ArgumentError, 'type invalid'
355            end
356          end
357
358          def magnitude
359            return numerator.to_f/denominator.to_f
360          end
361
362          def precision=(precision)
363            unless precision.nil?
364              unless precision == 0 || self.is_integral?
365                @precision = precision
366              else
367                raise ArgumentError, 'precision invalid'
368              end
369            end
370          end
371
372          def is_integral?
373            return denominator.integer? && numerator.integer?
374          end
375
376          def is_strictly_comparable_to?(other)
377            unless other.instance_of?(DvProportion)
378              return false
379            end
380            if other.type == @type
381              return true
382            else
383              return false
384            end
385          end
386        end # end of DvProportion
387      end # of Quantity
388    end # of Data_Types
389  end # of RM
390end # of OpenEHR
Note: See TracBrowser for help on using the repository browser.