module Sbuilder class Domain # @attr [Strin] name attr_reader :name # alias for alias domain_name :name # @attr [Domain] extension defined in setup, overrinding defaults attr_reader :extension # ------------------------------------------------------------------ # logger PROGNAME = nil # progname for logger default class name include Sbuilder::Utils::MyLogger # mix logger # ------------------------------------------------------------------ # @!group Constructor & configure def initialize( options = {} ) @logger = getLogger( PROGNAME, options ) @logger.debug( "#{__method__} initialized" ) end def to_s "#{self.class}: name=#{name}" end def setName( name ) @name = name self end def setExtension( extension ) @extension = extension end # @!endgroup # ------------------------------------------------------------------ # @!group Behaviour ## # Should we add Nil to domain set # # @return [Boolean] delegate to extenion, true default def includeNil return extension.includeNil if extension true end ## # It is safe to call +cardinality+, +domain_values+, # +numberOfElements+, +render_values+, ... # # @return true, extension may override # def tlaBaseType return extension.tlaBaseType if extension false end # Notice: number of elements include also nil element, which should # be calculated, when calculating elements in domain. # # # delegate to extension - return 1 if does not exist def cardinality return 1 unless extension extension.cardinality end # @return [integer] number of elements including nil def numberOfElements cardinality + 1 end ## # @return [Integer..Integer] range to access 'domain_entry' of # (maybe extentended) domain def domain_range return extension.domain_range if extension endIndx = includeNil ? cardinality : cardinality-1 0..endIndx end # @!endgroup # ------------------------------------------------------------------ # @!group Implementation details ## # @return [Boolean] false which is internal nil repreentation def nilValue false end ## # @return [Boolean] true if +includeNil+ && (Int(0) || Nil) private def isNil( i ) includeNil && ( (i.is_a?(Integer) && i == 0) || (i.is_a?(String) && i == 'Nil' )) end # @!endgroup # ------------------------------------------------------------------ # @!group Domain values # Return domain value for for element 'i'. Possibly delegate to sub-class. # # @param i [Integer|String] element index (interger) or String value non integer # # @return value of domain element 'i', false if i==0 def domain_entry( i ) # interpret 0 as Nil # return false if (i.is_a?(Integer) && i == 0) || (i.is_a?(String) && i == 'Nil' ) return nilValue if isNil( i ) # delegage - if possible return extension.domain_entry( i ) if extension raise DomainException.new <<-EOS unless i.is_a?(Integer) Unknown type '#{i.class}' with value '#{i}' in 'domain_entry' #{name}. Support only for Integer EOS raise DomainException.new <<-EOS if i > cardinality Requested cardinality #{i} exceeds cardinality #{cardinality} of domain #{name} EOS # defaults strings "d_#{domain_name}_#{i}" end ## # Default assumes that domain values are string elements, and they # need to be wrapped with " -chars. Sub-classes may define # integers, which should not be wrapped, and they override this # method. # # @return [String] wrapped around " def stringize( val ) return val if val.is_a?( FalseClass ) '"' + val + '"' end ## # Index from 1.. if domain (extension defines Nil), index from # 0 if no need to reserve space for nil (e.g. domain_range). # # Known override in domain range, where using index range does # not necassarily start with 0. # # @see #render_entry # # @return [Array] renderValues set of elements, which can be # outputted to TLA code (i.e. they wrapped with "-char, if # necassary). Does not include Nil. # def render_values startIndx = includeNil ? 1 : 0 endIndx = includeNil ? cardinality : cardinality-1 arr = *(startIndx..endIndx).map { |i| render_entry( i ) } return arr end # @!endgroup # ------------------------------------------------------------------ # @!group Model data ## # Return entry which can be rendered (string values wrapped with # "-marks, integers plain, constans, e.g. Nil not wrappedd. If # domain +includeNil+ values i==0 and i=='Nil' are wrapped to # 'nilValue' (=false). Actual value from +domain_entry+ # def render_entry( i ) return nilValue if isNil( i ) return extension.render_entry( i ) if extension stringize( domain_entry( i )) end ## # Called from model#templateData, used in mustache templates to # output elements in domain set. Nil NOT included in this set! # # Is not expected to be overridded by sub-classes. # # @see render_values returnin array of Hashes # # @see #includeNil whether Nil should be included # # @return [Hash:Array] array_of_hashes array of {:value,:_comma} # @option array_of_hashes [:Symbol] :value # @option array_of_hashes [:Symbol] :index # @option array_of_hashes ['String'] _comma def domain_values vals = extension.nil? ? render_values : extension.render_values # String is - name of a type, no need expand return { :value => vals, '_comma' => '', :index => 0, } unless vals.is_a?( Array ) arra = vals.map.with_index do |domain_entry, i| { :value => domain_entry, '_comma' => ',', :index => i+1, } end arra.last['_comma'] = '' if arra && arra.any? @logger.debug( "#{__method__} #{name}: arra #{arra.to_yaml}, includeNil=#{includeNil}" ) return arra end # @!endgroup end end