Class: RubyUIConverter::Transformer

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_ui_converter/transformer.rb

Overview

Walks the AST and writes Phlex/RubyUI Ruby source into a CodeBuilder.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config:, template: nil) ⇒ Transformer

Returns a new instance of Transformer.



10
11
12
13
14
# File 'lib/ruby_ui_converter/transformer.rb', line 10

def initialize(config:, template: nil)
  @config = config
  @template = template
  @form_stack = []
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



8
9
10
# File 'lib/ruby_ui_converter/transformer.rb', line 8

def config
  @config
end

#templateObject (readonly)

Returns the value of attribute template.



8
9
10
# File 'lib/ruby_ui_converter/transformer.rb', line 8

def template
  @template
end

Instance Method Details

#base_namespaceObject



46
47
48
# File 'lib/ruby_ui_converter/transformer.rb', line 46

def base_namespace
  config.base_namespace
end

#component_block(name, children, builder) ⇒ Object

Emits a component that wraps the given children with no attributes: ‘Name { inline }` for a single inlineable child, else a do/end block. Handy for ComponentMap emitters that nest content components (e.g. `AlertDescription { notice }`).



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/ruby_ui_converter/transformer.rb', line 98

def component_block(name, children, builder)
  kids = meaningful(children)

  if kids.empty?
    builder.line(name)
  elsif kids.length == 1 && inlineable?(kids.first)
    builder.line("#{name} { #{inline_value(kids.first)} }")
  else
    builder.line("#{name} do")
    builder.indent
    emit_children(kids, builder)
    builder.dedent
    builder.line("end")
  end
end

#current_formObject

The form scope (model:, param:) currently being emitted, if any. Set while inside a mapped form_with/form_for block; used by FormBuilder.



18
19
20
# File 'lib/ruby_ui_converter/transformer.rb', line 18

def current_form
  @form_stack.last
end

#current_namespace_partsObject



50
51
52
# File 'lib/ruby_ui_converter/transformer.rb', line 50

def current_namespace_parts
  template ? template.namespace_parts : []
end

#emit(document, builder) ⇒ Object

Entry point: emits the body of the view_template method.



23
24
25
# File 'lib/ruby_ui_converter/transformer.rb', line 23

def emit(document, builder)
  emit_children(meaningful(document.children), builder)
end

#emit_children(nodes, builder) ⇒ Object

— public helpers (also used by ComponentMap emitters) —————



29
30
31
# File 'lib/ruby_ui_converter/transformer.rb', line 29

def emit_children(nodes, builder)
  nodes.each { |node| emit_node(node, builder) }
end

#kit_component(name, element, builder, except: [], void: false, extra: nil) ⇒ Object

Emits a Phlex::Kit-style component call (‘Link(href: x) { “Home” }`). Parens are always kept — a bare capitalized name would be a constant. `void: true` components (Input, Checkbox…) never take a block. `extra:` prepends literal arguments (e.g. “variant: :destructive”).



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/ruby_ui_converter/transformer.rb', line 75

def kit_component(name, element, builder, except: [], void: false, extra: nil)
  attrs = [extra, render_attrs(element.attributes, except: except)]
          .compact.reject(&:empty?).join(", ")
  call = "#{name}(#{attrs})"
  kids = void ? [] : meaningful(element.children)

  if kids.empty?
    builder.line(call)
  elsif kids.length == 1 && inlineable?(kids.first)
    builder.line("#{call} { #{inline_value(kids.first)} }")
  else
    builder.line("#{call} do")
    builder.indent
    emit_children(kids, builder)
    builder.dedent
    builder.line("end")
  end
end

#meaningful(nodes) ⇒ Object



33
34
35
36
37
38
# File 'lib/ruby_ui_converter/transformer.rb', line 33

def meaningful(nodes)
  nodes.reject do |node|
    (node.is_a?(Nodes::Text) && node.content.strip.empty?) ||
      (node.is_a?(Nodes::RawText) && node.content.strip.empty?)
  end
end

#render_attrs(attributes, except: []) ⇒ Object



40
41
42
43
44
# File 'lib/ruby_ui_converter/transformer.rb', line 40

def render_attrs(attributes, except: [])
  attributes.reject { |name, _| except.include?(name) }
            .map { |name, parts| attr_pair(name, parts) }
            .join(", ")
end

#wrap_component(const, element, builder) ⇒ Object

Convenience for component emitters: render a component wrapping children.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/ruby_ui_converter/transformer.rb', line 55

def wrap_component(const, element, builder)
  attrs = render_attrs(element.attributes)
  call = attrs.empty? ? "#{const}.new" : "#{const}.new(#{attrs})"
  kids = meaningful(element.children)

  if kids.empty?
    builder.line("render #{call}")
  else
    builder.line("render #{call} do")
    builder.indent
    emit_children(kids, builder)
    builder.dedent
    builder.line("end")
  end
end