class Trenni::Builder
Build markup quickly and efficiently.
def self.fragment(output = nil, &block)
def self.fragment(output = nil, &block) if output.is_a?(Binding) output = Template.buffer(output) end if output.nil? return Fragment.new(block) end if output.is_a?(Builder) block.call(output) else block.call(Builder.new(output)) end return nil end
def self.tag(name, content, **attributes)
def self.tag(name, content, **attributes) self.fragment do |builder| builder.inline(name, attributes) do builder.text(content) end end end
def <<(content)
def <<(content) return unless content if content.is_a?(Fragment) inline! do content.call(self) end else Markup.append(@output, content) end end
def == other
def == other @output == String(other) end
def append(value)
def append(value) return unless value # The parent has one more child: @level[-1] += 1 if @indent value.each_line.with_index do |line, i| @output << indentation << line end else @output << value end end
def capture(*arguments, &block)
def capture(*arguments, &block) Template.capture(*arguments, output: self, &block) end
def doctype(attributes = 'html')
def doctype(attributes = 'html') @output << "<!DOCTYPE #{attributes}>\n" end
def encoding
def encoding @output.encoding end
def full_tag(name, attributes, indent_outer, indent_inner, &block)
def full_tag(name, attributes, indent_outer, indent_inner, &block) if block_given? if indent_outer @output << "\n" if @level.last > 0 @output << indentation end tag = Trenni::Tag.opened(name.to_s, attributes) tag.write_opening_tag(@output) @output << "\n" if indent_inner # The parent has one more child: @level[-1] += 1 @level << 0 yield children = @level.pop if indent_inner @output << "\n" if children > 0 @output << indentation end tag.write_closing_tag(@output) else # The parent has one more child: @level[-1] += 1 @output << indentation Trenni::Tag.append_tag(@output, name.to_s, attributes, nil) end end
def indentation
def indentation if @indent INDENT * (@level.size - 1) else '' end end
def initialize(output = nil, indent: true, encoding: Encoding::UTF_8)
def initialize(output = nil, indent: true, encoding: Encoding::UTF_8) # This field gets togged in #inline so we keep track of it separately from @indentation. @indent = indent # We don't need to use MarkupString here as Builder itself is considered markup and should be inserted directly into the output stream. @output = output || MarkupString.new.force_encoding(encoding) @level = [0] @children = [0] end
def inline!
def inline! original_indent = @indent @indent = false yield ensure @indent = original_indent end
def inline_tag(name, attributes = {}, &block)
def inline_tag(name, attributes = {}, &block) original_indent = @indent full_tag(name, attributes, @indent, false) do @indent = false yield if block_given? end ensure @indent = original_indent end
def raw(content)
def raw(content) @output << content end
def tag(name, attributes = {}, &block)
def tag(name, attributes = {}, &block) full_tag(name, attributes, @indent, @indent, &block) end
def text(content)
def text(content) return unless content if @indent @output << "\n" if @level.last > 0 @output << indentation end Markup.append(@output, content) if @indent @output << "\n" end end
def to_str
def to_str @output end