Class: RailroadDiagrams::DiagramItem

Inherits:
Object
  • Object
show all
Includes:
Enumerable, Enumerable[DiagramItem]
Defined in:
lib/railroad_diagrams/diagram_item.rb,
sig/generated/railroad_diagrams/diagram_item.rbs

Overview

Base class for diagram nodes and structural traversal.

Examples:

Sequence.new('a', 'b').each_node.map(&:class)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, attrs: {}, text: nil, id: nil, data_attrs: {}, cls: nil) ⇒ DiagramItem

Returns a new instance of DiagramItem.

Parameters:

  • name (String)
  • attrs: (Hash[String, String | Numeric]) (defaults to: {})
  • text: (String, nil) (defaults to: nil)
  • id: (Object) (defaults to: nil)
  • data_attrs: (Object) (defaults to: {})
  • cls: (Object) (defaults to: nil)


40
41
42
43
44
45
46
47
48
49
50
# File 'lib/railroad_diagrams/diagram_item.rb', line 40

def initialize(name, attrs: {}, text: nil, id: nil, data_attrs: {}, cls: nil)
  @name = name
  @up = 0
  @height = 0
  @down = 0
  @width = 0
  @needs_space = false
  @attrs = (attrs || {}).dup
  apply_user_attributes(id, data_attrs, cls)
  @children = text ? [text] : []
end

Instance Attribute Details

#attrs ⇒ Hash[String, String | Numeric] (readonly)

: Hash[String, String | Numeric]

Returns:

  • (Hash[String, String | Numeric])


33
34
35
# File 'lib/railroad_diagrams/diagram_item.rb', line 33

def attrs
  @attrs
end

#children ⇒ Array[DiagramItem | Path | Style | String] (readonly)

: Array[DiagramItem | Path | Style | String]

Returns:



34
35
36
# File 'lib/railroad_diagrams/diagram_item.rb', line 34

def children
  @children
end

#down ⇒ Numeric (readonly)

: Numeric

Returns:

  • (Numeric)


29
30
31
# File 'lib/railroad_diagrams/diagram_item.rb', line 29

def down
  @down
end

#height ⇒ Numeric (readonly)

: Numeric

Returns:

  • (Numeric)


30
31
32
# File 'lib/railroad_diagrams/diagram_item.rb', line 30

def height
  @height
end

#needs_space ⇒ Boolean (readonly)

: bool

Returns:

  • (Boolean)


32
33
34
# File 'lib/railroad_diagrams/diagram_item.rb', line 32

def needs_space
  @needs_space
end

#up ⇒ Numeric (readonly)

: Numeric

Returns:

  • (Numeric)


28
29
30
# File 'lib/railroad_diagrams/diagram_item.rb', line 28

def up
  @up
end

#width ⇒ Numeric (readonly)

: Numeric

Returns:

  • (Numeric)


31
32
33
# File 'lib/railroad_diagrams/diagram_item.rb', line 31

def width
  @width
end

Class Method Details

.inherited(subclass) ⇒ void

This method returns an undefined value.

Parameters:

  • subclass (Class)


23
24
25
26
# File 'lib/railroad_diagrams/diagram_item.rb', line 23

def self.inherited(subclass)
  super
  subclass.prepend(ResetChildrenOnFormat)
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?

Compare node structure and user attributes.

Examples:

Terminal.new('x') == Terminal.new('x') #=> true

Parameters:

  • other (Object)

Returns:

  • (Object)


109
110
111
# File 'lib/railroad_diagrams/diagram_item.rb', line 109

def ==(other)
  other.class == self.class && structural_state == other.send(:structural_state)
end

#add(parent) ⇒ DiagramItem

Parameters:

Returns:



67
68
69
70
# File 'lib/railroad_diagrams/diagram_item.rb', line 67

def add(parent)
  parent.children.push self
  self
end

#apply_user_attributes(id, data_attrs, cls) ⇒ Object

Parameters:

  • id (Object)
  • data_attrs (Object)
  • cls (Object)

Returns:

  • (Object)

Raises:



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/railroad_diagrams/diagram_item.rb', line 149

def apply_user_attributes(id, data_attrs, cls)
  if id
    raise InvalidArgument, 'id must be a valid SVG identifier' unless id.is_a?(String) && /\A[A-Za-z_][\w.-]*\z/.match?(id)

    @attrs['id'] = id
  end
  raise InvalidArgument, 'attrs must be a Hash' unless data_attrs.is_a?(Hash)

  data_attrs.each do |name, value|
    raise InvalidArgument, "unsupported SVG attribute: #{name.inspect}" unless name.is_a?(String) && /\Adata-[A-Za-z0-9_-]+\z/.match?(name)

    @attrs[name] = value.to_s
  end
  return if cls.nil?
  raise InvalidArgument, 'cls must be a String' unless cls.is_a?(String)
  return if cls.empty?

  @attrs['class'] = [@attrs['class'], cls].compact.join(' ').strip
end

#child_nodes ⇒ Object

Return the node's direct structural children.

Examples:

Sequence.new('a', 'b').child_nodes.size #=> 2

Returns:

  • (Object)


90
91
92
# File 'lib/railroad_diagrams/diagram_item.rb', line 90

def child_nodes
  []
end

#container_element? ⇒ Boolean

Returns:

  • (Boolean)


193
194
195
# File 'lib/railroad_diagrams/diagram_item.rb', line 193

def container_element?
  %w[g svg].include?(@name)
end

#determine_gaps(outer, inner) ⇒ [ Numeric, Numeric ]

Parameters:

  • outer (Numeric)
  • inner (Numeric)

Returns:

  • ([ Numeric, Numeric ])


206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/railroad_diagrams/diagram_item.rb', line 206

def determine_gaps(outer, inner)
  diff = outer - inner
  case INTERNAL_ALIGNMENT
  when 'left'
    [0, diff]
  when 'right'
    [diff, 0]
  else
    half = diff.is_a?(Integer) && diff.odd? ? diff / 2.0 : diff / 2
    [half, half]
  end
end

#each_node(&block) ⇒ void Also known as: each

This method returns an undefined value.

Visit this node and descendants in preorder.

Examples:

Sequence.new('a', 'b').each_node.map(&:class)


97
98
99
100
101
102
103
# File 'lib/railroad_diagrams/diagram_item.rb', line 97

def each_node(&block)
  return enum_for(:each_node) unless block

  block.call(self)
  child_nodes.each { |child| child.each_node(&block) if child.respond_to?(:each_node) }
  self
end

#format(x, y, width) ⇒ DiagramItem

Parameters:

  • x (Numeric)
  • y (Numeric)
  • width (Numeric)

Returns:



56
57
58
# File 'lib/railroad_diagrams/diagram_item.rb', line 56

def format(x, y, width)
  raise NotImplementedError
end

#hash ⇒ Object

Hash the same structural state used by equality.

Examples:

[Terminal.new('x'), Terminal.new('x')].uniq.size #=> 1

Returns:

  • (Object)


117
118
119
# File 'lib/railroad_diagrams/diagram_item.rb', line 117

def hash
  [self.class, structural_state].hash
end

#inspect ⇒ String

Examples:

Sequence.new('a', 'b').inspect

Returns:

  • (String)


137
138
139
# File 'lib/railroad_diagrams/diagram_item.rb', line 137

def inspect
  Introspection.call(self)
end

#structural_state ⇒ Object

Returns:

  • (Object)


143
144
145
146
147
# File 'lib/railroad_diagrams/diagram_item.rb', line 143

def structural_state
  to_h
rescue ParseError
  [@name, @attrs, @items&.map { |item| item.is_a?(Style) ? item.to_s : item.to_h }]
end

#text_diagram ⇒ TextDiagram

Returns:

  • (TextDiagram)


61
62
63
# File 'lib/railroad_diagrams/diagram_item.rb', line 61

def text_diagram
  raise NotImplementedError, "#{self.class}#text_diagram is not implemented"
end

#to_str ⇒ String

Returns:

  • (String)


129
130
131
132
# File 'lib/railroad_diagrams/diagram_item.rb', line 129

def to_str
  Deprecation.warn('DiagramItem#to_str is deprecated; use #inspect')
  inspect
end

#walk(callback) ⇒ void

This method returns an undefined value.



83
84
85
# File 'lib/railroad_diagrams/diagram_item.rb', line 83

def walk(callback)
  callback.call(self)
end

#wrap_string(value) ⇒ DiagramItem

Parameters:

Returns:



199
200
201
# File 'lib/railroad_diagrams/diagram_item.rb', line 199

def wrap_string(value)
  value.is_a?(DiagramItem) ? value : Terminal.new(value)
end

#write_children(write) ⇒ void

This method returns an undefined value.



182
183
184
185
186
187
188
189
190
# File 'lib/railroad_diagrams/diagram_item.rb', line 182

def write_children(write)
  @children.each do |child|
    if child.respond_to?(:write_svg)
      child.write_svg(write)
    else
      write.call(RailroadDiagrams.escape_html(child))
    end
  end
end

#write_opening_tag(write) ⇒ void

This method returns an undefined value.



171
172
173
174
175
176
177
178
# File 'lib/railroad_diagrams/diagram_item.rb', line 171

def write_opening_tag(write)
  write.call("<#{@name}")
  @attrs.sort.each do |name, value|
    write.call(" #{name}=\"#{RailroadDiagrams.escape_attr(value)}\"")
  end
  write.call('>')
  write.call("\n") if container_element?
end

#write_standalone(write, _css = nil) ⇒ void

This method returns an undefined value.

Parameters:

  • _css (Object) (defaults to: nil)


124
125
126
# File 'lib/railroad_diagrams/diagram_item.rb', line 124

def write_standalone(write, _css = nil)
  write_svg(write)
end

#write_svg(write) ⇒ void

This method returns an undefined value.

Parameters:

  • write (Object)


74
75
76
77
78
79
# File 'lib/railroad_diagrams/diagram_item.rb', line 74

def write_svg(write)
  write = Writer.wrap(write)
  write_opening_tag(write)
  write_children(write)
  write.call("</#{@name}>")
end