Class: Twb::Analysis::CalculatedFieldsAnalyzer

Inherits:
Object
  • Object
show all
Defined in:
lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb

Constant Summary collapse

@@ttlogfile =
'CalculatedFieldsAnalyzer.ttlog'
@@gvDotLocation =
'C:\\tech\\graphviz\\Graphviz2.38\\bin\\dot.exe'
@@processName =
'.CalculatedFields'
@@calcFieldsCSVFileName =
'TwbCalculatedFields.csv'
@@calcFieldsCSVFileHeader =
['Record #',
 'Workbook',      'Workbook Dir',
 'Data Source',   'Data Source Caption', 'Data Source Name (tech)',
 'Field Name',    'Field Caption',       'Field Name (tech)',
 'Data Source + Field Name (tech)',
 'Data Type',     'Role',  'Type',
 'Class',
 'Scope Isolation',
 'Formula Length',
 'Formula Code',
 'Formula',
 'Formula Comments',
 'Formula LOD?'
]
@@formFieldsCSVFileName =
'TwbFormulaFields.csv'
@@formFieldsCSVFileHeader =
['Rec #',
   'Workbook',   'Workbook Dir',
   'Data Source',
   'Field - Calculated',
   'Data Source - Formula (tech)',
   'Data Source - Formula',
   'Field - Formula (tech)',
   'Field - Formula',
   'Data Source + Field - Calculated',
   'Table'
]
@@dotHeader =
"  digraph g {\n      graph [rankdir=\"LR\" splines=line];\n      node  [shape=\"box\"  width=\"2\"];\n\n"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCalculatedFieldsAnalyzer



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 73

def initialize
    @csvCalculatedFields = []
    @csvFormulaFields    = []
    # @testFile = File.open('testCSV.csv','w')

    # @testFile.puts @@calcFieldsCSVFileHeader.inspect

    #-- Logging setup --

    @logger = Logger.new(@@ttlogfile)
    @logger.level = Logger::DEBUG
    #-- Counters setup --

      @twbCount              = 0
      @calculatedFieldsCount = 0
      @formulaFieldsCount    = 0
    # --

      @referencedFields     = SortedSet.new
    # --

      @dataFiles   = {'TwbCalculatedFields.csv' => 'Calculated Fields & their Formulas', 'TwbFormulaFields.csv' => 'Fields referenced in Formulas'}
    # --

      @localEmit  = false
      emit  "\n\nLogging activity to: #{File.basename(@@ttlogfile)}"
      @imageFiles  = []
end

Instance Attribute Details

#calculatedFieldsCountObject (readonly)

Returns the value of attribute calculatedFieldsCount.



27
28
29
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 27

def calculatedFieldsCount
  @calculatedFieldsCount
end

#dataFilesObject (readonly)

Returns the value of attribute dataFiles.



27
28
29
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 27

def dataFiles
  @dataFiles
end

#formulaFieldsCountObject (readonly)

Returns the value of attribute formulaFieldsCount.



27
28
29
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 27

def formulaFieldsCount
  @formulaFieldsCount
end

Instance Method Details

#closeDot(dotFile, twb) ⇒ Object



492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 492

def closeDot dotFile, twb
  dotFile.puts ' '
  dotFile.puts '// -------------------------------------------------------------'
  dotFile.puts ' '
  dotFile.puts '   subgraph cluster_1 {'
  # dotFile.puts '     color=white;'

  dotFile.puts '     style=invis;'
  # dotFile.puts '     border=0;'

  dotFile.puts '     node [border=blue];'
  dotFile.puts ' '
  dotFile.puts '     "" [style=invis]'
  dotFile.puts "     \"Tableau Tools\\nCalculated Fields Map\\nWorkbook '#{twb}'\\n#{Time.new.ctime}\"  [penwidth=0]"
  # dotFile.puts "     \"Tableau Tools Workbook  Calculated Fields Map\\n#{Time.new.ctime}\"  -> \"\"  [style=invis]"

  dotFile.puts ' '
  dotFile.puts '   }'
  dotFile.puts ' '
  dotFile.puts '}'
  dotFile.close
end

#emit(local = @localEmit, stuff) ⇒ Object



471
472
473
474
475
476
477
478
479
480
481
482
483
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 471

def emit(local=@localEmit, stuff)
    # puts "\nstuff.class #{stuff.class}  :: #{stuff}" if local

    if stuff.is_a? String then
      lines = stuff.split(/\n/)
      lines.each do |line|
        @logger.debug "#{@emitPrefix}#{line}"
                 puts "#{@emitPrefix}#{line}" if local
      end
    else
        @logger.debug "#{@emitPrefix}#{stuff}"
                 puts "#{@emitPrefix}#{stuff}" if local
    end
end

#emitCalcfield(calcField) ⇒ Object

def processDataSource



326
327
328
329
330
331
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 326

def emitCalcfield calcField
  emit "\t FIELD    cap :: #{calcField.caption} "
  emit "\t         tname:: #{calcField.name}"
  emit "\t        uiname:: #{calcField.uiname}"
  emit "\t       formula:: #{calculation.formulaFlat}"
end

#emitEdges(edges) ⇒ Object



398
399
400
401
402
403
404
405
406
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 398

def emitEdges edges
  emit  "  %-15s    %s" % ['type', 'Edge']
  emit  "  %-15s    %s" % ['-'*15, '-'*35]
  edges.each do |edge|
    emit  "  %-15s    %s" % [edge.from.type, edge.from]
    emit  "  %-15s    %s" % [edge.to.type,   edge.to]
    emit  "\n "
  end
end

#emitTypes(edges, dotFile) ⇒ Object



408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 408

def emitTypes edges, dotFile
  typedNodes = {}
  dotFile.puts "\n\n  //  2--------------------------------------------------------------------"
  edges.each do |edge|
    emit  "   EDGE  :: #{edge}"
    loadNodeType typedNodes, edge.from
    loadNodeType typedNodes, edge.to
  end
  typedNodes.each do |type, nodes|
    emit  "+++++++++ typedNodes of '#{type}''  "
    nodes.each do |node|
      emit  "           -n- #{node}"
    end
    rankSame(dotFile, type, nodes) unless type == :CalculatedField
  end
  # labelTypes dotFile, edges

end

#graphEdges(twb, edges) ⇒ Object



381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 381

def graphEdges twb, edges
  graphFile = File.new(twb + '.cypher', 'w')
  # graphFile.puts "OKEY DOKE, graphing away"

  cypherCode = Set.new
  edges.each do |edge|
    cypherCode.add edge.from.cypherCreate
    cypherCode.add edge.to.cypherCreate
    cypherCode.add edge.cypherCreate
  end
  cypherCode.each do |cc|
    graphFile.puts cc
  end
  graphFile.puts "\nreturn *"
  graphFile.close unless graphFile.nil?
  @imageFiles << File.basename(graphFile)
end

#initDot(twb) ⇒ Object



486
487
488
489
490
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 486

def initDot twb
  dotFile = File.open("#{twb}#{@@processName}.dot",'w')
  dotFile.puts @@dotHeader
  return dotFile
end

#labelTypes(dotFile, edges) ⇒ Object



452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 452

def labelTypes dotFile, edges
  fromTos = Set.new
  edges.each do |edge|
    # fromTos.add "\"Alien Data Source\"  -> \"Alien Data Source\""

    fromTos.add "\"#{edge.from.type}\""
    fromTos.add "\"#{edge.to.type}\""
  end
  return if fromTos.empty?
  dotFile.puts "\n  //  3--------------------------------------------------------------------"
  dotFile.puts '   subgraph cluster_0 {'
  dotFile.puts '     color=white;'
  dotFile.puts '     node [shape="box3d"  style="filled" ];'
  fromTos.each do |ft|
    dotFile.puts "    #{ft}"
  end
  dotFile.puts '   }'
end

#loadNodeType(set, node) ⇒ Object



426
427
428
429
430
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 426

def loadNodeType set, node
  type = node.type
  set[type] = Set.new unless set.include? type
  set[type].add node
end

#mapTwb(twb, edges, rootFields) ⇒ Object



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 333

def mapTwb twb, edges, rootFields
  dotFile     = initDot twb
  dotFileName = File.basename dotFile
  dotFile.puts "\n //  subgraph cluster_1 {"
  dotFile.puts "   //    color= grey;"
  dotFile.puts ""
  edgesAsStrings = SortedSet.new
  # this two step process coalesces the edges into a unique set, avoiding duplicating the dot

  # file entries, and can be shrunk when graph edges expose the bits necessary for management by Set

  emit "\n========================\nLoading Edges\n========================\n  From DC?  Referenced?  Edge \n  %s  %s  %s" % ['--------', '-----------', '-'*45]
  edges.each do |e|
    # don't want to emit edge which is from a Data Connection to a

    # Calculated Field which is also referenced by another calculated field

    isFromDC   = e.from.type == :TwbDataConnection
    isRefField = @referencedFields.include?(e.to.id)
    edgesAsStrings.add(e.dot) unless isFromDC && isRefField
  end
  emit "------------------------\n "
  edgesAsStrings.each do |es|
    dotFile.puts "        #{es}"
    emit "           #{es}"
  end
  emit "========================\n "
  dotFile.puts ""
  dotFile.puts "   // }"
  dotFile.puts "\n\n  //  4--------------------------------------------------------------------"
  # "table::JIRA_HARVEST_Correspondence__c::Jira" [label="JIRA_HARVEST_Correspondence__c"]

  nodes = SortedSet.new
  edges.each do |e|
    nodes.add e.from.dotLabel
    nodes.add e.to.dotLabel
  end
  nodes.each do |n|
    dotFile.puts n
  end
  dotFile.puts "\n\n  //  5--------------------------------------------------------------------"
  emitTypes(      edges,   dotFile )
  rankRootFields( dotFile, rootFields )
  closeDot(       dotFile, twb )
  # renderPng(twb.name,dotFileName)

  # renderPdf(twb.name,dotFileName)

  renderDot(twb,dotFileName,'pdf')
  renderDot(twb,dotFileName,'png')
  renderDot(twb,dotFileName,'svg')
  emitEdges edges
end

#processDataSource(ds) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 134

def processDataSource ds
  emit  "Datasource: '#{ds.uiname}'    -> #{ds.Parameters?}"
  dsFields = {}
  @twbFields[ds.uiname] = dsFields
  # next if ds.Parameters?  # don't process the Parameters data source

                          # it requires special handling, has different XML structure

  #-- For tracking unreferenced (root) calculated fields = calculatedFields - referencedFields

  calculatedFields = SortedSet.new
  referencedFields = SortedSet.new
  #--

  dsTechName  = ds.name
  dsCaption   = ds.caption
  dsName      = ds.uiname
  dsID        = dsTechName + ':::' + dsName
  emit  "\n\n "
  emit  "======================================================"
  emit  "======================================================"
  emit   "=======    DATA SOURCE: #{ds.uiname}    ====== "
  emit  "======================================================"
  emit  "======================================================\n\n "
  dsGraphNode = Twb::Util::Graphnode.new(name: dsName, id: dsID, type: :TwbDataConnection, properties: {workbook: twbWithDir})
  emit  "\t      dsgnode: #{dsGraphNode}"
  fieldUINames      = ds.fieldUINames
  emit  "ds.calculatedFields :: nil? #{ds.calculatedFields.nil?}"
  ds.calculatedFields.each do |calcField|
    emit "HANDLING CALCULATED FIELD::  #{calcField}"
    emit  '--'
    fldCaption,     = calcField.caption
    fldTechName     = calcField.name
    fldName         = calcField.uiname
    dataType        = calcField.datatype 
    role            = calcField.role     
    type            = calcField.type     
    fieldID         = fldTechName+'::'+dsName
    calculatedFields.add fieldID
    #--

    dsFields[fldName] = calcField
    srcGraphNode    = Twb::Util::Graphnode.new(name: fldName,     id: fieldID,      type: :CalculatedField, properties: {:DataSource => dsName})
    dsFieldEdge     = Twb::Util::Graphedge.new(from: dsGraphNode, to: srcGraphNode, relationship: 'contains')
    #--

    emit  "\t     srfnode: #{srcGraphNode} "
    emit  "\t     dsfedge: #{dsFieldEdge} "
    edges.add dsFieldEdge
    calculation     = calcField.calculation
    emit "calculation: f? %8s -> %s " % [calculation.has_formula, calculation.formula ]
    if calculation.has_formula
        formulaFlat     = calculation.formulaFlat
        uiFormula       = formulaFlat.gsub(' XX ',' ')
        formulaLOD      = formulaFlat.upcase =~ /^[ ]*{[ ]*(INCLUDE|FIXED|EXCLUDE)/
        resolvedFields  = calculation.resolvedFields
        resolvedFields.each do |rf|
          emit  "\tRESOLVED FLD: #{rf.inspect}"
          calcFieldName   = rf[:field]
          if rf[:source].nil?
            calcFieldRef = "[%s]" % [ calcFieldName ]
            dispFieldRef = "[%s]" % [ ds.fieldUIName(calcFieldName) ]
          else
            remoteDS     = @twb.datasource(rf[:source])
            if remoteDS.nil?
              calcFieldRef = "[DS_NOT_FOUND].[%s]" % [ calcFieldName ]
              dispFieldRef = calcFieldRef
            else
              remoteDSName = remoteDS.uiname 
              remoteDSFld  = remoteDS.fieldUIName(calcFieldName)
              calcFieldRef = "[%s].[%s]" % [ rf[:source],  calcFieldName ]
              dispFieldRef = "[%s].[%s]" % [ remoteDSName, remoteDSFld   ]
            end # remoteDS.nil?

          end # rf[:source].nil?

          emit  "\tcalcFieldRef: #{calcFieldRef}"
          emit  "\tdispFieldRef: #{dispFieldRef}"
          uiFormula    = uiFormula.gsub(calcFieldRef, dispFieldRef)
        end # resolvedFields.each

        @csvCalculatedFields.push [
                                    @calculatedFieldsCount += 1,
                                    twb,           
                                    twbDir,
                                    dsName,
                                    dsCaption,
                                    dsTechName,
                                    fldName,
                                    fldCaption,
                                    fldTechName,
                                    dsTechName + '::' + fldTechName,
                                    dataType,
                                    role,
                                    type,
                                    calculation.class,     
                                    calculation.scopeIsolation,
                                    calculation.formulaFlat.length, 
                                    calculation.formulaFlat,    
                                    uiFormula[0...200],
                                    calculation.comments,
                                    !formulaLOD.nil?
                                  ]
        resolvedFields.each do |rf|
          emit  "\t\t        res field : #{rf[:field]}    "
          emit  "\t\t        res source: #{rf[:source]}"
          calcFieldName   = rf[:field]
          calcDataSource  = rf[:source]
          localDataSource = rf[:source].nil?   # if there isn't a rf[:source] value

                                                 # the field is from this data source

                                                 # else the field is from an alien data source (in the same workbook)

          refDataSource     = localDataSource ? ds : @twb.datasource(calcDataSource)  # data source may not be in Workbook

          refDataSourceName = !refDataSource.nil? ? refDataSource.uiname : calcDataSource + '\n***DATA CONNECTION NOT IN WORKBOOK***'
          if !refDataSource.nil?
            dispFieldName   = refDataSource.fieldUIName(calcFieldName)
            calcFieldTable  = refDataSource.fieldTable(calcFieldName)
          else
            dispFieldName   = calcFieldName
            calcFieldTable  = calcFieldName
          end
          emit  "\t\t       calc field : #{dispFieldName}          nil?<#{dispFieldName.nil?}>"
          emit  "\t\t       data source: #{refDataSourceName}"
          emit  "\t\t             table: #{calcFieldTable}         nil?<#{calcFieldTable.nil?}>"
          properties = {'DataSource' => dsName, 'DataSourceReference' => 'local'}
          if dispFieldName.nil?
             dispFieldName = "<#{calcFieldName}>::<#{calcDataSource}> UNDEFINED"
             properties['status'] = 'UNDEFINED'
          end
          calcFieldID = "#{calcFieldName}::#{refDataSourceName}"
          if !localDataSource
            calcFieldID = "#{calcFieldName}:LDS:#{ds.uiname}:RDS:#{refDataSourceName}"
            properties['DataSourceReference'] = 'remote'
          end
          calcFieldTable = ds.fieldTable(calcFieldName)
          calcFieldType  = calcFieldTable.nil? ? :CalculatedField : :DatabaseField
          calcFieldNode  = Twb::Util::Graphnode.new(name: dispFieldName, id: calcFieldID,   type: calcFieldType, properties: properties)
          fieldFieldEdge = Twb::Util::Graphedge.new(from: srcGraphNode,  to: calcFieldNode, relationship: 'references')
          edges.add fieldFieldEdge
          referencedFields.add calcFieldID
          emit  "\t\t    calcFieldNode: #{calcFieldNode}"
          emit  "\t\t        graphEdge: #{fieldFieldEdge}"
          fldToDsNode = calcFieldNode
          if !calcFieldTable.nil?
             tableID        = calcFieldTable + ':::' + ds.uiname
             tableName      = "-[#{calcFieldTable}]-"
             tableNode      = Twb::Util::Graphnode.new(name: tableName,      id: tableID,   type: :DBTable, properties: properties)
             fieldFieldEdge = Twb::Util::Graphedge.new(from: calcFieldNode,  to: tableNode, relationship: 'is a field in')
             edges.add fieldFieldEdge
             fldToDsNode    = tableNode
          end
          if !localDataSource
            alienDSNode = Twb::Util::Graphnode.new(       name: '==>' + refDataSourceName,
                                                            id: "#{ds.uiname}::::=>#{refDataSourceName}",
                                                          type: :DBTable,
                                                    properties: {'Home Source' => dsName, 'Remote Source' => refDataSourceName}
                                                  )
            fieldFieldEdge  = Twb::Util::Graphedge.new(from: fldToDsNode,  to: alienDSNode, relationship: 'In Remote Data Source')
            edges.add fieldFieldEdge
          end

          # @csvFormulaFields.push [ @formulaFieldsCount+=1,



        end # resolvedFields.each do

    end # if calculation.has_formula

  end # ds.calculatedFields.each 


  dsRootFields = calculatedFields - referencedFields
  @referencedFields.merge referencedFields
  #--

  emit "--\nCalculated Fields\n-----------------"
  calculatedFields.each { |f| emit f }
  emit "--\nReferenced Fields\n-----------------"
  referencedFields.each { |f| emit f }
  emit "--\nDS Root Fields\n-----------------"
  dsRootFields.each { |f| emit f }
  emit "--"
  # --

  twbRootFields.merge dsRootFields
  @twbCount += 1
  mapTwb     twb, edges, twbRootFields
  graphEdges twb, edges
  emit "#######################"
  #--

  csvCF = File.open(@@calcFieldsCSVFileName, 'w')
  csvCF.puts @@calcFieldsCSVFileHeader.to_csv
  @csvCalculatedFields.each do |r| 
    csvCF.puts r.to_csv
  end
  csvCF.close
  #--

  csvFF = File.open(@@formFieldsCSVFileName, 'w')
  csvFF.puts @@formFieldsCSVFileHeader.to_csv
  @csvFormulaFields.each do |r| 
    csvFF.puts r.to_csv
  end
  csvFF.close
  #--

  return @imageFiles
end

#processTWB(twbWithDir) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 95

def processTWB twbWithDir
  twb = File.basename(twbWithDir)
  @twb = Twb::Workbook.new twbWithDir
  emit  "- Workbook: #{twbWithDir}"
  emit  "   version: #{@twb.version}"
  return if twbWithDir.end_with? == "Tableau Calculated Fields Analyses.twb"
  twbDir   = File.dirname(File.expand_path(twbWithDir))
  edges    = Set.new
  # -- processing

  dss = @twb.datasources
  puts "    # data sources: #{dss.length}"
  twbRootFields = Set.new
  @twbFields = {}
  dss.each do |ds|
    puts "\t\t - #{ds.uiname}  \t\t #{ds.calculatedFields.length}"
    next if ds.Parameters?  # don't process the Parameters data source

    ds.calculatedFields.each do |calcField|
      emit "HANDLING CALCULATED FIELD::  #{calcField}"
      emit "                         ::  #{calcField.calculation.formula}"
      emit "                         ::  #{calcField.calculation.formulaResolved}"
      dsTechName  = ds.name
      dsCaption   = ds.caption
      dsName      = ds.uiname
      dsID        = dsTechName + ':::' + dsName
      emit  "\n\n "
      emit  "======================================================"
      emit  "======================================================"
      emit   "=======    DATA SOURCE: #{ds.uiname}    ====== "
      emit  "======================================================"
      emit  "======================================================\n\n "
      dsGraphNode = Twb::Util::Graphnode.new(name: dsName, id: dsID, type: :TwbDataConnection, properties: {workbook: twbWithDir})
      emit  "\t      dsgnode: #{dsGraphNode}"
      fieldUINames      = ds.fieldUINames
      emit  "ds.calculatedFields :: nil? #{ds.calculatedFields.nil?}"
    end
    processDataSource ds
  end
end

#rankRootFields(dotFile, dsRootFields) ⇒ Object



442
443
444
445
446
447
448
449
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 442

def rankRootFields dotFile, dsRootFields
  dotFile.puts "\n  // Unreferenced (root) Calculated Fields -----------------------------------------"
  dotFile.puts "\n  {rank=same "
  dsRootFields.each do |rf|
    dotFile.puts "     \"#{rf}\""
  end
  dotFile.puts "  }"
end

#rankSame(dotFile, type, nodes) ⇒ Object



432
433
434
435
436
437
438
439
440
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 432

def rankSame dotFile, type, nodes
  dotFile.puts "\n  // '#{type}' --------------------------------------------------------------------"
  dotFile.puts "\n  {rank=same "
  # dotFile.puts "     \"#{type}\"  [shape=\"box3d\" style=\"filled\" ]" unless ''.eql? type # [shape=\"box3d\"  style=\"filled\" ]\"" unless label.equal? ''

  nodes.each do |node|
    dotFile.puts "     \"#{node.id}\""
  end
  dotFile.puts "  }"
end

#renderDot(twb, dot, format) ⇒ Object



513
514
515
516
517
518
519
520
521
522
# File 'lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb', line 513

def renderDot twb, dot, format
  emit  "Rendering DOT file\n  - #{twb}\n  - #{dot}\n  - #{format}"
  imageType = '-T' + format
  imageFile  = twb + @@processName + 'Graph.' + format
  imageParam = '-o' + imageFile
  emit  "system #{@@gvDotLocation} #{imageType} #{imageParam} #{dot}"
         # system  @@gvDotLocation,   imageType,   imageParam,   dot

  @imageFiles << imageFile
  return imageFile
end