Module: Sevgi::Graphics::Mixtures::Core

Extended by:
Forwardable
Defined in:
lib/sevgi/graphics/mixtures/core.rb

Overview

Core SVG tree and attribute DSL helpers.

Instance Method Summary collapse

Instance Method Details

#<<(element) ⇒ Sevgi::Graphics::Element

Appends an element as a child.

Parameters:

Returns:



248
249
250
# File 'lib/sevgi/graphics/mixtures/core.rb', line 248

def <<(element)
  Append(element)
end

#Adopt(new_parent = nil, index: -1)) ⇒ Sevgi::Graphics::Element

Moves this element under a new parent.

Parameters:

  • new_parent (Sevgi::Graphics::Element, nil) (defaults to: nil)

    target parent or current parent

  • index (Integer) (defaults to: -1))

    insertion index

Returns:

Raises:

  • (Sevgi::ArgumentError)

    when the target parent has a different element class

  • (Sevgi::ArgumentError)

    when the target parent is this element or one of its descendants

  • (Sevgi::ArgumentError)

    when index is not an Integer insertion position



57
58
59
60
61
62
63
64
65
66
67
# File 'lib/sevgi/graphics/mixtures/core.rb', line 57

def Adopt(new_parent = nil, index: -1)
  tap do
    new_parent ||= parent
    Adoption.validate(self, new_parent)

    insertion = Adoption.index_for(self, new_parent, index)

    self.Orphan()
    (@parent = new_parent).children.insert(insertion, self)
  end
end

#AdoptFirst(new_parent = nil) ⇒ Sevgi::Graphics::Element

Moves this element to the beginning of a parent.

Parameters:

Returns:

Raises:

  • (Sevgi::ArgumentError)

    when the target parent has a different element class

  • (Sevgi::ArgumentError)

    when the target parent is this element or one of its descendants



75
76
77
# File 'lib/sevgi/graphics/mixtures/core.rb', line 75

def AdoptFirst(*)
  Adopt(*, index: 0)
end

#Append(*elements) ⇒ Sevgi::Graphics::Element

Appends distinct existing elements as children in argument order. Each element transfers from its current parent. The complete batch is validated before any element moves.

Parameters:

Returns:

Raises:

  • (Sevgi::ArgumentError)

    when an argument has a different element class, is repeated, or is this target or its ancestor



84
85
86
# File 'lib/sevgi/graphics/mixtures/core.rb', line 84

def Append(*elements)
  tap { Adoption.batch(elements, self, front: false) }
end

#Classify(*classes) ⇒ Sevgi::Graphics::Element

Adds CSS classes without duplicating existing values.

Parameters:

  • classes (Array<String, Symbol, Array>)

    class tokens; strings are split on whitespace

Returns:



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/sevgi/graphics/mixtures/core.rb', line 91

def Classify(*classes)
  tap do
    tokens = proc do |value|
      case value
      when nil
        []
      when ::Array
        value.flat_map { tokens.call(it) }
      else
        value.to_s.split
      end
    end

    self[:class] = [*tokens.call(self[:class]), *tokens.call(classes)].uniq
  end
end

#Defaults(**attributes) ⇒ Sevgi::Graphics::Element

Assigns default attributes only when they are absent.

Parameters:

  • attributes (Hash)

    default attributes

Returns:



111
112
113
114
115
116
117
118
119
# File 'lib/sevgi/graphics/mixtures/core.rb', line 111

def Defaults(**attributes)
  tap do
    attributes.each do |key, value|
      next if has?(key)

      self[key] = value
    end
  end
end

#Element(tag, *contents, **attributes) { ... } ⇒ Sevgi::Graphics::Element

Builds a child element with an explicit tag name.

Parameters:

  • tag (Symbol, String)

    SVG tag name

  • contents (Array<Object>)

    text or content objects; non-content objects are stringified and XML-encoded

  • attributes (Hash)

    SVG attributes

Yields:

  • evaluates the drawing DSL in the new child element

Yield Returns:

  • (Object)

    ignored block result

Returns:

Raises:

  • (Sevgi::ArgumentError)

    when the tag, attributes, or content are not valid XML



129
130
131
# File 'lib/sevgi/graphics/mixtures/core.rb', line 129

def Element(tag, *contents, **attributes, &block)
  self.class.send(:new, tag, contents: Content.contents(*contents), attributes:, parent: self, &block)
end

#Forward(receiver, method, *args, **kwargs) ⇒ Object

Forwards this element as the first argument to another receiver.

Returns forwarded call result.

Parameters:

  • receiver (Object)

    target receiver

  • method (Symbol, String)

    method name

  • args (Array<Object>)

    additional arguments

  • kwargs (Hash)

    additional keyword arguments

Returns:

  • (Object)

    forwarded call result



140
141
142
# File 'lib/sevgi/graphics/mixtures/core.rb', line 140

def Forward(receiver, method, ...)
  receiver.public_send(method, self, ...)
end

#Is?(name) ⇒ Boolean

Reports whether this element has the given SVG name.

Parameters:

  • name (Symbol, String)

    SVG name

Returns:

  • (Boolean)


147
148
149
# File 'lib/sevgi/graphics/mixtures/core.rb', line 147

def Is?(name)
  self.name() == name.to_sym
end

#OrphanSevgi::Graphics::Element?

Removes this element from its parent.

Returns:



153
154
155
# File 'lib/sevgi/graphics/mixtures/core.rb', line 153

def Orphan
  parent.children&.delete(self) unless Root?()
end

#Prepend(*elements) ⇒ Sevgi::Graphics::Element

Prepends distinct existing elements as children in argument order. Each element transfers from its current parent. The complete batch is validated before any element moves.

Parameters:

Returns:

Raises:

  • (Sevgi::ArgumentError)

    when an argument has a different element class, is repeated, or is this target or its ancestor



162
163
164
# File 'lib/sevgi/graphics/mixtures/core.rb', line 162

def Prepend(*elements)
  tap { Adoption.batch(elements, self, front: true) }
end

#RootSevgi::Graphics::Element

Returns the root document element.



168
169
170
171
172
173
# File 'lib/sevgi/graphics/mixtures/core.rb', line 168

def Root
  element = self
  element = element.parent until element.Root?()

  element
end

#Root?Boolean

Reports whether this element is the root document element.

Returns:

  • (Boolean)


177
178
179
# File 'lib/sevgi/graphics/mixtures/core.rb', line 177

def Root?
  self.class.root?(self)
end

#Stay(value) ⇒ Sevgi::Graphics::Mixtures::Stop

Wraps a traversal return value as a stop token.

Parameters:

  • value (Object)

    value returned from traversal

Returns:



185
# File 'lib/sevgi/graphics/mixtures/core.rb', line 185

def Stay(...) = Stop.new(...)

#Traverse(depth = 0, leave = nil) {|element, depth| ... } ⇒ Sevgi::Graphics::Element, Object

Traverses the subtree depth-first.

Parameters:

  • depth (Integer) (defaults to: 0)

    starting depth

  • leave (Proc, nil) (defaults to: nil)

    optional leave callback

Yields:

  • (element, depth)

    visits each element before its children

Yield Parameters:

Yield Returns:

  • (Object)

    ignored unless it is a Stop token

Returns:

Raises:

  • (Sevgi::ArgumentError)

    when no block is given



196
197
198
199
200
# File 'lib/sevgi/graphics/mixtures/core.rb', line 196

def Traverse(depth = 0, leave = nil, &block)
  ArgumentError.("Block required") unless block

  Traversal.call(self, depth, leave, &block)
end

#TraverseUp(height = 0) {|element, height| ... } ⇒ Object?

Traverses ancestors from this element to the root.

Parameters:

  • height (Integer) (defaults to: 0)

    starting height

Yields:

  • (element, height)

    visits this element and each ancestor

Yield Parameters:

Yield Returns:

  • (Object)

    ignored unless it is a Stop token

Returns:

  • (Object, nil)

    value passed through Stay, or nil

Raises:

  • (Sevgi::ArgumentError)

    when no block is given



210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/sevgi/graphics/mixtures/core.rb', line 210

def TraverseUp(height = 0, &block)
  ArgumentError.("Block required") unless block

  element = self

  loop do
    yield(element, height).tap { return it.value if it.is_a?(Stop) }

    break if element.Root?()

    element = element.parent
    height += 1
  end
end

#With(*args, **kwargs) { ... } ⇒ Sevgi::Graphics::Element

Evaluates a block in the parent element context.

Parameters:

  • args (Array<Object>)

    optional receiver override followed by block arguments

  • kwargs (Hash)

    keyword arguments passed to the block

Yields:

  • evaluates in the selected receiver's parent context

Yield Returns:

  • (Object)

    ignored block result

Returns:



231
232
233
# File 'lib/sevgi/graphics/mixtures/core.rb', line 231

def With(*args, **kwargs, &block)
  tap { (args.shift || self).parent.instance_exec(*args, **kwargs, &block) }
end

#Within(*args, **kwargs) { ... } ⇒ Sevgi::Graphics::Element

Evaluates a block in this element context.

Parameters:

  • args (Array<Object>)

    optional receiver override followed by block arguments

  • kwargs (Hash)

    keyword arguments passed to the block

Yields:

  • evaluates in the selected receiver context

Yield Returns:

  • (Object)

    ignored block result

Returns:



241
242
243
# File 'lib/sevgi/graphics/mixtures/core.rb', line 241

def Within(*args, **kwargs, &block)
  tap { (args.shift || self).instance_exec(*args, **kwargs, &block) }
end