sevgi-graphics 0.73.2 → 0.93.1
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 +4 -4
- data/README.md +5 -0
- data/lib/sevgi/graphics/attribute.rb +58 -6
- data/lib/sevgi/graphics/auxiliary/canvas.rb +125 -0
- data/lib/sevgi/graphics/auxiliary/content.rb +145 -0
- data/lib/sevgi/graphics/auxiliary/margin.rb +93 -0
- data/lib/sevgi/graphics/auxiliary/paper.rb +163 -0
- data/lib/sevgi/graphics/auxiliary.rb +7 -0
- data/lib/sevgi/graphics/document/base.rb +6 -0
- data/lib/sevgi/graphics/document/default.rb +1 -0
- data/lib/sevgi/graphics/document/html.rb +1 -0
- data/lib/sevgi/graphics/document/inkscape.rb +1 -0
- data/lib/sevgi/graphics/document/minimal.rb +1 -0
- data/lib/sevgi/graphics/document.rb +137 -11
- data/lib/sevgi/graphics/element.rb +68 -8
- data/lib/sevgi/graphics/mixtures/call.rb +35 -3
- data/lib/sevgi/graphics/mixtures/core.rb +107 -18
- data/lib/sevgi/graphics/mixtures/duplicate.rb +14 -0
- data/lib/sevgi/graphics/mixtures/export.rb +29 -6
- data/lib/sevgi/graphics/mixtures/hatch.rb +24 -3
- data/lib/sevgi/graphics/mixtures/identify.rb +23 -1
- data/lib/sevgi/graphics/mixtures/include.rb +31 -4
- data/lib/sevgi/graphics/mixtures/inkscape.rb +51 -5
- data/lib/sevgi/graphics/mixtures/lint.rb +12 -0
- data/lib/sevgi/graphics/mixtures/polyfills.rb +11 -0
- data/lib/sevgi/graphics/mixtures/rdf.rb +40 -1
- data/lib/sevgi/graphics/mixtures/render.rb +90 -2
- data/lib/sevgi/graphics/mixtures/save.rb +21 -3
- data/lib/sevgi/graphics/mixtures/symbols.rb +7 -0
- data/lib/sevgi/graphics/mixtures/tile.rb +41 -6
- data/lib/sevgi/graphics/mixtures/transform.rb +54 -16
- data/lib/sevgi/graphics/mixtures/underscore.rb +10 -1
- data/lib/sevgi/graphics/mixtures/validate.rb +15 -1
- data/lib/sevgi/graphics/mixtures/wrappers.rb +54 -17
- data/lib/sevgi/graphics/mixtures.rb +35 -3
- data/lib/sevgi/graphics/version.rb +2 -1
- data/lib/sevgi/graphics.rb +57 -5
- metadata +9 -8
- data/lib/sevgi/graphics/auxilary/canvas.rb +0 -72
- data/lib/sevgi/graphics/auxilary/content.rb +0 -81
- data/lib/sevgi/graphics/auxilary/margin.rb +0 -49
- data/lib/sevgi/graphics/auxilary/paper.rb +0 -95
- data/lib/sevgi/graphics/auxilary.rb +0 -7
|
@@ -3,15 +3,31 @@
|
|
|
3
3
|
module Sevgi
|
|
4
4
|
module Graphics
|
|
5
5
|
module Mixtures
|
|
6
|
+
# DSL wrappers for common SVG shapes and content patterns.
|
|
6
7
|
module Wrappers
|
|
7
|
-
|
|
8
|
+
# Builds a line path ending at an absolute point.
|
|
9
|
+
# @param x2 [Numeric] ending x coordinate
|
|
10
|
+
# @param y2 [Numeric] ending y coordinate
|
|
11
|
+
# @param x1 [Numeric] starting x coordinate
|
|
12
|
+
# @param y1 [Numeric] starting y coordinate
|
|
13
|
+
# @return [Sevgi::Graphics::Element] path element
|
|
14
|
+
def LineTo(x2:, y2:, x1: 0, y1: 0, **)
|
|
8
15
|
path(d: "M #{x1} #{y1} L #{x2} #{y2}", **)
|
|
9
16
|
end
|
|
10
17
|
|
|
11
|
-
|
|
18
|
+
# Builds a horizontal line path ending at an absolute x coordinate.
|
|
19
|
+
# @param x2 [Numeric] ending x coordinate
|
|
20
|
+
# @param x1 [Numeric] starting x coordinate
|
|
21
|
+
# @param y1 [Numeric] starting y coordinate
|
|
22
|
+
# @return [Sevgi::Graphics::Element] path element
|
|
23
|
+
def HLineTo(x2:, x1: 0, y1: 0, **)
|
|
12
24
|
path(d: "M #{x1} #{y1} H #{x2}", **)
|
|
13
25
|
end
|
|
14
26
|
|
|
27
|
+
# Builds a titled SVG symbol.
|
|
28
|
+
# @param name [String] human-readable symbol name
|
|
29
|
+
# @param kwargs [Hash] symbol attributes
|
|
30
|
+
# @return [Sevgi::Graphics::Element] symbol element
|
|
15
31
|
def Symbol(name, **kwargs, &block)
|
|
16
32
|
id = (words = name.split).map(&:downcase).join("-")
|
|
17
33
|
title = words.map(&:capitalize).join(" ")
|
|
@@ -22,39 +38,60 @@ module Sevgi
|
|
|
22
38
|
end
|
|
23
39
|
end
|
|
24
40
|
|
|
25
|
-
|
|
41
|
+
# Builds a vertical line path ending at an absolute y coordinate.
|
|
42
|
+
# @param y2 [Numeric] ending y coordinate
|
|
43
|
+
# @param x1 [Numeric] starting x coordinate
|
|
44
|
+
# @param y1 [Numeric] starting y coordinate
|
|
45
|
+
# @return [Sevgi::Graphics::Element] path element
|
|
46
|
+
def VLineTo(y2:, x1: 0, y1: 0, **)
|
|
26
47
|
path(d: "M #{x1} #{y1} V #{y2}", **)
|
|
27
48
|
end
|
|
28
49
|
|
|
29
|
-
|
|
50
|
+
# Builds a relative line path from angle and length.
|
|
51
|
+
# @param angle [Numeric] angle in degrees
|
|
52
|
+
# @param length [Numeric] line length
|
|
53
|
+
# @param x [Numeric] starting x coordinate
|
|
54
|
+
# @param y [Numeric] starting y coordinate
|
|
55
|
+
# @return [Sevgi::Graphics::Element] path element
|
|
56
|
+
def LineBy(angle:, length:, x: 0, y: 0, **)
|
|
30
57
|
dx = length * ::Math.cos(angle.to_f / 180 * ::Math::PI)
|
|
31
58
|
dy = length * ::Math.sin(angle.to_f / 180 * ::Math::PI)
|
|
32
59
|
path(d: "M #{x} #{y} l #{dx} #{dy}", **)
|
|
33
60
|
end
|
|
34
61
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
62
|
+
# Builds a style element with CSS content.
|
|
63
|
+
# @param hash [Hash, nil] CSS rules
|
|
64
|
+
# @param attributes [Hash] style attributes or CSS rules when hash is nil
|
|
65
|
+
# @return [Sevgi::Graphics::Element] style element
|
|
66
|
+
# @raise [Sevgi::ArgumentError] when CSS content is not a hash
|
|
67
|
+
def css(hash = nil, **attributes)
|
|
68
|
+
hash, attributes = attributes, {} unless hash
|
|
38
69
|
|
|
39
|
-
|
|
40
|
-
dy = dx * ::Math.tan(angle.to_f / 180 * ::Math::PI)
|
|
41
|
-
path(d: "M #{x} #{y} l #{dx} #{dy}", **)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def cyline(angle:, dy:, x: 0, y: 0, **)
|
|
45
|
-
dx = dy / ::Math.tan(angle.to_f / 180 * ::Math::PI)
|
|
46
|
-
path(d: "M #{x} #{y} l #{dx} #{dy}", **)
|
|
70
|
+
style(Content.css(hash), type: "text/css", **attributes)
|
|
47
71
|
end
|
|
48
72
|
|
|
49
|
-
|
|
73
|
+
# Builds a relative horizontal line path.
|
|
74
|
+
# @param length [Numeric] line length
|
|
75
|
+
# @param x [Numeric] starting x coordinate
|
|
76
|
+
# @param y [Numeric] starting y coordinate
|
|
77
|
+
# @return [Sevgi::Graphics::Element] path element
|
|
78
|
+
def HLineBy(length:, x: 0, y: 0, **)
|
|
50
79
|
path(d: "M #{x} #{y} h #{length}", **)
|
|
51
80
|
end
|
|
52
81
|
|
|
82
|
+
# Builds a square rect.
|
|
83
|
+
# @param length [Numeric] side length
|
|
84
|
+
# @return [Sevgi::Graphics::Element] rect element
|
|
53
85
|
def square(length:, **)
|
|
54
86
|
rect(width: length, height: length, **)
|
|
55
87
|
end
|
|
56
88
|
|
|
57
|
-
|
|
89
|
+
# Builds a relative vertical line path.
|
|
90
|
+
# @param length [Numeric] line length
|
|
91
|
+
# @param x [Numeric] starting x coordinate
|
|
92
|
+
# @param y [Numeric] starting y coordinate
|
|
93
|
+
# @return [Sevgi::Graphics::Element] path element
|
|
94
|
+
def VLineBy(length:, x: 0, y: 0, **)
|
|
58
95
|
path(d: "M #{x} #{y} v #{length}", **)
|
|
59
96
|
end
|
|
60
97
|
end
|
|
@@ -2,11 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
module Sevgi
|
|
4
4
|
module Graphics
|
|
5
|
+
# Mixins that extend document classes with DSL helper methods.
|
|
5
6
|
module Mixtures
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
# @overload mixin(mod, document = Graphics::Document::Base, &block)
|
|
8
|
+
# Includes a named mixture and optional anonymous extension into a document class.
|
|
9
|
+
# @param mod [Symbol, String] mixture constant name
|
|
10
|
+
# @param document [Class] document class receiving the mixture
|
|
11
|
+
# @return [Module, nil] optional anonymous mixture when a block is given
|
|
12
|
+
# @raise [NameError] when the mixture does not exist
|
|
13
|
+
# @overload mixin(document = Graphics::Document::Base, &block)
|
|
14
|
+
# Includes only an anonymous extension into a document class.
|
|
15
|
+
# @param document [Class] document class receiving the mixture
|
|
16
|
+
# @return [Module] anonymous mixture
|
|
17
|
+
# @raise [Sevgi::ArgumentError] when no named mixture or block is given
|
|
18
|
+
def self.mixin(mod = Undefined, document = Graphics::Document::Base, &block)
|
|
19
|
+
mod, document = normalize(mod, document, block)
|
|
20
|
+
ArgumentError.("Mixture name or block required") if mod == Undefined && !block
|
|
21
|
+
|
|
22
|
+
document.mixture(mod) unless mod == Undefined
|
|
23
|
+
include_anonymous(document, &block) if block
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.anonymous_document?(mod, block)
|
|
27
|
+
block && mod.is_a?(::Class) && mod <= Graphics::Document::Proto
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.include_anonymous(document, &block)
|
|
31
|
+
::Module.new(&block).tap do |anonymous|
|
|
32
|
+
document.send(:include, anonymous)
|
|
33
|
+
document.extend(anonymous.const_get(:ClassMethods)) if anonymous.const_defined?(:ClassMethods, false)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.normalize(mod, document, block)
|
|
38
|
+
anonymous_document?(mod, block) ? [Undefined, mod] : [mod, document]
|
|
9
39
|
end
|
|
40
|
+
|
|
41
|
+
private_class_method :anonymous_document?, :include_anonymous, :normalize
|
|
10
42
|
end
|
|
11
43
|
end
|
|
12
44
|
end
|
data/lib/sevgi/graphics.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require "sevgi/function"
|
|
4
4
|
|
|
5
5
|
require_relative "graphics/attribute"
|
|
6
|
-
require_relative "graphics/
|
|
6
|
+
require_relative "graphics/auxiliary"
|
|
7
7
|
require_relative "graphics/element"
|
|
8
8
|
require_relative "graphics/mixtures"
|
|
9
9
|
|
|
@@ -12,23 +12,74 @@ require_relative "graphics/document"
|
|
|
12
12
|
require_relative "graphics/version"
|
|
13
13
|
|
|
14
14
|
module Sevgi
|
|
15
|
+
# SVG document builder and DSL namespace.
|
|
15
16
|
module Graphics
|
|
17
|
+
# @overload canvas(arg = Undefined, **kwargs)
|
|
18
|
+
# Builds a canvas from a paper profile or explicit size.
|
|
19
|
+
# @param arg [Sevgi::Graphics::Paper, Symbol, String, Sevgi::Undefined] paper profile or paper object
|
|
20
|
+
# @param kwargs [Hash] canvas keyword arguments
|
|
21
|
+
# @return [Sevgi::Graphics::Canvas]
|
|
22
|
+
# @raise [Sevgi::ArgumentError] when the paper profile is unknown
|
|
16
23
|
def canvas(...)
|
|
17
|
-
Graphics::Canvas.(...)
|
|
24
|
+
Graphics::Canvas.from_paper(...)
|
|
18
25
|
end
|
|
19
26
|
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
# Defines or returns a document profile class.
|
|
28
|
+
# @param name [Symbol, String, Sevgi::Undefined] profile name, or Undefined for an anonymous profile
|
|
29
|
+
# @param preambles [Array<String>, nil] document preamble lines
|
|
30
|
+
# @param attributes [Hash] default root attributes
|
|
31
|
+
# @return [Class] document class
|
|
32
|
+
# @raise [Sevgi::ArgumentError] when a named profile conflicts with an existing profile
|
|
33
|
+
def document(name = Undefined, preambles: [], attributes: {})
|
|
34
|
+
Graphics::Document.define(name, preambles:, attributes:)
|
|
22
35
|
end
|
|
23
36
|
|
|
37
|
+
# Defines or replaces a document profile class.
|
|
38
|
+
# @param name [Symbol, String] profile name
|
|
39
|
+
# @param preambles [Array<String>, nil] document preamble lines
|
|
40
|
+
# @param attributes [Hash] default root attributes
|
|
41
|
+
# @return [Class] document class
|
|
42
|
+
# @raise [Sevgi::ArgumentError] when the profile name is invalid
|
|
43
|
+
def document!(name, preambles: [], attributes: {})
|
|
44
|
+
Graphics::Document.define(name, preambles:, attributes:, overwrite: true)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Defines a paper profile unless the same profile already exists.
|
|
48
|
+
# @param width [Numeric] paper width
|
|
49
|
+
# @param height [Numeric] paper height
|
|
50
|
+
# @param name [Symbol, String] profile name
|
|
51
|
+
# @param unit [Symbol, String] SVG unit
|
|
52
|
+
# @return [Symbol, String] original profile name
|
|
53
|
+
# @raise [Sevgi::ArgumentError] when the profile is invalid or an existing profile has different dimensions
|
|
24
54
|
def paper(width, height, name = :custom, unit: "mm")
|
|
25
|
-
|
|
55
|
+
profile = Graphics::Paper[width, height, unit, name]
|
|
56
|
+
|
|
57
|
+
if Graphics::Paper.exist?(name)
|
|
58
|
+
ArgumentError.("Paper already defined differently: #{name}") unless Graphics::Paper.public_send(name) == profile
|
|
59
|
+
else
|
|
60
|
+
Graphics::Paper.define(name, width:, height:, unit:)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
name
|
|
26
64
|
end
|
|
27
65
|
|
|
66
|
+
# Defines or replaces a paper profile.
|
|
67
|
+
# @param width [Numeric] paper width
|
|
68
|
+
# @param height [Numeric] paper height
|
|
69
|
+
# @param name [Symbol, String] profile name
|
|
70
|
+
# @param unit [Symbol, String] SVG unit
|
|
71
|
+
# @return [Symbol, String] original profile name
|
|
72
|
+
# @raise [Sevgi::ArgumentError] when the profile is invalid or the profile name is reserved
|
|
28
73
|
def paper!(width, height, name = :custom, unit: "mm")
|
|
29
74
|
name.tap { Graphics::Paper.define(name, width:, height:, unit:) }
|
|
30
75
|
end
|
|
31
76
|
|
|
77
|
+
# Builds an SVG root document.
|
|
78
|
+
# @param document [Symbol, String, Class] document profile name or document class
|
|
79
|
+
# @param canvas [Sevgi::Graphics::Canvas, Sevgi::Graphics::Paper, Symbol, String, Sevgi::Undefined, nil] canvas input
|
|
80
|
+
# @param block [Proc, nil] DSL block evaluated in the root element
|
|
81
|
+
# @return [Sevgi::Graphics::Document::Proto] SVG root element
|
|
82
|
+
# @raise [Sevgi::ArgumentError] when the document or canvas profile is unknown
|
|
32
83
|
def SVG(document = :default, canvas = Undefined, **, &block)
|
|
33
84
|
Graphics::Document.(document, canvas, **, &block)
|
|
34
85
|
end
|
|
@@ -36,5 +87,6 @@ module Sevgi
|
|
|
36
87
|
extend self
|
|
37
88
|
end
|
|
38
89
|
|
|
90
|
+
# Top-level alias for the graphics DSL namespace.
|
|
39
91
|
SVG = Graphics
|
|
40
92
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sevgi-graphics
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.93.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Recai Oktaş
|
|
@@ -15,27 +15,28 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.93.1
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.93.1
|
|
26
26
|
description: Provides an extensible DSL for creating SVG content.
|
|
27
27
|
email: roktas@gmail.com
|
|
28
28
|
executables: []
|
|
29
29
|
extensions: []
|
|
30
30
|
extra_rdoc_files: []
|
|
31
31
|
files:
|
|
32
|
+
- README.md
|
|
32
33
|
- lib/sevgi/graphics.rb
|
|
33
34
|
- lib/sevgi/graphics/attribute.rb
|
|
34
|
-
- lib/sevgi/graphics/
|
|
35
|
-
- lib/sevgi/graphics/
|
|
36
|
-
- lib/sevgi/graphics/
|
|
37
|
-
- lib/sevgi/graphics/
|
|
38
|
-
- lib/sevgi/graphics/
|
|
35
|
+
- lib/sevgi/graphics/auxiliary.rb
|
|
36
|
+
- lib/sevgi/graphics/auxiliary/canvas.rb
|
|
37
|
+
- lib/sevgi/graphics/auxiliary/content.rb
|
|
38
|
+
- lib/sevgi/graphics/auxiliary/margin.rb
|
|
39
|
+
- lib/sevgi/graphics/auxiliary/paper.rb
|
|
39
40
|
- lib/sevgi/graphics/document.rb
|
|
40
41
|
- lib/sevgi/graphics/document/base.rb
|
|
41
42
|
- lib/sevgi/graphics/document/default.rb
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "forwardable"
|
|
4
|
-
|
|
5
|
-
module Sevgi
|
|
6
|
-
module Graphics
|
|
7
|
-
class Canvas
|
|
8
|
-
def self.call(arg = Undefined, **kwargs)
|
|
9
|
-
case arg
|
|
10
|
-
when Undefined
|
|
11
|
-
new(**kwargs)
|
|
12
|
-
when ::Symbol, ::String
|
|
13
|
-
new(**Paper.public_send(arg).to_h, **kwargs)
|
|
14
|
-
else
|
|
15
|
-
ArgumentError.("Argument must be a Paper symbol: #{arg}")
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
extend Forwardable
|
|
20
|
-
|
|
21
|
-
def_delegators :@margin, *Margin.members
|
|
22
|
-
def_delegators :@size, *Paper.members
|
|
23
|
-
|
|
24
|
-
attr_reader :size, :margin, :inner
|
|
25
|
-
|
|
26
|
-
def initialize(width:, height:, unit: "mm", name: :custom, margins: [])
|
|
27
|
-
@size = Paper[width, height, unit, name]
|
|
28
|
-
@margin = Margin[*margins]
|
|
29
|
-
|
|
30
|
-
compute
|
|
31
|
-
freeze
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def attributes(...) = {**viewport, viewBox: viewbox(...)}
|
|
35
|
-
|
|
36
|
-
def conforming(...) = self.class.conforming(self, ...)
|
|
37
|
-
|
|
38
|
-
def viewport = {width: "#{width}#{unit}", height: "#{height}#{unit}"}
|
|
39
|
-
|
|
40
|
-
def viewbox(origin = Undefined) = prettify(*originate(origin), width, height).join(" ")
|
|
41
|
-
|
|
42
|
-
def with(**kwargs) = self.class.new(**size.to_h, margins: kwargs.fetch(:margins, margin.to_a))
|
|
43
|
-
|
|
44
|
-
private
|
|
45
|
-
|
|
46
|
-
def compute
|
|
47
|
-
@inner = size.with(width: width - margin.left - margin.right, height: height - margin.top - margin.bottom)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def originate(origin)
|
|
51
|
-
case origin
|
|
52
|
-
when Undefined
|
|
53
|
-
[-margin.left, -margin.top]
|
|
54
|
-
when ::Numeric, ::NilClass
|
|
55
|
-
[origin.to_f, origin.to_f]
|
|
56
|
-
when ::Array
|
|
57
|
-
pair(origin)
|
|
58
|
-
else
|
|
59
|
-
ArgumentError.("Canvas origin must be an Array")
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def prettify(*floats)
|
|
64
|
-
floats.map { (it % 1).zero? ? it.to_i : it }
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def pair(array)
|
|
68
|
-
array.size == 2 ? array.map(&:to_f) : ArgumentError.("Argument must be an Array of size 2")
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Sevgi
|
|
4
|
-
module Graphics
|
|
5
|
-
class Content
|
|
6
|
-
attr_reader :content
|
|
7
|
-
|
|
8
|
-
def initialize(content) = @content = content
|
|
9
|
-
|
|
10
|
-
def render(_renderer, _depth) = raise NoMethodError, "#{self.class}#render must be implemented"
|
|
11
|
-
|
|
12
|
-
def to_s = content.to_s
|
|
13
|
-
|
|
14
|
-
def self.cdata(...) = CData.new(...)
|
|
15
|
-
|
|
16
|
-
def self.contents(*args) = args.map { it.is_a?(Content) ? it : encoded(it) }
|
|
17
|
-
|
|
18
|
-
def self.css(...) = CSS.new(...)
|
|
19
|
-
|
|
20
|
-
def self.encoded(...) = Encoded.new(...)
|
|
21
|
-
|
|
22
|
-
def self.text(contents) = Array(contents).join("\n")
|
|
23
|
-
|
|
24
|
-
def self.verbatim(...) = Verbatim.new(...)
|
|
25
|
-
|
|
26
|
-
class CData < Content
|
|
27
|
-
def render(renderer, depth)
|
|
28
|
-
depth += 1
|
|
29
|
-
|
|
30
|
-
renderer.append(depth, "<![CDATA[")
|
|
31
|
-
renderer.append(depth + 1, *Array(content))
|
|
32
|
-
renderer.append(depth, "]]>")
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
class CSS < Content
|
|
37
|
-
def initialize(content)
|
|
38
|
-
ArgumentError.("CSS content must be a hash: #{content}") unless content.is_a?(::Hash)
|
|
39
|
-
|
|
40
|
-
super
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# rubocop:disable Metrics/MethodLength
|
|
44
|
-
def render(renderer, depth)
|
|
45
|
-
depth += 1
|
|
46
|
-
|
|
47
|
-
renderer.append(depth, "<![CDATA[")
|
|
48
|
-
|
|
49
|
-
depth += 1
|
|
50
|
-
content.each do |rule, styles|
|
|
51
|
-
case styles
|
|
52
|
-
when ::Hash
|
|
53
|
-
renderer.append(depth, "#{rule} {")
|
|
54
|
-
renderer.append(depth + 1, *styles.map { |key, value| "#{key}: #{value};" })
|
|
55
|
-
renderer.append(depth, "}")
|
|
56
|
-
when ::String, ::Symbol, ::Numeric
|
|
57
|
-
renderer.append(depth, "#{rule}: #{styles};")
|
|
58
|
-
else
|
|
59
|
-
ArgumentError.("Malformed style: #{styles}")
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
depth -= 1
|
|
64
|
-
|
|
65
|
-
renderer.append(depth, "]]>")
|
|
66
|
-
end
|
|
67
|
-
# rubocop:enable Metrics/MethodLength
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
class Encoded < Content
|
|
71
|
-
def to_s = content.encode(xml: :text)
|
|
72
|
-
|
|
73
|
-
def render(renderer, depth) = renderer.append(depth + 1, to_s)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
class Verbatim < Content
|
|
77
|
-
def render(renderer, depth) = renderer.append(depth + 1, to_s)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Sevgi
|
|
4
|
-
module Graphics
|
|
5
|
-
Margin = Data.define(:top, :right, :bottom, :left) do
|
|
6
|
-
include Comparable
|
|
7
|
-
|
|
8
|
-
def initialize(top: nil, right: nil, bottom: nil, left: nil)
|
|
9
|
-
case [top, right, bottom, left]
|
|
10
|
-
in [Numeric, Numeric, Numeric, Numeric]
|
|
11
|
-
nil
|
|
12
|
-
in [Numeric, Numeric, Numeric, NilClass]
|
|
13
|
-
left = right
|
|
14
|
-
in [Numeric, Numeric, NilClass, NilClass]
|
|
15
|
-
bottom, left = top, right
|
|
16
|
-
in [Numeric, NilClass, NilClass, NilClass]
|
|
17
|
-
bottom, left, right = top, top, top
|
|
18
|
-
in [NilClass, NilClass, NilClass, NilClass]
|
|
19
|
-
top, bottom, left, right = 0, 0, 0, 0
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
super(top: Float(top), right: Float(right), bottom: Float(bottom), left: Float(left))
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def <=>(other) = deconstruct <=> other.deconstruct
|
|
26
|
-
|
|
27
|
-
def change(h, v) = self.class[top + v, right + h, bottom + v, left + h]
|
|
28
|
-
|
|
29
|
-
def eql?(other) = self.class == other.class && deconstruct == other.deconstruct
|
|
30
|
-
|
|
31
|
-
def hash = [self.class, *deconstruct].hash
|
|
32
|
-
|
|
33
|
-
def htotal = left + right
|
|
34
|
-
|
|
35
|
-
def vtotal = top + bottom
|
|
36
|
-
|
|
37
|
-
alias_method :==, :eql?
|
|
38
|
-
alias_method :to_a, :deconstruct
|
|
39
|
-
|
|
40
|
-
def self.margin(array)
|
|
41
|
-
self[
|
|
42
|
-
*(array = Array(array)[0...(size = Margin.members.size)]).fill(nil, array.size, size - array.size)
|
|
43
|
-
]
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def self.zero = (@zero ||= self[0.0, 0.0, 0.0, 0.0])
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Sevgi
|
|
4
|
-
module Graphics
|
|
5
|
-
Paper = Data.define(:width, :height, :unit, :name) do
|
|
6
|
-
include Comparable
|
|
7
|
-
|
|
8
|
-
def initialize(width:, height:, unit: "mm", name: :custom)
|
|
9
|
-
super(width: Float(width), height: Float(height), unit: unit.to_sym, name: name.to_sym)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def <=>(other) = deconstruct <=> other.deconstruct
|
|
13
|
-
|
|
14
|
-
def eql?(other) = self.class == other.class && deconstruct == other.deconstruct
|
|
15
|
-
|
|
16
|
-
def hash = [self.class, *deconstruct].hash
|
|
17
|
-
|
|
18
|
-
def longest = [width, height].max
|
|
19
|
-
|
|
20
|
-
def shortest = [width, height].min
|
|
21
|
-
|
|
22
|
-
alias_method :==, :eql?
|
|
23
|
-
|
|
24
|
-
def self.define!(name, ...)
|
|
25
|
-
raise ArgumentError, "Paper already defined: #{name}" if exist?(name)
|
|
26
|
-
|
|
27
|
-
define(name, ...)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def self.exist?(name) = respond_to?(name)
|
|
31
|
-
|
|
32
|
-
def self.define(name, **spec)
|
|
33
|
-
singleton_class.attr_reader(name)
|
|
34
|
-
instance_variable_set("@#{name}", new(name:, **spec))
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
{
|
|
38
|
-
a0: [841, 1189, "mm"],
|
|
39
|
-
a1: [594, 841, "mm"],
|
|
40
|
-
a2: [420, 594, "mm"],
|
|
41
|
-
a3: [297, 420, "mm"],
|
|
42
|
-
a4: [210, 297, "mm"],
|
|
43
|
-
a5: [148, 210, "mm"],
|
|
44
|
-
a6: [105, 148, "mm"],
|
|
45
|
-
a7: [740, 105, "mm"],
|
|
46
|
-
a8: [520, 74, "mm"],
|
|
47
|
-
a9: [370, 52, "mm"],
|
|
48
|
-
a10: [260, 37, "mm"],
|
|
49
|
-
|
|
50
|
-
b0: [1000, 1414, "mm"],
|
|
51
|
-
b1: [707, 1000, "mm"],
|
|
52
|
-
b2: [500, 707, "mm"],
|
|
53
|
-
b3: [353, 500, "mm"],
|
|
54
|
-
b4: [250, 353, "mm"],
|
|
55
|
-
b5: [176, 250, "mm"],
|
|
56
|
-
b6: [125, 176, "mm"],
|
|
57
|
-
b7: [88, 125, "mm"],
|
|
58
|
-
b8: [62, 88, "mm"],
|
|
59
|
-
b9: [44, 62, "mm"],
|
|
60
|
-
b10: [31, 44, "mm"],
|
|
61
|
-
|
|
62
|
-
c0: [917, 1297, "mm"],
|
|
63
|
-
c1: [648, 917, "mm"],
|
|
64
|
-
c2: [458, 648, "mm"],
|
|
65
|
-
c3: [324, 458, "mm"],
|
|
66
|
-
c4: [229, 324, "mm"],
|
|
67
|
-
c5: [162, 229, "mm"],
|
|
68
|
-
c6: [114, 162, "mm"],
|
|
69
|
-
c7: [81, 114, "mm"],
|
|
70
|
-
c8: [57, 81, "mm"],
|
|
71
|
-
c9: [40, 57, "mm"],
|
|
72
|
-
c10: [28, 40, "mm"],
|
|
73
|
-
|
|
74
|
-
business: [85, 55, "mm"],
|
|
75
|
-
large: [130, 210, "mm"],
|
|
76
|
-
passport: [88, 125, "mm"],
|
|
77
|
-
pocket: [90, 140, "mm"],
|
|
78
|
-
travelers: [110, 210, "mm"],
|
|
79
|
-
us: [216, 279, "mm"],
|
|
80
|
-
xlarge: [190, 250, "mm"],
|
|
81
|
-
|
|
82
|
-
icon16: [16, 16, "px"],
|
|
83
|
-
icon32: [32, 32, "px"],
|
|
84
|
-
icon64: [64, 64, "px"],
|
|
85
|
-
icon128: [128, 128, "px"],
|
|
86
|
-
icon256: [256, 256, "px"],
|
|
87
|
-
icon512: [512, 512, "px"]
|
|
88
|
-
}.each { |name, (width, height, unit)| define(name, width:, height:, unit:) }
|
|
89
|
-
|
|
90
|
-
class << self
|
|
91
|
-
alias_method :default, :a4
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|