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

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

move DvQuantified? test to rspec

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