lucidMachines 0.1.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.
@@ -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