gv 0.0.3 → 0.1.0

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
  SHA1:
3
- metadata.gz: df3b4f9e7e9dc7a1bb1c3f9fc0442c5032772570
4
- data.tar.gz: d74223b0a785b75df5aa6ada63c8eaf10b66a2cd
3
+ metadata.gz: 17e83e14df49d9b53bb2d2d32106be45b59bcfde
4
+ data.tar.gz: 71612086bd7676a972c8f2de30e7017024694d5d
5
5
  SHA512:
6
- metadata.gz: 61070b8eac8e61b06d970495df79d49efb46f6612e425228d02ed5c364effb5e0fc9b64f22ac0915db171478f8b86e355f326eadb03e85670fcecdac3d8c24a2
7
- data.tar.gz: 8ddeec3c092d86be9f144fa83926a1251456ac7536d1d308e4638c387ef77925001226e3ef7d5ab90b18bfa1609118f5c3cf761e86c48b31f791ac54397e261f
6
+ metadata.gz: 721459c62dd6543cc5a8510bcfc08c1abe87232dbaa621417537646d5f4b3196164b03027345b2580e00814d2a9d2dc4b5bb62812ede5fc9394023c07f67d962
7
+ data.tar.gz: fc708e42515acb0102f8ab9bd4d6ebea51d5bd02c8069000b1345b4ecc9e175098d9355b067aa491ac6b8f1900dc046cde4d71ca3db7ee14095cbd1be7be7b34
@@ -0,0 +1,2 @@
1
+ release:
2
+ tag: true
@@ -0,0 +1,8 @@
1
+ before_install:
2
+ - sudo add-apt-repository ppa:gviz-adm/graphviz-dev -y
3
+ - sudo apt-get -qq update
4
+ - sudo apt-get install -y libgraphviz-dev graphviz libgraphviz4
5
+ language: ruby
6
+ rvm:
7
+ - 2.3.1
8
+ - jruby-9.0.5.0
data/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ [![Gem Version](https://badge.fury.io/rb/gv.svg)](https://badge.fury.io/rb/gv)
2
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/furunkel/gv/master/frames)
3
+ [![Build Status](https://travis-ci.org/furunkel/gv.svg?branch=master)](https://travis-ci.org/furunkel/gv)
4
+
1
5
  # GV
2
6
 
3
7
  Ruby bindings for libgvc (Graphviz) using FFI.
@@ -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
- ![resilt](/spec/render.png)
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
data/Rakefile CHANGED
@@ -1,7 +1,14 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rake/testtask'
3
+ require 'yard'
3
4
 
4
5
  Rake::TestTask.new do |t|
5
6
  t.libs.push 'lib'
6
7
  t.pattern = "spec/*_spec.rb"
7
- end
8
+ end
9
+
10
+
11
+ YARD::Rake::YardocTask.new
12
+
13
+
14
+ task :default => :test
data/gv.gemspec CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.add_development_dependency "bundler", "~> 1.7"
21
21
  spec.add_development_dependency "rake", "~> 10.0"
22
22
  spec.add_development_dependency "minitest"
23
+ spec.add_development_dependency "yard"
23
24
 
24
25
  spec.add_dependency "ffi"
25
26
  end
data/lib/gv.rb CHANGED
@@ -3,45 +3,34 @@ require 'ffi'
3
3
 
4
4
  module GV
5
5
 
6
- module FFI
7
- extend ::FFI::Library
6
+ module LibCGraph
7
+ extend FFI::Library
8
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
9
+ ffi_lib 'cgraph'
15
10
 
11
+ class AGraph < FFI::AutoPointer
16
12
  def self.release(ptr)
17
- FFI.agclose(ptr) unless ptr.null?
13
+ LibCGraph.agclose(ptr) unless ptr.null?
18
14
  end
19
15
  end
20
16
 
21
- typedef :pointer, :gvc
17
+
22
18
  typedef :pointer, :ag_node
23
19
  typedef :pointer, :ag_edge
24
20
 
25
- attach_function :gvContext, [], :pointer
26
- attach_function :gvFreeLayout, [:gvc, AGraph.by_ref], :int
27
- attach_function :gvLayout, [:gvc, AGraph.by_ref, :string], :int
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
21
 
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
22
+ attach_function :agmemread, [:string], AGraph
23
+ attach_function :agopen, [:string, :long, :pointer], AGraph
24
+ attach_function :agclose, [AGraph], :int
36
25
 
37
26
  attach_variable :Agundirected, :long
38
27
  attach_variable :Agstrictundirected, :long
39
28
  attach_variable :Agdirected, :long
40
29
  attach_variable :Agstrictdirected, :long
41
30
 
42
- attach_function :agnode, [AGraph.by_ref, :string, :int], :ag_node
43
- attach_function :agedge, [AGraph.by_ref, :ag_node, :ag_node, :string, :int], :ag_edge
44
- attach_function :agsubg, [AGraph.by_ref, :string, :int], :pointer
31
+ attach_function :agnode, [AGraph, :string, :int], :ag_node
32
+ attach_function :agedge, [AGraph, :ag_node, :ag_node, :string, :int], :ag_edge
33
+ attach_function :agsubg, [AGraph, :string, :int], :pointer
45
34
 
46
35
  attach_function :agnameof, [:pointer], :string
47
36
  attach_function :agraphof, [:pointer], :pointer
@@ -51,22 +40,44 @@ module GV
51
40
  attach_function :agget, [:pointer, :string], :string
52
41
 
53
42
  attach_function :agsafeset, [:pointer, :string, :string, :string], :pointer
54
- attach_function :agstrdup_html, [AGraph.by_ref, :string], :pointer
55
- attach_function :agstrfree, [AGraph.by_ref, :pointer], :int
43
+ attach_function :agstrdup_html, [AGraph, :string], :pointer
44
+ attach_function :agstrfree, [AGraph, :pointer], :int
56
45
 
57
- attach_function :agisdirected, [AGraph.by_ref], :int
58
- attach_function :agisstrict, [AGraph.by_ref], :int
46
+ attach_function :agisdirected, [AGraph], :int
47
+ attach_function :agisstrict, [AGraph], :int
59
48
  end
49
+ private_constant :LibCGraph
50
+
51
+ module LibGVC
52
+ extend FFI::Library
53
+ ffi_lib 'gvc'
54
+
55
+ typedef :pointer, :gvc
56
+
57
+ attach_function :gvContext, [], :pointer
58
+ attach_function :gvFreeLayout, [:gvc, LibCGraph::AGraph], :int
59
+ attach_function :gvLayout, [:gvc, LibCGraph::AGraph, :string], :int
60
+
61
+ attach_function :gvRenderFilename, [:gvc, LibCGraph::AGraph, :string, :string], :int
62
+ attach_function :gvRenderData, [:gvc, LibCGraph::AGraph, :string, :pointer, :pointer], :int
63
+ attach_function :gvFreeRenderData, [:pointer], :void
64
+ end
65
+ private_constant :LibGVC
60
66
 
61
67
  class Component
62
- @@gvc = FFI.gvContext()
68
+ # @!visibility private
69
+ @@gvc = LibGVC.gvContext()
63
70
 
71
+ # @return [Graph, SubGraph] the graph this component belongs to
64
72
  attr_reader :graph
65
73
 
74
+ # Creates an HTML label
75
+ # @param string [String] the HTML to parse
76
+ # @return [Object] a HTML label
66
77
  def html(string)
67
- ptr = FFI.agstrdup_html(graph.ptr, string)
78
+ ptr = LibCGraph.agstrdup_html(graph.ptr, string)
68
79
  string = ptr.read_string
69
- FFI.agstrfree graph.ptr, ptr
80
+ LibCGraph.agstrfree graph.ptr, ptr
70
81
 
71
82
  string
72
83
  end
@@ -81,16 +92,25 @@ module GV
81
92
 
82
93
  alias :eql? :==
83
94
 
95
+ # @return [String] the component's name
84
96
  def name
85
- FFI.agnameof ptr
97
+ LibCGraph.agnameof ptr
86
98
  end
87
99
 
100
+ # Sets an attribute
101
+ # @param attr [Symbol, String] attribute name
102
+ # @see http://www.graphviz.org/doc/info/attrs.html Node, Edge and Graph Attributes
103
+ # @param value [Object] attribute value
88
104
  def []=(attr, value)
89
- FFI.agsafeset(ptr, attr.to_s, value.to_s, "")
105
+ LibCGraph.agsafeset(ptr, attr.to_s, value.to_s, "")
90
106
  end
91
107
 
108
+ # Retrieves the value of an attribute
109
+ # @param attr [Symbol, String] attribute name
110
+ # @see http://www.graphviz.org/doc/info/attrs.html Node, Edge and Graph Attributes
111
+ # @return [Object] the attribute value
92
112
  def [](attr)
93
- FFI.agget(ptr, attr.to_s)
113
+ LibCGraph.agget(ptr, attr.to_s)
94
114
  end
95
115
 
96
116
  protected
@@ -102,7 +122,7 @@ module GV
102
122
  @graph = graph
103
123
  case name_or_ptr
104
124
  when String
105
- @ptr = FFI.agnode(graph.ptr, name_or_ptr, 1)
125
+ @ptr = LibCGraph.agnode(graph.ptr, name_or_ptr, 1)
106
126
  else
107
127
  @ptr = name_or_ptr
108
128
  end
@@ -113,28 +133,50 @@ module GV
113
133
  def initialize(graph, name, tail, head)
114
134
  @graph = graph
115
135
 
116
- @ptr = FFI.agedge(graph.ptr, tail.ptr, head.ptr, name, 1)
136
+ @ptr = LibCGraph.agedge(graph.ptr, tail.ptr, head.ptr, name, 1)
117
137
  end
118
138
 
139
+ # @return [Node] the head node of the edge
119
140
  def head
120
- Node.new @graph, FFI.aghead(ptr)
141
+ Node.new @graph, LibCGraph.aghead(ptr)
121
142
  end
122
143
 
144
+ # @return [Node] the tail node of the edge
123
145
  def tail
124
- Node.new @graph, FFI.agtail(ptr)
146
+ Node.new @graph, LibCGraph.agtail(ptr)
125
147
  end
126
148
  end
127
149
 
128
150
  class BaseGraph < Component
129
151
 
152
+ # Creates a new node
153
+ # @param name [String] the name (identifier) of the node
154
+ # @param attrs [Hash{String, Symbol => Object}] the attributes
155
+ # to associate with this node
156
+ # @see http://www.graphviz.org/doc/info/attrs.html Node, Edge and Graph Attributes
157
+ # @return [Node] the newly created node
130
158
  def node(name, attrs = {})
131
159
  component Node, [name], attrs
132
160
  end
133
161
 
162
+ # Creates a new edge
163
+ # @param name [String] the name (identifier) of the edge
164
+ # @param tail [Node] the edge's tail node
165
+ # @param head [Node] the edge's head node
166
+ # @param attrs [Hash{String, Symbol => Object}] the attributes
167
+ # to associate with this edge
168
+ # @see http://www.graphviz.org/doc/info/attrs.html Node, Edge and Graph Attributes
169
+ # @return [Edge] the newly created edge
134
170
  def edge(name, tail, head, attrs = {})
135
171
  component Edge, [name, tail, head], attrs
136
172
  end
137
173
 
174
+ # Creates a new sub-graph
175
+ # @param name [String] the name (identifier) of the sub-graph
176
+ # @param attrs [Hash{String, Symbol => Object}] the attributes
177
+ # to associate with this sub-graph
178
+ # @see http://www.graphviz.org/doc/info/attrs.html Node, Edge and Graph Attributes
179
+ # @return [SubGraph] the newly created sub-graph
138
180
  def sub_graph(name, attrs = {})
139
181
  graph = component SubGraph, [name], attrs
140
182
  yield graph if block_given?
@@ -142,12 +184,14 @@ module GV
142
184
  graph
143
185
  end
144
186
 
187
+ # @return whether this graph is directed
145
188
  def directed?
146
- FFI.agisdirected(ptr) == 1
189
+ LibCGraph.agisdirected(ptr) == 1
147
190
  end
148
191
 
192
+ # @return whether this graph is strict
149
193
  def strict?
150
- FFI.agisstrict(ptr) == 1
194
+ LibCGraph.agisstrict(ptr) == 1
151
195
  end
152
196
 
153
197
  private
@@ -166,7 +210,7 @@ module GV
166
210
  class SubGraph < BaseGraph
167
211
  def initialize(graph, name)
168
212
  @graph = graph
169
- @ptr = FFI.agsubg(graph.ptr, name, 1)
213
+ @ptr = LibCGraph.agsubg(graph.ptr, name, 1)
170
214
  end
171
215
  end
172
216
 
@@ -174,17 +218,24 @@ module GV
174
218
 
175
219
  class << self
176
220
  private :new
177
- def open(name, type = :directed, strict = :normal)
178
- ag_type = case [type, strict]
179
- when [:directed, :normal] then FFI.Agdirected
180
- when [:undirected, :normal] then FFI.Agundirected
181
- when [:directed, :strict] then FFI.Agstrictdirected
182
- when [:undirected, :strict] then FFI.Agstrictundirected
221
+
222
+ # Creates a new graph
223
+ # @param type [:directed, :undirected] the graphs type
224
+ # @param strictness [:strict, :normal] the graphs strict type
225
+ # @see http://www.graphviz.org/doc/info/attrs.html Node, Edge and Graph Attributes
226
+ # @yieldparam graph [Graph] the newly created graph
227
+ # @return [Graph] the newly created graph
228
+ def open(name, type = :directed, strictness = :normal)
229
+ ag_type = case [type, strictness]
230
+ when [:directed, :normal] then LibCGraph.Agdirected
231
+ when [:undirected, :normal] then LibCGraph.Agundirected
232
+ when [:directed, :strict] then LibCGraph.Agstrictdirected
233
+ when [:undirected, :strict] then LibCGraph.Agstrictundirected
183
234
  else
184
- raise ArgumentError, "invalid graph type #{[type, strict]}"
235
+ raise ArgumentError, "invalid graph type #{[type, strictness]}"
185
236
  end
186
237
 
187
- graph = new(FFI.agopen(name, ag_type, ::FFI::Pointer::NULL))
238
+ graph = new(LibCGraph.agopen(name, ag_type, FFI::Pointer::NULL))
188
239
 
189
240
  if block_given?
190
241
  yield graph
@@ -193,13 +244,16 @@ module GV
193
244
  graph
194
245
  end
195
246
 
247
+ # Loads a graph from a string of file
248
+ # @param io [IO, String] the resource to load from
249
+ # @return the newly loaded graph
196
250
  def load(io)
197
251
  data = if io.is_a? String
198
252
  io
199
253
  else
200
254
  io.read
201
255
  end
202
- new FFI.agmemread(data)
256
+ new LibCGraph.agmemread(data)
203
257
  end
204
258
  end
205
259
 
@@ -211,26 +265,37 @@ module GV
211
265
  self
212
266
  end
213
267
 
214
- def write(filename, format = 'png', layout = 'dot')
215
- FFI.gvLayout(@@gvc, ptr, layout.to_s)
216
- FFI.gvRenderFilename(@@gvc, ptr, format.to_s, filename);
217
- FFI.gvFreeLayout(@@gvc, ptr)
268
+ # Renders the graph to an images and saves the result to a file
269
+ # @param filename [String] the filename
270
+ # @param format [String] the image format to use, e.g. 'svg', 'pdf' etc.
271
+ # @param layout [String] the layout to use, e.g. 'dot' or 'neato' etc.
272
+ # @return [nil]
273
+ def save(filename, format = 'png', layout = 'dot')
274
+ LibGVC.gvLayout(@@gvc, ptr, layout.to_s)
275
+ LibGVC.gvRenderFilename(@@gvc, ptr, format.to_s, filename);
276
+ LibGVC.gvFreeLayout(@@gvc, ptr)
277
+
278
+ nil
218
279
  end
219
280
 
281
+ # Renders the graph to an image and returns the result as a string
282
+ # @param format [String] the image format to use, e.g. 'svg', 'pdf' etc.
283
+ # @param layout [String] the layout to use, e.g. 'dot' or 'neato' etc.
284
+ # @return [String] the rendered graph in the given format
220
285
  def render(format = 'png', layout = 'dot')
221
- FFI.gvLayout(@@gvc, ptr, layout.to_s)
286
+ LibGVC.gvLayout(@@gvc, ptr, layout.to_s)
222
287
 
223
- data_ptr = ::FFI::MemoryPointer.new(:pointer, 1)
224
- len_ptr = ::FFI::MemoryPointer.new(:int, 1)
288
+ data_ptr = FFI::MemoryPointer.new(:pointer, 1)
289
+ len_ptr = FFI::MemoryPointer.new(:int, 1)
225
290
 
226
- FFI.gvRenderData(@@gvc, ptr, format.to_s, data_ptr, len_ptr);
291
+ LibGVC.gvRenderData(@@gvc, ptr, format.to_s, data_ptr, len_ptr);
227
292
  len = len_ptr.read_uint
228
293
  data_ptr = data_ptr.read_pointer
229
294
 
230
- data = data_ptr.read_string_length len
295
+ data = data_ptr.read_string len
231
296
 
232
- FFI.gvFreeRenderData(data_ptr)
233
- FFI.gvFreeLayout(@@gvc, ptr)
297
+ LibGVC.gvFreeRenderData(data_ptr)
298
+ LibGVC.gvFreeLayout(@@gvc, ptr)
234
299
 
235
300
  data
236
301
  end
@@ -1,3 +1,3 @@
1
1
  module GV
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -15,7 +15,7 @@ describe Graph do
15
15
  end
16
16
 
17
17
  it "takes a block" do
18
- graph = Graph.open 'test' do |g|
18
+ Graph.open 'test' do |g|
19
19
  g.directed?.must_equal true
20
20
  g.strict?.must_equal false
21
21
  end
@@ -24,8 +24,8 @@ describe Graph do
24
24
 
25
25
  describe :load do
26
26
  it "loads graph from file" do
27
- f = lambda do |f|
28
- graph = Graph.load f
27
+ f = lambda do |filename|
28
+ graph = Graph.load filename
29
29
  graph.directed?.must_equal true
30
30
  graph.strict?.must_equal false
31
31
  graph.name.must_equal 'g'
@@ -92,12 +92,12 @@ describe Graph do
92
92
  end
93
93
  end
94
94
 
95
- describe :write do
95
+ describe :save do
96
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
99
  filename = File.join Dir.tmpdir, Dir::Tmpname.make_tmpname(['gv_test', '.png'], nil)
100
- graph.write filename
100
+ graph.save filename
101
101
  File.file?(filename).must_equal true
102
102
  File.unlink filename
103
103
  end
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - furunkel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-27 00:00:00.000000000 Z
11
+ date: 2016-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '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'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: ffi
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -73,7 +87,9 @@ executables: []
73
87
  extensions: []
74
88
  extra_rdoc_files: []
75
89
  files:
90
+ - ".gemrelease"
76
91
  - ".gitignore"
92
+ - ".travis.yml"
77
93
  - Gemfile
78
94
  - LICENSE.txt
79
95
  - README.md
@@ -105,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
121
  version: '0'
106
122
  requirements: []
107
123
  rubyforge_project:
108
- rubygems_version: 2.4.5
124
+ rubygems_version: 2.5.1
109
125
  signing_key:
110
126
  specification_version: 4
111
127
  summary: Graphviz for Ruby, using libgvc via FFI
@@ -114,3 +130,4 @@ test_files:
114
130
  - spec/render.png
115
131
  - spec/simple_graph.dot
116
132
  - spec/spec_helper.rb
133
+ has_rdoc: