victor 0.3.4 → 0.5.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
  SHA256:
3
- metadata.gz: 4f308143350a9236bbdf1c046de94a94728ecd90051004482e78cf9734484ef6
4
- data.tar.gz: 36b35af10ea11a1bc39063384c6a23e247c257d0364edb24b5914cfd73029a88
3
+ metadata.gz: 86eac1cab671c40d60409cf11e0e06800add519f2a11e80f33adbb8a516b7906
4
+ data.tar.gz: ff574def00c021acf82c0071ce6d9467576a74e0651663ecd7291ca2e5884ea7
5
5
  SHA512:
6
- metadata.gz: 353fd957d007ad7dd020f84a8866634a799e39ae94ba2ea65edf4eb09b6e8a354aa09961492a6cac0a530bcee5e904738df13bffc68c3b00f983348844adc074
7
- data.tar.gz: 3993f70f671cb4097e83279bc4b5b68d510aa74a40ae320960d56b4a6b1aa537270893975c473cbf66a263496cea39398cd742b217af6b327b595edef84ea36b
6
+ metadata.gz: 1fa1657d2e98c4bf98468f9f1e9a69a07c0c049eac6033d0bb3d2bbe603627cb448034923f94e6aef31db755ca66916a484ad521c86534c32274ef764a31ed79
7
+ data.tar.gz: 1a0662ce919d6abed8bea839c4fef03f7314960dbeaa5602b1627b44e4f69082e3ce933de57170c17973a58ab8f61ee7bb214796c99e641b35a3dec59a54d945
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
- ![Victor](/examples/16_victor_logo.svg)
1
+ <div align='center'>
2
+ <img src='assets/logo.svg' width=500>
2
3
 
3
4
  # Victor - Ruby SVG Image Builder
4
5
 
@@ -6,32 +7,14 @@
6
7
  [![Build Status](https://github.com/DannyBen/victor/workflows/Test/badge.svg)](https://github.com/DannyBen/victor/actions?query=workflow%3ATest)
7
8
  [![Maintainability](https://api.codeclimate.com/v1/badges/85cc05c219d6d233ab78/maintainability)](https://codeclimate.com/github/DannyBen/victor/maintainability)
8
9
 
9
- ---
10
-
11
- Victor is a direct Ruby-to-SVG builder. All method calls are converted
12
- directly to SVG elements.
10
+ ## [victor.dannyb.co](https://victor.dannyb.co)
13
11
 
14
- ![Demo](assets/animated.gif)
12
+ </div>
15
13
 
16
14
  ---
17
15
 
18
- ## Table of Contents
19
-
20
- * [Install](#install)
21
- * [Examples](#examples)
22
- * [Usage](#usage)
23
- * [Features](#features)
24
- * [Composite SVG](#composite-svg)
25
- * [Saving the Output](#saving-the-output)
26
- * [SVG Templates](#svg-templates)
27
- * [CSS](#css)
28
- * [Tagless Elements](#tagless-elements)
29
- * [XML Encoding](#xml-encoding)
30
- * [XML Newlines](#xml-newlines)
31
- * [DSL Syntax](#dsl-syntax)
32
- * [Using with Rails](#using-with-rails)
33
- * [Related Projects](#related-projects)
34
- * [Contributing / Support](#contributing--support)
16
+ **Victor** is a lightweight, zero-dependencies Ruby library that lets you build
17
+ SVG images using Ruby code.
35
18
 
36
19
  ---
37
20
 
@@ -41,483 +24,46 @@ directly to SVG elements.
41
24
  $ gem install victor
42
25
  ```
43
26
 
44
- Or with bundler:
45
-
46
- ```ruby
47
- gem 'victor'
48
- ```
49
-
50
- ## Examples
51
-
52
- ```ruby
53
- require 'victor'
54
-
55
- svg = Victor::SVG.new width: 140, height: 100, style: { background: '#ddd' }
56
-
57
- svg.build do
58
- rect x: 10, y: 10, width: 120, height: 80, rx: 10, fill: '#666'
59
-
60
- circle cx: 50, cy: 50, r: 30, fill: 'yellow'
61
- circle cx: 58, cy: 32, r: 4, fill: 'black'
62
- polygon points: %w[45,50 80,30 80,70], fill: '#666'
63
-
64
- 3.times do |i|
65
- x = 80 + i*18
66
- circle cx: x, cy: 50, r: 4, fill: 'yellow'
67
- end
68
- end
69
-
70
- svg.save 'pacman'
71
- ```
72
-
73
- Output:
74
-
75
- [![pacman](https://cdn.rawgit.com/DannyBen/victor/master/examples/10_pacman.svg)](https://github.com/DannyBen/victor/blob/master/examples/10_pacman.rb)
76
-
77
-
78
- See the [examples] folder for several ruby scripts and their SVG output.
79
-
80
-
81
- ## Usage
82
-
83
- Initialize your SVG image:
84
-
85
- ```ruby
86
- require 'victor'
87
- svg = Victor::SVG.new
88
- ```
89
-
90
- Any option you provide to `SVG.new` will be added as an attribute to the
91
- main `<svg>` element. By default, `height` and `width` are set to 100%.
92
-
93
- ```ruby
94
- svg = Victor::SVG.new width: '100%', height: '100%'
95
- # same as just Victor::SVG.new
96
-
97
- svg = Victor::SVG.new width: '100%', height: '100%', viewBox: "0 0 200 100"
98
- ```
99
-
100
- As an alternative, you can set the root SVG attributes using the `setup` method:
101
-
102
- ```ruby
103
- require 'victor'
104
- svg = Victor::SVG.new
105
- svg.setup width: 200, height: 150
106
- ```
107
-
108
- Victor uses a single method (`element`) to generate all SVG elements:
109
-
110
- ```ruby
111
- svg.element :rect, x: 2, y: 2, width: 200, height: 200
112
- # => <rect x="2" y="2" width="200" height="200"/>
113
- ```
114
-
115
- But you can omit it. Calls to any other method, will be delegated to the
116
- `element` method, so normal usage looks more like this:
117
-
118
- ```ruby
119
- svg.rect x: 2, y: 2, width: 200, height: 200
120
- # => <rect x="2" y="2" width="200" height="200"/>
121
- ```
122
-
123
- In other words, these are the same:
124
-
125
- ```ruby
126
- svg.element :anything, option: 'value'
127
- svg.anything option: 'value'
128
- ```
129
-
130
- You can use the `build` method, to generate the SVG with a block
131
-
132
- ```ruby
133
- svg.build do
134
- rect x: 0, y: 0, width: 100, height: 100, fill: '#ccc'
135
- rect x: 20, y: 20, width: 60, height: 60, fill: '#f99'
136
- end
137
- ```
138
-
139
- If the value of an attribute is a hash, it will be converted to a
140
- style-compatible string:
141
-
142
- ```ruby
143
- svg.rect x: 0, y: 0, width: 100, height: 100, style: { stroke: '#ccc', fill: 'red' }
144
- # => <rect x=0 y=0 width=100 height=100 style="stroke:#ccc; fill:red"/>
145
- ```
146
-
147
- If the value of an attribute is an array, it will be converted to a
148
- space delimited string:
149
-
150
- ```ruby
151
- svg.path d: ['M', 150, 0, 'L', 75, 200, 'L', 225, 200, 'Z']
152
- # => <path d="M 150 0 L 75 200 L 225 200 Z"/>
153
- ```
154
-
155
- For SVG elements that have an inner content - such as text - simply pass it as
156
- the first argument:
157
-
158
- ```ruby
159
- svg.text "Victor", x: 40, y: 50
160
- # => <text x="40" y="50">Victor</text>
161
- ```
162
-
163
- You can also nest elements with blocks:
164
-
165
- ```ruby
166
- svg.build do
167
- g font_size: 30, font_family: 'arial', fill: 'white' do
168
- text "Scalable Victor Graphics", x: 40, y: 50
169
- end
170
- end
171
- # => <g font-size="30" font-family="arial" fill="white">
172
- # <text x="40" y="50">Scalable Victor Graphics</text>
173
- # </g>
174
- ```
175
-
176
- Underscores in attribute names are converted to dashes:
177
-
178
- ```ruby
179
- svg.text "Victor", x: 40, y: 50, font_family: 'arial', font_weight: 'bold', font_size: 40
180
- # => <text x="40" y="50" font-family="arial" font-weight="bold" font-size="40">
181
- # Victor
182
- # </text>
183
- ```
184
-
185
- ## Features
186
-
187
- ### Composite SVG
188
-
189
- Victor also supports the ability to combine several smaller SVG objects into
190
- one using the `<<` operator or the `#append` method.
191
-
192
- This operator expects to receive any object that responds to `#to_s` (can be another `SVG` object).
193
-
194
- ```ruby
195
- require 'victor'
196
- include Victor
197
-
198
- # Create a reusable SVG object
199
- frame = SVG.new
200
- frame.rect x: 0, y: 0, width: 100, height: 100, fill: '#336'
201
- frame.rect x: 10, y: 10, width: 80, height: 80, fill: '#fff'
202
-
203
- # ... and another
204
- troll = SVG.new
205
- troll.circle cx: 50, cy: 60, r: 24, fill: 'yellow'
206
- troll.polygon points: %w[24,50 50,14 76,54], fill: 'red'
207
-
208
- # Combine objects into a single image
209
- svg = SVG.new viewBox: '0 0 100 100'
210
- svg << frame
211
- svg << troll
212
-
213
- # ... and save it
214
- svg.save 'framed-troll'
215
- ```
216
-
217
- Output:
218
-
219
- [![troll](https://cdn.rawgit.com/DannyBen/victor/master/examples/14_composite_svg.svg)](https://cdn.rawgit.com/DannyBen/victor/master/examples/14_composite_svg.svg)
220
-
221
- These two calls are identical:
27
+ ## Example
222
28
 
223
- ```ruby
224
- svg << other
225
- svg.append other
226
- ```
29
+ <table><tr><td width="250">
227
30
 
228
- To make this common use case a little easier to use, you can use a block when instantiating a new `SVG` object:
31
+ <img src='assets/ghost.svg' width=250>
229
32
 
230
- ```ruby
231
- troll = SVG.new do
232
- circle cx: 50, cy: 60, r: 24, fill: 'yellow'
233
- end
234
- ```
235
-
236
- Which is the same as:
33
+ </td><td>
237
34
 
238
35
  ```ruby
239
- troll = SVG.new
240
- troll.build do
241
- circle cx: 50, cy: 60, r: 24, fill: 'yellow'
242
- end
243
- ```
244
-
245
- Another approach to a more modular SVG composition, would be to subclass
246
- `Victor::SVG`.
247
-
248
- See the [composite svg example](https://github.com/DannyBen/victor/tree/master/examples#14-composite-svg)
249
- or the [subclassing example](https://github.com/DannyBen/victor/tree/master/examples#15-subclassing)
250
- for more details.
251
-
252
-
253
- ### Saving the Output
254
-
255
- Generate the full SVG to a string with `render`:
256
-
257
- ```ruby
258
- result = svg.render
259
- ```
260
-
261
- Or, save it to a file with `save`:
262
-
263
- ```ruby
264
- svg.save 'filename'
265
- # the '.svg' extension is optional
266
- ```
36
+ setup viewBox: '0 0 100 100'
267
37
 
268
- ### SVG Templates
269
-
270
- The `:default` SVG template is designed to be a full XML document (i.e.,
271
- a standalone SVG image). If you wish to use the output as an SVG element
272
- inside HTML, you can change the SVG template:
273
-
274
- ```ruby
275
- svg = Victor::SVG.new template: :html
276
- # accepts :html, :minimal, :default or a filename
277
- ```
278
-
279
- You can also point it to any other template file:
280
-
281
- ```ruby
282
- svg = Victor::SVG.new template: 'path/to/template.svg'
283
- ```
284
-
285
- See the [templates] folder for an understanding of how templates are
286
- structured.
287
-
288
- Templates can also be provided when rendering or saving the output:
289
-
290
- ```ruby
291
- svg.save 'filename', template: :minimal
292
- svg.render template: :minimal
293
- ```
294
-
295
-
296
- ### CSS
297
-
298
- CSS gets a special treatment in `Victor::SVG`, with these objectives in mind:
299
-
300
- - Hide implementation details (such as the need for a `CDATA` marker)
301
- - Provide a DSL-like syntax for CSS rules
302
-
303
- The `Victor::SVG` objects has a `css` property, which can contain either a
304
- Hash or a String:
305
-
306
- ```ruby
307
- svg = Victor::SVG.new
308
-
309
- svg.css = css_hash_or_string
310
- # or without the equal sign:
311
- svg.css css_hash_or_string
312
-
313
- svg.build do
314
- # ...
315
- end
316
- ```
317
-
318
- This flexibility allows you to apply CSS in multiple ways. Below are some
319
- examples.
320
-
321
- #### Assigning CSS rules using the hash syntax
322
-
323
- ```ruby
324
- svg = Victor::SVG.new
325
-
326
- svg.build do
327
- css['.main'] = {
328
- stroke: "green",
329
- stroke_width: 2,
330
- fill: "yellow"
331
- }
332
-
333
- circle cx: 35, cy: 35, r: 20, class: 'main'
334
- end
335
- ```
336
-
337
- #### Assigning a full hash to the CSS property
338
-
339
- ```ruby
340
- svg.css = {
341
- '.bar': {
342
- fill: '#666',
343
- stroke: '#fff',
344
- stroke_width: 1
345
- },
346
- '.negative': {
347
- fill: '#f66'
348
- },
349
- '.positive': {
350
- fill: '#6f6'
351
- }
352
- }
353
- ```
354
-
355
- Underscore characters will be converted to dashes (`stroke_width` becomes
356
- `stroke-width`).
357
-
358
- #### Importing CSS from an external file
359
-
360
- ```ruby
361
- svg.css = File.read 'styles.css'
362
- ```
363
-
364
- #### CSS `@import` directives
365
-
366
- If you need to add CSS statements , like `@import`, use the following syntax:
367
-
368
- ```ruby
369
- css['@import'] = [
370
- "url('https://fonts.googleapis.com/css?family=Audiowide')",
371
- "url('https://fonts.googleapis.com/css?family=Pacifico')"
372
- ]
373
- ```
374
-
375
- This is achieved thanks to the fact that when Victor encounters an array
376
- in the CSS hash, it will prefix each of the array elements with the hash
377
- key, so the above will result in two `@import url(...)` rows.
378
-
379
- See the [css example](https://github.com/DannyBen/victor/tree/master/examples#08-css),
380
- [css string example](https://github.com/DannyBen/victor/tree/master/examples#09-css-string),
381
- or the [custom fonts example](https://github.com/DannyBen/victor/tree/master/examples#13-custom-fonts).
382
-
383
-
384
- ### Tagless Elements
385
-
386
- Using underscore (`_`) as the element name will simply add the value to the
387
- generated SVG, without any surrounding element. This is designed to allow
388
- generating something like this:
389
-
390
- ```xml
391
- <text>
392
- You are
393
- <tspan font-weight="bold">not</tspan>
394
- a banana
395
- </text>
396
- ```
397
-
398
- using this Ruby code:
38
+ build do
39
+ rect x: 0, y: 0, width: 100, height: 100, fill: :white
40
+ circle cx: 50, cy: 50, r: 40, fill: 'yellow'
41
+ rect x: 10, y: 50, width: 80, height: 50, fill: :yellow
399
42
 
400
- ```ruby
401
- svg.build do
402
- text do
403
- _ 'You are'
404
- tspan 'not', font_weight: "bold"
405
- _ 'a banana'
43
+ [25, 50].each do |x|
44
+ circle cx: x, cy: 40, r: 8, fill: :white
406
45
  end
407
- end
408
- ```
409
-
410
- See the [tagless elements example](https://github.com/DannyBen/victor/tree/master/examples#17-tagless-elements).
411
-
412
-
413
- ### XML Encoding
414
46
 
415
- Plain text values are encoded automatically:
416
-
417
- ```ruby
418
- svg.build do
419
- text "Ben & Jerry's"
420
- end
421
- # <text>Ben &amp; Jerry's</text>
422
- ```
423
-
424
- If you need to use the raw, unencoded string, add `!` to the element's name:
425
-
426
- ```ruby
427
- svg.build do
428
- text! "Ben & Jerry's"
47
+ path fill: 'white', d: %w[
48
+ M11 100 l13 -15 l13 15 l13 -15
49
+ l13 15 l13 -15 l13 15 Z
50
+ ]
429
51
  end
430
- # <text>Ben & Jerry's</text>
431
52
  ```
432
53
 
433
- See the [xml encoding example](https://github.com/DannyBen/victor/tree/master/examples#18-xml-encoding).
54
+ </td></tr></table>
434
55
 
435
56
 
436
- ### XML Newlines
437
-
438
- By default, the generated SVGs will have a newline glue between the elements.
439
- You can change this (for example, to an empty string) if the default newlines
440
- are not appropriate for your use case.
441
-
442
- ```ruby
443
- svg = Victor::SVG.new glue: ''
444
- ```
445
-
446
- The glue can also be provided when rendering or saving the output:
447
-
448
- ```ruby
449
- svg.save 'filename', glue: ''
450
- svg.render glue: ''
451
- ```
452
-
453
- ### DSL Syntax
454
-
455
- Victor also supports a DSL-like syntax. To use it, simply `require 'victor/script'`.
456
-
457
- Once required, you have access to:
458
-
459
- - `svg` - returns an instance of `Victor::SVG`
460
- - All the methods that are available on the `SVG` object, are included at the root level.
461
-
462
- For example:
463
-
464
- ```ruby
465
- require 'victor/script'
466
-
467
- setup width: 100, height: 100
468
-
469
- build do
470
- circle cx: 50, cy: 50, r: 30, fill: "yellow"
471
- end
472
-
473
- puts render
474
- save 'output.svg'
475
- ```
476
-
477
- See the [dsl example](https://github.com/DannyBen/victor/tree/master/examples#19-dsl).
478
-
479
- ## Using with Rails
480
-
481
- See the [example_rails](example_rails) folder.
482
-
483
-
484
- ## Related Projects
485
-
486
- ### [Victor CLI][victor-cli]
487
-
488
- A command line utility that allows converting Ruby to SVG as well as SVG to
489
- Victor Ruby scripts.
490
-
491
- ### [Victor Opal][victor-opal]
492
-
493
- A Victor playground that works in the browser.
494
-
495
- ### [Minichart][minichart]
496
-
497
- A Ruby gem that uses Victor to generate SVG charts
498
-
499
- [![Minichart](assets/minichart.svg)][minichart]
500
-
501
-
502
- ### [Icodi][icodi]
503
-
504
- A Ruby gem that uses Victor to generate consistent random icon
505
- images, similar to GitHub's identicon.
506
-
507
- [![Icodi](assets/icodi.svg)][icodi]
57
+ ## Documentation
508
58
 
59
+ - [Victor Homepage][docs]
509
60
 
510
61
  ## Contributing / Support
511
62
 
512
63
  If you experience any issue, have a question or a suggestion, or if you wish
513
- to contribute, feel free to [open an issue][issues].
514
-
515
- ---
64
+ to contribute, feel free to [open an issue][issues] or
65
+ [start a discussion][discussions].
516
66
 
517
- [examples]: https://github.com/DannyBen/victor/tree/master/examples#examples
518
- [templates]: https://github.com/DannyBen/victor/tree/master/lib/victor/templates
519
- [icodi]: https://github.com/DannyBen/icodi
520
- [minichart]: https://github.com/DannyBen/minichart
521
- [victor-opal]: https://kuboon.github.io/victor-opal/
522
- [victor-cli]: https://github.com/DannyBen/victor-cli
523
67
  [issues]: https://github.com/DannyBen/victor/issues
68
+ [discussions]: https://github.com/DannyBen/victor/discussions
69
+ [docs]: https://victor.dannyb.co/
@@ -1,11 +1,10 @@
1
1
  module Victor
2
-
3
2
  # Handles conversion from a Hash of attributes, to an XML string or
4
3
  # a CSS string.
5
4
  class Attributes
6
5
  attr_reader :attributes
7
6
 
8
- def initialize(attributes={})
7
+ def initialize(attributes = {})
9
8
  @attributes = attributes
10
9
  end
11
10
 
@@ -13,10 +12,11 @@ module Victor
13
12
  mapped = attributes.map do |key, value|
14
13
  key = key.to_s.tr '_', '-'
15
14
 
16
- if value.is_a? Hash
15
+ case value
16
+ when Hash
17
17
  style = Attributes.new(value).to_style
18
18
  "#{key}=\"#{style}\""
19
- elsif value.is_a? Array
19
+ when Array
20
20
  "#{key}=\"#{value.join ' '}\""
21
21
  else
22
22
  "#{key}=#{value.to_s.encode(xml: :attr)}"
@@ -42,7 +42,5 @@ module Victor
42
42
  def []=(key, value)
43
43
  attributes[key] = value
44
44
  end
45
-
46
45
  end
47
-
48
- end
46
+ end
@@ -0,0 +1,61 @@
1
+ require 'forwardable'
2
+
3
+ module Victor
4
+ class Component
5
+ extend Forwardable
6
+ include Marshaling
7
+
8
+ def_delegators :svg, :save, :render, :content, :element, :tag, :css, :to_s
9
+
10
+ # Marshaling data
11
+ def marshaling = %i[width height x y svg merged_css]
12
+
13
+ # Subclasses MUST implement this
14
+ def body
15
+ raise(NotImplementedError, "#{self.class.name} must implement `body'")
16
+ end
17
+
18
+ # Subclasses MUST override these methods, OR assign instance vars
19
+ def height
20
+ @height || raise(NotImplementedError,
21
+ "#{self.class.name} must implement `height' or `@height'")
22
+ end
23
+
24
+ def width
25
+ @width || raise(NotImplementedError,
26
+ "#{self.class.name} must implement `width' or `@width'")
27
+ end
28
+
29
+ # Subclasses MAY override these methods, OR assign instance vars
30
+ def style = @style ||= {}
31
+ def x = @x ||= 0
32
+ def y = @y ||= 0
33
+
34
+ # Appending/Embedding - DSL for the `#body` implementation
35
+ def append(component)
36
+ svg_instance.append component.svg
37
+ merged_css.merge! component.merged_css
38
+ end
39
+ alias embed append
40
+
41
+ # SVG / CSS
42
+ def svg
43
+ @svg ||= begin
44
+ body
45
+ svg_instance.css = merged_css
46
+ svg_instance
47
+ end
48
+ end
49
+
50
+ protected
51
+
52
+ # Start with an ordinary SVG instance
53
+ def svg_instance = @svg_instance ||= SVG.new(viewBox: "#{x} #{y} #{width} #{height}")
54
+
55
+ # Internal DSL to enable `add.anything` in the `#body` implementation
56
+ alias add svg_instance
57
+
58
+ # Start with a copy of our own style
59
+ def merged_css = @merged_css ||= style.dup
60
+ end
61
+ end
data/lib/victor/css.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  module Victor
2
-
3
2
  class CSS
4
3
  attr_reader :attributes
5
4
 
@@ -13,12 +12,13 @@ module Victor
13
12
 
14
13
  def render
15
14
  return '' if attributes.empty?
16
- %Q{<style type="text/css">\n<![CDATA[\n#{self}\n]]>\n</style>\n}
15
+
16
+ %[<style>\n#{self}\n</style>\n]
17
17
  end
18
18
 
19
19
  protected
20
20
 
21
- def convert_hash(hash, indent=2)
21
+ def convert_hash(hash, indent = 2)
22
22
  return hash unless hash.is_a? Hash
23
23
 
24
24
  result = []
@@ -33,13 +33,14 @@ module Victor
33
33
  def css_block(key, value, indent)
34
34
  result = []
35
35
 
36
- my_indent = " " * indent
36
+ my_indent = ' ' * indent
37
37
 
38
- if value.is_a? Hash
38
+ case value
39
+ when Hash
39
40
  result.push "#{my_indent}#{key} {"
40
- result.push convert_hash(value, indent+2)
41
+ result.push convert_hash(value, indent + 2)
41
42
  result.push "#{my_indent}}"
42
- elsif value.is_a? Array
43
+ when Array
43
44
  value.each do |row|
44
45
  result.push "#{my_indent}#{key} #{row};"
45
46
  end
@@ -50,5 +51,4 @@ module Victor
50
51
  result
51
52
  end
52
53
  end
53
-
54
- end
54
+ end
data/lib/victor/dsl.rb CHANGED
@@ -3,7 +3,7 @@ require 'forwardable'
3
3
  module Victor
4
4
  module DSL
5
5
  extend Forwardable
6
- def_delegators :svg, :setup, :build, :save, :render, :append, :element, :css
6
+ def_delegators :svg, :setup, :build, :save, :render, :append, :element, :tag, :css
7
7
 
8
8
  def svg
9
9
  @svg ||= Victor::SVG.new
@@ -0,0 +1,33 @@
1
+ module Victor
2
+ module Marshaling
3
+ def marshaling
4
+ raise NotImplementedError, "#{self.class.name} must implement `marshaling'"
5
+ end
6
+
7
+ # YAML serialization methods
8
+ def encode_with(coder)
9
+ marshaling.each do |attr|
10
+ coder[attr.to_s] = send(attr)
11
+ end
12
+ end
13
+
14
+ def init_with(coder)
15
+ marshaling.each do |attr|
16
+ instance_variable_set(:"@#{attr}", coder[attr.to_s])
17
+ end
18
+ end
19
+
20
+ # Marshal serialization methods
21
+ def marshal_dump
22
+ marshaling.to_h do |attr|
23
+ [attr, send(attr)]
24
+ end
25
+ end
26
+
27
+ def marshal_load(data)
28
+ marshaling.each do |attr|
29
+ instance_variable_set(:"@#{attr}", data[attr])
30
+ end
31
+ end
32
+ end
33
+ end
data/lib/victor/svg.rb CHANGED
@@ -1,7 +1,11 @@
1
1
  module Victor
2
2
  class SVG < SVGBase
3
- def method_missing(method_sym, *arguments, &block)
4
- element method_sym, *arguments, &block
3
+ def method_missing(method_sym, ...)
4
+ tag(method_sym, ...)
5
+ end
6
+
7
+ def respond_to_missing?(*)
8
+ true
5
9
  end
6
10
  end
7
- end
11
+ end
@@ -1,24 +1,31 @@
1
1
  module Victor
2
-
3
2
  class SVGBase
3
+ include Marshaling
4
+
4
5
  attr_accessor :template, :glue
5
6
  attr_reader :content, :svg_attributes
7
+ attr_writer :css
6
8
 
7
9
  def initialize(attributes = nil, &block)
8
10
  setup attributes
9
11
  @content = []
10
- build &block if block_given?
12
+ build(&block) if block
13
+ end
14
+
15
+ def marshaling
16
+ %i[template glue svg_attributes css content]
11
17
  end
12
18
 
13
19
  def <<(additional_content)
14
20
  content.push additional_content.to_s
15
21
  end
16
22
  alias append <<
23
+ alias embed <<
17
24
 
18
25
  def setup(attributes = nil)
19
26
  attributes ||= {}
20
- attributes[:width] ||= "100%"
21
- attributes[:height] ||= "100%"
27
+ attributes[:width] ||= '100%'
28
+ attributes[:height] ||= '100%'
22
29
 
23
30
  @template = attributes[:template] || @template || :default
24
31
  @glue = attributes[:glue] || @glue || "\n"
@@ -30,10 +37,10 @@ module Victor
30
37
  end
31
38
 
32
39
  def build(&block)
33
- self.instance_eval(&block)
40
+ instance_eval(&block)
34
41
  end
35
42
 
36
- def element(name, value=nil, attributes={}, &_block)
43
+ def tag(name, value = nil, attributes = {})
37
44
  if value.is_a? Hash
38
45
  attributes = value
39
46
  value = nil
@@ -50,17 +57,18 @@ module Victor
50
57
  empty_tag = name.to_s == '_'
51
58
 
52
59
  if block_given? || value
53
- content.push "<#{name} #{attributes}".strip + ">" unless empty_tag
60
+ content.push "#{"<#{name} #{attributes}".strip}>" unless empty_tag
54
61
  if value
55
62
  content.push(escape ? value.to_s.encode(xml: :text) : value)
56
63
  else
57
64
  yield
58
65
  end
59
66
  content.push "</#{name}>" unless empty_tag
60
- else
67
+ else
61
68
  content.push "<#{name} #{attributes}/>"
62
69
  end
63
70
  end
71
+ alias element tag
64
72
 
65
73
  def css(defs = nil)
66
74
  @css ||= {}
@@ -68,20 +76,16 @@ module Victor
68
76
  @css
69
77
  end
70
78
 
71
- def css=(defs)
72
- @css = defs
73
- end
74
-
75
79
  def render(template: nil, glue: nil)
76
80
  @template = template if template
77
81
  @glue = glue if glue
78
82
  css_handler = CSS.new css
79
83
 
80
84
  svg_template % {
81
- css: css_handler,
82
- style: css_handler.render,
85
+ css: css_handler,
86
+ style: css_handler.render,
83
87
  attributes: svg_attributes,
84
- content: to_s
88
+ content: to_s,
85
89
  }
86
90
  end
87
91
 
@@ -90,7 +94,7 @@ module Victor
90
94
  end
91
95
 
92
96
  def save(filename, template: nil, glue: nil)
93
- filename = "#{filename}.svg" unless filename =~ /\..{2,4}$/
97
+ filename = "#{filename}.svg" unless /\..{2,4}$/.match?(filename)
94
98
  File.write filename, render(template: template, glue: glue)
95
99
  end
96
100
 
@@ -108,5 +112,4 @@ module Victor
108
112
  end
109
113
  end
110
114
  end
111
-
112
- end
115
+ end
@@ -1,11 +1,4 @@
1
- <?xml version="1.0" standalone="no"?>
2
- <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
-
4
- <svg %{attributes}
5
- xmlns="http://www.w3.org/2000/svg"
6
- xmlns:xlink="http://www.w3.org/1999/xlink">
7
-
1
+ <svg %{attributes} xmlns="http://www.w3.org/2000/svg">
8
2
  %{style}
9
3
  %{content}
10
-
11
- </svg>
4
+ </svg>
@@ -1,4 +1,4 @@
1
1
  <svg %{attributes}>
2
2
  %{style}
3
3
  %{content}
4
- </svg>
4
+ </svg>
@@ -1,3 +1,3 @@
1
1
  module Victor
2
- VERSION = "0.3.4"
3
- end
2
+ VERSION = '0.5.0'
3
+ end
data/lib/victor.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  require 'victor/version'
2
- require 'victor/svg_base'
3
- require 'victor/svg'
4
- require 'victor/attributes'
5
- require 'victor/css'
6
- require 'victor/dsl'
7
2
 
8
- require 'byebug' if ENV['BYEBUG']
3
+ module Victor
4
+ autoload :Attributes, 'victor/attributes'
5
+ autoload :Component, 'victor/component'
6
+ autoload :CSS, 'victor/css'
7
+ autoload :DSL, 'victor/dsl'
8
+ autoload :Marshaling, 'victor/marshaling'
9
+ autoload :SVG, 'victor/svg'
10
+ autoload :SVGBase, 'victor/svg_base'
11
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: victor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-01 00:00:00.000000000 Z
11
+ date: 2024-08-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Build SVG images with ease
14
14
  email: db@dannyben.com
@@ -19,20 +19,26 @@ files:
19
19
  - README.md
20
20
  - lib/victor.rb
21
21
  - lib/victor/attributes.rb
22
+ - lib/victor/component.rb
22
23
  - lib/victor/css.rb
23
24
  - lib/victor/dsl.rb
25
+ - lib/victor/marshaling.rb
24
26
  - lib/victor/script.rb
25
27
  - lib/victor/svg.rb
26
28
  - lib/victor/svg_base.rb
27
29
  - lib/victor/templates/default.svg
28
- - lib/victor/templates/html.svg
29
30
  - lib/victor/templates/minimal.svg
30
31
  - lib/victor/version.rb
31
32
  homepage: https://github.com/DannyBen/victor
32
33
  licenses:
33
34
  - MIT
34
- metadata: {}
35
- post_install_message:
35
+ metadata:
36
+ bug_tracker_uri: https://github.com/DannyBen/victor/issues
37
+ changelog_uri: https://github.com/DannyBen/victor/blob/master/CHANGELOG.md
38
+ homepage_uri: https://victor.dannyb.co/
39
+ source_code_uri: https://github.com/DannyBen/victor
40
+ rubygems_mfa_required: 'true'
41
+ post_install_message:
36
42
  rdoc_options: []
37
43
  require_paths:
38
44
  - lib
@@ -40,15 +46,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
40
46
  requirements:
41
47
  - - ">="
42
48
  - !ruby/object:Gem::Version
43
- version: 2.6.0
49
+ version: 3.0.0
44
50
  required_rubygems_version: !ruby/object:Gem::Requirement
45
51
  requirements:
46
52
  - - ">="
47
53
  - !ruby/object:Gem::Version
48
54
  version: '0'
49
55
  requirements: []
50
- rubygems_version: 3.3.14
51
- signing_key:
56
+ rubygems_version: 3.5.17
57
+ signing_key:
52
58
  specification_version: 4
53
59
  summary: SVG Builder
54
60
  test_files: []
@@ -1,8 +0,0 @@
1
- <svg %{attributes}
2
- xmlns="http://www.w3.org/2000/svg"
3
- xmlns:xlink="http://www.w3.org/1999/xlink">
4
-
5
- %{style}
6
- %{content}
7
-
8
- </svg>