twb 2.2.1 → 3.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/lib/twb.rb +13 -1
  3. data/lib/twb/action.rb +5 -1
  4. data/lib/twb/analysis/AnnotatedFieldsCSVEmitter.rb +3 -0
  5. data/lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb +276 -287
  6. data/lib/twb/analysis/CalculatedFields/MarkdownEmitter.rb +48 -34
  7. data/lib/twb/analysis/DataSources/DataSourceFieldsCSVEmitter.rb +103 -103
  8. data/lib/twb/analysis/DataSources/googlesheetdatasourcesanalyzer.rb +79 -0
  9. data/lib/twb/analysis/DocumentedFieldsMarkdownEmitter.rb +1 -1
  10. data/lib/twb/analysis/Sheets/sheetfieldsanalyzer.rb +82 -0
  11. data/lib/twb/analysis/Sheets/sheetfiltersanalyzer.rb +214 -0
  12. data/lib/twb/calculatedfield.rb +20 -5
  13. data/lib/twb/codedfield.rb +87 -0
  14. data/lib/twb/columnfield.rb +21 -2
  15. data/lib/twb/connection.rb +33 -0
  16. data/lib/twb/dashboard.rb +5 -1
  17. data/lib/twb/datasource.rb +131 -20
  18. data/lib/twb/dbfield.rb +4 -0
  19. data/lib/twb/field.rb +5 -1
  20. data/lib/twb/fieldcalculation.rb +134 -78
  21. data/lib/twb/localfield.rb +5 -1
  22. data/lib/twb/mappedfield.rb +5 -1
  23. data/lib/twb/metadatafield.rb +5 -1
  24. data/lib/twb/storyboard.rb +5 -1
  25. data/lib/twb/tabclass.rb +71 -0
  26. data/lib/twb/tabtest.rb +31 -0
  27. data/lib/twb/tabtool.rb +63 -0
  28. data/lib/twb/twbcodedfield.rb +87 -0
  29. data/lib/twb/util/cypher.rb +112 -0
  30. data/lib/twb/util/cypherpython.rb +128 -0
  31. data/lib/twb/util/docprep.rb +46 -0
  32. data/lib/twb/util/fielddomainloader.rb +108 -0
  33. data/lib/twb/util/gml.rb +144 -0
  34. data/lib/twb/util/gmledge.rb +73 -0
  35. data/lib/twb/util/graph.rb +30 -0
  36. data/lib/twb/util/graphedge.rb +8 -9
  37. data/lib/twb/util/graphnode.rb +46 -29
  38. data/lib/twb/util/tabgraph.rb +30 -0
  39. data/lib/twb/window.rb +5 -1
  40. data/lib/twb/workbook.rb +18 -5
  41. data/lib/twb/worksheet.rb +5 -1
  42. data/test/fieldAliases.rb +10 -0
  43. data/test/testFieldAliases.rb +65 -0
  44. data/test/testFieldDomainLoaded.rb +14 -0
  45. data/test/testFieldDomainLoader.rb +131 -0
  46. metadata +22 -1
@@ -0,0 +1,128 @@
1
+ # Copyright (C) 2012, 2015 Chris Gerrard
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'csv'
17
+
18
+ module Twb
19
+ module Util
20
+
21
+ class CypherPython
22
+
23
+ # @@hasher = Digest::SHA256.new
24
+
25
+ @@docfileName = './ttdoc/cypherpython.log'
26
+
27
+ #====================================================================
28
+
29
+ attr_accessor :nodes, :edges
30
+ attr_accessor :fileName, :fileName
31
+ attr_accessor :user, :password
32
+ attr_accessor :cleanup
33
+
34
+ def initialize
35
+ @docfile = File.open(@@docfileName,'a+')
36
+ @docfile.puts "Starting up the Cypher in Python process"
37
+ @fileName = 'Neo4jCypherPython'
38
+ @user = 'neo4j'
39
+ @password = 'imthepwd2oo'
40
+ @nodes = []
41
+ @edges = []
42
+ @cleanup = false
43
+ end
44
+
45
+ def render
46
+ @file = File.open("./ttdoc/#{@fileName}.py",'w')
47
+ @file.puts '# -*- coding: latin-1 -*-'
48
+ @file.puts ' '
49
+ @file.puts 'from py2neo import Graph'
50
+ @file.puts "graph = Graph('http://localhost:7474/db/data', user='#{@user}', password='#{@password}')"
51
+ @file.puts ' '
52
+ renderNodes
53
+ renderEdges
54
+ @file.close
55
+ return @file
56
+ end
57
+
58
+ def renderNodes
59
+ csv = CSV.open("./ttdoc/#{@fileName}.py.nodes.csv",'w')
60
+ csv << ['Type','Name','UUID']
61
+ nodesCSV = Set.new
62
+ nodeCmds = SortedSet.new
63
+ nodesByType = Hash.new { |type,nodes| type[nodes] = [] }
64
+ @nodes.each do |node|
65
+ nodesCSV << [node.type, node.name, node.uuid]
66
+ nodeCmds << encodeNode('MERGE','node',node,';')
67
+ nodesByType[node.type] << node
68
+ end
69
+ if @cleanup
70
+ nodesByType.keys.each do |type|
71
+ @file.puts "DROP CONSTRAINT ON (node:#{type}) ASSERT node.uuid IS UNIQUE ;"
72
+ end
73
+ @file.puts "MATCH (n) DETACH DELETE n ;"
74
+ nodesByType.keys.each do |type|
75
+ @file.puts "CREATE CONSTRAINT ON (node:#{type}) ASSERT node.uuid IS UNIQUE ;"
76
+ end
77
+ @file.puts "//--"
78
+ end
79
+ nodesCSV.each do |rec|
80
+ csv << rec
81
+ end
82
+ nodeCmds.each do |cmd|
83
+ @file.puts cmd
84
+ end
85
+ csv.close
86
+ end
87
+ # USING PERIODIC COMMIT
88
+ # LOAD CSV WITH HEADERS FROM "file:://C:/tech/Tableau/Tableau Tools/Ruby/experiments/GraphElements.nodes.csv" AS row
89
+ # CREATE (:row.Type {name: row.Name, uuid: row.UUID});
90
+
91
+ def renderEdges
92
+ csv = CSV.open("./ttdoc/#{@fileName}.edges.csv",'w')
93
+ csv << ['Source Type' , 'Source Name' , 'Source UUID' , 'Relationship', 'Target Type', 'Target Name', 'Target UUID' ]
94
+ @edges.each do |edge|
95
+ relationship = edge.relationship.upcase.gsub(/[ ]+/,'_')
96
+ csv << [edge.from.type, edge.from.name, edge.from.uuid, relationship , edge.to.type , edge.to.name, edge.to.uuid ]
97
+ @file.puts ' '
98
+ @file.puts 'query = """'
99
+ @file.puts encodeEdge('MATCH', 'source', edge.from)
100
+ @file.puts encodeEdge('MATCH', 'target', edge.to)
101
+ @file.puts "%-8s (source)-[r:%s]->(target) " % ['MERGE', edge.relationship.upcase.gsub(/[ ]+/,'_')]
102
+ @file.puts "RETURN source.name, type(r), target.name ;"
103
+ @file.puts '"""'
104
+ @file.puts 'graph.run(query)'
105
+ @file.puts "print '-',"
106
+ end
107
+ csv.close
108
+ end
109
+
110
+ def encodeNode command, varName, node, terminator=''
111
+ # "g.run('MERGE (node:CalculatedField { name:\"YTD Cost Amount\", uuid: \"ccd4f66d0c8ee09eca10ab3a1adabe35\" } ) ');"
112
+ # "g.run"
113
+ "graph.run( \"%-8s (%s:%s { name:'%s', uuid: '%s' } ) %s\")\nprint '.'," % [command, varName, node.type, node.name.gsub('"','\"'), node.uuid, terminator ]
114
+ end
115
+
116
+ def encodeEdge command, varName, node, terminator=''
117
+ "%-8s (%s:%s { uuid: '%s' } ) %s" % [command, varName, node.type, node.uuid, terminator ]
118
+ end
119
+
120
+ def to_s
121
+ "file:#{@fileName}; #nodes:#{@nodes.length}; #edges:#{@edges.length}"
122
+ end
123
+
124
+
125
+ end
126
+
127
+ end # module Util
128
+ end # module Twb
@@ -0,0 +1,46 @@
1
+ # Copyright (C) 2018 Chris Gerrard
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ module Twb
17
+ module Util
18
+
19
+ class DocPrep
20
+
21
+ @@dir = './ttdoc'
22
+
23
+ attr_accessor :dir
24
+
25
+ def initialize
26
+ reset
27
+ end
28
+
29
+ def reset
30
+ @dir = @@dir
31
+ init
32
+ end
33
+
34
+ def prepFile fileName
35
+ "#{@dir}/#{fileName}"
36
+ end
37
+
38
+ def init dirName
39
+ Dir.mkdir @Name
40
+ end
41
+
42
+
43
+ end # class DocPrep
44
+
45
+ end # module Util
46
+ end # module Twb
@@ -0,0 +1,108 @@
1
+ # Copyright (C) 2018 Chris Gerrard
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ module Twb
17
+ module Util
18
+
19
+ require 'creek'
20
+ require 'csv'
21
+
22
+ class FieldDomainLoader
23
+
24
+ @@xmlLocation = './ttdoc'
25
+
26
+ attr_reader :domains
27
+ attr_accessor :xmllocation, :workboook, :datasource, :csvOption
28
+
29
+ def initialize
30
+ reset
31
+ end
32
+
33
+ def reset
34
+ @workbok = nil
35
+ @xmllocation = @@xmlLocation
36
+ @csvOption = 'w'
37
+ initCSV @csvOption
38
+ end
39
+
40
+ def initCSV opt
41
+ @csvFile = CSV.open(@xmllocation + '/TwbFieldDomains.csv', opt )
42
+ if 'w'.eql? opt
43
+ @csvFile << ['Workbook', 'Data Source', 'Field', 'Value']
44
+ end
45
+ end
46
+
47
+ def load
48
+ path = @xmllocation + '/*.xlsx'
49
+ Dir.glob(path) do |fileName|
50
+ end
51
+ end
52
+
53
+ def loadWorkbook twb
54
+ @workbook = twb.name
55
+ dsFieldDomains = {}
56
+ dss = twb.datasources
57
+ dsFieldDomains = {}
58
+ dss.each do |ds|
59
+ fieldDomains = loadDataSource ds
60
+ dsFieldDomains[ds.uiname] = fieldDomains
61
+ end
62
+ return dsFieldDomains
63
+ end
64
+
65
+ def loadDataSource ds
66
+ @datasource = ds.uiname
67
+ fieldDomains = loadxlsx(@xmllocation + '/' + @datasource + '.xlsx')
68
+ end
69
+
70
+ def loadxlsx fileName
71
+ fieldDomains = {}
72
+ if File.file?(fileName)
73
+ xlsx = Creek::Book.new fileName
74
+ sheets = xlsx.sheets
75
+ sheets.each do |sheet|
76
+ rows = sheet.rows.to_a
77
+ if rows.count > 1
78
+ fieldValues = parseRows(rows)
79
+ unless fieldValues.empty? || fieldValues.values.first.empty?
80
+ fieldDomains[fieldValues.keys.first] = fieldValues.values.first
81
+ end
82
+ end
83
+ end
84
+ else
85
+ puts "#### ALERT #### XLSX file does not exist: #{fileName}"
86
+ end
87
+ return fieldDomains
88
+ end
89
+
90
+ def parseRows rows
91
+ fieldValues = {}
92
+ unless rows.empty?
93
+ firstRow = rows[0].to_a[0]
94
+ fieldName = firstRow[1].to_s
95
+ fieldValues[fieldName] = SortedSet.new
96
+ values = rows[1..-1]
97
+ values.each do |row|
98
+ value = row.to_a[0][1].to_s
99
+ fieldValues[fieldName] << value
100
+ end
101
+ end
102
+ return fieldValues
103
+ end
104
+
105
+ end # class FieldDomainLoader
106
+
107
+ end # module Util
108
+ end # module Twb
@@ -0,0 +1,144 @@
1
+ # Copyright (C) 2012, 2015 Chris Gerrard
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'digest/md5'
17
+
18
+ module Twb
19
+ module Util
20
+
21
+ class GML
22
+
23
+ include TabTool
24
+
25
+ @@hasher = Digest::SHA256.new
26
+
27
+ @@docfileName = './ttdoc/gml.log'
28
+
29
+ #====================================================================
30
+ @@gmlHeader = <<GMLHEADER
31
+ graph [
32
+ directed 1
33
+ rankdir "LR"
34
+ splines "line"
35
+
36
+ GMLHEADER
37
+
38
+ @@gmlFooter = "\n]"
39
+
40
+ attr_accessor :nodes, :edges, :fileName, :gmlHeader
41
+
42
+ def initialize
43
+ # @docFile = File.open(@@docfileName,'w')
44
+ # @docFile.puts "Starting up the GML process"
45
+ @gmlHeader = @@gmlHeader
46
+ @fileName = 'gmlFile'
47
+ @nodes = SortedSet.new
48
+ @edges = SortedSet.new
49
+ end
50
+
51
+ # def gmlHeader=(text)
52
+ # @gmlHeader = text
53
+ # end
54
+
55
+ # def init fileName
56
+ # # do stuff for new GML file here
57
+ # @fileName = fileName
58
+ # prepare
59
+ # end
60
+
61
+ def prepare
62
+ @nodes = SortedSet.new
63
+ @edges = SortedSet.new
64
+ end
65
+
66
+ def render
67
+ # puts "GML.render - rendering into #{@fileName}"
68
+ file = File.open(docFile("#{@fileName}.gml"),'w')
69
+ file.puts @gmlHeader
70
+ renderNodes file
71
+ renderEdges file
72
+ file.puts @@gmlFooter
73
+ file.close
74
+ return file
75
+ end
76
+
77
+ def renderNodes file
78
+ nodes = Set.new
79
+ @nodes.each do |node|
80
+ gmlID = Digest::MD5.hexdigest(node.id)
81
+ gmlName = node.name.gsub('&','&amp;').gsub('"','&quot;')
82
+ nodes << "node [\n id \"#{gmlID}\" \n label \"#{gmlName}\" \n ]"
83
+ end
84
+ nodes.each do |node|
85
+ file.puts node
86
+ end
87
+ end
88
+
89
+ def renderEdges file
90
+ edges = Set.new
91
+ @edges.each do |edge|
92
+ gmlSourceID = Digest::MD5.hexdigest(edge.from.id)
93
+ gmlTargetID = Digest::MD5.hexdigest(edge.to.id)
94
+ edges << "edge [\n source \"#{gmlSourceID}\" \n target \"#{gmlTargetID}\" \n ]"
95
+ end
96
+ edges.each do |edge|
97
+ file.puts edge
98
+ end
99
+ end
100
+
101
+ def to_s
102
+ "file:#{@fileName}; #nodes:#{@nodes.length}; #edges:#{@edges.length}"
103
+ end
104
+
105
+
106
+ end
107
+
108
+ end # module Util
109
+ end # module Twb
110
+
111
+
112
+ # node [
113
+ # id 7
114
+ # label "5"
115
+ # edgeAnchor "corners"
116
+ # labelAnchor "n"
117
+ # graphics [
118
+ # center [ x 82.0000 y 42.0000 ]
119
+ # w 16.0000
120
+ # h 16.0000
121
+ # type "rectangle"
122
+ # fill "#000000"
123
+ # ]
124
+ # ]
125
+ # edge [
126
+ # label "24"
127
+ # labelAnchor "first"
128
+ # source 7
129
+ # target 15
130
+ # graphics [
131
+ # type "line"
132
+ # arrow "last"
133
+ # Line [
134
+ # point [ x 82.0000 y 42.0000 ]
135
+ # point [ x 10.0000 y 10.0000 ]
136
+ # point [ x 100.000 y 100.000 ]
137
+ # point [ x 80.0000 y 30.0000 ]
138
+ # point [ x 120.000 y 230.000 ]
139
+ # point [ x 73.0000 y 160.000 ]
140
+ # ]
141
+ # ]
142
+ # ]
143
+
144
+
@@ -0,0 +1,73 @@
1
+ # Copyright (C) 2018 Chris Gerrard
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ module Twb
17
+ module Util
18
+
19
+ class GMLedge
20
+
21
+ # @from - the origin node
22
+ # @to - the destination node
23
+ # @relationship - useful for categorizing the edge
24
+ # @properties - useful for categorizing the edge
25
+ attr_reader :from, :to, :relationship
26
+ attr_accessor :properties
27
+ attr_reader :cypherCreate
28
+
29
+ # Neo4J cypher variable quote character: `
30
+
31
+ def initialize (from:, to:, relationship:, properties: {})
32
+ raise ArgumentError.new("from: parameter must be a Graphnode, is a '#{from.class}'") unless from.is_a? Twb::Util::Graphnode
33
+ raise ArgumentError.new( "to: parameter must be a Graphnode, is a '#{to.class}'" ) unless to.is_a? Twb::Util::Graphnode
34
+ @from = from
35
+ @to = to
36
+ @relationship = relationship
37
+ @properties = properties
38
+ @cypherCreate = "CREATE #{cypher_s}"
39
+ end
40
+
41
+ def eql? other
42
+ @from == other.from && @to == other.to && @relationship == other.relationship && @properties == other.properties
43
+ end
44
+
45
+ def hash
46
+ [@from.hash, @to.hash, @relationship, @properties].hash
47
+ end
48
+
49
+ def to_s
50
+ "'#{@from.name}//{@from.id}' --#{@relationship}--> '#{@to.name}//#{@to.id}'"
51
+ end
52
+
53
+ def dot
54
+ "%s -> %s" % [dotquote(from.id), dotquote(to.id)]
55
+ end
56
+
57
+ def dotquote str
58
+ ns = str.gsub(/(["])/,'\\"')
59
+ return "\"#{ns}\""
60
+ end
61
+
62
+ def cypher_s
63
+ "(%s)-[:`%s`]->(%s)" % [@from.cypherID,@relationship,@to.cypherID]
64
+ end
65
+
66
+ def gml
67
+ "%s -> %s" % [dotquote(from.id), dotquote(to.id)]
68
+ end
69
+
70
+ end
71
+
72
+ end # module Util
73
+ end # module Twb