Module: Sevgi::Graphics::Document

Defined in:
lib/sevgi/graphics/document.rb,
lib/sevgi/graphics/document/base.rb,
lib/sevgi/graphics/document/html.rb,
lib/sevgi/graphics/document/default.rb,
lib/sevgi/graphics/document/minimal.rb,
lib/sevgi/graphics/document/inkscape.rb

Overview

SVG document profile factory and process-global named-profile registry.

A profile owns SVG root attributes and optional preamble lines, but not canvas size. Built-in and named profiles can be passed to SVG; an anonymous profile class is useful when library code needs one-off metadata without adding a global name.

Profile Preamble Root metadata Additional DSL
:minimal none none common document DSL
:default XML declaration SVG namespace common document DSL
:html none SVG namespace common document DSL
:inkscape XML declaration SVG and editor namespaces; crisp edges Draw, Hatch, and editor/RDF helpers

The Inkscape root adds Sevgi, Inkscape, and Sodipodi namespaces plus shape-rendering="crispEdges". Every selectable profile has the same validation and lint lifecycle; :minimal changes serialization metadata, not checking policy. Base is the public common extension layer rather than a selectable profile. Minimal and Default are sibling concrete profiles: Minimal contributes no metadata and is not the semantic base of the other profiles. Targeting Base through Mixtures.mixin changes every descendant profile process-wide; subclass Base first when an extension should remain scoped.

Defined Under Namespace

Classes: Base, Default, HTML, Inkscape, Minimal, Profile, Proto

Class Method Summary collapse

Class Method Details

.call(document, canvas = Undefined) { ... } ⇒ Sevgi::Graphics::Document::Proto

Builds a root SVG element from a document profile.

Examples:

Build from a scoped Base-derived profile

Card = Class.new(Sevgi::Graphics::Document::Base)
Sevgi::Graphics::Document.(Card) { rect width: 10, height: 5 }

Parameters:

Yields:

  • evaluates the drawing DSL in the new root element

Yield Returns:

  • (Object)

    ignored block result

Returns:

Raises:

  • (Sevgi::ArgumentError)

    when the document profile or root XML attributes are invalid



133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/sevgi/graphics/document.rb', line 133

def self.call(document, canvas = Undefined, **, &block)
  klass = case document
  when ::Class
    document if document <= Proto
  else
    fetch(document)
  end

  ArgumentError.("Unknown document profile: #{document}") unless klass

  klass.root(**klass.attributes, **canvas_attributes(canvas), **, &block)
end

.define(name = Undefined, preambles: Undefined, attributes: Undefined, overwrite: false) ⇒ Class

Defines, looks up, or returns an anonymous document profile class.

A name without metadata performs lookup. A name plus either metadata keyword defines or compatibly reuses a named profile. Omitting the name creates an anonymous class and leaves the registry unchanged. Named profiles are process-global; use them for shared vocabulary rather than per-call configuration. Profile metadata is captured before class or thread-atomic registry mutation. Mutable non-container attribute values are stringified once, attribute names and nested Hash keys are normalized, and nil attributes are omitted during capture. Successful named definitions return the canonical class stored by the registry, including when identical definitions race.

Examples:

Define a reusable library profile

profile = Sevgi::Graphics::Document.define(
  :icon,
  preambles: [],
  attributes: {xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24"}
)
Sevgi::Graphics::Document.(profile) { circle cx: 12, cy: 12, r: 10 }.Render

Build an anonymous one-off profile

profile = Sevgi::Graphics::Document.define(attributes: {viewBox: "0 0 10 10"})
profile.profile.name # => nil

Parameters:

  • name (Symbol, String, Sevgi::Undefined) (defaults to: Undefined)

    profile name, or Undefined for an anonymous profile

  • preambles (Array<String>, nil, Sevgi::Undefined) (defaults to: Undefined)

    document preamble lines

  • attributes (Hash, nil, Sevgi::Undefined) (defaults to: Undefined)

    default root attributes

  • overwrite (Boolean) (defaults to: false)

    true to replace an existing profile

Returns:

  • (Class)

    document class

Raises:

  • (Sevgi::ArgumentError)

    when overwrite is not Boolean, a name conflicts, or metadata is invalid XML, cyclic, or cannot be stringified



220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/sevgi/graphics/document.rb', line 220

def self.define(name = Undefined, preambles: Undefined, attributes: Undefined, overwrite: false)
  overwrite!(overwrite)
  return anonymous(attributes:, preambles:) if name == Undefined

  return lookup(name) if preambles == Undefined && attributes == Undefined

  name = Name.normalize!(name)
  current = reuse(name, attributes:, preambles:, overwrite:)
  return current if current

  attributes, preambles = defaults(attributes:, preambles:)
  Class.new(Base) { document(name, preambles:, attributes:, overwrite:) }
  Registry[name]
end

.exist?(name) ⇒ Boolean

Reports whether a normalizable document profile name is registered. Invalid converters return false and do not change the registry.

Examples:

Check a built-in profile

Sevgi::Graphics::Document.exist?(:minimal) # => true

Parameters:

  • name (Object)

    profile name

Returns:

  • (Boolean)


177
178
179
180
# File 'lib/sevgi/graphics/document.rb', line 177

def self.exist?(name)
  name = Name.normalize(name)
  name ? !Registry[name].nil? : false
end

.fetch(name) ⇒ Class

Returns a registered document class by profile name.

Examples:

Look up a document class and its metadata

klass = Sevgi::Graphics::Document.fetch(:minimal)
Sevgi::Graphics::Document.profile(:minimal) # => klass.profile

Parameters:

  • name (Symbol, String)

    profile name

Returns:

  • (Class)

    registered subclass of Proto

Raises:

  • (Sevgi::ArgumentError)

    when name is invalid or unknown



166
167
168
169
# File 'lib/sevgi/graphics/document.rb', line 166

def self.fetch(name)
  name = Name.normalize!(name)
  Registry[name] || ArgumentError.("Unknown document profile: #{name}")
end

.keysArray<Symbol>

Returns registered document profile names.

Returns:

  • (Array<Symbol>)

    frozen name snapshot



184
# File 'lib/sevgi/graphics/document.rb', line 184

def self.keys = Registry.available.keys.freeze

.profile(name) ⇒ Sevgi::Graphics::Document::Profile

Returns immutable metadata for a registered document profile.

Parameters:

  • name (Symbol, String)

    profile name

Returns:

Raises:

  • (Sevgi::ArgumentError)

    when name is invalid or unknown



190
# File 'lib/sevgi/graphics/document.rb', line 190

def self.profile(name) = fetch(name).profile