Execution

Use Sevgi.execute when trusted Ruby source needs the full Sevgi script scope, or Sevgi.execute_file when that source already lives in a .sevgi file. Both return a result instead of raising failures produced by the script.

Inspect the result

result = Sevgi.execute(
  'SVG(:minimal) { circle r: 4 }.Render',
  file: "inline-icon.sevgi",
  line: 12
)

if result.success?
  svg = result.value
else
  warn result.error.message
end

success? and error? describe the outcome. value is the last expression on success; error is an Executor::Error on failure; stack is the immutable list of visited Sevgi sources. For diagnostics, result.error.cause is the original exception and result.error.load_backtrace keeps backtrace entries belonging to those sources.

The public observable types are Sevgi::Executor::Result, Sevgi::Executor::Error, and Sevgi::Executor::CycleError. The custom receiver and boot runner beneath the two Sevgi entrypoints is internal.

Source context

OptionMeaning
file:Diagnostic name and relative-load origin for inline source
line:Starting line used in inline-source errors and backtraces
as:Basename used by execute_file for evaluation, diagnostics, and caller-derived output defaults
require:Ruby library loaded before the Sevgi source
main: falseDefault isolated module scope; does not install the DSL on Ruby's main object
main: trueOpt-in main-object mode for code that deliberately relies on top-level method and constant lookup

execute_file also accepts as:. Its extension becomes .sevgi, while the physical input directory and load-cycle identity remain intact:

result = Sevgi.execute_file("drawings/card.sevgi", as: "proof")

An implicit Save in that source writes drawings/proof.svg; relative Load calls still start in drawings. Without as:, the input path supplies the evaluation name and starting line. Empty source without require: is a strict no-op. Use the isolated default unless compatibility with code that expects Sevgi on Ruby's top-level main object is the actual requirement.

Nested Load

Within an active execution, Load resolves .sevgi files relative to the source that calls it:

require "tmpdir"

Dir.mktmpdir do |dir|
  File.write(File.join(dir, "palette.sevgi"), '@ink = "tomato"')
  File.write(
    File.join(dir, "icon.sevgi"),
    "Load 'palette'\nSVG(:minimal) { circle r: 4, fill: @ink }.Render\n"
  )

  result = Sevgi.execute_file(File.join(dir, "icon.sevgi"))
  raise result.error if result.error?
end

Repeated non-recursive loads run again. Loading a source already active in the same chain produces a captured CycleError; inspect the result stack and load_backtrace to locate the cycle. Outside active execution, use Ruby's require rather than Load.

Trust boundary

Execution isolation is namespace hygiene, not a security sandbox. Both entrypoints run trusted Ruby with the current process's file, network, and system authority. For SVG/XML input, use Derender: its public conversion and inclusion APIs treat XML as data, so callers do not evaluate the generated Ruby source themselves.