graphy 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +9 -5
- data/examples/example00.rb +7 -7
- data/examples/example00.rb.png +0 -0
- data/examples/example01.rb +1 -1
- data/examples/example01.rb.png +0 -0
- data/examples/example02.rb +3 -4
- data/examples/example02.rb.png +0 -0
- data/examples/example03.rb +15 -0
- data/examples/example03.rb.png +0 -0
- data/lib/graphy.rb +2 -1
- data/lib/graphy/diagram.rb +75 -0
- data/lib/graphy/dsl.rb +12 -55
- data/lib/graphy/entity.rb +12 -4
- data/lib/graphy/node.rb +49 -19
- data/lib/graphy/registry.rb +28 -0
- data/lib/graphy/version.rb +1 -1
- metadata +6 -4
- data/Gemfile.lock +0 -25
- data/lib/graphy/dependency.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90422fd37ee6183c87ab531c8841bfea10d9da59385f10f9d440b4095aeb24a8
|
4
|
+
data.tar.gz: 8bcb771712386cbeb5f9d2fb2e9e76030c9a6a18e79d8550f3bf28610d7d4624
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5980d5b6a4c0ef3ef5867a11cf91b8c927431803c8f2d74b6b091b2d789b06fa1715cce4b6b6db927708bafb61c405e47027945388a087fc4e1c35232401d102
|
7
|
+
data.tar.gz: 3526fbda93e7ad3a960eb4e722024a89d1633414f45eeac5309ca7f8f2d7e223c9a900954d9ef05db4de543e256fc0d437ed33ec9bb3084f0e8daa92a08ac3cd
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Graphy
|
2
2
|
|
3
|
-
|
3
|
+
DSL to create graph diagrams as code
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -23,7 +23,7 @@ Or install it yourself as:
|
|
23
23
|
### Module
|
24
24
|
|
25
25
|
```ruby
|
26
|
-
Graphy.define '
|
26
|
+
Graphy.define 'Life View' do
|
27
27
|
entity 'Friendly'
|
28
28
|
namespace "Animal Kingdom" do
|
29
29
|
entity 'Animal' do
|
@@ -31,12 +31,12 @@ Graphy.define 'UML View' do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
entity 'Dog', 'Animal' do
|
34
|
-
|
34
|
+
attrs :color
|
35
35
|
uses 'Friendly'
|
36
36
|
end
|
37
37
|
|
38
38
|
entity 'Cat', 'Animal' do
|
39
|
-
|
39
|
+
meths :scratch
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
@@ -44,10 +44,13 @@ Graphy.define 'UML View' do
|
|
44
44
|
end
|
45
45
|
```
|
46
46
|
|
47
|
+
![example02.png](https://github.com/3zcurdia/graphy/blob/master/examples/example02.rb.png)
|
48
|
+
|
49
|
+
|
47
50
|
### State machine
|
48
51
|
|
49
52
|
```ruby
|
50
|
-
Graphy.define 'State machine' do
|
53
|
+
Graphy.define 'State machine', orientation: :horizontal do
|
51
54
|
node 'A'
|
52
55
|
node 'B', shape: 'diamond'
|
53
56
|
node 'C'
|
@@ -62,6 +65,7 @@ Graphy.define 'State machine' do
|
|
62
65
|
write(png: 'steps.png')
|
63
66
|
end
|
64
67
|
```
|
68
|
+
![example01.png](https://github.com/3zcurdia/graphy/blob/master/examples/example01.rb.png)
|
65
69
|
|
66
70
|
## Development
|
67
71
|
|
data/examples/example00.rb
CHANGED
@@ -2,12 +2,12 @@ require 'bundler/setup'
|
|
2
2
|
require 'graphviz/dsl'
|
3
3
|
|
4
4
|
digraph :example do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
cluster_0 do
|
6
|
+
graph[label: 'Animal Kingdom']
|
7
|
+
animal << dog
|
8
|
+
animal << cat
|
9
|
+
end
|
10
|
+
friendly << dog
|
11
11
|
|
12
|
-
|
12
|
+
output(png: "#{$0}.png")
|
13
13
|
end
|
data/examples/example00.rb.png
CHANGED
Binary file
|
data/examples/example01.rb
CHANGED
data/examples/example01.rb.png
CHANGED
Binary file
|
data/examples/example02.rb
CHANGED
@@ -2,18 +2,17 @@ require 'bundler/setup'
|
|
2
2
|
require 'graphy'
|
3
3
|
|
4
4
|
Graphy.define 'Life View' do
|
5
|
-
entity 'Friendly'
|
6
5
|
entity 'Animal' do
|
7
|
-
|
6
|
+
attrs :name, :other
|
8
7
|
end
|
9
8
|
|
10
9
|
entity 'Dog', 'Animal' do
|
11
|
-
|
10
|
+
attrs :color
|
12
11
|
uses 'Friendly'
|
13
12
|
end
|
14
13
|
|
15
14
|
entity 'Cat', 'Animal' do
|
16
|
-
|
15
|
+
meths :scratch
|
17
16
|
end
|
18
17
|
|
19
18
|
write png: "#{$0}.png"
|
data/examples/example02.rb.png
CHANGED
Binary file
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'graphy'
|
3
|
+
|
4
|
+
Graphy.define 'Life View' do
|
5
|
+
entity 'Friendly'
|
6
|
+
namespace 'Animal Kingdom' do
|
7
|
+
entity 'Animal'
|
8
|
+
entity 'Dog', 'Animal' do
|
9
|
+
uses 'Friendly'
|
10
|
+
end
|
11
|
+
entity 'Cat', 'Animal'
|
12
|
+
end
|
13
|
+
|
14
|
+
write png: "#{$0}.png"
|
15
|
+
end
|
Binary file
|
data/lib/graphy.rb
CHANGED
@@ -0,0 +1,75 @@
|
|
1
|
+
module Graphy
|
2
|
+
## GraphViz wrapper
|
3
|
+
class Diagram
|
4
|
+
attr_accessor :graph, :edges
|
5
|
+
|
6
|
+
GRAPH_ATTRIBUTES = {
|
7
|
+
ranksep: 0.5,
|
8
|
+
nodesep: 0.4,
|
9
|
+
pad: '0.4,0.4',
|
10
|
+
margin: '0,0',
|
11
|
+
concentrate: true,
|
12
|
+
labelloc: :t,
|
13
|
+
fontsize: 14,
|
14
|
+
fontname: 'Arial BoldMT',
|
15
|
+
splines: 'spline'
|
16
|
+
}
|
17
|
+
|
18
|
+
NODE_ATTRIBUTES = {
|
19
|
+
shape: "Mrecord",
|
20
|
+
fontsize: 12,
|
21
|
+
fontname: "ArialMT",
|
22
|
+
margin: "0.07,0.05",
|
23
|
+
penwidth: 1.0
|
24
|
+
}
|
25
|
+
|
26
|
+
EDGE_ATTRIBUTES = {
|
27
|
+
fontname: "ArialMT",
|
28
|
+
fontsize: 10,
|
29
|
+
arrowsize: 0.9,
|
30
|
+
penwidth: 1.0,
|
31
|
+
labelangle: 32,
|
32
|
+
labeldistance: 1.8,
|
33
|
+
}
|
34
|
+
|
35
|
+
def initialize(name, options = {})
|
36
|
+
graph_opts = {
|
37
|
+
parent: options[:parent],
|
38
|
+
type: options[:parent]&.type
|
39
|
+
}.compact
|
40
|
+
@graph = GraphViz.new(name, **graph_opts)
|
41
|
+
|
42
|
+
GRAPH_ATTRIBUTES.each { |attribute, value| @graph[attribute] = value }
|
43
|
+
NODE_ATTRIBUTES.each { |attribute, value| @graph.node[attribute] = value }
|
44
|
+
EDGE_ATTRIBUTES.each { |attribute, value| @graph.edge[attribute] = value }
|
45
|
+
|
46
|
+
@graph[:rankdir] = options[:orientation] == :horizonal ? :LR : :TB
|
47
|
+
@graph[:label] = "#{name}\\n\\n"
|
48
|
+
@edges = []
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_node(name)
|
52
|
+
graph.search_node(name)
|
53
|
+
end
|
54
|
+
|
55
|
+
def node_exists?(name)
|
56
|
+
!!get_node(name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def draw_node(name, options = {})
|
60
|
+
graph.add_nodes(name, options)
|
61
|
+
end
|
62
|
+
|
63
|
+
def draw_edge(from, to, options)
|
64
|
+
graph.add_edges(from, to, options)
|
65
|
+
end
|
66
|
+
|
67
|
+
def draw_graph(diagram)
|
68
|
+
graph.add_graph(diagram.graph)
|
69
|
+
end
|
70
|
+
|
71
|
+
def write(options = {})
|
72
|
+
graph.output(options)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/graphy/dsl.rb
CHANGED
@@ -1,24 +1,14 @@
|
|
1
1
|
module Graphy
|
2
2
|
class Dsl
|
3
|
-
|
4
|
-
@edges = []
|
5
|
-
|
6
|
-
def self.registry
|
7
|
-
@registry
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.edges
|
11
|
-
@edges
|
12
|
-
end
|
3
|
+
attr_accessor :diagram
|
13
4
|
|
14
5
|
def initialize(name, options = {}, &block)
|
15
|
-
@
|
16
|
-
instance_eval(&block) if
|
6
|
+
@diagram = Diagram.new(name, options, &block)
|
7
|
+
instance_eval(&block) if block_given?
|
17
8
|
end
|
18
9
|
|
19
10
|
def namespace(name, &block)
|
20
|
-
|
21
|
-
graph.add_graph(Dsl.new(name, opts, &block).graph)
|
11
|
+
diagram.draw_graph(Dsl.new(name, { parent: diagram.graph }, &block).diagram)
|
22
12
|
end
|
23
13
|
|
24
14
|
def component(name, &block)
|
@@ -30,55 +20,22 @@ module Graphy
|
|
30
20
|
end
|
31
21
|
|
32
22
|
def node(name, shape: 'circle', &block)
|
33
|
-
|
34
|
-
|
35
|
-
node = Node.new(name, graph: graph, shape: shape)
|
36
|
-
node.instance_eval(&block) if block_given?
|
37
|
-
Dsl.registry[name] = node
|
23
|
+
options = {diagram: diagram, shape: shape}
|
24
|
+
Node.for(name, **options).build(&block)
|
38
25
|
end
|
39
26
|
|
40
27
|
def entity(name, parent = nil, &block)
|
41
|
-
|
42
|
-
|
43
|
-
entity
|
44
|
-
entity.add_dependency(parent, type: :parent) if parent
|
45
|
-
entity.instance_eval(&block) if block_given?
|
46
|
-
Dsl.registry[name] = entity
|
47
|
-
end
|
48
|
-
|
49
|
-
def step(from, to:, options: {})
|
50
|
-
return if Dsl.edges.any? { |x| [from, to] == x }
|
51
|
-
source = Dsl.registry[from].graph_node
|
52
|
-
dest = Dsl.registry[to].graph_node
|
53
|
-
return if source.nil? || dest.nil?
|
54
|
-
|
55
|
-
Dsl.edges << [from, to]
|
56
|
-
graph.add_edge(source, dest, options)
|
28
|
+
entity = Entity.new(name: name, diagram: diagram)
|
29
|
+
entity.build(&block)
|
30
|
+
entity.add_dependency(parent, color: 'blue') if parent
|
57
31
|
end
|
58
32
|
|
59
|
-
def
|
60
|
-
|
61
|
-
@graph
|
33
|
+
def step(from, to:, **options)
|
34
|
+
Node.for(from, diagram: diagram).add_dependency(to, **options)
|
62
35
|
end
|
63
36
|
|
64
37
|
def write(options = {})
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
def build
|
71
|
-
Dsl.registry.each do |name, node|
|
72
|
-
node.dependencies.each do |dep|
|
73
|
-
step(dep.ref, to: name, options: dep.edge_attributes)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def map_options(options = {})
|
79
|
-
align = options.delete(:align)
|
80
|
-
rankdir = align == :horizontal ? 'LR' : nil
|
81
|
-
options.merge(rankdir: rankdir).compact
|
38
|
+
diagram.write(options)
|
82
39
|
end
|
83
40
|
end
|
84
41
|
end
|
data/lib/graphy/entity.rb
CHANGED
@@ -1,16 +1,24 @@
|
|
1
1
|
module Graphy
|
2
2
|
class Entity < Node
|
3
|
-
def initialize(
|
4
|
-
super(
|
3
|
+
def initialize(**params)
|
4
|
+
super(**params.merge(shape: 'Mrecord'))
|
5
5
|
@attributes = []
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
8
|
+
def attrs(*values)
|
9
9
|
@attributes = values
|
10
10
|
end
|
11
11
|
|
12
|
+
def meths(*values)
|
13
|
+
@attributes << values.map { |x| "#{x}()"}
|
14
|
+
end
|
15
|
+
|
12
16
|
protected
|
13
17
|
|
18
|
+
def draw_edge(dependency, **options)
|
19
|
+
diagram.draw_edge(dependency.gnode, gnode, options)
|
20
|
+
end
|
21
|
+
|
14
22
|
def label
|
15
23
|
"{ #{name} #{attributes_label} }"
|
16
24
|
end
|
@@ -19,7 +27,7 @@ module Graphy
|
|
19
27
|
|
20
28
|
def attributes_label
|
21
29
|
return if @attributes.empty?
|
22
|
-
"| #{@attributes.join("\n")}"
|
30
|
+
"| #{@attributes.join("\n")}"
|
23
31
|
end
|
24
32
|
end
|
25
33
|
end
|
data/lib/graphy/node.rb
CHANGED
@@ -1,38 +1,68 @@
|
|
1
1
|
module Graphy
|
2
2
|
class Node
|
3
|
-
attr_accessor :
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
attr_accessor :name, :shape, :diagram
|
4
|
+
|
5
|
+
def self.for(node, **params)
|
6
|
+
case node
|
7
|
+
when Entity, Node
|
8
|
+
node
|
9
|
+
when String
|
10
|
+
self.new(**params.merge(name: node))
|
11
|
+
else
|
12
|
+
raise 'Invalid node class'
|
13
|
+
end
|
9
14
|
end
|
10
15
|
|
11
|
-
def
|
12
|
-
@
|
16
|
+
def initialize(**params)
|
17
|
+
@name = params[:name].to_s
|
18
|
+
@diagram = params[:diagram]
|
19
|
+
@shape = params.fetch(:shape, 'circle')
|
13
20
|
end
|
14
21
|
|
15
|
-
def add_dependency(dependency,
|
16
|
-
|
22
|
+
def add_dependency(dependency, **options)
|
23
|
+
dependency = self.class.for(dependency, diagram: diagram)
|
24
|
+
return if Registry.edge?(self, dependency)
|
25
|
+
|
26
|
+
Registry.add_edge(self, dependency)
|
27
|
+
draw_edge(dependency, **options)
|
17
28
|
end
|
18
29
|
alias :uses :add_dependency
|
19
30
|
|
31
|
+
def build(&block)
|
32
|
+
instance_eval(&block) if block_given?
|
33
|
+
gnode
|
34
|
+
end
|
35
|
+
|
36
|
+
def gnode
|
37
|
+
@gnode ||= find_or_draw
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
"#{self.class}<#{name}>"
|
42
|
+
end
|
43
|
+
|
20
44
|
protected
|
21
45
|
|
22
|
-
def
|
46
|
+
def draw_edge(dependency, **options)
|
47
|
+
diagram.draw_edge(gnode, dependency.gnode, options)
|
48
|
+
end
|
49
|
+
|
50
|
+
def node_params
|
23
51
|
{
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
fontname: 'Helvetica',
|
28
|
-
style: style,
|
29
|
-
fillcolor: fillcolor,
|
30
|
-
label: label
|
31
|
-
}.compact
|
52
|
+
label: label,
|
53
|
+
shape: shape
|
54
|
+
}
|
32
55
|
end
|
33
56
|
|
34
57
|
def label
|
35
58
|
"#{name}\n"
|
36
59
|
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def find_or_draw
|
64
|
+
return diagram.get_node(name) if diagram.node_exists?(name)
|
65
|
+
diagram.draw_node(name, node_params)
|
66
|
+
end
|
37
67
|
end
|
38
68
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Graphy
|
4
|
+
class Registry
|
5
|
+
include Singleton
|
6
|
+
attr_accessor :edges
|
7
|
+
|
8
|
+
def self.edge?(source, destiny)
|
9
|
+
instance.edge?(source, destiny)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.add_edge(source, destiny)
|
13
|
+
instance.add_edge(source, destiny)
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@edges = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def edge?(source, destiny)
|
21
|
+
edges.key?("#{source}->#{destiny}")
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_edge(source, destiny, options = {})
|
25
|
+
self.edges["#{source}->#{destiny}"] = options
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/graphy/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luis Ezcurdia Razo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-09-
|
11
|
+
date: 2020-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-graphviz
|
@@ -35,7 +35,6 @@ files:
|
|
35
35
|
- ".travis.yml"
|
36
36
|
- CODE_OF_CONDUCT.md
|
37
37
|
- Gemfile
|
38
|
-
- Gemfile.lock
|
39
38
|
- LICENSE.txt
|
40
39
|
- README.md
|
41
40
|
- Rakefile
|
@@ -47,12 +46,15 @@ files:
|
|
47
46
|
- examples/example01.rb.png
|
48
47
|
- examples/example02.rb
|
49
48
|
- examples/example02.rb.png
|
49
|
+
- examples/example03.rb
|
50
|
+
- examples/example03.rb.png
|
50
51
|
- graphy.gemspec
|
51
52
|
- lib/graphy.rb
|
52
|
-
- lib/graphy/
|
53
|
+
- lib/graphy/diagram.rb
|
53
54
|
- lib/graphy/dsl.rb
|
54
55
|
- lib/graphy/entity.rb
|
55
56
|
- lib/graphy/node.rb
|
57
|
+
- lib/graphy/registry.rb
|
56
58
|
- lib/graphy/version.rb
|
57
59
|
homepage: https://github.com/3zcurdia/graphy
|
58
60
|
licenses:
|
data/Gemfile.lock
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
arq (0.1.0)
|
5
|
-
ruby-graphviz (~> 1.2.0)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
minitest (5.14.2)
|
11
|
-
rake (12.3.3)
|
12
|
-
rexml (3.2.4)
|
13
|
-
ruby-graphviz (1.2.5)
|
14
|
-
rexml
|
15
|
-
|
16
|
-
PLATFORMS
|
17
|
-
ruby
|
18
|
-
|
19
|
-
DEPENDENCIES
|
20
|
-
arq!
|
21
|
-
minitest (~> 5.0)
|
22
|
-
rake (~> 12.0)
|
23
|
-
|
24
|
-
BUNDLED WITH
|
25
|
-
2.1.4
|
data/lib/graphy/dependency.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
module Graphy
|
2
|
-
class Dependency
|
3
|
-
def self.for(reference, type: nil)
|
4
|
-
case type
|
5
|
-
when :parent
|
6
|
-
Parent
|
7
|
-
else
|
8
|
-
Default
|
9
|
-
end.new(reference)
|
10
|
-
end
|
11
|
-
|
12
|
-
class Default
|
13
|
-
attr_accessor :ref
|
14
|
-
def initialize(ref)
|
15
|
-
@ref = ref
|
16
|
-
end
|
17
|
-
|
18
|
-
def edge_attributes
|
19
|
-
{}
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class Parent < Default
|
24
|
-
def edge_attributes
|
25
|
-
{ style: 'dotted', color: 'blue' }
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|