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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -0
  3. data/lib/sevgi/graphics/attribute.rb +58 -6
  4. data/lib/sevgi/graphics/auxiliary/canvas.rb +125 -0
  5. data/lib/sevgi/graphics/auxiliary/content.rb +145 -0
  6. data/lib/sevgi/graphics/auxiliary/margin.rb +93 -0
  7. data/lib/sevgi/graphics/auxiliary/paper.rb +163 -0
  8. data/lib/sevgi/graphics/auxiliary.rb +7 -0
  9. data/lib/sevgi/graphics/document/base.rb +6 -0
  10. data/lib/sevgi/graphics/document/default.rb +1 -0
  11. data/lib/sevgi/graphics/document/html.rb +1 -0
  12. data/lib/sevgi/graphics/document/inkscape.rb +1 -0
  13. data/lib/sevgi/graphics/document/minimal.rb +1 -0
  14. data/lib/sevgi/graphics/document.rb +137 -11
  15. data/lib/sevgi/graphics/element.rb +68 -8
  16. data/lib/sevgi/graphics/mixtures/call.rb +35 -3
  17. data/lib/sevgi/graphics/mixtures/core.rb +107 -18
  18. data/lib/sevgi/graphics/mixtures/duplicate.rb +14 -0
  19. data/lib/sevgi/graphics/mixtures/export.rb +29 -6
  20. data/lib/sevgi/graphics/mixtures/hatch.rb +24 -3
  21. data/lib/sevgi/graphics/mixtures/identify.rb +23 -1
  22. data/lib/sevgi/graphics/mixtures/include.rb +31 -4
  23. data/lib/sevgi/graphics/mixtures/inkscape.rb +51 -5
  24. data/lib/sevgi/graphics/mixtures/lint.rb +12 -0
  25. data/lib/sevgi/graphics/mixtures/polyfills.rb +11 -0
  26. data/lib/sevgi/graphics/mixtures/rdf.rb +40 -1
  27. data/lib/sevgi/graphics/mixtures/render.rb +90 -2
  28. data/lib/sevgi/graphics/mixtures/save.rb +21 -3
  29. data/lib/sevgi/graphics/mixtures/symbols.rb +7 -0
  30. data/lib/sevgi/graphics/mixtures/tile.rb +41 -6
  31. data/lib/sevgi/graphics/mixtures/transform.rb +54 -16
  32. data/lib/sevgi/graphics/mixtures/underscore.rb +10 -1
  33. data/lib/sevgi/graphics/mixtures/validate.rb +15 -1
  34. data/lib/sevgi/graphics/mixtures/wrappers.rb +54 -17
  35. data/lib/sevgi/graphics/mixtures.rb +35 -3
  36. data/lib/sevgi/graphics/version.rb +2 -1
  37. data/lib/sevgi/graphics.rb +57 -5
  38. metadata +9 -8
  39. data/lib/sevgi/graphics/auxilary/canvas.rb +0 -72
  40. data/lib/sevgi/graphics/auxilary/content.rb +0 -81
  41. data/lib/sevgi/graphics/auxilary/margin.rb +0 -49
  42. data/lib/sevgi/graphics/auxilary/paper.rb +0 -95
  43. 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
- def Cline(x2:, y2:, x1: 0, y1: 0, **)
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
- def Hline(x2:, x1: 0, y1: 0, **)
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
- def Vline(y2:, x1: 0, y1: 0, **)
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
- def cline(angle:, length:, x: 0, y: 0, **)
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
- def css(hash, **)
36
- style(Content.css(hash), type: "text/css", **)
37
- end
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
- def cxline(angle:, dx:, x: 0, y: 0, **)
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
- def hline(length:, x: 0, y: 0, **)
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
- def vline(length:, x: 0, y: 0, **)
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
- def self.mixin(mod, document = Graphics::Document::Base, &block)
7
- document.mixture(mod)
8
- document.mixture(::Module.new(&block)) if block
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
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Sevgi
4
4
  module Graphics
5
- VERSION = "0.73.2"
5
+ # Current graphics component version.
6
+ VERSION = "0.93.1"
6
7
  end
7
8
  end
@@ -3,7 +3,7 @@
3
3
  require "sevgi/function"
4
4
 
5
5
  require_relative "graphics/attribute"
6
- require_relative "graphics/auxilary"
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
- def document(name = :default, preambles: [], attributes: {})
21
- Class.new(Graphics::Document::Base) { document(name, preambles:, attributes:) }
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
- name.tap { Graphics::Paper.define(name, width:, height:, unit:) unless Graphics::Paper.exist?(name) }
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.73.2
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.73.2
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.73.2
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/auxilary.rb
35
- - lib/sevgi/graphics/auxilary/canvas.rb
36
- - lib/sevgi/graphics/auxilary/content.rb
37
- - lib/sevgi/graphics/auxilary/margin.rb
38
- - lib/sevgi/graphics/auxilary/paper.rb
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
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "auxilary/margin"
4
- require_relative "auxilary/paper"
5
-
6
- require_relative "auxilary/canvas"
7
- require_relative "auxilary/content"