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:



223
224
225
# File 'lib/sevgi/graphics/mixtures/core.rb', line 223

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



49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/sevgi/graphics/mixtures/core.rb', line 49

def Adopt(new_parent = nil, index: -1)
  tap do
    if new_parent
      unless instance_of?(new_parent.class)
        ArgumentError.("Element type does not match the new parent type: #{self.class}")
      end
    else
      new_parent = parent
    end

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

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

Moves this element to the beginning of a parent.

Parameters:

Returns:



68
69
70
# File 'lib/sevgi/graphics/mixtures/core.rb', line 68

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

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

Appends existing elements as children.

Parameters:

Returns:



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

def Append(*elements)
  tap { elements.each { it.Adopt(self) } }
end

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

Adds CSS classes without duplicating existing values.

Parameters:

  • classes (Array<String, Symbol>)

    class names

Returns:



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/sevgi/graphics/mixtures/core.rb', line 82

def Classify(*classes)
  tap do
    klasses = case self[:class]
    when ::Array
      self[:class]
    when ::String
      self[:class].split
    when nil
      []
    else
      [self[:class]]
    end

    classes.each { klasses << it unless klasses.include?(it) }
    self[:class] = klasses
  end
end

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

Assigns default attributes only when they are absent.

Parameters:

  • attributes (Hash)

    default attributes

Returns:



103
104
105
106
107
108
109
110
111
# File 'lib/sevgi/graphics/mixtures/core.rb', line 103

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

      self[key] = value
    end
  end
end

#Element(tag, *contents, **attributes, &block) ⇒ 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

  • attributes (Hash)

    SVG attributes

Returns:



118
119
120
# File 'lib/sevgi/graphics/mixtures/core.rb', line 118

def Element(tag, *contents, **attributes, &block)
  self.class.send(:new, tag.to_sym, 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



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

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)


136
137
138
# File 'lib/sevgi/graphics/mixtures/core.rb', line 136

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

#OrphanArray<Sevgi::Graphics::Element>?

Removes this element from its parent.

Returns:



142
143
144
# File 'lib/sevgi/graphics/mixtures/core.rb', line 142

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

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

Prepends existing elements as children.

Parameters:

Returns:



149
150
151
# File 'lib/sevgi/graphics/mixtures/core.rb', line 149

def Prepend(*elements)
  tap { elements.each { it.AdoptFirst(self) } }
end

#RootSevgi::Graphics::Element

Returns the root document element.



155
156
157
158
159
160
# File 'lib/sevgi/graphics/mixtures/core.rb', line 155

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)


164
165
166
# File 'lib/sevgi/graphics/mixtures/core.rb', line 164

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

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

Wraps a traversal return value as a stop token.

Parameters:

  • value (Object)

    value returned from traversal

Returns:

  • (Sevgi::Graphics::Mixtures::Traversal)


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

def Stay(...) = Traversal.new(...)

#Traverse(depth = 0, leave = nil, &block) ⇒ 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

Returns:

Raises:

  • (Sevgi::ArgumentError)

    when no block is given



179
180
181
182
183
# File 'lib/sevgi/graphics/mixtures/core.rb', line 179

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

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

#TraverseUp(height = 0, &block) ⇒ Object?

Traverses ancestors from this element to the root.

Parameters:

  • height (Integer) (defaults to: 0)

    starting height

Returns:

  • (Object, nil)

    value passed through Stay, or nil

Raises:

  • (Sevgi::ArgumentError)

    when no block is given



189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/sevgi/graphics/mixtures/core.rb', line 189

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?(Traversal) }

    break if element.Root?()

    element = element.parent
    height += 1
  end
end

#With(*args, **kwargs, &block) ⇒ 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

Returns:



208
209
210
# File 'lib/sevgi/graphics/mixtures/core.rb', line 208

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

#Within(*args, **kwargs, &block) ⇒ 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

Returns:



216
217
218
# File 'lib/sevgi/graphics/mixtures/core.rb', line 216

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