class Roadie::Document

The main entry point for Roadie. A document represents a working unit and is built with the input HTML and the configuration options you need.

A Document must never be used from two threads at the same time. Reusing Documents is discouraged.

Stylesheets are added to the HTML from three different sources:

  1. Stylesheets inside the document ( +<style>+ elements)

  2. Stylesheets referenced by the DOM ( +<link>+ elements)

  3. The internal stylesheet (see {#add_css})

The internal stylesheet is used last and gets the highest priority. The rest is used in the same order as browsers are supposed to use them.

The execution methods are {#transform} and {#transform_partial}.

@attr [#call] before_transformation Callback to call just before {#transform}ation begins. Will be called with the parsed DOM tree and the {Document} instance. @attr [#call] after_transformation Callback to call just before {#transform}ation is completed. Will be called with the current DOM tree and the {Document} instance.

Constants

VALID_MODES

Attributes

after_transformation[RW]
asset_providers[R]
before_transformation[RW]
external_asset_providers[R]
html[R]
keep_uninlinable_css[RW]

Should CSS that cannot be inlined be kept in a new ‘<style>` element in `<head>`?

merge_media_queries[RW]

Merge media queries to increase performance and reduce email size if enabled. This will change specificity in some cases, like for example:

@media(max-width: 600px) { .col-6 { display: block; } }
@media(max-width: 400px) { .col-12 { display: inline-block; } }
@media(max-width: 600px) { .col-12 { display: block; } }

will become

@media(max-width: 600px) { .col-6 { display: block; } .col-12 { display: block; } }
@media(max-width: 400px) { .col-12 { display: inline-block; } }

which would change the styling on the page

mode[R]

The mode to generate markup in. Valid values are ‘:html` (default) and `:xhtml`.

serialization_options[R]

Integer representing a bitmap set of options used by Nokogiri during serialization. For the complete set of available options look into Nokogiri::XML::Node::SaveOptions.

url_options[RW]

URL options. If none are given no URL rewriting will take place. @see UrlGenerator#initialize

Public Class Methods

new(html) click to toggle source

@param [String] html the input HTML

# File lib/roadie/document.rb, line 53
def initialize(html)
  @keep_uninlinable_css = true
  @merge_media_queries = true
  @serialization_options =
    Nokogiri::XML::Node::SaveOptions::NO_DECLARATION |
    Nokogiri::XML::Node::SaveOptions::NO_EMPTY_TAGS
  @html = html
  @asset_providers = ProviderList.wrap(FilesystemProvider.new)
  @external_asset_providers = ProviderList.empty
  @css = +""
  @mode = :html
end

Public Instance Methods

add_css(new_css) click to toggle source

Append additional CSS to the document’s internal stylesheet. @param [String] new_css

# File lib/roadie/document.rb, line 68
def add_css(new_css)
  @css << "\n\n" << new_css
end
asset_providers=(list) click to toggle source

Assign new normal asset providers. The supplied list will be wrapped in a {ProviderList} using {ProviderList.wrap}.

# File lib/roadie/document.rb, line 138
def asset_providers=(list)
  @asset_providers = ProviderList.wrap(list)
end
external_asset_providers=(list) click to toggle source

Assign new external asset providers. The supplied list will be wrapped in a {ProviderList} using {ProviderList.wrap}.

# File lib/roadie/document.rb, line 143
def external_asset_providers=(list)
  @external_asset_providers = ProviderList.wrap(list)
end
mode=(mode) click to toggle source

Change the mode. The mode affects how the resulting markup is generated.

Valid modes:

`:html` (default)
`:xhtml`
`:xml`
# File lib/roadie/document.rb, line 160
def mode=(mode)
  if VALID_MODES.include?(mode)
    @mode = mode
  else
    raise ArgumentError, "Invalid mode #{mode.inspect}. Valid modes are: #{VALID_MODES.inspect}"
  end
end
serialization_options=(options) click to toggle source

Integer representing a bitmap set of options used by Nokogiri during serialization. For the complete set of available options look into Nokogiri::XML::Node::SaveOptions. (To change the mode in which the document is generated use {#mode=} however.)

# File lib/roadie/document.rb, line 150
def serialization_options=(options)
  @serialization_options = options || 0
end
transform() click to toggle source

Transform the input HTML as a full document and returns the processed HTML.

Before the transformation begins, the {#before_transformation} callback will be called with the parsed HTML tree and the {Document} instance, and after all work is complete the {#after_transformation} callback will be invoked in the same way.

Most of the work is delegated to other classes. A list of them can be seen below.

@see MarkupImprover MarkupImprover (improves the markup of the DOM) @see Inliner Inliner (inlines the stylesheets) @see UrlRewriter UrlRewriter (rewrites URLs and makes them absolute) @see transform_partial Transforms partial documents (fragments)

@return [String] the transformed HTML

# File lib/roadie/document.rb, line 89
def transform
  dom = Nokogiri::HTML.parse html

  callback before_transformation, dom

  improve dom
  inline dom, keep_uninlinable_in: :head
  rewrite_urls dom

  callback after_transformation, dom

  remove_ignore_markers dom
  serialize_document dom
end
transform_partial() click to toggle source

Transform the input HTML as a HTML fragment/partial and returns the processed HTML.

Before the transformation begins, the {#before_transformation} callback will be called with the parsed HTML tree and the {Document} instance, and after all work is complete the {#after_transformation} callback will be invoked in the same way.

The main difference between this and {#transform} is that this does not treat the HTML as a full document and does not try to fix it by adding doctypes, {<head>} elements, etc.

Most of the work is delegated to other classes. A list of them can be seen below.

@see Inliner Inliner (inlines the stylesheets) @see UrlRewriter UrlRewriter (rewrites URLs and makes them absolute) @see transform Transforms full documents

@return [String] the transformed HTML

# File lib/roadie/document.rb, line 124
def transform_partial
  dom = Nokogiri::HTML.fragment html

  callback before_transformation, dom

  inline dom, keep_uninlinable_in: :root
  rewrite_urls dom

  callback after_transformation, dom

  serialize_document dom
end

Private Instance Methods

callback(callable, dom) click to toggle source
# File lib/roadie/document.rb, line 215
def callback(callable, dom)
  if callable.respond_to?(:call)
    callable.call(dom, self)
  end
end
improve(dom) click to toggle source
# File lib/roadie/document.rb, line 177
def improve(dom)
  MarkupImprover.new(dom, html).improve
end
inline(dom, options = {}) click to toggle source
# File lib/roadie/document.rb, line 181
def inline(dom, options = {})
  keep_uninlinable_in = options.fetch(:keep_uninlinable_in)
  dom_stylesheets = AssetScanner.new(dom, asset_providers, external_asset_providers).extract_css
  Inliner.new(dom_stylesheets + [stylesheet], dom).inline(
    keep_uninlinable_css: keep_uninlinable_css,
    keep_uninlinable_in: keep_uninlinable_in,
    merge_media_queries: merge_media_queries
  )
end
make_url_rewriter() click to toggle source
# File lib/roadie/document.rb, line 207
def make_url_rewriter
  if url_options
    UrlRewriter.new(UrlGenerator.new(url_options))
  else
    NullUrlRewriter.new
  end
end
remove_ignore_markers(dom) click to toggle source
# File lib/roadie/document.rb, line 221
def remove_ignore_markers(dom)
  dom.css("[data-roadie-ignore]").each do |node|
    node.remove_attribute "data-roadie-ignore"
  end
end
rewrite_urls(dom) click to toggle source
# File lib/roadie/document.rb, line 191
def rewrite_urls(dom)
  make_url_rewriter.transform_dom(dom)
end
serialize_document(dom) click to toggle source
# File lib/roadie/document.rb, line 195
def serialize_document(dom)
  # #dup is called since it fixed a few segfaults in certain versions of Nokogiri
  save_options = Nokogiri::XML::Node::SaveOptions
  format = {
    html: save_options::AS_HTML,
    xhtml: save_options::AS_XHTML,
    xml: save_options::AS_XML
  }.fetch(mode)

  dom.dup.to_html(save_with: (serialization_options | format))
end
stylesheet() click to toggle source
# File lib/roadie/document.rb, line 173
def stylesheet
  Stylesheet.new "(Document styles)", @css
end