gv 0.0.3 → 0.1.1
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 +5 -5
- data/.gemrelease +2 -0
- data/.travis.yml +8 -0
- data/README.md +9 -5
- data/Rakefile +8 -1
- data/gv.gemspec +13 -10
- data/lib/gv/version.rb +1 -1
- data/lib/gv.rb +155 -85
- data/spec/graph_spec.rb +48 -45
- data/spec/render.png +0 -0
- data/spec/spec_helper.rb +4 -1
- metadata +60 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 92d208286b90fddbf8c5c1660c0ef7a9c571c4de2c798f2329456cda47b1b375
|
4
|
+
data.tar.gz: 247302d77d98a3709826893687b518e78bbb4c59bd7e187ab46f91c8bdbe77e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 153040bdbaed5d91e3438cb2354203b1c1dd8ba0fe9e328d7b23fb3101f7160f5cea7277f23d27ff58b434e9b175044e203a5b517316400835e9b9bf4c75d584
|
7
|
+
data.tar.gz: 34b4de2d1454cfdd059ee0fac8f989820fc39322dd3e27eb4607363f8c4966a60886e3fd52fc45442d4168bf887e2efa6122c16b97930e7ef813560bf9eb1693
|
data/.gemrelease
ADDED
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
|
1
|
+
[](https://badge.fury.io/rb/gv)
|
2
|
+
[](http://inch-ci.org/github/furunkel/gv)
|
3
|
+
[](https://travis-ci.org/furunkel/gv)
|
2
4
|
|
3
|
-
|
5
|
+
# Graphviz FFI
|
6
|
+
|
7
|
+
Ruby bindings for libcgraph and libgvc (Graphviz) using FFI.
|
4
8
|
|
5
9
|
## Installation
|
6
10
|
|
@@ -25,8 +29,7 @@ Or install it yourself as:
|
|
25
29
|
require 'gv'
|
26
30
|
|
27
31
|
graph = GV::Graph.open 'g'
|
28
|
-
graph.edge 'e', graph.node('A'), graph.node('B', shape: 'polygon')
|
29
|
-
|
32
|
+
graph.edge 'e', graph.node('A'), graph.node('B', shape: 'polygon', label: graph.html('<b>bold</b>'))
|
30
33
|
# render to string
|
31
34
|
graph.render 'png'
|
32
35
|
|
@@ -35,7 +38,7 @@ graph.write 'result.png'
|
|
35
38
|
```
|
36
39
|
|
37
40
|
#### Result
|
38
|
-

|
39
42
|
|
40
43
|
### Load existing graph from `.dot` file:
|
41
44
|
```ruby
|
@@ -46,6 +49,7 @@ graph = GV::Graph.load File.open('g.dot')
|
|
46
49
|
# render graph
|
47
50
|
graph.render
|
48
51
|
```
|
52
|
+
See the [documentation](http://www.rubydoc.info/gems/gv) for details.
|
49
53
|
|
50
54
|
## Contributing
|
51
55
|
|
data/Rakefile
CHANGED
data/gv.gemspec
CHANGED
@@ -4,22 +4,25 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'gv/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'gv'
|
8
8
|
spec.version = GV::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
9
|
+
spec.authors = ['furunkel']
|
10
|
+
spec.email = ['furunkel@polyadic.com']
|
11
11
|
spec.summary = %q{Graphviz for Ruby, using libgvc via FFI}
|
12
|
-
spec.homepage =
|
13
|
-
spec.license =
|
12
|
+
spec.homepage = 'https://github.com/furunkel/gv'
|
13
|
+
spec.license = 'MIT'
|
14
14
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0")
|
16
16
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
-
spec.require_paths = [
|
18
|
+
spec.require_paths = ['lib']
|
19
19
|
|
20
|
-
spec.
|
21
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
-
spec.add_development_dependency "minitest"
|
20
|
+
spec.add_dependency 'ffi', '>= 1.11'
|
23
21
|
|
24
|
-
spec.
|
22
|
+
spec.add_development_dependency 'bundler', '>= 2'
|
23
|
+
spec.add_development_dependency 'rake', '>= 10.0'
|
24
|
+
spec.add_development_dependency 'yard', '>= 0.9'
|
25
|
+
spec.add_development_dependency 'minitest', '>= 5.8'
|
26
|
+
spec.add_development_dependency 'minitest-reporters', '> 1.1'
|
27
|
+
spec.add_development_dependency 'rubocop', '>= 0.41'
|
25
28
|
end
|
data/lib/gv/version.rb
CHANGED
data/lib/gv.rb
CHANGED
@@ -2,71 +2,80 @@ require 'gv/version'
|
|
2
2
|
require 'ffi'
|
3
3
|
|
4
4
|
module GV
|
5
|
+
module Libcgraph
|
6
|
+
extend FFI::Library
|
5
7
|
|
6
|
-
|
7
|
-
extend ::FFI::Library
|
8
|
-
|
9
|
-
ffi_lib 'gvc', 'cgraph', 'cgraph'
|
10
|
-
|
11
|
-
class AGraph < ::FFI::ManagedStruct
|
12
|
-
# dummy layout, only ever used by reference
|
13
|
-
layout :_1, :int,
|
14
|
-
:_2, :int
|
8
|
+
ffi_lib 'cgraph'
|
15
9
|
|
10
|
+
class AGraph < FFI::AutoPointer
|
16
11
|
def self.release(ptr)
|
17
|
-
|
12
|
+
Libcgraph.agclose(ptr) unless ptr.null?
|
18
13
|
end
|
19
14
|
end
|
20
15
|
|
21
|
-
typedef :pointer, :gvc
|
22
16
|
typedef :pointer, :ag_node
|
23
17
|
typedef :pointer, :ag_edge
|
24
18
|
|
25
|
-
attach_function :
|
26
|
-
attach_function :
|
27
|
-
attach_function :
|
28
|
-
|
29
|
-
attach_function :gvRenderFilename, [:gvc, AGraph.by_ref, :string, :string], :int
|
30
|
-
attach_function :gvRenderData, [:gvc, AGraph.by_ref, :string, :pointer, :pointer], :int
|
31
|
-
attach_function :gvFreeRenderData, [:pointer], :void
|
32
|
-
|
33
|
-
attach_function :agmemread, [:string], AGraph.by_ref
|
34
|
-
attach_function :agopen, [:string, :long, :pointer], AGraph.by_ref
|
35
|
-
attach_function :agclose, [AGraph.by_ref], :int
|
19
|
+
attach_function :agmemread, [:string], AGraph
|
20
|
+
attach_function :agopen, %i[string long pointer], AGraph
|
21
|
+
attach_function :agclose, [AGraph], :int
|
36
22
|
|
37
23
|
attach_variable :Agundirected, :long
|
38
24
|
attach_variable :Agstrictundirected, :long
|
39
25
|
attach_variable :Agdirected, :long
|
40
26
|
attach_variable :Agstrictdirected, :long
|
41
27
|
|
42
|
-
attach_function :agnode, [AGraph
|
43
|
-
attach_function :agedge, [AGraph
|
44
|
-
attach_function :agsubg, [AGraph
|
28
|
+
attach_function :agnode, [AGraph, :string, :int], :ag_node
|
29
|
+
attach_function :agedge, [AGraph, :ag_node, :ag_node, :string, :int], :ag_edge
|
30
|
+
attach_function :agsubg, [AGraph, :string, :int], :pointer
|
45
31
|
|
46
32
|
attach_function :agnameof, [:pointer], :string
|
47
33
|
attach_function :agraphof, [:pointer], :pointer
|
48
34
|
|
49
35
|
attach_function :agtail, [:ag_edge], :ag_node
|
50
36
|
attach_function :aghead, [:ag_edge], :ag_node
|
51
|
-
attach_function :agget, [
|
37
|
+
attach_function :agget, %i[pointer string], :string
|
52
38
|
|
53
|
-
attach_function :agsafeset, [
|
54
|
-
attach_function :agstrdup_html, [AGraph
|
55
|
-
attach_function :agstrfree, [AGraph
|
39
|
+
attach_function :agsafeset, %i[pointer string string string], :pointer
|
40
|
+
attach_function :agstrdup_html, [AGraph, :string], :pointer
|
41
|
+
attach_function :agstrfree, [AGraph, :pointer], :int
|
42
|
+
|
43
|
+
attach_function :agisdirected, [AGraph], :int
|
44
|
+
attach_function :agisstrict, [AGraph], :int
|
45
|
+
end
|
46
|
+
private_constant :Libcgraph
|
47
|
+
|
48
|
+
module Libgvc
|
49
|
+
extend FFI::Library
|
50
|
+
ffi_lib 'gvc'
|
51
|
+
|
52
|
+
typedef :pointer, :gvc
|
53
|
+
|
54
|
+
attach_function :gvContext, [], :pointer
|
55
|
+
attach_function :gvFreeLayout, [:gvc, Libcgraph::AGraph], :int
|
56
|
+
attach_function :gvLayout, [:gvc, Libcgraph::AGraph, :string], :int
|
56
57
|
|
57
|
-
attach_function :
|
58
|
-
attach_function :
|
58
|
+
attach_function :gvRenderFilename, [:gvc, Libcgraph::AGraph, :string, :string], :int
|
59
|
+
attach_function :gvRenderData, [:gvc, Libcgraph::AGraph, :string, :pointer, :pointer], :int
|
60
|
+
attach_function :gvFreeRenderData, [:pointer], :void
|
59
61
|
end
|
62
|
+
private_constant :Libgvc
|
60
63
|
|
64
|
+
# Common super-class for edges, nodes and graphs
|
61
65
|
class Component
|
62
|
-
|
66
|
+
# @!visibility private
|
67
|
+
@@gvc = Libgvc.gvContext
|
63
68
|
|
69
|
+
# @return [Graph, SubGraph] the graph this component belongs to
|
64
70
|
attr_reader :graph
|
65
71
|
|
72
|
+
# Creates an HTML label
|
73
|
+
# @param string [String] the HTML to parse
|
74
|
+
# @return [Object] a HTML label
|
66
75
|
def html(string)
|
67
|
-
ptr =
|
76
|
+
ptr = Libcgraph.agstrdup_html(graph.ptr, string)
|
68
77
|
string = ptr.read_string
|
69
|
-
|
78
|
+
Libcgraph.agstrfree graph.ptr, ptr
|
70
79
|
|
71
80
|
string
|
72
81
|
end
|
@@ -79,62 +88,97 @@ module GV
|
|
79
88
|
other.is_a?(Component) && ptr == other.ptr
|
80
89
|
end
|
81
90
|
|
82
|
-
alias
|
91
|
+
alias eql? ==
|
83
92
|
|
93
|
+
# @return [String] the component's name
|
84
94
|
def name
|
85
|
-
|
95
|
+
Libcgraph.agnameof ptr
|
86
96
|
end
|
87
97
|
|
98
|
+
# Sets an attribute
|
99
|
+
# @param attr [Symbol, String] attribute name
|
100
|
+
# @see http://www.graphviz.org/doc/info/attrs.html Node, Edge and Graph Attributes
|
101
|
+
# @param value [Object] attribute value
|
88
102
|
def []=(attr, value)
|
89
|
-
|
103
|
+
Libcgraph.agsafeset(ptr, attr.to_s, value.to_s, '')
|
90
104
|
end
|
91
105
|
|
106
|
+
# Retrieves the value of an attribute
|
107
|
+
# @param attr [Symbol, String] attribute name
|
108
|
+
# @see http://www.graphviz.org/doc/info/attrs.html Node, Edge and Graph Attributes
|
109
|
+
# @return [Object] the attribute value
|
92
110
|
def [](attr)
|
93
|
-
|
111
|
+
Libcgraph.agget(ptr, attr.to_s)
|
94
112
|
end
|
95
113
|
|
96
114
|
protected
|
115
|
+
|
97
116
|
attr_reader :ptr
|
98
117
|
end
|
99
118
|
|
119
|
+
# Represents a node in the graph
|
100
120
|
class Node < Component
|
101
121
|
def initialize(graph, name_or_ptr)
|
102
122
|
@graph = graph
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
123
|
+
@ptr =
|
124
|
+
case name_or_ptr
|
125
|
+
when String
|
126
|
+
Libcgraph.agnode(graph.ptr, name_or_ptr, 1)
|
127
|
+
else
|
128
|
+
name_or_ptr
|
129
|
+
end
|
109
130
|
end
|
110
131
|
end
|
111
132
|
|
133
|
+
# Represents a connection between nodes
|
112
134
|
class Edge < Component
|
113
135
|
def initialize(graph, name, tail, head)
|
114
136
|
@graph = graph
|
115
137
|
|
116
|
-
@ptr =
|
138
|
+
@ptr = Libcgraph.agedge(graph.ptr, tail.ptr, head.ptr, name, 1)
|
117
139
|
end
|
118
140
|
|
141
|
+
# @return [Node] the head node of the edge
|
119
142
|
def head
|
120
|
-
Node.new @graph,
|
143
|
+
Node.new @graph, Libcgraph.aghead(ptr)
|
121
144
|
end
|
122
145
|
|
146
|
+
# @return [Node] the tail node of the edge
|
123
147
|
def tail
|
124
|
-
Node.new @graph,
|
148
|
+
Node.new @graph, Libcgraph.agtail(ptr)
|
125
149
|
end
|
126
150
|
end
|
127
151
|
|
152
|
+
# Common super-class for graphs and sub-graphs
|
128
153
|
class BaseGraph < Component
|
129
|
-
|
154
|
+
# Creates a new node
|
155
|
+
# @param name [String] the name (identifier) of the node
|
156
|
+
# @param attrs [Hash{String, Symbol => Object}] the attributes
|
157
|
+
# to associate with this node
|
158
|
+
# @see http://www.graphviz.org/doc/info/attrs.html Node, Edge and Graph Attributes
|
159
|
+
# @return [Node] the newly created node
|
130
160
|
def node(name, attrs = {})
|
131
161
|
component Node, [name], attrs
|
132
162
|
end
|
133
163
|
|
164
|
+
# Creates a new edge
|
165
|
+
# @param name [String] the name (identifier) of the edge
|
166
|
+
# @param tail [Node] the edge's tail node
|
167
|
+
# @param head [Node] the edge's head node
|
168
|
+
# @param attrs [Hash{String, Symbol => Object}] the attributes
|
169
|
+
# to associate with this edge
|
170
|
+
# @see http://www.graphviz.org/doc/info/attrs.html Node, Edge and Graph Attributes
|
171
|
+
# @return [Edge] the newly created edge
|
134
172
|
def edge(name, tail, head, attrs = {})
|
135
173
|
component Edge, [name, tail, head], attrs
|
136
174
|
end
|
137
175
|
|
176
|
+
# Creates a new sub-graph
|
177
|
+
# @param name [String] the name (identifier) of the sub-graph
|
178
|
+
# @param attrs [Hash{String, Symbol => Object}] the attributes
|
179
|
+
# to associate with this sub-graph
|
180
|
+
# @see http://www.graphviz.org/doc/info/attrs.html Node, Edge and Graph Attributes
|
181
|
+
# @return [SubGraph] the newly created sub-graph
|
138
182
|
def sub_graph(name, attrs = {})
|
139
183
|
graph = component SubGraph, [name], attrs
|
140
184
|
yield graph if block_given?
|
@@ -142,15 +186,18 @@ module GV
|
|
142
186
|
graph
|
143
187
|
end
|
144
188
|
|
189
|
+
# @return whether this graph is directed
|
145
190
|
def directed?
|
146
|
-
|
191
|
+
Libcgraph.agisdirected(ptr) == 1
|
147
192
|
end
|
148
193
|
|
194
|
+
# @return whether this graph is strict
|
149
195
|
def strict?
|
150
|
-
|
196
|
+
Libcgraph.agisstrict(ptr) == 1
|
151
197
|
end
|
152
198
|
|
153
199
|
private
|
200
|
+
|
154
201
|
def component(klass, args, attrs = {})
|
155
202
|
comp = klass.new self, *args
|
156
203
|
|
@@ -160,46 +207,58 @@ module GV
|
|
160
207
|
|
161
208
|
comp
|
162
209
|
end
|
163
|
-
|
164
210
|
end
|
165
211
|
|
212
|
+
# Represents a sub-graph
|
166
213
|
class SubGraph < BaseGraph
|
167
214
|
def initialize(graph, name)
|
168
215
|
@graph = graph
|
169
|
-
@ptr =
|
216
|
+
@ptr = Libcgraph.agsubg(graph.ptr, name, 1)
|
170
217
|
end
|
171
218
|
end
|
172
219
|
|
220
|
+
# Represents a toplevel graph
|
173
221
|
class Graph < BaseGraph
|
174
|
-
|
175
222
|
class << self
|
176
223
|
private :new
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
224
|
+
|
225
|
+
# Creates a new graph
|
226
|
+
# @param type [:directed, :undirected] the graphs type
|
227
|
+
# @param strictness [:strict, :normal] the graphs strict type
|
228
|
+
# @see http://www.graphviz.org/doc/info/attrs.html Node, Edge and Graph Attributes
|
229
|
+
# @yieldparam graph [Graph] the newly created graph
|
230
|
+
# @return [Graph] the newly created graph
|
231
|
+
def open(name, type = :directed, strictness = :normal)
|
232
|
+
ag_type = case [type, strictness]
|
233
|
+
when %i[directed normal]
|
234
|
+
Libcgraph.Agdirected
|
235
|
+
when %i[undirected normal]
|
236
|
+
Libcgraph.Agundirected
|
237
|
+
when %i[directed strict]
|
238
|
+
Libcgraph.Agstrictdirected
|
239
|
+
when %i[undirected strict]
|
240
|
+
Libcgraph.Agstrictundirected
|
241
|
+
else
|
242
|
+
raise ArgumentError, "invalid graph type #{[type, strictness]}"
|
243
|
+
end
|
244
|
+
|
245
|
+
graph = new(Libcgraph.agopen(name, ag_type, FFI::Pointer::NULL))
|
246
|
+
|
247
|
+
yield graph if block_given?
|
192
248
|
|
193
249
|
graph
|
194
250
|
end
|
195
251
|
|
252
|
+
# Loads a graph from a string of file
|
253
|
+
# @param io [IO, String] the resource to load from
|
254
|
+
# @return the newly loaded graph
|
196
255
|
def load(io)
|
197
256
|
data = if io.is_a? String
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
new
|
257
|
+
io
|
258
|
+
else
|
259
|
+
io.read
|
260
|
+
end
|
261
|
+
new Libcgraph.agmemread(data)
|
203
262
|
end
|
204
263
|
end
|
205
264
|
|
@@ -211,26 +270,37 @@ module GV
|
|
211
270
|
self
|
212
271
|
end
|
213
272
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
273
|
+
# Renders the graph to an images and saves the result to a file
|
274
|
+
# @param filename [String] the filename
|
275
|
+
# @param format [String] the image format to use, e.g. 'svg', 'pdf' etc.
|
276
|
+
# @param layout [String] the layout to use, e.g. 'dot' or 'neato' etc.
|
277
|
+
# @return [nil]
|
278
|
+
def save(filename, format = 'png', layout = 'dot')
|
279
|
+
Libgvc.gvLayout(@@gvc, ptr, layout.to_s)
|
280
|
+
Libgvc.gvRenderFilename(@@gvc, ptr, format.to_s, filename)
|
281
|
+
Libgvc.gvFreeLayout(@@gvc, ptr)
|
282
|
+
|
283
|
+
nil
|
218
284
|
end
|
219
285
|
|
286
|
+
# Renders the graph to an image and returns the result as a string
|
287
|
+
# @param format [String] the image format to use, e.g. 'svg', 'pdf' etc.
|
288
|
+
# @param layout [String] the layout to use, e.g. 'dot' or 'neato' etc.
|
289
|
+
# @return [String] the rendered graph in the given format
|
220
290
|
def render(format = 'png', layout = 'dot')
|
221
|
-
|
291
|
+
Libgvc.gvLayout(@@gvc, ptr, layout.to_s)
|
222
292
|
|
223
|
-
data_ptr =
|
224
|
-
len_ptr =
|
293
|
+
data_ptr = FFI::MemoryPointer.new(:pointer, 1)
|
294
|
+
len_ptr = FFI::MemoryPointer.new(:int, 1)
|
225
295
|
|
226
|
-
|
296
|
+
Libgvc.gvRenderData(@@gvc, ptr, format.to_s, data_ptr, len_ptr)
|
227
297
|
len = len_ptr.read_uint
|
228
298
|
data_ptr = data_ptr.read_pointer
|
229
|
-
|
230
|
-
data = data_ptr.read_string_length len
|
231
299
|
|
232
|
-
|
233
|
-
|
300
|
+
data = data_ptr.read_string len
|
301
|
+
|
302
|
+
Libgvc.gvFreeRenderData(data_ptr)
|
303
|
+
Libgvc.gvFreeLayout(@@gvc, ptr)
|
234
304
|
|
235
305
|
data
|
236
306
|
end
|
data/spec/graph_spec.rb
CHANGED
@@ -1,36 +1,37 @@
|
|
1
1
|
require_relative 'spec_helper'
|
2
|
+
require 'tmpdir'
|
2
3
|
|
3
4
|
include GV
|
4
5
|
|
5
6
|
describe Graph do
|
6
7
|
describe :open do
|
7
|
-
it
|
8
|
+
it 'creates a new graph' do
|
8
9
|
graph = Graph.open 'test'
|
9
|
-
graph.directed
|
10
|
-
graph.strict
|
10
|
+
assert graph.directed?
|
11
|
+
refute graph.strict?
|
11
12
|
|
12
13
|
graph = Graph.open 'test', :directed, :strict
|
13
|
-
graph.strict
|
14
|
-
graph.directed
|
14
|
+
assert graph.strict?
|
15
|
+
assert graph.directed?
|
15
16
|
end
|
16
17
|
|
17
|
-
it
|
18
|
-
|
19
|
-
g.directed
|
20
|
-
g.strict
|
18
|
+
it 'takes a block' do
|
19
|
+
Graph.open 'test' do |g|
|
20
|
+
assert g.directed?
|
21
|
+
refute g.strict?
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
25
26
|
describe :load do
|
26
|
-
it
|
27
|
-
f = lambda do |
|
28
|
-
graph = Graph.load
|
29
|
-
graph.directed
|
30
|
-
graph.strict
|
31
|
-
|
27
|
+
it 'loads graph from file' do
|
28
|
+
f = lambda do |filename|
|
29
|
+
graph = Graph.load filename
|
30
|
+
assert graph.directed?
|
31
|
+
refute graph.strict?
|
32
|
+
assert_equal 'g', graph.name
|
32
33
|
end
|
33
|
-
|
34
|
+
|
34
35
|
filename = File.join(__dir__, 'simple_graph.dot')
|
35
36
|
file = File.open filename
|
36
37
|
f.call file
|
@@ -45,12 +46,12 @@ describe Graph do
|
|
45
46
|
@graph = Graph.open 'test'
|
46
47
|
end
|
47
48
|
|
48
|
-
it
|
49
|
-
@graph.node('test')
|
49
|
+
it 'creates a new node' do
|
50
|
+
assert_kind_of Node, @graph.node('test')
|
50
51
|
end
|
51
52
|
|
52
|
-
it
|
53
|
-
@graph.node('test', color: 'green')[:color]
|
53
|
+
it 'sets given attributes' do
|
54
|
+
assert_equal 'green', @graph.node('test', color: 'green')[:color]
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
@@ -59,23 +60,22 @@ describe Graph do
|
|
59
60
|
@graph = Graph.open 'test'
|
60
61
|
end
|
61
62
|
|
62
|
-
it
|
63
|
-
@graph.sub_graph('test')
|
63
|
+
it 'creates a new sub graph' do
|
64
|
+
assert_kind_of SubGraph, @graph.sub_graph('test')
|
64
65
|
end
|
65
66
|
|
66
|
-
it
|
67
|
-
@graph.sub_graph('test', color: 'green')[:color]
|
67
|
+
it 'sets given attributes' do
|
68
|
+
assert_equal 'green', @graph.sub_graph('test', color: 'green')[:color]
|
68
69
|
end
|
69
70
|
|
70
|
-
it
|
71
|
+
it 'takes a block' do
|
71
72
|
graph = @graph.sub_graph('test') do |g|
|
72
73
|
g[:color] = 'green'
|
73
74
|
end
|
74
|
-
graph[:color]
|
75
|
+
assert_equal 'green', graph[:color]
|
75
76
|
end
|
76
77
|
end
|
77
78
|
|
78
|
-
|
79
79
|
describe :edge do
|
80
80
|
before do
|
81
81
|
@graph = Graph.open 'test'
|
@@ -83,35 +83,38 @@ describe Graph do
|
|
83
83
|
@tail = @graph.node 'tail'
|
84
84
|
end
|
85
85
|
|
86
|
-
it
|
87
|
-
@graph.edge('test', @tail, @head)
|
86
|
+
it 'creates a new edge' do
|
87
|
+
assert_kind_of Edge, @graph.edge('test', @tail, @head)
|
88
88
|
end
|
89
89
|
|
90
|
-
it
|
91
|
-
@graph.edge('test', @tail, @head, color: 'green')[:color]
|
90
|
+
it 'sets given attributes' do
|
91
|
+
assert_equal 'green', @graph.edge('test', @tail, @head, color: 'green')[:color]
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
-
describe :
|
96
|
-
it
|
95
|
+
describe :save do
|
96
|
+
it 'renders the graph to the given filename' do
|
97
97
|
graph = Graph.open 'test'
|
98
98
|
graph.edge 'e', graph.node('A'), graph.node('B')
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
99
|
+
Tempfile.create(%w(gv_test .png)) do |file|
|
100
|
+
graph.save file.path
|
101
|
+
assert_equal true, File.file?(file.path)
|
102
|
+
end
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
106
106
|
describe :render do
|
107
|
-
it
|
107
|
+
it 'renders the graph to a string' do
|
108
108
|
graph = Graph.open 'test'
|
109
|
-
graph.edge 'e', graph.node('A'),
|
109
|
+
graph.edge 'e', graph.node('A'),
|
110
|
+
graph.node('B', shape: 'polygon',
|
111
|
+
label: graph.html('<b>bold</b>'))
|
112
|
+
|
110
113
|
data = graph.render
|
111
114
|
|
112
115
|
graph = nil
|
113
116
|
GC.start
|
114
|
-
|
117
|
+
assert_kind_of String, data
|
115
118
|
|
116
119
|
File.write 'spec/render.png', data
|
117
120
|
end
|
@@ -127,17 +130,17 @@ describe Edge do
|
|
127
130
|
end
|
128
131
|
|
129
132
|
it 'gives access to head and tail' do
|
130
|
-
@
|
131
|
-
@
|
133
|
+
assert_equal @head, @edge.head
|
134
|
+
assert_equal @tail, @edge.tail
|
132
135
|
end
|
133
136
|
|
134
137
|
it 'gives access to name' do
|
135
|
-
@edge.name
|
138
|
+
assert_equal 'test', @edge.name
|
136
139
|
end
|
137
140
|
|
138
141
|
it 'gives access to attributes' do
|
139
|
-
@edge[:color]
|
142
|
+
assert_nil @edge[:color]
|
140
143
|
@edge[:color] = 'green'
|
141
|
-
@edge[:color]
|
144
|
+
assert_equal 'green', @edge[:color]
|
142
145
|
end
|
143
146
|
end
|
data/spec/render.png
CHANGED
Binary file
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,79 +1,123 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- furunkel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.11'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
16
30
|
requirements:
|
17
|
-
- - "
|
31
|
+
- - ">="
|
18
32
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
33
|
+
version: '2'
|
20
34
|
type: :development
|
21
35
|
prerelease: false
|
22
36
|
version_requirements: !ruby/object:Gem::Requirement
|
23
37
|
requirements:
|
24
|
-
- - "
|
38
|
+
- - ">="
|
25
39
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
40
|
+
version: '2'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rake
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
|
-
- - "
|
45
|
+
- - ">="
|
32
46
|
- !ruby/object:Gem::Version
|
33
47
|
version: '10.0'
|
34
48
|
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
|
-
- - "
|
52
|
+
- - ">="
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: yard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.9'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.9'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: minitest
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
44
72
|
requirements:
|
45
73
|
- - ">="
|
46
74
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
75
|
+
version: '5.8'
|
48
76
|
type: :development
|
49
77
|
prerelease: false
|
50
78
|
version_requirements: !ruby/object:Gem::Requirement
|
51
79
|
requirements:
|
52
80
|
- - ">="
|
53
81
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
82
|
+
version: '5.8'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
84
|
+
name: minitest-reporters
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.1'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.1'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
57
99
|
requirement: !ruby/object:Gem::Requirement
|
58
100
|
requirements:
|
59
101
|
- - ">="
|
60
102
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :
|
103
|
+
version: '0.41'
|
104
|
+
type: :development
|
63
105
|
prerelease: false
|
64
106
|
version_requirements: !ruby/object:Gem::Requirement
|
65
107
|
requirements:
|
66
108
|
- - ">="
|
67
109
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
110
|
+
version: '0.41'
|
69
111
|
description:
|
70
112
|
email:
|
71
|
-
-
|
113
|
+
- furunkel@polyadic.com
|
72
114
|
executables: []
|
73
115
|
extensions: []
|
74
116
|
extra_rdoc_files: []
|
75
117
|
files:
|
118
|
+
- ".gemrelease"
|
76
119
|
- ".gitignore"
|
120
|
+
- ".travis.yml"
|
77
121
|
- Gemfile
|
78
122
|
- LICENSE.txt
|
79
123
|
- README.md
|
@@ -104,8 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
148
|
- !ruby/object:Gem::Version
|
105
149
|
version: '0'
|
106
150
|
requirements: []
|
107
|
-
|
108
|
-
rubygems_version: 2.4.5
|
151
|
+
rubygems_version: 3.3.3
|
109
152
|
signing_key:
|
110
153
|
specification_version: 4
|
111
154
|
summary: Graphviz for Ruby, using libgvc via FFI
|