lucidMachines 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,132 @@
1
+ class Chart
2
+ attr_reader :pages, :blocks, :links
3
+
4
+ def initialize
5
+ @pages = {}
6
+ @blocks = {}
7
+ @links = {}
8
+ end
9
+
10
+ def states
11
+ @blocks.each_value.select{|b| b.is_state?}
12
+ end
13
+
14
+ def states_on_page(page)
15
+ @blocks.each_value.select{|b| b.is_state? and b.page == page }
16
+ end
17
+
18
+ def blocks_on_page(page)
19
+ @blocks.each_value.select{|b| b.page == page }
20
+ end
21
+
22
+ def get_blocks_of_type(type)
23
+ @blocks.each_value.select do |b|
24
+ b.type.eql? type
25
+ end
26
+ end
27
+
28
+
29
+ def add_page(page)
30
+ @pages[page.id] = page
31
+ end
32
+
33
+ def get_page(id)
34
+ return @pages[id]
35
+ end
36
+
37
+ def page(name_to_find)
38
+ out = @pages.values.select do |p|
39
+ p.name.eql? name_to_find
40
+ end
41
+
42
+ return nil if out.empty?
43
+ return out.first
44
+ end
45
+
46
+ # same for blocks
47
+ def add_block(b) ; @blocks[b.id] = b; end
48
+ def get_block(id); @blocks[id] ; end
49
+
50
+ # same for links
51
+ def add_link(l) ; @links[l.id] = l; end
52
+ def get_link(id); @links[id] ; end
53
+
54
+ def has_block?(id)
55
+ @blocks.has_key? id
56
+ end
57
+
58
+
59
+ # replace text with objects
60
+ def set_pages
61
+ @pages.each_value do |page|
62
+ @blocks.each_value do |block|
63
+ page.set_block(block.id, block) if block.page_id == page.id
64
+ end
65
+ @links.each_value do |link|
66
+ link.set_page(page) if link.page_id == page.id
67
+ end
68
+ end
69
+ end
70
+
71
+ # replace text with objects
72
+ def set_links
73
+ @links.each_value do |link|
74
+ source_block = get_block(link.source)
75
+ destination_block = get_block(link.destination)
76
+
77
+ next if source_block.nil? or destination_block.nil?
78
+
79
+ source_block.link_to destination_block, link
80
+ destination_block.link_from source_block, link
81
+ end
82
+ end
83
+
84
+ def check_initial
85
+ @blocks.each_value do |b|
86
+ next unless b.has_links?
87
+ b.links_from.each_value do |b2|
88
+ if b2.text.eql? "Initial"
89
+ b2.hide
90
+ b.set_initial
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+
97
+ def subchart_for_page(page)
98
+ chart = Chart.new
99
+
100
+ # add the page
101
+ chart.add_page!( { page.id => page} )
102
+
103
+ # add the blocks of this page
104
+
105
+ @blocks.each do |block_id, block|
106
+ next unless block.page == page
107
+ chart.add_block!({ block_id => block })
108
+ end
109
+
110
+ # add the links of this page
111
+ @links.each do |link_id, link|
112
+ next unless link.page == page
113
+ chart.add_link!({ link_id => link })
114
+ end
115
+
116
+ return chart
117
+ end
118
+
119
+ def add_page!(page)
120
+ @pages.merge!(page)
121
+ end
122
+
123
+ def add_block!(block)
124
+ @blocks.merge!(block)
125
+ end
126
+
127
+ def add_link!(link)
128
+ @links.merge!(link)
129
+ end
130
+
131
+ end
132
+
@@ -0,0 +1,68 @@
1
+ require 'thor'
2
+ require 'ruby-graphviz'
3
+
4
+ module LucidMachines
5
+ class CLI < Thor
6
+
7
+ desc "convert", "Convert a CSV file"
8
+ def convert(csv_file, sheet)
9
+
10
+ puts "Exporting #{csv_file}, sheet: #{sheet}."
11
+
12
+ chart = ChartLoader.new(csv_file).chart
13
+ # export_all chart
14
+ export(chart, sheet)
15
+ end
16
+
17
+ end
18
+ end
19
+
20
+
21
+
22
+ # # coding: utf-8
23
+ # require 'ruby-graphviz'
24
+ # require 'csv'
25
+
26
+ # require 'aasm'
27
+ # require 'aasm-diagram'
28
+
29
+ # require './loader'
30
+ # require './elements'
31
+ # require './chart'
32
+ # require './aasm_export'
33
+ # require './graphviz_export'
34
+ # require './exporter'
35
+
36
+ # # IRB.CurrentContext.echo = true
37
+ # include ChartReader
38
+
39
+ # # chart = ChartLoader.new("integration2.csv").chart; nil;
40
+
41
+ # chart = ChartLoader.new("integration.csv").chart
42
+ # # export_all chart
43
+ # export(chart,"state machine def")
44
+ # export(chart,"ex4")
45
+ # export(chart,"ex3")
46
+
47
+
48
+ # # p_ex2 = @chart.page "ex2" ; nil ;
49
+ # # @ex2 = @chart.subchart_for_page p_ex2; nil ;
50
+ # # GraphVizExport.new(@ex2).build_graph("chart-ex2.png") ; nil ;
51
+
52
+
53
+ # # @ae = AASMExport.new(@ex2); nil ;
54
+ # # JobTest.class_eval @ae.export
55
+ # # @ae.generate_methods_placeholder_for(JobTest)
56
+
57
+
58
+ # # @j = JobTest.new
59
+ # # ## Todo write in a file ?
60
+
61
+ # # AASMDiagram::Diagram.new(@j.aasm, 'ex2-2.png')
62
+
63
+ # # open('ex2.rb', 'w') do |f|
64
+ # # f << @ae.export
65
+ # # f << @ae.generate_methods_placeholder
66
+ # # end
67
+
68
+
@@ -0,0 +1,107 @@
1
+ class Element
2
+ attr_reader :id, :page_id
3
+ attr_reader :text, :type
4
+
5
+ attr_reader :page
6
+ attr_reader :initial, :hidden
7
+
8
+ def initialize(entry)
9
+ @id = entry["Id"]
10
+ @type = entry["Name"]
11
+ @text = entry["Text Area 1"]
12
+ @page_id = entry["Page ID"]
13
+ @link_to = {}
14
+ @link_from = {}
15
+ @initial = false
16
+ end
17
+
18
+ def set_initial ; @initial = true; end
19
+ def is_initial? ; @initial; end
20
+
21
+ def hide ; @hidden = true; end
22
+ def is_hidden? ; @hidden; end
23
+
24
+ def is_state?
25
+
26
+ # not is_hidden? and has_links? and not text.nil?
27
+ return false if is_hidden? or not has_links?
28
+
29
+ if text.nil?
30
+ type.eql? "transition"
31
+ else
32
+ true
33
+ end
34
+ end
35
+
36
+ def link_to(element, link)
37
+ @link_to[link] = element
38
+ end
39
+
40
+ def link_from(element, link)
41
+ @link_from[link] = element
42
+ end
43
+
44
+ def links_to; @link_to; end
45
+ def links_from; @link_from; end
46
+
47
+ def links_to_type(type)
48
+ @link_to.each_value.select{ |b| b.type.eql? type }
49
+ end
50
+
51
+ def links_from_type(type)
52
+ @link_from.each_value.select{ |b| b.type.eql? type }
53
+ end
54
+
55
+
56
+ def has_links?
57
+ @link_to.size != 0 or @link_from.size != 0
58
+ end
59
+
60
+ def set_page(p)
61
+ @page = p
62
+ end
63
+
64
+ def to_s
65
+ "Element: " + @id
66
+ end
67
+ end
68
+
69
+ class Page < Element
70
+ attr_reader :name
71
+ attr_reader :blocks
72
+
73
+ def initialize(entry)
74
+ super(entry)
75
+ puts "ERROR: You cannot create this page" unless is_page? entry
76
+ @name = entry["Text Area 1"]
77
+ @blocks = {}
78
+ end
79
+
80
+ def set_block(id, block)
81
+ @blocks[id] = block
82
+ block.set_page(self)
83
+ end
84
+
85
+ def to_s
86
+ "Page: " + @name.to_s
87
+ end
88
+
89
+ end
90
+
91
+ class Link < Element
92
+ attr_reader :source, :destination
93
+ attr_reader :source_arrow, :destination_arrow
94
+
95
+ def initialize(entry)
96
+ super(entry)
97
+ @source = entry["Line Source"]
98
+ @destination = entry["Line Destination"]
99
+
100
+ @source_arrow = entry["Source Arrow"]
101
+ @destination_arrow= entry["Destination Arrow"]
102
+ end
103
+
104
+ def to_s
105
+ "Link : " + @source.to_s + " -> " + @destination.to_s
106
+ end
107
+ end
@@ -0,0 +1,39 @@
1
+ class JobTest
2
+ include AASM
3
+ def tie_shoes
4
+ puts "Tying the shoes ..."
5
+ end
6
+ end
7
+
8
+ def export_all(chart)
9
+ chart.pages.each_value do |p|
10
+ export(chart, p.name)
11
+ end
12
+ end
13
+
14
+ def export(chart, page_name)
15
+ p_ex2 = chart.page page_name
16
+ page = chart.subchart_for_page p_ex2
17
+
18
+ # export GraphViz 1
19
+ GraphVizExport.new(page).build_graph("export/chart-#{page_name}.png")
20
+
21
+ # export AASM
22
+ page_aasm_export = AASMExport.new(page)
23
+
24
+ # export to a file
25
+ open("export/#{page_name}_generated.rb", 'w') do |f|
26
+ f << page_aasm_export.export
27
+ f << page_aasm_export.generate_methods_placeholder
28
+ end
29
+
30
+ # export GraphViz 2 (through aasm-diagram)
31
+
32
+ ## Extend the JobTest class
33
+ # JobTest.class_eval page_aasm_export.export
34
+ # page_aasm_export.generate_methods_placeholder_for(JobTest)
35
+ # @j = JobTest.new
36
+ # AASMDiagram::Diagram.new(@j.aasm, "export/chart-#{page_name}-2.png")
37
+
38
+ end
39
+
@@ -0,0 +1,71 @@
1
+ class GraphVizExport
2
+ def initialize(chart)
3
+ @chart = chart
4
+ @g = GraphViz.new( :G, :type => :digraph )
5
+
6
+ @node_map = {}
7
+ @edge_map = {}
8
+ end
9
+
10
+ def build_graph(output_name)
11
+ create_nodes
12
+ create_edges
13
+ @g.output( :png => output_name )
14
+ end
15
+
16
+ def create_nodes
17
+ @chart.states.each do |b|
18
+
19
+ n = @g.add_node(b.id)
20
+ @node_map[b] = n
21
+
22
+ n[:label] = b.text.to_s
23
+ n[:color] = "purple" if b.is_initial?
24
+ n[:shape] = "box" # look like lucid@chart
25
+
26
+ n[:shape] = "diamond" if b.type.eql? "event"
27
+ n[:shape] = "circle" if b.type.eql? "transition"
28
+ end
29
+ end
30
+
31
+ def create_edges
32
+ @chart.states.each do |b|
33
+
34
+ src = @node_map[b]
35
+
36
+ b.links_to.each do |link, b2|
37
+
38
+ next unless b2.is_state?
39
+
40
+ dst = @node_map[b2]
41
+ next if b2.is_hidden?
42
+ e = @g.add_edges(src, dst)
43
+
44
+ # b.add_edge(e)
45
+ @edge_map[b] = [] if @edge_map[b].nil?
46
+ @edge_map[b] << e
47
+
48
+ # style
49
+ e[:arrowhead] = get_arrow_style(link.destination_arrow)
50
+ e[:arrowtail] = get_arrow_style(link.source_arrow)
51
+
52
+ # if link.source_arrow.eql? "None"
53
+
54
+ unless link.text.nil?
55
+ e[:label] = link.text
56
+ e[:color] = "red" if link.text.eql? "No"
57
+ e[:color] = "green" if link.text.eql? "Yes"
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def get_arrow_style(lucid_style)
64
+ return "none" if lucid_style.eql? "None"
65
+ return "normal" if lucid_style.eql? "Arrow"
66
+ return "empty" if lucid_style.eql? "Hollow Arrow"
67
+ return "open" if lucid_style.eql? "Open Arrow"
68
+
69
+ return "none"
70
+ end
71
+ end
@@ -0,0 +1,95 @@
1
+ TextTypes = ["Text", "Process", "Terminator", "Decision"]
2
+ Containers = ["Swim Lane"]
3
+ StructTypes = ["Page", "Line"] + Containers
4
+ Links = ["Line"]
5
+
6
+ ValidArrows = ["Arrow"]
7
+ InvalidArrow = ["None"]
8
+ ArrowTypes = ValidArrows + InvalidArrow
9
+
10
+ def is_page?(d); d["Page ID"].nil? and d["Name"] == "Page"; end
11
+
12
+ class ChartLoader
13
+ attr_reader :chart, :raw_data
14
+
15
+ def initialize(name)
16
+
17
+ arr_of_arrs = CSV.read name
18
+
19
+ @header = arr_of_arrs.first
20
+ @raw_data = arr_of_arrs[1..-1]
21
+ d = @raw_data.first
22
+
23
+ @struct_data = arr_of_arrs[1..-1].map{ |d| create_entry(@header, d)}
24
+ @chart = Chart.new
25
+
26
+ # 1. Pages and Get rid of them...
27
+ pages = load_pages
28
+ @struct_data.reject!{ |d| pages.include? d }
29
+
30
+ # 2. Containers
31
+ # load_containers ## TODO
32
+
33
+ # Links, and get rid of them
34
+ links = load_links
35
+ @struct_data.reject!{ |d| links.include? d }
36
+
37
+ # Blocks, and get rid of them
38
+ blocks = load_all_blocks
39
+ @struct_data.reject!{ |d| blocks.include? d }
40
+
41
+ # puts "Elements left: " + @struct_data.size.to_s
42
+
43
+ @chart.set_pages
44
+ @chart.set_links
45
+ @chart.check_initial
46
+ end
47
+
48
+
49
+ def create_entry(header, data)
50
+ output = {}
51
+ data.each_with_index do |d, i|
52
+ next unless d != nil
53
+ output[header[i]] = d
54
+ end
55
+ output
56
+ end
57
+
58
+
59
+ def load_pages
60
+ pages_raw = @struct_data.select{|d| is_page? d }
61
+ pages_raw.map do |d|
62
+ p = Page.new(d)
63
+ @chart.add_page p
64
+ d
65
+ end
66
+ end
67
+
68
+ def load_blocks
69
+ # It is a text type
70
+ blocks = @struct_data.select {|d| TextTypes.any? d["Name"] }
71
+ blocks.map do |d|
72
+ e = Element.new(d)
73
+ @chart.add_block e
74
+ d
75
+ end
76
+ end
77
+
78
+ def load_all_blocks
79
+ # It is a text type
80
+ blocks = @struct_data
81
+ blocks.map do |d|
82
+ @chart.add_block(Element.new(d))
83
+ d
84
+ end
85
+ end
86
+
87
+ def load_links
88
+ links = @struct_data.select{|d| Links.any? d["Name"] }
89
+ links.map do |d|
90
+ @chart.add_link(Link.new(d))
91
+ d
92
+ end
93
+ end
94
+
95
+ end
@@ -0,0 +1,3 @@
1
+ module LucidMachines
2
+ VERSION = "0.1.2"
3
+ end
@@ -0,0 +1,19 @@
1
+
2
+ require 'aasm'
3
+ require 'aasm-diagram'
4
+ require 'csv'
5
+
6
+ module LucidMachines
7
+
8
+ require 'lucidMachines/elements'
9
+ require 'lucidMachines/chart'
10
+ require 'lucidMachines/loader'
11
+
12
+ require 'lucidMachines/aasm_export'
13
+ require 'lucidMachines/exporter'
14
+ require 'lucidMachines/graphviz_export'
15
+
16
+
17
+ class Error < StandardError; end
18
+ # Your code goes here...
19
+ end
data/loader.rb ADDED
@@ -0,0 +1,99 @@
1
+ module ChartReader
2
+
3
+ TextTypes = ["Text", "Process", "Terminator", "Decision"]
4
+ Containers = ["Swim Lane"]
5
+ StructTypes = ["Page", "Line"] + Containers
6
+ Links = ["Line"]
7
+
8
+ ValidArrows = ["Arrow"]
9
+ InvalidArrow = ["None"]
10
+ ArrowTypes = ValidArrows + InvalidArrow
11
+
12
+ def is_page?(d); d["Page ID"].nil? and d["Name"] == "Page"; end
13
+
14
+ class ChartLoader
15
+ attr_reader :chart, :raw_data
16
+
17
+ def initialize(name)
18
+
19
+ arr_of_arrs = CSV.read name
20
+
21
+ @header = arr_of_arrs.first
22
+ @raw_data = arr_of_arrs[1..-1]
23
+ d = @raw_data.first
24
+
25
+ @struct_data = arr_of_arrs[1..-1].map{ |d| create_entry(@header, d)}
26
+ @chart = Chart.new
27
+
28
+ # 1. Pages and Get rid of them...
29
+ pages = load_pages
30
+ @struct_data.reject!{ |d| pages.include? d }
31
+
32
+ # 2. Containers
33
+ # load_containers ## TODO
34
+
35
+ # Links, and get rid of them
36
+ links = load_links
37
+ @struct_data.reject!{ |d| links.include? d }
38
+
39
+ # Blocks, and get rid of them
40
+ blocks = load_all_blocks
41
+ @struct_data.reject!{ |d| blocks.include? d }
42
+
43
+ # puts "Elements left: " + @struct_data.size.to_s
44
+
45
+ @chart.set_pages
46
+ @chart.set_links
47
+ @chart.check_initial
48
+ end
49
+
50
+
51
+ def create_entry(header, data)
52
+ output = {}
53
+ data.each_with_index do |d, i|
54
+ next unless d != nil
55
+ output[header[i]] = d
56
+ end
57
+ output
58
+ end
59
+
60
+
61
+ def load_pages
62
+ pages_raw = @struct_data.select{|d| is_page? d }
63
+ pages_raw.map do |d|
64
+ p = Page.new(d)
65
+ @chart.add_page p
66
+ d
67
+ end
68
+ end
69
+
70
+ def load_blocks
71
+ # It is a text type
72
+ blocks = @struct_data.select {|d| TextTypes.any? d["Name"] }
73
+ blocks.map do |d|
74
+ e = Element.new(d)
75
+ @chart.add_block e
76
+ d
77
+ end
78
+ end
79
+
80
+ def load_all_blocks
81
+ # It is a text type
82
+ blocks = @struct_data
83
+ blocks.map do |d|
84
+ @chart.add_block(Element.new(d))
85
+ d
86
+ end
87
+ end
88
+
89
+ def load_links
90
+ links = @struct_data.select{|d| Links.any? d["Name"] }
91
+ links.map do |d|
92
+ @chart.add_link(Link.new(d))
93
+ d
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ end
@@ -0,0 +1,48 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "lucidMachines/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "lucidMachines"
8
+ spec.version = LucidMachines::VERSION
9
+ spec.authors = ["Jeremy Laviole"]
10
+ spec.email = ["poqudrof@gmail.com"]
11
+
12
+ spec.summary = %q{Creates AASM state machines from LucidChart diagrams.}
13
+ spec.description = %q{This gem converts diagrams exported from LucidChard in CSV format to AASM code in ruby. It can also convert to other formats such as in GraphViz.}
14
+ spec.homepage = "https://forge.pole-aquinetic.net/RealityTech/lucid-machines"
15
+
16
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
18
+ if spec.respond_to?(:metadata)
19
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
20
+
21
+ spec.metadata["homepage_uri"] = spec.homepage
22
+ spec.metadata["source_code_uri"] = "https://forge.pole-aquinetic.net/RealityTech/lucid-machines"
23
+ spec.metadata["changelog_uri"] = "https://forge.pole-aquinetic.net/RealityTech/lucid-machines"
24
+ else
25
+ raise "RubyGems 2.0 or newer is required to protect against " \
26
+ "public gem pushes."
27
+ end
28
+
29
+ # Specify which files should be added to the gem when it is released.
30
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
31
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
32
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
33
+ end
34
+ spec.bindir = "exe"
35
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
36
+ spec.require_paths = ["lib"]
37
+
38
+ spec.add_development_dependency "bundler", "~> 2.0"
39
+ spec.add_development_dependency "rake", "~> 10.0"
40
+
41
+ spec.add_dependency 'aasm'
42
+ spec.add_dependency 'aasm-diagram'
43
+ spec.add_dependency 'ruby-graphviz'
44
+
45
+ ## CLI
46
+ spec.add_dependency "thor"
47
+
48
+ end
@@ -0,0 +1 @@
1
+ ../../credentials.json