gv 0.0.3 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/gv.svg)](https://badge.fury.io/rb/gv)
|
2
|
+
[![Inline docs](http://inch-ci.org/github/furunkel/gv.svg?branch=master)](http://inch-ci.org/github/furunkel/gv)
|
3
|
+
[![Build Status](https://travis-ci.org/furunkel/gv.svg?branch=master)](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
|
-
![
|
41
|
+
![Result](https://raw.githubusercontent.com/furunkel/gv/master/spec/render.png)
|
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
|