rsvgr 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/rsvgr.rb +405 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cd4d756ecd876ced14a6866dd9594a1c93666f6e
|
4
|
+
data.tar.gz: d3e3f0d0e9da5624f44ebe704132cf6adfb2a17e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f508fc6214a96e9411ef2830e5e6bd79ae9476425be762854812b0edbf4f79f2e08928e99376f465d718483e9232b27e4d63919fb285f7e2993a7654e90e4098
|
7
|
+
data.tar.gz: 37c542277ac4c4f7184458b83820067259ae155c056f24c0dc8d7dfa63794beef0a406ded045f5473972d52f81af941730d0bda0da6fe009b39a5ba25897235e
|
data/lib/rsvgr.rb
ADDED
@@ -0,0 +1,405 @@
|
|
1
|
+
# I don't give a fuck about namespaces, xslt, etc.
|
2
|
+
# I don't use any xml library, because I just don't really need it here
|
3
|
+
# I don't give a fuck about xslt and other shit
|
4
|
+
# I JUST A PSYCHO REDING THIS AND DOING THE EASIEST WAY
|
5
|
+
|
6
|
+
# http://www.w3.org/TR/SVGTiny12/single-page.html
|
7
|
+
|
8
|
+
|
9
|
+
module RSVGR
|
10
|
+
|
11
|
+
DEFAULT_SIZE = 100.0
|
12
|
+
UNSUPPORTED = ->{ raise "not supported currently" }
|
13
|
+
|
14
|
+
class Node
|
15
|
+
def initialize args = {}
|
16
|
+
args[:x1] ||= 0
|
17
|
+
args[:y1] ||= 0
|
18
|
+
args[:x2] ||= DEFAULT_SIZE
|
19
|
+
args[:y2] ||= DEFAULT_SIZE
|
20
|
+
args.each{ |k,v| instance_variable_set "@#{k}",v }
|
21
|
+
end
|
22
|
+
def to_s
|
23
|
+
raise "you had to override me, while ascending from #{self.class.name} class"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class CanIHazChildren < Node
|
28
|
+
def initialize args = {}
|
29
|
+
@children = []
|
30
|
+
super
|
31
|
+
end
|
32
|
+
def << x
|
33
|
+
@children << x
|
34
|
+
self
|
35
|
+
end
|
36
|
+
def to_s_children additional_child = []
|
37
|
+
[*@children, *additional_child].map{ |child|
|
38
|
+
child.to_s.gsub(/.+/, ' \0')
|
39
|
+
}.join
|
40
|
+
end
|
41
|
+
def save_as what, where
|
42
|
+
File.open(where, "w"){ |f| f.puts what }
|
43
|
+
self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Group < CanIHazChildren
|
48
|
+
def to_s additional_child = []
|
49
|
+
"<g transform=\"" \
|
50
|
+
"#{"translate(#{@x || 0},#{@y || 0}) " if @x || @y}" \
|
51
|
+
"#{"scale(#{@scale_x || @scale || 1},#{@scale_y || @scale || 1}) " if @scale_x || @scale_y || @scale}" \
|
52
|
+
"#{"rotate(#{@rotate})" if @rotate}\"" \
|
53
|
+
"#{" id=\"#{@id}\"" if @id}" \
|
54
|
+
"#{" fill=\"#{@fill_color}\"" if @fill_color}" \
|
55
|
+
"#{" stroke-width=\"#{@stroke_width}\"" if @stroke_width}" \
|
56
|
+
"#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" \
|
57
|
+
">\n" + to_s_children(additional_child) + "</g>\n"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class Root < CanIHazChildren
|
62
|
+
def initialize args = {}
|
63
|
+
@fill_color = "silver"
|
64
|
+
@stroke_color = "black"
|
65
|
+
@stroke_width = DEFAULT_SIZE*0.01
|
66
|
+
@stroke_linecap = "round"
|
67
|
+
super
|
68
|
+
end
|
69
|
+
def to_s
|
70
|
+
"<?xml version=\"1.0\"?>\n" \
|
71
|
+
"<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.2\" baseProfile=\"tiny\"" \
|
72
|
+
" viewBox=\"#{[@x1, @y1, @x2, @y2].join " "}\"" \
|
73
|
+
" fill=\"#{@fill_color}\"" \
|
74
|
+
" stroke=\"#{@stroke_color}\"" \
|
75
|
+
" stroke-width=\"#{@stroke_width}\"" \
|
76
|
+
" stroke-linecap=\"#{@stroke_linecap}\"" \
|
77
|
+
" preserveAspectRatio=\"xMidYMid meet\"" \
|
78
|
+
">\n <title>Generated by RubySVGmakeR v0.1 (c) Nakilon</title>\n" +
|
79
|
+
to_s_children + "</svg>\n"
|
80
|
+
end
|
81
|
+
def to_html
|
82
|
+
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" \
|
83
|
+
" <head>\n" \
|
84
|
+
" <title>#{Time.now}</title>\n" \
|
85
|
+
" <style type=\"text/css\" media=\"screen\">\n" \
|
86
|
+
" body {\n" \
|
87
|
+
" background:lightgrey;\n" \
|
88
|
+
" margin:0;\n" \
|
89
|
+
" }\n" \
|
90
|
+
" svg {\n" \
|
91
|
+
" display:block;\n" \
|
92
|
+
" border:2px solid grey;\n" \
|
93
|
+
" position:absolute;\n" \
|
94
|
+
" top:3%;\n" \
|
95
|
+
" left:3%;\n" \
|
96
|
+
" width:94%;\n" \
|
97
|
+
" height:94%;\n" \
|
98
|
+
" background:white;\n" \
|
99
|
+
" }\n" \
|
100
|
+
" </style>\n" \
|
101
|
+
" </head>\n" \
|
102
|
+
" <body>\n" + to_s + " </body>\n</html>\n"
|
103
|
+
end
|
104
|
+
def cat
|
105
|
+
puts self.to_s
|
106
|
+
self
|
107
|
+
end
|
108
|
+
def save
|
109
|
+
save_as to_s, "temp.svg"
|
110
|
+
end
|
111
|
+
def save_html
|
112
|
+
UNSUPPORTED
|
113
|
+
save_as to_html, "temp.html"
|
114
|
+
end
|
115
|
+
def save_as what, where
|
116
|
+
UNSUPPORTED
|
117
|
+
File.open(where, "w"){ |f| f.puts what }
|
118
|
+
self
|
119
|
+
end
|
120
|
+
def open_with app
|
121
|
+
RUBY_PLATFORM["mingw"] ? `#{app} temp.svg` : `open -a #{app} temp.svg`
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
class Script < CanIHazChildren
|
127
|
+
def to_s
|
128
|
+
"<script" \
|
129
|
+
" type=\"text/ecmascript\"" \
|
130
|
+
"#{" id=\"#{@id}\"" if @id}" \
|
131
|
+
"><![CDATA[\n" + to_s_children + "]]></script>\n"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class Text < CanIHazChildren
|
136
|
+
def initialize args = {}
|
137
|
+
args[:x] ||= DEFAULT_SIZE/2
|
138
|
+
args[:y] ||= DEFAULT_SIZE/2
|
139
|
+
args[:size] ||= DEFAULT_SIZE*0.8
|
140
|
+
args[:anchor] ||= "middle"
|
141
|
+
args[:baseline] ||= "central"
|
142
|
+
args[:fill_color] ||= "black"
|
143
|
+
super
|
144
|
+
end
|
145
|
+
def to_s
|
146
|
+
"<text" \
|
147
|
+
"#{" id=\"#{@id}\"" if @id}" \
|
148
|
+
"#{" visibility=\"#{@visibility}\"" if @visibility}" \
|
149
|
+
" x=\"#{@x}\"" \
|
150
|
+
" y=\"#{@y}\"" \
|
151
|
+
" font-size=\"#{@size}\"" \
|
152
|
+
" text-anchor=\"#{@anchor}\"" \
|
153
|
+
" dominant-baseline=\"#{@baseline}\"" \
|
154
|
+
" fill=\"#{@fill_color}\"" \
|
155
|
+
"#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" \
|
156
|
+
"#{" style=\"#{@style}\"" if @style}" \
|
157
|
+
">\n" + to_s_children + "</text>\n"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class Line < Node
|
162
|
+
def to_s
|
163
|
+
"<line " \
|
164
|
+
"x1=\"#{@x1}\" " \
|
165
|
+
"x2=\"#{@x2}\" " \
|
166
|
+
"y1=\"#{@y1}\" " \
|
167
|
+
"y2=\"#{@y2}\" " \
|
168
|
+
"#{"stroke=\"#{@stroke_color}\" " if @stroke_color}" \
|
169
|
+
"/>\n"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class Path < Node
|
174
|
+
def initialize args = {}
|
175
|
+
args[:d] = "M " + args[:points].map{ |x, y| "#{x} #{y}" }.join(" L ")
|
176
|
+
args[:fill_color] ||= "none"
|
177
|
+
super
|
178
|
+
end
|
179
|
+
def to_s
|
180
|
+
"<path" \
|
181
|
+
" d=\"#{@d}\"" \
|
182
|
+
"#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" \
|
183
|
+
" fill=\"#{@fill_color}\"" \
|
184
|
+
"/>\n"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
class Circle < Node
|
189
|
+
def initialize args = {}
|
190
|
+
args[:r] ||= DEFAULT_SIZE*0.5
|
191
|
+
super
|
192
|
+
end
|
193
|
+
def to_s
|
194
|
+
"<circle" \
|
195
|
+
"#{" cx=\"#{@x}\"" if @x}" \
|
196
|
+
"#{" cy=\"#{@y}\"" if @y}" \
|
197
|
+
" r=\"#{@r}\"" \
|
198
|
+
"#{" fill=\"#{@fill_color}\"" if @fill_color}" \
|
199
|
+
"#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" \
|
200
|
+
"#{" onmousemove=\"#{@onmousemove}\"" if @onmousemove}" \
|
201
|
+
"#{" onmouseout=\"#{@onmouseout}\"" if @onmouseout}" \
|
202
|
+
"/>\n"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
class Rect < Node
|
207
|
+
def initialize args = {}
|
208
|
+
args[:width] ||= DEFAULT_SIZE
|
209
|
+
args[:height] ||= DEFAULT_SIZE
|
210
|
+
super
|
211
|
+
end
|
212
|
+
def to_s
|
213
|
+
"<rect" \
|
214
|
+
"#{" x=\"#{@x1}\"" if @x1}" \
|
215
|
+
"#{" y=\"#{@y1}\"" if @y1}" \
|
216
|
+
" width=\"#{@width}\"" \
|
217
|
+
" height=\"#{@height}\"" \
|
218
|
+
"#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" \
|
219
|
+
"#{" stroke-width=\"#{@stroke_width}\"" if @stroke_width}" \
|
220
|
+
"#{" fill=\"#{@fill_color}\"" if @fill_color}" \
|
221
|
+
"/>\n"
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
module Samples
|
227
|
+
def self.face args = {}
|
228
|
+
args[:scale_x] = args[:scale_y] = args[:size]/DEFAULT_SIZE if args[:size]
|
229
|
+
args[:fill_color] = "yellow"
|
230
|
+
args[:x] = DEFAULT_SIZE/2
|
231
|
+
args[:y] = DEFAULT_SIZE/2
|
232
|
+
args[:stroke_width] = DEFAULT_SIZE/10
|
233
|
+
args[:stroke_color] = :black
|
234
|
+
Group.new(args) <<
|
235
|
+
Circle.new <<
|
236
|
+
Circle.new(x:-0.2*DEFAULT_SIZE, y:-0.2*DEFAULT_SIZE, r:0.1*DEFAULT_SIZE) <<
|
237
|
+
Circle.new(x:+0.2*DEFAULT_SIZE, y:-0.2*DEFAULT_SIZE, r:0.1*DEFAULT_SIZE) <<
|
238
|
+
Line.new(x1:-0.2*DEFAULT_SIZE, y1:+0.2*DEFAULT_SIZE, x2:+0.2*DEFAULT_SIZE, y2:+0.2*DEFAULT_SIZE)
|
239
|
+
end
|
240
|
+
class Grid < Group
|
241
|
+
def initialize args = {}
|
242
|
+
#args[:x2] ||= args[:xn] + args[:x1] ||= 0
|
243
|
+
#args[:y2] ||= args[:yn] + args[:y1] ||= 0
|
244
|
+
args[:fill_color] = "white"
|
245
|
+
super
|
246
|
+
if @xn*(@y2-@y1) > (@x2-@x1)*@yn
|
247
|
+
y = (@x2-@x1)*@yn/@xn
|
248
|
+
@y1 = (DEFAULT_SIZE-y)/2
|
249
|
+
@y2 = (DEFAULT_SIZE+y)/2
|
250
|
+
else
|
251
|
+
x = (@y2-@y1)*@xn/@yn
|
252
|
+
@x1 = (DEFAULT_SIZE-x)/2
|
253
|
+
@x2 = (DEFAULT_SIZE+x)/2
|
254
|
+
end
|
255
|
+
w = (@x2 - @x1)/@xn
|
256
|
+
h = (@y2 - @y1)/@yn
|
257
|
+
[*0...@yn].product([*0...@xn]) do |i,j|
|
258
|
+
self << cell = Group.new(
|
259
|
+
x: @x1+j*w,
|
260
|
+
y: @y1+i*h,
|
261
|
+
scale_x: w/DEFAULT_SIZE,
|
262
|
+
scale_y: h/DEFAULT_SIZE,
|
263
|
+
)
|
264
|
+
cell << Rect.new(stroke_color:"silver", stroke_width:DEFAULT_SIZE/10) << inside = Group.new(
|
265
|
+
x: DEFAULT_SIZE*0.1,
|
266
|
+
y: DEFAULT_SIZE*0.1,
|
267
|
+
scale_x: 0.8,
|
268
|
+
scale_y: 0.8,
|
269
|
+
)
|
270
|
+
yield inside,i,j if block_given?
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
class Plot < Group
|
275
|
+
def initialize args = {}
|
276
|
+
args[:stroke_width] = DEFAULT_SIZE * 0.002
|
277
|
+
args[:fill_color] = "white"
|
278
|
+
super
|
279
|
+
@lines = []
|
280
|
+
end
|
281
|
+
def add_line args = {}
|
282
|
+
args[:data_pairs] = Hash[args[:data_pairs].to_a]
|
283
|
+
@lines << args
|
284
|
+
self
|
285
|
+
end
|
286
|
+
def to_s
|
287
|
+
return @to_s_cached if @to_s_cached
|
288
|
+
ticks = lambda do |basics|
|
289
|
+
if basics.any?{ |i| ! i.is_a? Integer }
|
290
|
+
[
|
291
|
+
basics.uniq,
|
292
|
+
-> x { DEFAULT_SIZE * basics.index(x) / (basics.size-1) }
|
293
|
+
]
|
294
|
+
else
|
295
|
+
min, max = basics.minmax
|
296
|
+
[
|
297
|
+
[min, *(1...8).map{ |i| (max-min)*i/8 }, max],
|
298
|
+
-> x { DEFAULT_SIZE * (x - min) / (max - min) }
|
299
|
+
]
|
300
|
+
end
|
301
|
+
end
|
302
|
+
ticks_x, f_x = ticks[ @ticks_x || @lines.flat_map{ |line| line[:data_pairs].keys } ]
|
303
|
+
ticks_y, f_y = ticks[ @lines.flat_map{ |line| line[:data_pairs].values } ]
|
304
|
+
top, left, scale = 0.05, 0.1
|
305
|
+
size = DEFAULT_SIZE * 0.03
|
306
|
+
self << field = Group.new(id:"TODOfield", x: DEFAULT_SIZE * left, y: DEFAULT_SIZE * top, scale: 0.7)
|
307
|
+
hsv2rgb = lambda do |h,s,v|
|
308
|
+
vmin = (100-s)*v/100
|
309
|
+
a = (v - vmin)*(h % 60)/60.0
|
310
|
+
vinc = vmin + a
|
311
|
+
vdec = v - a
|
312
|
+
case h/60
|
313
|
+
when 0 ; [v, vinc, vmin]
|
314
|
+
when 1 ; [vdec, v, vmin]
|
315
|
+
when 2 ; [vmin, v, vinc]
|
316
|
+
when 3 ; [vmin, vdec, v]
|
317
|
+
when 4 ; [vinc, vmin, v]
|
318
|
+
when 5 ; [v, vmin, vdec]
|
319
|
+
end.map{ |i| (2.55 * i).floor }
|
320
|
+
end
|
321
|
+
colors = (0...@lines.size).map{ |i| ?# + hsv2rgb[i*360/@lines.size, 100, 100].pack("C*").unpack("H*").first }
|
322
|
+
@lines.zip(colors).each_with_index do |(line, color), i|
|
323
|
+
#@@id = defined?(@@id) ? @@id + 1 : 0
|
324
|
+
field << (Text.new(
|
325
|
+
#id: @@id,
|
326
|
+
fill_color: "black",# color.tr("0123456789abcdef", "fedcba9876543210"),
|
327
|
+
stroke_color: "none",
|
328
|
+
size: DEFAULT_SIZE * 0.03,
|
329
|
+
x: DEFAULT_SIZE * 0.12,
|
330
|
+
y: DEFAULT_SIZE * (0.05 + i * 0.03),
|
331
|
+
anchor: "begin",
|
332
|
+
baseline: "text-before-edge",
|
333
|
+
) << line[:title])
|
334
|
+
field << Rect.new(
|
335
|
+
x1: DEFAULT_SIZE * 0.05,
|
336
|
+
y1: DEFAULT_SIZE * (0.05 + i * 0.03),
|
337
|
+
width: DEFAULT_SIZE * 0.05,
|
338
|
+
height: DEFAULT_SIZE * 0.03,
|
339
|
+
fill_color: color,
|
340
|
+
)
|
341
|
+
end
|
342
|
+
@lines.zip(colors).each_with_index do |(line, color), i|
|
343
|
+
field << Path.new(
|
344
|
+
stroke_color: color,
|
345
|
+
points: line[:data_pairs].map{ |k,v| [f_x[k], DEFAULT_SIZE-f_y[v]] }
|
346
|
+
)
|
347
|
+
end
|
348
|
+
field << Text.new(
|
349
|
+
id: "tooltip",
|
350
|
+
visibility: "hidden",
|
351
|
+
baseline: "before-edge",
|
352
|
+
size: DEFAULT_SIZE * 0.03,
|
353
|
+
stroke_color: "none",
|
354
|
+
)
|
355
|
+
field << (Script.new(id: "TODOscript") << "
|
356
|
+
var svg = document.getElementById(\"TODOscript\").ownerSVGElement;
|
357
|
+
svg.tooltip = svg.getElementById(\"tooltip\");
|
358
|
+
function show_tooltip(evt, text, x, y) {
|
359
|
+
var tooltip = evt.target.ownerSVGElement.tooltip;
|
360
|
+
tooltip.setAttributeNS(null, \"x\", x);
|
361
|
+
tooltip.setAttributeNS(null, \"y\", y);
|
362
|
+
tooltip.textContent = text;
|
363
|
+
tooltip.setAttributeNS(null, \"visibility\", \"visible\");
|
364
|
+
}
|
365
|
+
function hide_tooltip(evt) { evt.target.ownerSVGElement.tooltip.setAttributeNS(null, \"visibility\", \"hidden\"); }
|
366
|
+
")
|
367
|
+
@lines.zip(colors) do |line, color| line[:data_pairs].each do |k,v|
|
368
|
+
x = f_x[k]
|
369
|
+
y = DEFAULT_SIZE - f_y[v]
|
370
|
+
field << Circle.new(
|
371
|
+
fill_color: color,
|
372
|
+
stroke_color: color,
|
373
|
+
x: x,
|
374
|
+
y: y,
|
375
|
+
r: DEFAULT_SIZE * 0.005,
|
376
|
+
onmousemove: "show_tooltip(evt, '#{k}/#{v} - #{line[:title]}', #{x}, #{y - DEFAULT_SIZE*0.025})",
|
377
|
+
onmouseout: "hide_tooltip(evt)",
|
378
|
+
)
|
379
|
+
end end
|
380
|
+
field << Rect.new(fill_color:"none")
|
381
|
+
ticks_x.each_with_index{ |tick, i| _ = f_x[tick]
|
382
|
+
field << Line.new(y1: DEFAULT_SIZE * 1.025, x1:_, x2:_)
|
383
|
+
field << tick_group = Group.new(x: _, y: DEFAULT_SIZE * 1.025, rotate: 90)
|
384
|
+
tick_group << (Text.new(x: 0, y: 0, size: size,
|
385
|
+
#baseline: "text-before-edge",
|
386
|
+
anchor: "begin",
|
387
|
+
#style: "writing-mode: tb;",
|
388
|
+
) << tick.to_s)
|
389
|
+
}
|
390
|
+
ticks_y.each{ |tick| _ = f_y[tick]
|
391
|
+
field << Line.new(x2: -DEFAULT_SIZE * 0.025, y1:_, y2:_) <<
|
392
|
+
(Text.new(y: DEFAULT_SIZE - _, x: -DEFAULT_SIZE * left * 0.3, size: size, anchor: "end") << tick.to_s)
|
393
|
+
}
|
394
|
+
@to_s_cached = super
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
end
|
400
|
+
|
401
|
+
|
402
|
+
if __FILE__ == $0
|
403
|
+
puts `ruby -Cexamples chart.rb`
|
404
|
+
end
|
405
|
+
|
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rsvgr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Victor Maslov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-07-10 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: not ready for public usage -- uploaded for personal usage
|
14
|
+
email: nakilon@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/rsvgr.rb
|
20
|
+
homepage: http://rubygems.org/gems/rsvgr
|
21
|
+
licenses:
|
22
|
+
- MIT
|
23
|
+
metadata: {}
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.0.0
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
requirements: []
|
39
|
+
rubyforge_project:
|
40
|
+
rubygems_version: 2.0.14
|
41
|
+
signing_key:
|
42
|
+
specification_version: 4
|
43
|
+
summary: Ruby SVG Renderer.
|
44
|
+
test_files: []
|