sevgi 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4696b409358c595a5196f8e4e037edf1cf6f2e171d3f083fa56438d36dd5750f
4
- data.tar.gz: 857df564a95208647e8f3d5de0ae8f8289d4afcbe7433b74be05f2b433293256
3
+ metadata.gz: 5f8e80618af5d1d88338b10db45b911cbca256c113ec3b7458b5b4e6e3a9ba7e
4
+ data.tar.gz: f879baa77b005b91cb674d350d8ed79551f2be36132c7039f188ddb64ba58779
5
5
  SHA512:
6
- metadata.gz: a2687e5ec21afdc64e569a814a1ab0ff78436d93eb929bc661f5462f621da5305bdfada1fd256dd3960dbbc82bd4e64ea4f5d098a39870a83493b76b5a1844f2
7
- data.tar.gz: 267238636b3ee84ada012dfd585889071aa0552abae6418922b423f6ee15bafe150ad721ae8d6718e45966f659669ac38972985c033dc77252d2ec2c8c14c627
6
+ metadata.gz: fbce000770d881a72ac107ba52b39aa6bdc9ffcbfaacd2d2609cb7c6fef7251a0976fee6989c3a97b87973507dbaecfedcce78dfe72a59e80eea124c8e53a641
7
+ data.tar.gz: 7a4dc86d8c75f75092a9e159fa4e023aeefa14cc1feb338f4e561095d331e535d45dc2da4e39e5b289d78444cf7c9d731393914290f917dd98366a4f30ab2d1b
data/README.md CHANGED
@@ -0,0 +1,5 @@
1
+ # Sevgi
2
+
3
+ Provides the top-level API and `.sevgi` script runner.
4
+
5
+ See the root [README](../README.md) and the documentation site for usage.
@@ -2,8 +2,14 @@
2
2
 
3
3
  require "sevgi"
4
4
 
5
+ # Extends FileUtils with Sevgi script helpers for Rake tasks.
5
6
  module FileUtils
6
7
  # Thin DSL wrapper to call a script without spawning a shell.
8
+ # @param file [String] Sevgi script file, with or without `.sevgi` extension
9
+ # @param args [Array] positional arguments exposed to the script as `ARGA`
10
+ # @param kwargs [Hash] keyword arguments exposed to the script as `ARGH`
11
+ # @return [Sevgi::Executor::Scope, nil] execution scope, or nil for an empty file
12
+ # @raise [Sevgi::ArgumentError] when the script file cannot be found
7
13
  def sevgi(file, *args, **kwargs)
8
14
  Sevgi.execute_file(F.existing!(file, [EXTENSION])) do |mod|
9
15
  include(Sevgi)
@@ -3,15 +3,25 @@
3
3
  require "sevgi"
4
4
 
5
5
  module Sevgi
6
+ # Command-line entrypoint implementations shipped with Sevgi.
6
7
  module Binaries
8
+ # Implements the `sevgi` executable.
7
9
  module Sevgi
8
10
  extend self
9
11
 
12
+ # Executable name used in help output.
10
13
  PROGNAME = "sevgi"
11
14
 
15
+ # Error raised for invalid command-line usage.
12
16
  Error = Class.new(::Sevgi::Error)
13
17
 
18
+ # Parsed command-line options for the `sevgi` executable.
19
+ # @api private
14
20
  Options = Struct.new(:require, :nomain, :vomit, :help, :version) do
21
+ # Parses command-line options and removes them from the argv array.
22
+ # @param argv [Array<String>] mutable command-line argument array
23
+ # @return [Sevgi::Binaries::Sevgi::Options] parsed options
24
+ # @raise [Sevgi::Binaries::Sevgi::Error] when an option is not recognized
15
25
  def self.parse(argv)
16
26
  new.tap do |options|
17
27
  argv.first.start_with?("-") ? option(argv, options) : break until argv.empty?
@@ -25,7 +35,7 @@ module Sevgi
25
35
  case (arg = argv.shift)
26
36
  when "-r", "--require"
27
37
  options.require = argv.shift
28
- when "-m", "--nomain"
38
+ when "-n", "--nomain"
29
39
  options.nomain = true
30
40
  when "-x", "--exception"
31
41
  options.vomit = true
@@ -43,6 +53,12 @@ module Sevgi
43
53
 
44
54
  private_constant :Options
45
55
 
56
+ # Runs the `sevgi` command-line interface.
57
+ # @param argv [Array<String>, String, nil] command-line arguments
58
+ # @return [nil]
59
+ # @raise [LoadError] when a required Ruby library cannot be loaded
60
+ # @raise [Sevgi::Executor::Error] when `--exception` or `SEVGI_VOMIT` requests raw errors
61
+ # @raise [SystemExit] when command-line usage or script execution aborts
46
62
  def call(argv)
47
63
  return puts(help) if (options = Options.parse(argv = Array(argv))).help
48
64
  return puts(::Sevgi::VERSION) if options.version
@@ -2,9 +2,18 @@
2
2
 
3
3
  module Sevgi
4
4
  class Executor
5
+ # Wraps an exception raised while executing Sevgi script source.
5
6
  class Error < ::Sevgi::Error
7
+ # @!attribute [r] error
8
+ # @return [Exception] original exception raised by script execution
9
+ # @!attribute [r] scope
10
+ # @return [Sevgi::Executor::Scope] executor scope active when the error was captured
6
11
  attr_reader :error, :scope
7
12
 
13
+ # Builds an executor error wrapper.
14
+ # @param error [Exception] original exception
15
+ # @param scope [Sevgi::Executor::Scope] executor scope active at failure time
16
+ # @return [void]
8
17
  def initialize(error, scope)
9
18
  @error = error
10
19
  @scope = scope
@@ -12,13 +21,19 @@ module Sevgi
12
21
  super(error.message)
13
22
  end
14
23
 
24
+ # Returns backtrace entries that belong to the Sevgi load stack.
25
+ # @return [Array<String>] filtered backtrace lines relative to the current directory
15
26
  def backtrace!
27
+ sources = stack.map { ::File.expand_path(it) }
28
+
16
29
  error
17
30
  .backtrace
18
- .select { |line| stack.any? { line.start_with?(::File.expand_path(it)) } }
31
+ .select { sources.include?(::File.expand_path(it.split(":", 2).first)) }
19
32
  .map { |line| line.delete_prefix("#{::Dir.pwd}/") }
20
33
  end
21
34
 
35
+ # Returns the script load stack active at failure time.
36
+ # @return [Array<String>] script file names in load order
22
37
  def stack = scope.stack
23
38
  end
24
39
  end
@@ -2,11 +2,22 @@
2
2
 
3
3
  module Sevgi
4
4
  class Executor
5
+ # Holds one isolated Sevgi script execution scope and its result.
5
6
  class Scope
7
+ # Error raised by low-level executor scope operations.
6
8
  Error = Class.new(::Sevgi::Error)
7
9
 
10
+ # @!attribute [r] scope
11
+ # @return [Module] isolated module where script source is evaluated
12
+ # @!attribute [r] recent
13
+ # @return [Object, nil] last expression result from the executed source
14
+ # @!attribute [r] error
15
+ # @return [Sevgi::Executor::Error, nil] captured execution error
8
16
  attr_reader :scope, :recent, :error
9
17
 
18
+ # Creates a script execution scope.
19
+ # @param scope [Module, nil] existing module to evaluate source in
20
+ # @return [void]
10
21
  def initialize(scope = nil)
11
22
  @scope = scope || main
12
23
  @recent = nil
@@ -14,16 +25,22 @@ module Sevgi
14
25
  @stack = {}
15
26
  end
16
27
 
28
+ # Reports whether execution captured an error.
29
+ # @return [Boolean] true when execution failed
17
30
  def error? = !error.nil?
18
31
 
32
+ # Executes one source object in this scope.
33
+ # @param source [Sevgi::Executor::Source] source to evaluate
34
+ # @param receiver [Object, nil] receiver used while booting the DSL
35
+ # @yield optional boot block that installs DSL methods before evaluation
36
+ # @yieldreturn [void]
37
+ # @return [Sevgi::Executor::Scope] self, with recent or error populated
38
+ # @api private
19
39
  def call(source, receiver = nil, &boot)
20
40
  push(source)
21
41
 
22
42
  tap do
23
- @recent = begin
24
- boot(receiver, &boot)
25
- evaluate(source)
26
- end
43
+ @recent = run(source, receiver, &boot)
27
44
 
28
45
  # rubocop:disable Lint/RescueException
29
46
  rescue Exception => e
@@ -34,12 +51,25 @@ module Sevgi
34
51
  end
35
52
  end
36
53
 
54
+ # Loads a file into this existing execution scope.
55
+ # @param file [String] source file to read and evaluate
56
+ # @yield optional boot block that installs DSL methods before evaluation
57
+ # @yieldreturn [void]
58
+ # @return [Sevgi::Executor::Scope] self, with recent or error populated
59
+ # @raise [Errno::ENOENT] when the file cannot be read
60
+ # @api private
37
61
  def load(file, &block) = call(Source.load(file), &block)
38
62
 
63
+ # Returns the unique source stack for this execution.
64
+ # @return [Array<String>] source file keys in load order
39
65
  def stack = @stack.keys
40
66
 
67
+ # Returns the most recently pushed source.
68
+ # @return [Sevgi::Executor::Source, nil] most recent source object
69
+ # @api private
41
70
  def peek = @stack[@stack.keys.last]
42
71
 
72
+ # Constant name used for the temporary script module under {Sevgi}.
43
73
  MAIN_MODULE = :Main
44
74
 
45
75
  private
@@ -65,6 +95,11 @@ module Sevgi
65
95
  def push(source)
66
96
  tap { @stack[source.key] = source }
67
97
  end
98
+
99
+ def run(source, receiver, &boot)
100
+ boot(receiver, &boot)
101
+ evaluate(source)
102
+ end
68
103
  end
69
104
  end
70
105
  end
@@ -2,13 +2,32 @@
2
2
 
3
3
  module Sevgi
4
4
  class Executor
5
+ # Describes Ruby source evaluated by the Sevgi executor.
6
+ # @api private
5
7
  Source = Data.define(:string, :file, :line) do
8
+ # @overload call(string:, file: nil, line: nil)
9
+ # Builds a source object.
10
+ # @param string [String] Ruby source string
11
+ # @param file [String, nil] source file name for diagnostics
12
+ # @param line [Integer, nil] starting source line for diagnostics
13
+ # @return [Sevgi::Executor::Source] source object
6
14
  def self.call(...) = new(...)
7
15
 
16
+ # Builds a source object from a file.
17
+ # @param file [String] source file to read
18
+ # @return [Sevgi::Executor::Source] source object with file contents
19
+ # @raise [Errno::ENOENT] when the file cannot be read
8
20
  def self.load(file) = new(string: ::File.read(file), file: file, line: 1)
9
21
 
22
+ # Creates a source object.
23
+ # @param string [String] Ruby source string
24
+ # @param file [String, nil] source file name for diagnostics
25
+ # @param line [Integer, nil] starting source line for diagnostics
26
+ # @return [void]
10
27
  def initialize(string:, file: nil, line: nil) = super(string:, file: file || "sevgi", line: line || 1)
11
28
 
29
+ # Returns the stack key used for this source.
30
+ # @return [String] source file name
12
31
  def key = file
13
32
  end
14
33
  end
@@ -7,44 +7,86 @@ require_relative "executor/scope"
7
7
  require_relative "executor/source"
8
8
 
9
9
  module Sevgi
10
+ # Executes Sevgi script source inside an isolated module scope.
11
+ #
12
+ # The executor is used by script mode and by the `Load` DSL word to preserve a
13
+ # useful load stack while keeping DSL methods out of the caller's global object
14
+ # whenever possible.
10
15
  class Executor
11
16
  include Singleton
12
17
 
18
+ # Loads a script file inside the current executor scope.
19
+ # @param file [String] path to a Sevgi script file
20
+ # @return [Sevgi::Executor::Scope] current execution scope
21
+ # @raise [Sevgi::PanicError] when there is no active executor scope
22
+ # @api private
13
23
  def self.load(file, ...)
14
24
  PanicError.("box stack empty; create a box first") unless instance.current
15
25
 
16
26
  instance.current.load(file, ...)
17
27
  end
18
28
 
29
+ # Executes Ruby source inside a managed Sevgi script scope.
30
+ # @param string [String] source to evaluate
31
+ # @param file [String, nil] source file name used for errors and backtraces
32
+ # @param line [Integer, nil] starting source line used for errors and backtraces
33
+ # @param require [String, nil] optional Ruby library to require before execution
34
+ # @param receiver [Object, nil] receiver used while booting the DSL
35
+ # @yield optional boot block that installs DSL methods before evaluation
36
+ # @yieldreturn [void]
37
+ # @return [Sevgi::Executor::Scope, nil] execution scope, or nil for empty source
38
+ # @raise [LoadError] when the optional required library cannot be loaded
19
39
  def self.execute(string, file: nil, line: nil, require: nil, receiver: nil, &block)
20
40
  return if string.empty?
21
41
 
22
- Signal.trap("INT") { Kernel.abort("") }
42
+ interrupt = Signal.trap("INT") { Kernel.abort("") }
23
43
 
24
44
  ::Kernel.require(require) if require
25
45
 
26
- catch(:result) do
27
- instance.create.call(Source.new(string:, file:, line:), receiver, &block)
28
- end
46
+ scope = instance.create
47
+ catch(:result) { scope.call(Source.new(string:, file:, line:), receiver, &block) }
29
48
 
30
49
  ensure
31
- instance.shutdown
50
+ Signal.trap("INT", interrupt) if interrupt
51
+ instance.shutdown if scope
32
52
  end
33
53
 
54
+ # Executes a file inside a managed Sevgi script scope.
55
+ # @param file [String] source file to read and execute
56
+ # @param require [String, nil] optional Ruby library to require before execution
57
+ # @param receiver [Object, nil] receiver used while booting the DSL
58
+ # @yield optional boot block that installs DSL methods before evaluation
59
+ # @yieldreturn [void]
60
+ # @return [Sevgi::Executor::Scope, nil] execution scope, or nil for an empty file
61
+ # @raise [Errno::ENOENT] when the file cannot be read
62
+ # @raise [LoadError] when the optional required library cannot be loaded
34
63
  def self.execute_file(file, require: nil, receiver: nil, &block)
35
64
  execute(::File.read(file), file: file, line: 1, require:, receiver:, &block)
36
65
  end
37
66
 
67
+ # Removes the current executor scope.
68
+ # @return [Sevgi::Executor::Scope, nil] removed scope
69
+ # @api private
38
70
  def self.shutdown
39
71
  instance.shutdown
40
72
  end
41
73
 
42
74
  def initialize = @scopes = []
43
75
 
76
+ # Creates and pushes a new executor scope.
77
+ # @param scope [Module, nil] existing module scope to reuse
78
+ # @return [Sevgi::Executor::Scope] created scope
79
+ # @api private
44
80
  def create(scope = nil) = Scope.new(scope).tap { @scopes << it }
45
81
 
82
+ # Returns the active executor scope.
83
+ # @return [Sevgi::Executor::Scope, nil] active scope, if any
84
+ # @api private
46
85
  def current = @scopes.last
47
86
 
87
+ # Removes the active executor scope.
88
+ # @return [Sevgi::Executor::Scope, nil] removed scope
89
+ # @api private
48
90
  def shutdown = @scopes.pop
49
91
  end
50
92
  end
@@ -4,12 +4,20 @@ require "sevgi/derender"
4
4
 
5
5
  module Sevgi
6
6
  module Toplevel
7
- def Decompile(file, id) = Derender.decompile_file(file, id:)
7
+ # Converts an SVG/XML file into a derender node.
8
+ # @param file [String] path to the source SVG/XML file
9
+ # @param id [String, nil] optional SVG id selecting a node inside the source
10
+ # @return [Sevgi::Derender::Node] selected node in the derender tree
11
+ # @raise [Sevgi::ArgumentError] when the file cannot be found or the id is absent
12
+ # @see Sevgi::Derender.decompile_file
13
+ def Decompile(file, id = nil) = Derender.decompile_file(file, id:)
8
14
 
9
- def Decompile!(file, id) = Derender.decompile_file!(file, id:)
10
-
11
- def Derender(file, id) = Derender.derender_file(file, id:)
12
-
13
- def Derender!(file, id) = Derender.derender_file!(file, id:)
15
+ # Converts an SVG/XML file into Sevgi DSL Ruby source.
16
+ # @param file [String] path to the source SVG/XML file
17
+ # @param id [String, nil] optional SVG id selecting a node inside the source
18
+ # @return [String] formatted Sevgi DSL source
19
+ # @raise [Sevgi::ArgumentError] when the file cannot be found or the id is absent
20
+ # @see Sevgi::Derender.derender_file
21
+ def Derender(file, id = nil) = Derender.derender_file(file, id:)
14
22
  end
15
23
  end
@@ -7,11 +7,29 @@ module Sevgi
7
7
 
8
8
  private_constant :BootBlock
9
9
 
10
+ # Executes Sevgi script source with the full top-level DSL installed.
11
+ # @param args [Array] arguments forwarded to {Sevgi::Executor.execute}
12
+ # @param kwargs [Hash] keyword arguments forwarded to {Sevgi::Executor.execute}
13
+ # @return [Sevgi::Executor::Scope, nil] execution result, or nil for empty source
14
+ # @raise [LoadError] when the optional `require:` library cannot be loaded
15
+ # @see Sevgi::Executor.execute
10
16
  def self.execute(*args, **kwargs) = Executor.execute(*args, **kwargs, &BootBlock)
11
17
 
18
+ # Executes a Sevgi script file with the full top-level DSL installed.
19
+ # @param args [Array] arguments forwarded to {Sevgi::Executor.execute_file}
20
+ # @param kwargs [Hash] keyword arguments forwarded to {Sevgi::Executor.execute_file}
21
+ # @return [Sevgi::Executor::Scope, nil] execution result, or nil for an empty file
22
+ # @raise [Errno::ENOENT] when the file cannot be read
23
+ # @raise [LoadError] when the optional `require:` library cannot be loaded
24
+ # @see Sevgi::Executor.execute_file
12
25
  def self.execute_file(*args, **kwargs) = Executor.execute_file(*args, **kwargs, &BootBlock)
13
26
 
14
27
  module Toplevel
28
+ # Loads one or more Sevgi files relative to the caller's source file.
29
+ # @param files [Array<String>] Sevgi script files to locate and execute
30
+ # @return [Array<String>] the input file list
31
+ # @raise [Sevgi::PanicError] when called without an active executor scope
32
+ # @raise [Sevgi::Error] when a file cannot be located
15
33
  def Load(*files)
16
34
  start = ::File.dirname(caller_locations(1..1).first.path)
17
35
 
@@ -4,6 +4,12 @@ require "sevgi/function"
4
4
 
5
5
  module Sevgi
6
6
  module Toplevel
7
+ # Function helper namespace promoted as `F` by the full top-level DSL.
8
+ #
9
+ # @example Use helper functions inside script mode
10
+ # SVG do
11
+ # text F.pluralize("axis")
12
+ # end
7
13
  module Function
8
14
  extend Sevgi::Function::Color
9
15
  extend Sevgi::Function::Math
@@ -4,14 +4,45 @@ require "sevgi/graphics"
4
4
 
5
5
  module Sevgi
6
6
  module Toplevel
7
+ # @overload Mixin(mod, document = Sevgi::Graphics::Document::Base, &block)
8
+ # Adds graphics mixture methods to a document class.
9
+ # @param mod [Symbol, String] named mixture to mix into the document
10
+ # @param document [Class] document class receiving the mixture
11
+ # @yield optional anonymous mixture module body
12
+ # @yieldreturn [void]
13
+ # @return [void]
14
+ # @raise [NameError] when a named mixture cannot be resolved
15
+ # @see Sevgi::Graphics::Mixtures.mixin
16
+ # @overload Mixin(document = Sevgi::Graphics::Document::Base, &block)
17
+ # Adds an anonymous graphics mixture to a document class.
18
+ # @param document [Class] document class receiving the mixture
19
+ # @yield anonymous mixture module body
20
+ # @yieldreturn [void]
21
+ # @return [Module] anonymous mixture
22
+ # @raise [Sevgi::ArgumentError] when no named mixture or block is given
23
+ # @see Sevgi::Graphics::Mixtures.mixin
7
24
  def Mixin(...) = Graphics::Mixtures.mixin(...)
8
25
 
9
- def Paper(width, height, name = :custom, unit: "mm")
10
- name.tap { Graphics::Paper.define(name, width:, height:, unit:) unless Graphics::Paper.exist?(name) }
11
- end
26
+ # @overload Paper(width, height, name = :custom, unit: "mm")
27
+ # Defines or validates a named paper profile for DSL use.
28
+ # @param width [Numeric] paper width
29
+ # @param height [Numeric] paper height
30
+ # @param name [Symbol] paper profile name
31
+ # @param unit [String, Symbol] size unit
32
+ # @return [Symbol] the paper profile name
33
+ # @raise [Sevgi::ArgumentError] when the profile is invalid or an existing profile differs
34
+ # @see Sevgi::Graphics#paper
35
+ def Paper(...) = Graphics.paper(...)
12
36
 
13
- def Paper!(width, height, name = :custom, unit: "mm")
14
- name.tap { Graphics::Paper.define(name, width:, height:, unit:) }
15
- end
37
+ # @overload Paper!(width, height, name = :custom, unit: "mm")
38
+ # Defines or overwrites a named paper profile for DSL use.
39
+ # @param width [Numeric] paper width
40
+ # @param height [Numeric] paper height
41
+ # @param name [Symbol] paper profile name
42
+ # @param unit [String, Symbol] size unit
43
+ # @return [Symbol] the paper profile name
44
+ # @raise [Sevgi::ArgumentError] when the profile is invalid or the paper name is reserved
45
+ # @see Sevgi::Graphics#paper!
46
+ def Paper!(...) = Graphics.paper!(...)
16
47
  end
17
48
  end
@@ -4,6 +4,12 @@ require "sevgi/sundries"
4
4
 
5
5
  module Sevgi
6
6
  module Toplevel
7
+ # Builds a drawable grid from a graphics canvas.
8
+ # @param canvas [Sevgi::Graphics::Canvas] canvas defining page size and margins
9
+ # @param unit [Numeric] minor grid unit
10
+ # @param multiple [Numeric] number of minor units in each major interval
11
+ # @return [Sevgi::Sundries::Grid] grid fitted to the canvas
12
+ # @raise [Sevgi::ArgumentError] when canvas, unit, multiple, or fitting span is invalid
7
13
  def Grid(canvas, unit:, multiple:)
8
14
  ArgumentError.("Must be a Canvas: #{canvas}") unless canvas.is_a?(Graphics::Canvas)
9
15
 
@@ -1,6 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sevgi
4
+ # Shared implementation for the full Sevgi top-level DSL.
5
+ #
6
+ # This module is installed by `include Sevgi` or `extend Sevgi`; it should not
7
+ # normally be included directly.
8
+ #
9
+ # @see Sevgi
4
10
  module Toplevel
5
11
  @constants = {}
6
12
 
@@ -12,7 +18,11 @@ module Sevgi
12
18
  def inject(base)
13
19
  return if base.instance_variable_defined?("@_toplevel_injected_")
14
20
 
15
- @constants.each { |args| (base.is_a?(::Module) ? base : base.class).const_set(*args) }
21
+ target = base.is_a?(::Module) ? base : base.class
22
+ @constants.each do |name, constant|
23
+ target.const_set(name, constant) unless target.const_defined?(name, false)
24
+ end
25
+
16
26
  base.instance_variable_set("@_toplevel_injected_", true)
17
27
  end
18
28
 
@@ -21,11 +31,19 @@ module Sevgi
21
31
  end
22
32
  end
23
33
 
34
+ # Injects promoted constants when the DSL is included.
35
+ # @param base [Module] the class or module receiving promoted constants
36
+ # @return [void]
37
+ # @api private
24
38
  def self.included(base)
25
39
  super
26
40
  inject(base)
27
41
  end
28
42
 
43
+ # Injects promoted constants when the DSL is extended.
44
+ # @param base [Object] the object or module receiving promoted constants
45
+ # @return [void]
46
+ # @api private
29
47
  def self.extended(base)
30
48
  super
31
49
  inject(base)
data/lib/sevgi/version.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sevgi
4
- VERSION = "0.73.2"
4
+ # Current version of the Sevgi top-level gem.
5
+ VERSION = "0.93.1"
5
6
  end
data/lib/sevgi.rb CHANGED
@@ -9,20 +9,48 @@ require "sevgi/sundries"
9
9
 
10
10
  require "sevgi/version"
11
11
 
12
- # Minimal Toplevel Interface (activated with 'require "sevgi"')
12
+ # Minimal top-level SVG interface installed by `require "sevgi"`.
13
+ # @return [Module] the graphics module used as the SVG DSL namespace
13
14
  SVG = Sevgi::Graphics
15
+
16
+ # @overload SVG(document = :default, canvas = Undefined, **attributes, &block)
17
+ # Builds an SVG document through the default top-level DSL entrypoint.
18
+ # @param document [Symbol, Class] document profile name or document class
19
+ # @param canvas [Object] optional canvas or paper profile argument
20
+ # @param attributes [Hash] root SVG attributes
21
+ # @yield the document block evaluated in the SVG document context
22
+ # @yieldreturn [void]
23
+ # @return [Sevgi::Graphics::Document::Proto] a rendered SVG document object
24
+ # @raise [Sevgi::ArgumentError] when the document, paper, or canvas arguments are invalid
14
25
  def SVG(...) = Sevgi::Graphics.SVG(...)
15
26
 
16
- # Maximal Toplevel Interface (activated with 'include Sevgi')
27
+ # Full top-level API for Sevgi library and script consumers.
28
+ #
29
+ # Including or extending this module installs DSL methods such as `Paper`, `Load`,
30
+ # and `Grid`, plus convenience constants such as `F`, `Geometry`, `Origin`, and
31
+ # `Export`.
32
+ #
33
+ # @example Include the DSL in an object
34
+ # class Drawing
35
+ # include Sevgi
36
+ # end
17
37
  module Sevgi
18
38
  # See sevgi/toplevel/*.rb files for details
19
39
  require_relative "sevgi/toplevel"
20
40
 
41
+ # Installs the full toplevel DSL into an including class or module.
42
+ # @param base [Module] the class or module receiving the DSL methods
43
+ # @return [void]
44
+ # @api private
21
45
  def self.included(base)
22
46
  super
23
47
  base.include(Toplevel)
24
48
  end
25
49
 
50
+ # Installs the full toplevel DSL into an extending object or module.
51
+ # @param base [Object] the receiver extended with the DSL methods
52
+ # @return [void]
53
+ # @api private
26
54
  def self.extended(base)
27
55
  super
28
56
  base.extend(Toplevel)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sevgi
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,84 +15,84 @@ 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
  - !ruby/object:Gem::Dependency
27
27
  name: sevgi-function
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - '='
31
31
  - !ruby/object:Gem::Version
32
- version: 0.73.2
32
+ version: 0.93.1
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - '='
38
38
  - !ruby/object:Gem::Version
39
- version: 0.73.2
39
+ version: 0.93.1
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: sevgi-geometry
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - '='
45
45
  - !ruby/object:Gem::Version
46
- version: 0.73.2
46
+ version: 0.93.1
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - '='
52
52
  - !ruby/object:Gem::Version
53
- version: 0.73.2
53
+ version: 0.93.1
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: sevgi-graphics
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - '='
59
59
  - !ruby/object:Gem::Version
60
- version: 0.73.2
60
+ version: 0.93.1
61
61
  type: :runtime
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - '='
66
66
  - !ruby/object:Gem::Version
67
- version: 0.73.2
67
+ version: 0.93.1
68
68
  - !ruby/object:Gem::Dependency
69
69
  name: sevgi-standard
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - '='
73
73
  - !ruby/object:Gem::Version
74
- version: 0.73.2
74
+ version: 0.93.1
75
75
  type: :runtime
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - '='
80
80
  - !ruby/object:Gem::Version
81
- version: 0.73.2
81
+ version: 0.93.1
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: sevgi-sundries
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - '='
87
87
  - !ruby/object:Gem::Version
88
- version: 0.73.2
88
+ version: 0.93.1
89
89
  type: :runtime
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
93
  - - '='
94
94
  - !ruby/object:Gem::Version
95
- version: 0.73.2
95
+ version: 0.93.1
96
96
  description: Provides a scriptable DSL with utilities for creating SVG content with
97
97
  Ruby.
98
98
  email: roktas@gmail.com