1  # This modules are implemented from the UML shown bellow


2  # http://www.openehr.org/uml/release1.0.1/Browsable/_9_0_76d0249_1109599337877_94556_1510Report.html


3  # Ticket refs #50


4  #require 'assumed_library_types'


5  module 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 = 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  (@magnitudeother.magnitude).abs)


161  end


162 


163  def subtract(a_diff)


164  type_check(a_diff)


165  return result_builder(DvAbsoluteQuantity,


166  @magnitudea_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  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


236 


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?


251  if others.instance_of?(DvQuantity) && 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  # accuracy???


266  def +(other)


267  dv_amount = super(other)


268  return DvQuantity.new(dv_amount.magnitude, @units,


269  @magnitude_status, @precision,


270  @accuracy, @accuracy_percent, @normal_range,


271  @normal_status, @other_reference_ranges)


272  end


273  end


274 


275  class DvCount < DvAmount


276 


277  end


278 


279  class ReferenceRange


280  attr_reader :meaning, :range


281 


282  def initialize(args = {})


283  self.meaning = args[:meaning]


284  self.range = args[:range]


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


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


304  end


305 


306  module ProportionKind


307  PK_RATIO = 0


308  PK_UNITARY = 1


309  PK_PERCENT = 2


310  PK_FRACTION = 3


311  PK_INTEGER_FRACTION = 4


312 


313  def ProportionKind.valid_proportion_kind?(kind)


314  return true if kind >= 0 && kind <= 4


315  return false


316  end


317  end # end of ProportionKind


318 


319  class DvProportion < DvAmount


320  include ProportionKind


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


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


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)


369  if ProportionKind.valid_proportion_kind?(type)


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)


395  unless other.instance_of?(DvProportion)


396  return false


397  end


398  if other.type == @type


399  return true


400  else


401  return false


402  end


403  end


404  end # end of DvProportion


405  end # of Quantity


406  end # of Data_Types


407  end # of RM


408  end # of OpenEHR

