gv 0.0.3 → 0.1.0

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