gviz 0.0.6 → 0.0.7
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.
- data/lib/gviz.rb +1 -0
- data/lib/gviz/core.rb +86 -5
- data/lib/gviz/edge.rb +8 -3
- data/lib/gviz/node.rb +2 -1
- data/lib/gviz/system_extension.rb +6 -0
- data/lib/gviz/version.rb +1 -1
- data/spec/gviz_edge_spec.rb +20 -0
- data/spec/gviz_node_spec.rb +6 -7
- data/spec/gviz_spec.rb +30 -0
- data/spec/system_extension_spec.rb +52 -26
- metadata +2 -2
data/lib/gviz.rb
CHANGED
data/lib/gviz/core.rb
CHANGED
@@ -11,16 +11,22 @@ class Gviz
|
|
11
11
|
@ranks = []
|
12
12
|
end
|
13
13
|
|
14
|
+
# Access to all defined node objects.
|
14
15
|
def nodeset
|
15
16
|
@nodes.values
|
16
17
|
end
|
17
18
|
|
19
|
+
# Access to all defined edge objects.
|
18
20
|
def edgeset
|
19
21
|
@edges.values
|
20
22
|
end
|
21
23
|
|
24
|
+
# Define a node or update a node attributes.
|
25
|
+
# The first argument is `id` of the node which must a symbol form.
|
26
|
+
#
|
27
|
+
# node(:a, color:'red', shape:'circle')
|
28
|
+
#
|
22
29
|
def node(id, attrs={})
|
23
|
-
raise ArgumentError, '`id` must a symbol' unless id.is_a?(Symbol)
|
24
30
|
Node[id, attrs].tap do |node|
|
25
31
|
if exist = @nodes[node.id]
|
26
32
|
exist.attrs.update(node.attrs)
|
@@ -30,11 +36,29 @@ class Gviz
|
|
30
36
|
end
|
31
37
|
end
|
32
38
|
|
39
|
+
# Difine a edge or update a edge attributes.
|
40
|
+
# The first argument is `id` of the edge, which is a symbol or string constructed
|
41
|
+
# from two nodes joined with '_'(underscore).
|
42
|
+
#
|
43
|
+
# edge(:a_b, color:'red')
|
44
|
+
#
|
45
|
+
# The corresponding nodes will be defined if these are not exist.
|
46
|
+
#
|
47
|
+
# When `id` includes '*'(asterisk), multiple edges are updated.
|
48
|
+
#
|
49
|
+
# add(:a => [:b, :c])
|
50
|
+
# edge(:a_*, arrowhead:'none')
|
51
|
+
#
|
52
|
+
# is equivalent to:
|
53
|
+
#
|
54
|
+
# edge(:a_b, arrowhead:'none')
|
55
|
+
# edge(:a_c, arrowhead:'none')
|
33
56
|
def edge(id, attrs={})
|
34
|
-
|
35
|
-
|
57
|
+
if md = id.match(/\*/)
|
58
|
+
return multiple_edge(md, attrs)
|
36
59
|
end
|
37
|
-
|
60
|
+
|
61
|
+
Edge[id, attrs].tap do |edge|
|
38
62
|
if exist = @edges[id.intern]
|
39
63
|
exist.attrs.update(edge.attrs)
|
40
64
|
else
|
@@ -44,18 +68,28 @@ class Gviz
|
|
44
68
|
end
|
45
69
|
end
|
46
70
|
|
71
|
+
# Define all nodes attributes.
|
47
72
|
def nodes(attrs)
|
48
73
|
@gnode_attrs.update(attrs)
|
49
74
|
end
|
50
75
|
|
76
|
+
# Define all edges attributes.
|
51
77
|
def edges(attrs)
|
52
78
|
@gedge_attrs.update(attrs)
|
53
79
|
end
|
54
80
|
|
81
|
+
# Define graph global attributes.
|
55
82
|
def global(attrs)
|
56
83
|
@graph_attrs.update(attrs)
|
57
84
|
end
|
58
85
|
|
86
|
+
# Define subgraph.
|
87
|
+
#
|
88
|
+
# subgraph do
|
89
|
+
# global label:sub1
|
90
|
+
# add :a => :b
|
91
|
+
# end
|
92
|
+
#
|
59
93
|
def subgraph(&blk)
|
60
94
|
Gviz.new("cluster#{subgraphs.size}", :subgraph).tap do |graph|
|
61
95
|
subgraphs << graph
|
@@ -63,18 +97,52 @@ class Gviz
|
|
63
97
|
end
|
64
98
|
end
|
65
99
|
|
100
|
+
# +graph+ is a shorcut method.
|
101
|
+
#
|
102
|
+
# gv = Gviz.new
|
103
|
+
# gv.graph do
|
104
|
+
# add :a => :b
|
105
|
+
# node :a, color:'red'
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
# is equivalent to:
|
109
|
+
#
|
110
|
+
# gv = Gviz.new
|
111
|
+
# gv.add :a => :b
|
112
|
+
# gv.node :a, color:'red'
|
113
|
+
#
|
66
114
|
def graph(&blk)
|
67
115
|
instance_eval(&blk)
|
68
116
|
self
|
69
117
|
end
|
70
118
|
|
119
|
+
# Define nodes or routes(node-edge combinaitons).
|
120
|
+
# When an argument is a symbol, a node is defined.
|
121
|
+
#
|
122
|
+
# add :a, :b
|
123
|
+
#
|
124
|
+
# is equivalent to:
|
125
|
+
#
|
126
|
+
# node :a
|
127
|
+
# node :b
|
128
|
+
#
|
129
|
+
# When an argument is a hash, edges are defined.
|
130
|
+
#
|
131
|
+
# add :a => [:b, :c], :c => :d
|
132
|
+
#
|
133
|
+
# is equivalent to:
|
134
|
+
#
|
135
|
+
# edge :a_b
|
136
|
+
# edge :a_c
|
137
|
+
# edge :c_d
|
138
|
+
#
|
71
139
|
def add(*nodes_or_routes)
|
72
140
|
nodes_or_routes.each do |unit|
|
73
141
|
case unit
|
74
142
|
when Hash
|
75
143
|
unit.each do |sts, eds|
|
76
144
|
Array(sts).product(Array(eds))
|
77
|
-
.each { |st, ed| edge
|
145
|
+
.each { |st, ed| edge "#{st}_#{ed}" }
|
78
146
|
end
|
79
147
|
when Symbol
|
80
148
|
node(unit)
|
@@ -86,6 +154,11 @@ class Gviz
|
|
86
154
|
end
|
87
155
|
alias :route :add
|
88
156
|
|
157
|
+
# Define a rank to nodes.
|
158
|
+
# :same, :min, :max, :source and :sink are acceptable types.
|
159
|
+
#
|
160
|
+
# rank(:same, :a, :b)
|
161
|
+
#
|
89
162
|
def rank(type, *nodes)
|
90
163
|
types = [:same, :min, :max, :source, :sink]
|
91
164
|
unless types.include?(type)
|
@@ -133,6 +206,8 @@ class Gviz
|
|
133
206
|
result.join("\n")
|
134
207
|
end
|
135
208
|
|
209
|
+
# Create a graphviz dot file. When an image type is specified,
|
210
|
+
# the image is also created.
|
136
211
|
def save(path, type=nil)
|
137
212
|
File.open("#{path}.dot", "w") { |f| f.puts self }
|
138
213
|
system "dot -T#{type} #{path}.dot -o #{path}.#{type}" if type
|
@@ -151,4 +226,10 @@ class Gviz
|
|
151
226
|
arr = attrs.map { |k, v| %(#{k}="#{v}").gsub("\n", "\\n") }
|
152
227
|
join ? '[' + arr.join(',') + ']' : arr
|
153
228
|
end
|
229
|
+
|
230
|
+
def multiple_edge(md, attrs)
|
231
|
+
st = [md.pre_match, md.post_match].detect { |e| !e.empty? }.delete('_')
|
232
|
+
edges = edgeset.select { |edge| edge.nodes.include? st.intern }
|
233
|
+
edges.each { |eg| edge eg.id, attrs }
|
234
|
+
end
|
154
235
|
end
|
data/lib/gviz/edge.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Gviz::Edge < Struct.new(:id, :attrs)
|
2
2
|
attr_reader :st, :ed, :seq, :st_port, :ed_port
|
3
3
|
def initialize(id, attrs={})
|
4
|
-
raise ArgumentError, "`attrs` must a hash" unless attrs.is_a?(Hash)
|
4
|
+
raise ArgumentError, "edge `attrs` must a hash" unless attrs.is_a?(Hash)
|
5
5
|
id, @st, @ed, @seq, @st_port, @ed_port = parse_id(id)
|
6
6
|
super(id, attrs)
|
7
7
|
end
|
@@ -18,11 +18,16 @@ class Gviz::Edge < Struct.new(:id, :attrs)
|
|
18
18
|
|
19
19
|
private
|
20
20
|
def parse_id(id)
|
21
|
-
|
21
|
+
unless id.match(/._./)
|
22
|
+
raise ArgumentError, 'edge `id` must a symbol in which node names joined with "_"'
|
23
|
+
end
|
24
|
+
if id.match(/[^\d\w:-]/)
|
25
|
+
raise ArgumentError, "edge `id` must not include other than ASCII words, colon or minus"
|
26
|
+
end
|
22
27
|
st, ed, seq = "#{id}".split('_')
|
23
28
|
st, st_port = st.split(':').map(&:intern)
|
24
29
|
ed, ed_port = ed.split(':').map(&:intern)
|
25
|
-
id =
|
30
|
+
id = seq ? :"#{st}_#{ed}_#{seq}" : :"#{st}_#{ed}"
|
26
31
|
[id, st, ed, seq.to_i, st_port, ed_port]
|
27
32
|
end
|
28
33
|
end
|
data/lib/gviz/node.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
class Gviz::Node < Struct.new(:id, :attrs)
|
2
2
|
def initialize(id, attrs={})
|
3
|
-
raise ArgumentError,
|
3
|
+
raise ArgumentError, 'node `id` must a symbol' unless id.is_a?(Symbol)
|
4
|
+
raise ArgumentError, "node `id` must not include underscores" if id.match(/_/)
|
4
5
|
super
|
5
6
|
end
|
6
7
|
|
data/lib/gviz/version.rb
CHANGED
data/spec/gviz_edge_spec.rb
CHANGED
@@ -58,10 +58,30 @@ describe Gviz::Edge do
|
|
58
58
|
its(:attrs) { should eq opts }
|
59
59
|
end
|
60
60
|
|
61
|
+
context "when a number string passed" do
|
62
|
+
subject { Gviz::Edge.new('1234_1235') }
|
63
|
+
its(:id) { should be :'1234_1235' }
|
64
|
+
its(:st) { should be :'1234' }
|
65
|
+
its(:ed) { should be :'1235' }
|
66
|
+
end
|
67
|
+
|
68
|
+
context "when a string with minus sign" do
|
69
|
+
subject { Gviz::Edge.new('-123_124') }
|
70
|
+
its(:id) { should be :'-123_124' }
|
71
|
+
its(:st) { should be :'-123' }
|
72
|
+
its(:ed) { should be :'124' }
|
73
|
+
end
|
74
|
+
|
61
75
|
context "when a string with other than words or colon passed" do
|
62
76
|
it "raise an error" do
|
63
77
|
->{ Gviz::Edge.new('a!b_c') }.should raise_error(ArgumentError)
|
64
78
|
end
|
65
79
|
end
|
80
|
+
|
81
|
+
context "when a symbol without underscore passed" do
|
82
|
+
it "raise an error" do
|
83
|
+
->{ Gviz::Edge.new(:abc) }.should raise_error(ArgumentError)
|
84
|
+
end
|
85
|
+
end
|
66
86
|
end
|
67
87
|
end
|
data/spec/gviz_node_spec.rb
CHANGED
@@ -10,13 +10,6 @@ describe Gviz::Node do
|
|
10
10
|
its(:attrs) { should be_empty }
|
11
11
|
end
|
12
12
|
|
13
|
-
context "when only a string passed" do
|
14
|
-
subject { Gviz::Node.new('a') }
|
15
|
-
it { should be_a_instance_of Gviz::Node }
|
16
|
-
its(:id) { should eq 'a' }
|
17
|
-
its(:attrs) { should be_empty }
|
18
|
-
end
|
19
|
-
|
20
13
|
context "when a symbol and hash options passed" do
|
21
14
|
opts = { shape:'circle', style:'filled' }
|
22
15
|
subject { Gviz::Node.new(:a, opts) }
|
@@ -29,6 +22,12 @@ describe Gviz::Node do
|
|
29
22
|
->{ Gviz::Node.new(:a_b) }.should raise_error(ArgumentError)
|
30
23
|
end
|
31
24
|
end
|
25
|
+
|
26
|
+
context "when a string passed" do
|
27
|
+
it "raise an error" do
|
28
|
+
->{ Gviz::Node.new('a') }.should raise_error(ArgumentError)
|
29
|
+
end
|
30
|
+
end
|
32
31
|
end
|
33
32
|
|
34
33
|
describe "#to_s" do
|
data/spec/gviz_spec.rb
CHANGED
@@ -36,6 +36,17 @@ describe Gviz do
|
|
36
36
|
it { should be { color:'blue', label:'hello', shape:'box' } }
|
37
37
|
end
|
38
38
|
|
39
|
+
context "update node attrs which node is created by add method" do
|
40
|
+
before do
|
41
|
+
name = 'hello'
|
42
|
+
gv.add(:a => name.to_id)
|
43
|
+
gv.node(name.to_id, color:'red')
|
44
|
+
gv.nodeset.map(&:id)
|
45
|
+
end
|
46
|
+
subject { gv.nodeset.map(&:attrs) }
|
47
|
+
it { should eql [{}, {color:'red'}] }
|
48
|
+
end
|
49
|
+
|
39
50
|
context "when pass a string" do
|
40
51
|
it "raise an error" do
|
41
52
|
->{ gv.node('a') }.should raise_error(ArgumentError)
|
@@ -74,6 +85,25 @@ describe Gviz do
|
|
74
85
|
subject { gv.edgeset }
|
75
86
|
its(:size) { should eql 2 }
|
76
87
|
end
|
88
|
+
|
89
|
+
context "when a string with *(asterisk) passed" do
|
90
|
+
before do
|
91
|
+
gv.add(:a => [:b, :c], :c => :d)
|
92
|
+
gv.edge('a_*', color:'red')
|
93
|
+
end
|
94
|
+
subject { gv.edgeset.map(&:attrs) }
|
95
|
+
it { should eql [{ color:'red' }, { color:'red' }, {}] }
|
96
|
+
end
|
97
|
+
|
98
|
+
context "when a string with *(asterisk) passed 2" do
|
99
|
+
before do
|
100
|
+
gv.add(:main => [:a, :b], :main2 => :sub)
|
101
|
+
gv.add(:main => :sub)
|
102
|
+
gv.edge('*_main', color:'red')
|
103
|
+
end
|
104
|
+
subject { gv.edgeset.map(&:attrs) }
|
105
|
+
it { should eql [{color:'red'}, {color:'red'}, {}, {color:'red'}] }
|
106
|
+
end
|
77
107
|
end
|
78
108
|
|
79
109
|
describe "#add" do
|
@@ -1,33 +1,59 @@
|
|
1
|
-
|
1
|
+
# encoding: UTF-8
|
2
|
+
require_relative 'spec_helper'
|
2
3
|
|
3
4
|
describe Numeric do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
describe "#norm" do
|
6
|
+
context "normalize into 0.0-1.0" do
|
7
|
+
it "works for integer" do
|
8
|
+
5.norm(0..10).should eql 0.5
|
9
|
+
2.norm(0..10).should eql 0.2
|
10
|
+
0.norm(0..10).should eql 0.0
|
11
|
+
10.norm(0..10).should eql 1.0
|
12
|
+
5.norm(5..10).should eql 0.0
|
13
|
+
10.norm(5..10).should eql 1.0
|
14
|
+
7.norm(5..10).should eql 0.4
|
15
|
+
end
|
16
|
+
|
17
|
+
it "works for float" do
|
18
|
+
2.5.norm(0..10).should eql 0.25
|
19
|
+
7.4.norm(0..10).should eql 0.74
|
20
|
+
0.0.norm(0..10).should eql 0.0
|
21
|
+
10.0.norm(0..10).should eql 1.0
|
22
|
+
15.0.norm(10..20).should eql 0.5
|
23
|
+
end
|
13
24
|
end
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
25
|
+
|
26
|
+
context "normalize into other than 0.0-1.0" do
|
27
|
+
it "works for integer" do
|
28
|
+
5.norm(0..10, 0..20).should eql 10.0
|
29
|
+
2.norm(0..10, 10..20).should eql 12.0
|
30
|
+
0.norm(0..10, 10..15).should eql 10.0
|
31
|
+
10.norm(0..10, 10..15).should eql 15.0
|
32
|
+
5.norm(0..10, 10..15).should eql 12.5
|
33
|
+
end
|
34
|
+
|
35
|
+
it "works for float" do
|
36
|
+
2.5.norm(0..10, 0..5).should eql 1.25
|
37
|
+
2.5.norm(0..10, 5..10).should eql 6.25
|
38
|
+
end
|
21
39
|
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe Object do
|
44
|
+
describe "#to_id" do
|
45
|
+
describe "return a uniq symbol for node id" do
|
46
|
+
context "for integer" do
|
47
|
+
subject { 10.to_id }
|
48
|
+
it { should be_a_kind_of Symbol }
|
49
|
+
it { should be 10.to_id }
|
50
|
+
end
|
22
51
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
5.norm(0..10, 10..15).should eql 12.5
|
29
|
-
2.5.norm(0..10, 0..5).should eql 1.25
|
30
|
-
2.5.norm(0..10, 5..10).should eql 6.25
|
52
|
+
context "for unicode" do
|
53
|
+
subject { "グラフ".to_id }
|
54
|
+
it { should be_a_kind_of Symbol }
|
55
|
+
it { should be "グラフ".to_id }
|
56
|
+
end
|
31
57
|
end
|
32
58
|
end
|
33
|
-
end
|
59
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gviz
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|