Module: RailroadDiagrams::Transform::AutoWrap

Defined in:
lib/railroad_diagrams/transform/auto_wrap.rb

Overview

Splits wide sequences into stacked rows for SVG output.

Examples:

Transform::AutoWrap.call(Diagram.new('a', 'b'), Context.new, max_width: 120)

Class Method Summary collapse

Class Method Details

.call(diagram, context, max_width:) ⇒ Object

Returns a wrapped copy when the diagram exceeds max_width.

Examples:

Transform::AutoWrap.call(Diagram.new('a', 'b'), Context.new, max_width: 120)


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/railroad_diagrams/transform/auto_wrap.rb', line 17

def call(diagram, context, max_width:)
  unless max_width.is_a?(Numeric) && !max_width.is_a?(Complex) && max_width.finite? && max_width.positive?
    raise InvalidArgument, 'max_width must be a finite positive number'
  end
  return diagram if context.metrics(diagram).width + 40 <= max_width

  nodes = diagram.child_nodes
  first = nodes.first if nodes.first.is_a?(Start)
  last = nodes.last if nodes.last.is_a?(End)
  body = nodes[(first ? 1 : 0)...(last ? -1 : nodes.length)]
  return diagram if body.empty?

  edge_width = [first, last].compact.sum { |node| context.metrics(node).width }
  budget = max_width - 40 - edge_width - (context.options.arc_radius * 2) - 40
  items = flatten_wide_sequences(body, context, budget)
  rows = pack(items, context, budget)
  return diagram if rows.size < 2

  stack = Stack.new(*rows.map { |row| row.size == 1 ? row.first : Sequence.new(*row) })
  copy = diagram.dup
  styles = diagram.instance_variable_get(:@items).grep(Style)
  copy.instance_variable_set(:@items, [*styles, first, stack, last].compact)
  copy
end