graphy 0.1.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5855af538a3e42839fb6291076af3a81d7d6e117624e0ff912dfb537599b1d78
4
- data.tar.gz: 43f3be7f19de34cf97743b03bdab151ae7cbc3d8fbe970802434dc11618dca33
3
+ metadata.gz: 90422fd37ee6183c87ab531c8841bfea10d9da59385f10f9d440b4095aeb24a8
4
+ data.tar.gz: 8bcb771712386cbeb5f9d2fb2e9e76030c9a6a18e79d8550f3bf28610d7d4624
5
5
  SHA512:
6
- metadata.gz: 811d052517b6a4a32b354818976a62f6fd38dc695ad7df03b21601b58793f923909d7337aa1968547d55eb4e6c5a4f7f92213740210a63396376a1485de22bd1
7
- data.tar.gz: 51c60f6b786035b87ee4357358db75b7edab3d7f0ffd6f605412b3d221081fc598f12ac4261cc7e02cc80685f779f3eba53c0788830c9794c078b6746042229d
6
+ metadata.gz: 5980d5b6a4c0ef3ef5867a11cf91b8c927431803c8f2d74b6b091b2d789b06fa1715cce4b6b6db927708bafb61c405e47027945388a087fc4e1c35232401d102
7
+ data.tar.gz: 3526fbda93e7ad3a960eb4e722024a89d1633414f45eeac5309ca7f8f2d7e223c9a900954d9ef05db4de543e256fc0d437ed33ec9bb3084f0e8daa92a08ac3cd
data/.gitignore CHANGED
@@ -6,3 +6,4 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ Gemfile.lock
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Graphy
2
2
 
3
- Create any diagram as code
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 'UML View' do
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
- attributes :color
34
+ attrs :color
35
35
  uses 'Friendly'
36
36
  end
37
37
 
38
38
  entity 'Cat', 'Animal' do
39
- attributes :scratch
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
 
@@ -2,12 +2,12 @@ require 'bundler/setup'
2
2
  require 'graphviz/dsl'
3
3
 
4
4
  digraph :example do
5
- cluster_0 do
6
- graph[label: 'Animal Kingdom']
7
- animal << dog
8
- animal << cat
9
- end
10
- friendly << dog
5
+ cluster_0 do
6
+ graph[label: 'Animal Kingdom']
7
+ animal << dog
8
+ animal << cat
9
+ end
10
+ friendly << dog
11
11
 
12
- output(png: "#{$0}.png")
12
+ output(png: "#{$0}.png")
13
13
  end
Binary file
@@ -1,7 +1,7 @@
1
1
  require 'bundler/setup'
2
2
  require 'graphy'
3
3
 
4
- Graphy.define do
4
+ Graphy.define 'State machine', orientation: :horizonal do
5
5
  node 'A'
6
6
  node 'B', shape: 'diamond'
7
7
  node 'C'
Binary file
@@ -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
- attributes :name, :other
6
+ attrs :name, :other
8
7
  end
9
8
 
10
9
  entity 'Dog', 'Animal' do
11
- attributes :color
10
+ attrs :color
12
11
  uses 'Friendly'
13
12
  end
14
13
 
15
14
  entity 'Cat', 'Animal' do
16
- attributes :scratch
15
+ meths :scratch
17
16
  end
18
17
 
19
18
  write png: "#{$0}.png"
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
@@ -1,8 +1,9 @@
1
1
  require 'graphviz'
2
2
  require 'graphy/node'
3
3
  require 'graphy/entity'
4
- require 'graphy/dependency'
4
+ require 'graphy/diagram'
5
5
  require 'graphy/dsl'
6
+ require 'graphy/registry'
6
7
  require 'graphy/version'
7
8
 
8
9
  module Graphy
@@ -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
@@ -1,24 +1,14 @@
1
1
  module Graphy
2
2
  class Dsl
3
- @registry = {}
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
- @graph = GraphViz.new(name, map_options(options.merge(label: name)))
16
- instance_eval(&block) if block
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
- opts = { parent: graph, type: graph.type }
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
- return graph.get_node(name) unless graph.get_node(name.to_s).nil?
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
- return graph.get_node(name) unless graph.get_node(name.to_s).nil?
42
-
43
- entity = Entity.new(name, graph: graph)
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 graph
60
- build
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
- graph.output(options)
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
@@ -1,16 +1,24 @@
1
1
  module Graphy
2
2
  class Entity < Node
3
- def initialize(name, graph:)
4
- super(name, graph: graph, shape: 'record')
3
+ def initialize(**params)
4
+ super(**params.merge(shape: 'Mrecord'))
5
5
  @attributes = []
6
6
  end
7
7
 
8
- def attributes(*values)
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
@@ -1,38 +1,68 @@
1
1
  module Graphy
2
2
  class Node
3
- attr_accessor :graph, :name, :shape, :penwidth, :fontsize, :style, :fillcolor, :dependencies
4
- def initialize(name, graph:, shape: 'circle')
5
- @name = name
6
- @graph = graph
7
- @shape = shape
8
- @dependencies = []
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 graph_node
12
- @graph_node ||= graph.add_nodes(name, node_attributes)
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, type: nil)
16
- @dependencies << Dependency.for(dependency, type: type)
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 node_attributes
46
+ def draw_edge(dependency, **options)
47
+ diagram.draw_edge(gnode, dependency.gnode, options)
48
+ end
49
+
50
+ def node_params
23
51
  {
24
- shape: shape,
25
- penwidth: penwidth,
26
- fontsize: fontsize,
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
@@ -1,3 +1,3 @@
1
1
  module Graphy
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.1.2'.freeze
3
3
  end
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.0
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-21 00:00:00.000000000 Z
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/dependency.rb
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:
@@ -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
@@ -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