# Used by +Rtml::ReverseEngineering::Simulator+ to track the value of a variable. Attempts # to build a logical value by processing the setvar's :lo, :op and :ro attributes. References to # other variables are automatically resolved. References to nonexistent values assume built-in variables # and assign generic values to them. # # Implements a #== method to see if one variable's value is equal to another's, though this may not always be accurate. # class Rtml::ReverseEngineering::Simulator::VariableValue include Rtml::ReverseEngineering::Simulator::VariableLookup attr_reader :value def initialize(setvar, all_variables, known_variable_types) @setvar, @all_variables, @known_variable_types = setvar, all_variables, known_variable_types @value = setvar.to_s %w(lo op ro).each { |i| instance_variable_set("@#{i}", resolve(self.send(i), all_variables, known_variable_types)) } catch(:done) do check_for_assignment check_for_operation end do_casting check_boundaries end def ==(other) self.value == other.value end private attr_reader :setvar, :all_variables, :known_variable_types def type @type ||= known_variable_types[setvar['name']] end def check_boundaries case type when :integer unless (-999999999..999999999).include? @value raise RulesViolationError, "TML numbers must be no more than 9 digits in length: #{@value}" end end end def do_casting @value = case type when :integer then value.to_i else value.to_s end end def check_for_operation unless setvar['op'].blank? method_name = "perform_operation_#{setvar['op']}" @value = self.send(method_name) throw :done end rescue NoMethodError raise Rtml::Error::InvalidOperation end def check_for_assignment if setvar['op'].blank? && !setvar['lo'].blank? @value = setvar['lo'] throw :done end end def lo; @lo ||= setvar['lo']; end def op; @op ||= setvar['op']; end def ro; @ro ||= setvar['ro']; end def perform_operation_plus case type when :integer then lo.to_i + ro.to_i when :string then lo.to_s + ro.to_s when :date then "#{lo.to_s} + #{ro.to_s}" else raise Rtml::Errors::InvalidOperation end end def perform_operation_minus case type when :integer then lo.to_i - ro.to_i when :string then lo.to_s[0..-(ro.to_i+1)] when :date then "#{lo.to_s} - #{ro.to_s}" else raise Rtml::Errors::InvalidOperation end end def perform_operation_number case type when :integer then lo.split(/;/).length else raise Rtml::Errors::InvalidOperation end end def perform_operation_item case type when :string then lo.split(/;/)[ro.to_i] else raise Rtml::Errors::InvalidOperation end end end