gviz 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|