class RSpec::Formatters::YARD

An RSpec output formatter that writes in a specific HTML format that can be imported by the YARD template. The output can also be viewed as a stand-alone test report.

Constants

CSS_FILE

@return [String] the path to the CSS file in the YARD-template, which

will be imported into the header so the output HTML can
be viewed as a stand-alone document.

Public Class Methods

new(output) click to toggle source
# File lib/rspec/formatters/yard.rb, line 26
def initialize(output)
  @output = output
  @document = REXML::Document.new("<!DOCTYPE html>")

  html = @document.add_element("html")
  head = html.add_element("head")
  head.add_element("style").text = IO.read(CSS_FILE)
  @body = html.add_element("body")
end

Public Instance Methods

example_failed(failure) click to toggle source

Called by RSpec for each example that failes. @param failure [RSpec::Core::Notifications::FailedExampleNotification]

# File lib/rspec/formatters/yard.rb, line 52
def example_failed(failure)
  node = xml_node_for_notification(failure, :show_when_pending)
  node.attributes["class"] = "rspec_example_failed"
  node.add_element("exception").text = failure.exception.message
  node.add_element("backtrace").text = failure.formatted_backtrace.join("\n")
end
example_passed(passed) click to toggle source

Called by RSpec for each example that passes. @param passed [RSpec::Core::Notifications::ExampleNotification]

# File lib/rspec/formatters/yard.rb, line 38
def example_passed(passed)
  node = xml_node_for_notification(passed, :show_when_passed)
  node.attributes["class"] = "rspec_example_passed"
end
example_pending(pending) click to toggle source

Called by RSpec for each example that is pending. @param pending [RSpec::Core::Notifications::ExampleNotification]

# File lib/rspec/formatters/yard.rb, line 45
def example_pending(pending)
  node = xml_node_for_notification(pending, :show_when_pending)
  node.attributes["class"] = "rspec_example_pending"
end
stop(notification) click to toggle source

Called by RSpec when the test suite is complete. @param notification [RSpec::Core::Notifications::ExamplesNotification]

# File lib/rspec/formatters/yard.rb, line 61
def stop(notification)
  @document.elements["html/head"].add_element("title").text =
    RSpec.configuration.title
  @document.write @output
end

Private Instance Methods

node_for_illustration(illustration) click to toggle source

Creates a <div> node for the given illustration. @param illustration [Hash] the illustration. @return [REXML::Element] the XML node for the illustration.

# File lib/rspec/formatters/yard.rb, line 86
def node_for_illustration(illustration)
  node = REXML::Element.new("div")
  node.add_attribute('class', 'rspec_illustration')

  if label = illustration[:label] then
    node.add_element("p", {'class'=>'rspec_illustration_label'}).text = label
  end

  if illustration.has_key?(:html) then
    node.add_element(REXML::Document.new(illustration[:html]).root)
  else
    node.add_element("pre", {'class'=>'rspec_illustration_content'}).text =
      REXML::Text.new(illustration[:text], true, nil, false)
  end

  node
end
xml_child_node_for_group(id, caption, parent=@body) click to toggle source

@param id [String] the id of the node. @param caption [String] the description of the node. @param parent [REXML::Element] the parent node to search within. @return [REXML::Element] the xml child node with the id and caption, which will be

created if it doesn't exist.
# File lib/rspec/formatters/yard.rb, line 140
def xml_child_node_for_group(id, caption, parent=@body)
  child_node = parent.elements["div[@id='rspec_#{id}']"]
  return child_node.elements["div[@class='rspec_example_group_children']"] if child_node

  child_node = parent.add_element "div", {'id' => "rspec_#{id}",
                                          'class'=>"rspec_example_group"}
  child_node.add_element("div", {'class'=>'rspec_example_group_title'}).text = caption
  child_node.add_element("div", {'class'=>'rspec_example_group_children'})
end
xml_node_for_example_group(example_group) click to toggle source

@param example_group [RSpec::Core::ExampleGroup] @return [REXML::Element] the XML node that corresponds to the specific example group,

which will be created if it doesn't exist.
# File lib/rspec/formatters/yard.rb, line 107
def xml_node_for_example_group(example_group)
  node = @body

  path = example_group.parent_groups.reverse
  if example_group.described_class then
    path = path.drop_while{|group|
      group.described_class != example_group.described_class
    }

    # use the class/module description as the YARD specific CodeObject id
    codeobject_id = path.shift.description

    # merge root with first element if it is a method.
    if path.size >= 1 && (path.first.description.start_with?('#')  ||
                          path.first.description.start_with?('.')) then
      codeobject_id = "#{codeobject_id}#{path.shift.description}"
    end

    # create first node with YARD-specific 'CodeObject' path as id.
    node = xml_child_node_for_group(codeobject_id, codeobject_id, @body)
  end

  path.inject(node){|node, group|
    xml_child_node_for_group(group.name, group.description, node)
  }
end
xml_node_for_notification(notification, filter_key) click to toggle source

@param notification @return [REXML::Element] a new XML node that corresponds to the specific example.

# File lib/rspec/formatters/yard.rb, line 71
def xml_node_for_notification(notification, filter_key)
  example = notification.example
  node = xml_node_for_example_group(example.example_group).add_element("div")
  node.add_element("p", {'class'=>'rspec_example_paragraph'}).text = example.description

  filter(illustrations_of(notification), filter_key).each{|illustration|
    node.add_element(node_for_illustration(illustration))
  }

  node
end