class PostRunner::HTMLBuilder

Nokogiri is great, but I don’t like the HTMLBuilder interface. This class is a wrapper around Nokogiri that provides a more Ruby-like interface.

Public Class Methods

new(title) click to toggle source

Create a new HTMLBuilder object.

# File lib/postrunner/HTMLBuilder.rb, line 22
    def initialize(title)
      # This is the Nokogiri Document that will store all the data.
      @doc = Nokogiri::HTML::Document.new
      # We only need to keep a stack of the currently edited nodes so we know
      # where we are in the node tree.
      @node_stack = []
      @tags = []

      @html = create_node('html') {
        @head = create_node('head') {
          create_node('meta', { 'http-equiv' => 'Content-Type',
                      'content' => 'text/html; charset=utf-8' })
          create_node('title', title)
          @init_script = create_node('script', <<EOT
function postrunner_init() {
};
EOT
                                    )
        }
        @body = create_node('body')
        @body['onload'] = 'postrunner_init()'
      }
      @node_stack << @html
      @node_stack << @body
    end

Public Instance Methods

body(*args) { || ... } click to toggle source

Append nodes provided in block to body section of HTML document.

# File lib/postrunner/HTMLBuilder.rb, line 58
def body(*args)
  @node_stack.push(@body)
  args.each do |arg|
    if arg.is_a?(Hash)
      arg.each { |k, v| @body[k] = v }
    end
  end
  yield if block_given?
  unless @node_stack.pop == @body
    raise ArgumentError, "node_stack corrupted in body"
  end
end
body_init_script(script) click to toggle source
# File lib/postrunner/HTMLBuilder.rb, line 71
def body_init_script(script)
  # We have to insert the new script snippet after the last snippet and
  # before the tailing "};\n".
  @init_script.content = @init_script.text[0..-4] + script + "\n};\n"
end
head() { || ... } click to toggle source

Append nodes provided in block to head section of HTML document.

# File lib/postrunner/HTMLBuilder.rb, line 49
def head
  @node_stack.push(@head)
  yield if block_given?
  unless @node_stack.pop == @head
    raise ArgumentError, "node_stack corrupted in head"
  end
end
method_missing(method_name, *args, &block) click to toggle source

Any call to an undefined method will create a HTML node of the same name.

# File lib/postrunner/HTMLBuilder.rb, line 88
def method_missing(method_name, *args, &block)
  create_node(method_name.to_s, *args, &block)
end
respond_to?(method) click to toggle source

Only needed to comply with style guides. This all calls to unknown method will be handled properly. So, we always return true.

# File lib/postrunner/HTMLBuilder.rb, line 94
def respond_to?(method)
  true
end
to_html() click to toggle source

Dump the HTML document as HTML formatted String.

# File lib/postrunner/HTMLBuilder.rb, line 99
def to_html
  @doc.to_html
end
unique(tag) { || ... } click to toggle source

Only execute the passed block if the provided tag has not been added yet.

# File lib/postrunner/HTMLBuilder.rb, line 79
def unique(tag)
  unless @tags.include?(tag)
    @tags << tag
    yield if block_given?
  end
end

Private Instance Methods

add_child(parent, node) click to toggle source
# File lib/postrunner/HTMLBuilder.rb, line 128
def add_child(parent, node)
  if parent
    parent.add_child(node)
  else
    @doc.add_child(node)
  end
end
create_node(name, *args) { || ... } click to toggle source
# File lib/postrunner/HTMLBuilder.rb, line 105
def create_node(name, *args)
  node = Nokogiri::XML::Node.new(name, @doc)
  if (parent = @node_stack.last)
    parent.add_child(node)
  else
    @doc.add_child(node)
  end
  @node_stack.push(node)

  args.each do |arg|
    if arg.is_a?(String)
      node.add_child(Nokogiri::XML::Text.new(arg, @doc))
    elsif arg.is_a?(Hash)
      # Hash arguments are attribute sets for the node. We just pass them
      # directly to the node.
      arg.each { |k, v| node[k] = v }
    end
  end

  yield if block_given?
  @node_stack.pop
end