class GitCommitMailer::HTMLMailBodyFormatter

Constants

GITHUB_MARKUP_PATTERN_COMMIT
GITHUB_MARKUP_PATTERN_GH_ISSUE
GITHUB_MARKUP_PATTERN_ISSUE
GITHUB_MARKUP_PATTERN_MENTION
PATTERN_EMAIL
PATTERN_HTML_SPECIAL_CHARACTER

Public Instance Methods

format() click to toggle source
Calls superclass method
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 26
def format
  @indent_level = 0
  super
end

Private Instance Methods

border_styles() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 472
def border_styles
  {
    "border"      => "1px solid #aaa",
  }
end
commit_file_line_number_url(file, direction, line_number) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 780
def commit_file_line_number_url(file, direction, line_number)
  base_url = commit_url
  return nil if base_url.nil?

  case @mailer.repository_browser
  when "github"
    file_md5 = Digest::MD5.hexdigest(file)
    url = "#{base_url}#diff-#{file_md5}"
    if line_number
      url << ((direction == :from) ? "L" : "R")
      url << line_number.to_s
    end
    url
  else
    nil
  end
end
commit_file_url(file) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 764
def commit_file_url(file)
  case @mailer.repository_browser
  when "github"
    base_url = commit_url
    return nil if base_url.nil?
    file_md5 = Digest::MD5.hexdigest(file)
    "#{base_url}#diff-#{file_md5}"
  when "github-wiki"
    commit_file_url_github_wiki(file)
  when "gitlab-wiki"
    commit_file_url_gitlab_wiki(file)
  else
    nil
  end
end
dd(content) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 468
def dd(content)
  "#{dd_start}#{content}</dd>"
end
dd_start() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 461
def dd_start
  tag_start("dd",
            "style" => {
              "margin-left" => "#{dt_margin + 0.5}em",
            })
end
div_diff_section_start() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 493
def div_diff_section_start
  tag_start("div",
            "class" => "diff-section",
            "style" => {
              "clear" => "both",
            })
end
div_diff_start() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 501
def div_diff_start
  tag_start("div",
            "class" => "diff",
            "style" => {
              "margin-left"  => "1em",
              "margin-right" => "1em",
            })
end
dl_start() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 436
def dl_start
  tag_start("dl",
            "style" => {
              "margin-left" => "2em",
              "line-height" => "1.5",
            })
end
dt(content) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 448
def dt(content)
  tag("dt",
      {
        "style" => {
          "clear"       => "both",
          "float"       => "left",
          "width"       => "#{dt_margin}em",
          "font-weight" => "bold",
        },
      },
      content)
end
dt_margin() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 444
def dt_margin
  8
end
flush_content_lines(column, lines) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 220
def flush_content_lines(column, lines)
  return if lines.empty?

  added_lines = []
  deleted_lines = []
  lines.each do |type, line|
    if type == :added
      added_lines << line
    else
      deleted_lines << line
    end
  end

  if added_lines.size == deleted_lines.size
    nth_added = 0
    nth_deleted = 0
    lines.each do |type, line|
      if type == :added
        deleted_line = deleted_lines[nth_added]
        formatted_added_line = format_added_words(line, deleted_line)
        column << span_diff_added(formatted_added_line) << "\n"
        nth_added += 1
      else
        added_line = added_lines[nth_deleted]
        formatted_deleted_line = format_deleted_words(line, added_line)
        column << span_diff_deleted(formatted_deleted_line) << "\n"
        nth_deleted += 1
      end
    end
  else
    lines.each do |type, line|
      if type == :added
        column << span_diff_added(h(line)) << "\n"
      else
        column << span_diff_deleted(h(line)) << "\n"
      end
    end
  end
  lines.clear
end
format_added_words(added_line, deleted_line) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 292
def format_added_words(added_line, deleted_line)
  format_changed_words(added_line, deleted_line) do |chars|
    span_diff_added_word(chars)
  end
end
format_body_columns(diff) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 170
def format_body_columns(diff)
  from_line_column = ""
  to_line_column = ""
  content_column = ""
  content_lines = []

  file_path = diff.file_path
  diff.changes.each do |type, line_number, line|
    case type
    when :hunk_header
      from_line_number, to_line_number = line_number
      from_line_column << span_line_number_hunk_header(file_path, :from,
                                                       from_line_number)
      to_line_column << span_line_number_hunk_header(file_path, :to,
                                                     to_line_number)

      flush_content_lines(content_column, content_lines)
      case line
      when /\A(@@[\s0-9\-+,]+@@\s*)(.+)(\s*)\z/
        hunk_info = $1
        context = $2
        formatted_line = h(hunk_info) + span_diff_context(h(context))
      else
        formatted_line = h(line)
      end
      content_column << span_diff_hunk_header(formatted_line) << "\n"
    when :added
      from_line_column << span_line_number_nothing
      to_line_column << span_line_number_added(file_path, line_number)
      content_lines << [:added, line]
    when :deleted
      from_line_column << span_line_number_deleted(file_path, line_number)
      to_line_column << span_line_number_nothing
      content_lines << [:deleted, line]
    when :not_changed
      from_line_number, to_line_number = line_number
      from_line_column << span_line_number_not_changed(file_path, :from,
                                                       from_line_number)
      to_line_column << span_line_number_not_changed(file_path, :to,
                                                     to_line_number)
      flush_content_lines(content_column, content_lines)
      content_column << span_diff_not_changed(h(line)) << "\n"
    end
    from_line_column << "\n"
    to_line_column << "\n"
  end
  flush_content_lines(content_column, content_lines)
  [from_line_column, to_line_column, content_column]
end
format_changed_words(from_line, to_line, &formatter) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 261
def format_changed_words(from_line, to_line, &formatter)
  line = h(from_line[0, 1])
  changed_chars = ""

  flush_changed_chars = lambda do
    unless changed_chars.empty?
      line << formatter.call(h(changed_chars))
      changed_chars.clear
    end
  end

  Diff::LCS.sdiff(from_line[1..-1], to_line[1..-1]).each do |diff|
    action, from, _to = *diff
    _from_nth, from_char = from
    next if from_char.nil?

    case action
    when "="
      flush_changed_chars.call
      line << h(from_char)
    when "!", "-"
      changed_chars << from_char
    when "+"
      flush_changed_chars.call
    end
  end
  flush_changed_chars.call

  line
end
format_deleted_words(deleted_line, added_line) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 298
def format_deleted_words(deleted_line, added_line)
  format_changed_words(deleted_line, added_line) do |chars|
    span_diff_deleted_word(chars)
  end
end
format_diff(diff) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 127
def format_diff(diff)
  header_column = format_header_column(diff)
  from_line_column, to_line_column, content_column =
    format_body_columns(diff)

  table_diff do
    head = tag("thead") do
      tr_diff_header do
        tag("td", {"colspan" => "3"}) do
          pre_column(header_column)
        end
      end
    end

    body = tag("tbody") do
      tag("tr") do
        [
          th_diff_line_number {pre_column(from_line_column)},
          th_diff_line_number {pre_column(to_line_column)},
          td_diff_content     {pre_column(content_column)},
        ]
      end
    end

    [head, body]
  end
end
format_diffs() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 114
def format_diffs
  return "" if @info.diffs.empty?

  formatted_diff = ""
  formatted_diff << "    #{div_diff_section_start}\n"
  @indent_level = 3
  @info.diffs.each do |diff|
    formatted_diff << "#{format_diff(diff)}\n"
  end
  formatted_diff << "    </div>\n"
  formatted_diff
end
format_file(file) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 105
def format_file(file)
  content = h(file)
  url = commit_file_url(file)
  if url
    content = tag("a", {"href" => url}, content)
  end
  content
end
format_files(title, items) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 83
def format_files(title, items)
  return "" if items.empty?

  formatted_files = ""
  formatted_files << "      #{dt(h(title) + ' files')}\n"
  formatted_files << "      #{dd_start}\n"
  formatted_files << "        <ul>\n"
  items.each do |item_name, new_item_name|
    if new_item_name.nil?
      formatted_files << "          <li>#{format_file(item_name)}</li>\n"
    else
      formatted_files << "          <li>\n"
      formatted_files << "            #{format_file(new_item_name)}<br>\n"
      formatted_files << "            (from #{item_name})\n"
      formatted_files << "          </li>\n"
    end
  end
  formatted_files << "        </ul>\n"
  formatted_files << "      </dd>\n"
  formatted_files
end
format_header_column(diff) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 155
def format_header_column(diff)
  header_column = ""
  diff.format_header.each_line do |line|
    line = line.chomp
    case line
    when /^=/
      header_column << span_diff_header_mark(h(line))
    else
      header_column << span_diff_header(h(line))
    end
    header_column << "\n"
  end
  header_column
end
format_message(message) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 304
def format_message(message)
  message = message.strip
  case @mailer.repository_browser
  when "github"
    format_message_github(message)
  else
    h(message)
  end
end
format_message_github(message) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 320
def format_message_github(message)
  message.gsub(/
                 #{PATTERN_HTML_SPECIAL_CHARACTER}|
                 #{PATTERN_EMAIL}|
                 #{GITHUB_MARKUP_PATTERN_GH_ISSUE}|
                 #{GITHUB_MARKUP_PATTERN_ISSUE}|
                 #{GITHUB_MARKUP_PATTERN_COMMIT}|
                 #{GITHUB_MARKUP_PATTERN_MENTION}
               /x) do |matched|
    case matched
    when /\A#{PATTERN_HTML_SPECIAL_CHARACTER}\z/
      h(matched)
    when /\A#{PATTERN_EMAIL}\z/
      h(matched)
    when /\A#{GITHUB_MARKUP_PATTERN_GH_ISSUE}\z/
      issue_number = matched.gsub(/\AGH-/, "")
      tag("a",
          {
            "href" => github_issue_url(issue_number),
          },
          h(matched))
    when /\A#{GITHUB_MARKUP_PATTERN_ISSUE}\z/
      issue_number = matched.gsub(/\A\#/, "")
      tag("a",
          {
            "href" => github_issue_url(issue_number),
          },
          h(matched))
    when /\A#{GITHUB_MARKUP_PATTERN_COMMIT}\z/
      revision = matched
      tag("a",
          {
            "href" => commit_url_github(revision),
          },
          h(matched))
    when /\A#{GITHUB_MARKUP_PATTERN_MENTION}\z/
      user_name = matched.gsub(/\A@/, "")
      tag("a",
          {
            "href" => user_url_github(user_name),
          },
          h(matched))
    else
      h(matched)
    end
  end
end
format_revision() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 72
def format_revision
  revision = @info.revision
  url = commit_url
  if url
    formatted_revision = tag("a", {"href" => url}, h(revision))
  else
    formatted_revision = h(revision)
  end
  formatted_revision
end
github_issue_url(id) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 368
def github_issue_url(id)
  "#{@mailer.github_base_url}/#{@mailer.github_user}/#{@mailer.github_repository}/issues/#{id}"
end
pre(content, styles={}) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 478
def pre(content, styles={})
  font_families = [
    "Consolas", "Menlo", "\"Liberation Mono\"",
    "Courier", "monospace"
  ]
  pre_styles = {
    "font-family" => font_families.join(", "),
    "line-height" => "1.2",
    "padding"     => "0.5em",
    "width"       => "auto",
  }
  pre_styles = pre_styles.merge(border_styles)
  tag("pre", {"style" => pre_styles.merge(styles)}, content)
end
pre_column(column) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 548
def pre_column(column)
  pre(column,
      "white-space" => "normal",
      "margin" => "0",
      "border" => "0")
end
span_added_styles() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 583
def span_added_styles
  {
    "background-color" => "#eaffea",
    "color"            => "#000000",
  }
end
span_added_word_styles() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 590
def span_added_word_styles
  {
    "background-color" => "#a6f3a6",
    "color"            => "#000000",
  }
end
span_common_styles() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 555
def span_common_styles
  {
    "white-space" => "pre",
    "display"     => "block",
  }
end
span_context_styles() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 562
def span_context_styles
  {
    "background-color" => "#ffffaa",
    "color"            => "#000000",
  }
end
span_deleted_styles() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 569
def span_deleted_styles
  {
    "background-color" => "#ffecec",
    "color"            => "#000000",
  }
end
span_deleted_word_styles() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 576
def span_deleted_word_styles
  {
    "background-color" => "#f8cbcb",
    "color"            => "#000000",
  }
end
span_diff_added(content) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 737
def span_diff_added(content)
  tag("span",
      {
        "class" => "diff-added",
        "style" => span_diff_styles.merge(span_added_styles),
      },
      content)
end
span_diff_added_word(content) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 746
def span_diff_added_word(content)
  tag("span",
      {
        "class" => "diff-added-word",
        "style" => span_added_word_styles,
      },
      content)
end
span_diff_context(content) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 710
def span_diff_context(content)
  tag("span",
      {
        "class" => "diff-context",
        "style" => span_context_styles,
      },
      content)
end
span_diff_deleted(content) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 719
def span_diff_deleted(content)
  tag("span",
      {
        "class" => "diff-deleted",
        "style" => span_diff_styles.merge(span_deleted_styles),
      },
      content)
end
span_diff_deleted_word(content) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 728
def span_diff_deleted_word(content)
  tag("span",
      {
        "class" => "diff-deleted-word",
        "style" => span_deleted_word_styles,
      },
      content)
end
span_diff_header(content) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 683
def span_diff_header(content)
  tag("span",
      {
        "class" => "diff-header",
        "style" => span_diff_metadata_styles,
      },
      content)
end
span_diff_header_mark(content) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 692
def span_diff_header_mark(content)
  tag("span",
      {
        "class" => "diff-header-mark",
        "style" => span_diff_metadata_styles,
      },
      content)
end
span_diff_hunk_header(content) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 701
def span_diff_hunk_header(content)
  tag("span",
      {
        "class" => "diff-hunk-header",
        "style" => span_diff_metadata_styles,
      },
      content)
end
span_diff_metadata_styles() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 675
def span_diff_metadata_styles
  styles = {
    "background-color" => "#eaf2f5",
    "color"            => "#999999",
  }
  span_diff_styles.merge(styles)
end
span_diff_not_changed(content) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 755
def span_diff_not_changed(content)
  tag("span",
      {
        "class" => "diff-not-changed",
        "style" => span_diff_styles,
      },
      content)
end
span_diff_styles() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 671
def span_diff_styles
  span_common_styles
end
span_line_number_added(file_path, line_number) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 643
def span_line_number_added(file_path, line_number)
  content = h(line_number.to_s)
  url = commit_file_line_number_url(file_path, :to, line_number)
  if url
    content = tag("a", {"href" => url}, content)
  end
  tag("span",
      {
        "class" => "diff-line-number-added",
        "style" => span_line_number_styles.merge(span_added_styles),
      },
      content)
end
span_line_number_deleted(file_path, line_number) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 629
def span_line_number_deleted(file_path, line_number)
  content = h(line_number.to_s)
  url = commit_file_line_number_url(file_path, :from, line_number)
  if url
    content = tag("a", {"href" => url}, content)
  end
  tag("span",
      {
        "class" => "diff-line-number-deleted",
        "style" => span_line_number_styles.merge(span_deleted_styles),
      },
      content)
end
span_line_number_hunk_header(file_path, direction, offset) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 610
def span_line_number_hunk_header(file_path, direction, offset)
  content = "..."
  if offset <= 1
    offset_omitted = nil
  else
    offset_omitted = offset - 1
  end
  url = commit_file_line_number_url(file_path, direction, offset_omitted)
  if url
    content = tag("a", {"href" => url}, content)
  end
  tag("span",
      {
        "class" => "diff-line-number-hunk-header",
        "style" => span_line_number_styles,
      },
      content)
end
span_line_number_not_changed(file_path, direction, line_number) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 657
def span_line_number_not_changed(file_path, direction, line_number)
  content = h(line_number.to_s)
  url = commit_file_line_number_url(file_path, direction, line_number)
  if url
    content = tag("a", {"href" => url}, content)
  end
  tag("span",
      {
        "class" => "diff-line-number-not-changed",
        "style" => span_line_number_styles,
      },
      content)
end
span_line_number_nothing() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 601
def span_line_number_nothing
  tag("span",
      {
        "class" => "diff-line-number-nothing",
        "style" => span_line_number_styles,
      },
      "&nbsp;")
end
span_line_number_styles() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 597
def span_line_number_styles
  span_common_styles
end
table_diff(&block) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 510
def table_diff(&block)
  styles = {
    "border-collapse" => "collapse",
  }
  tag("table",
      {
        "style" => border_styles.merge(styles),
      },
      &block)
end
tag(name, attributes={}, content=nil) { |content| ... } click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 403
def tag(name, attributes={}, content=nil, &block)
  block_used = false
  if content.nil? and block_given?
    @indent_level += 1
    if block.arity == 1
      content = []
      yield(content)
    else
      content = yield
    end
    @indent_level -= 1
    block_used = true
  end
  content ||= ""
  if content.is_a?(Array)
    if block_used
      separator = "\n"
    else
      separator = ""
    end
    content = content.join(separator)
  end

  formatted_tag = ""
  formatted_tag << "  " * @indent_level if block_used
  formatted_tag << tag_start(name, attributes)
  formatted_tag << "\n" if block_used
  formatted_tag << content
  formatted_tag << "\n" + ("  " * @indent_level) if block_used
  formatted_tag << "</#{name}>"
  formatted_tag
end
tag_start(name, attributes) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 376
def tag_start(name, attributes)
  start_tag = "<#{name}"
  unless attributes.empty?
    sorted_attributes = attributes.sort_by do |key, value|
      key
    end
    formatted_attributes = sorted_attributes.collect do |key, value|
      if value.is_a?(Hash)
        sorted_value = value.sort_by do |value_key, value_value|
          value_key
        end
        value = sorted_value.collect do |value_key, value_value|
          "#{value_key}: #{value_value}"
        end
      end
      if value.is_a?(Array)
        value = value.sort.join("; ")
      end
      "#{h(key)}=\"#{h(value)}\""
    end
    formatted_attributes = formatted_attributes.join(" ")
    start_tag << " #{formatted_attributes}"
  end
  start_tag << ">"
  start_tag
end
td_diff_content(&block) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 539
def td_diff_content(&block)
  tag("td",
      {
        "class" => "diff-content",
        "style" => border_styles,
      },
      &block)
end
template() click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 32
    def template
      <<-TEMPLATE
<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <%= dl_start %>
      <%= dt("Author") %>
      <%= dd(h("\#{@info.author_name} <\#{@info.author_email}>")) %>
      <%= dt("Date") %>
      <%= dd(h(@mailer.format_time(@info.date))) %>
      <%= dt("New Revision") %>
      <%= dd(format_revision) %>
<% unless @info.merge_messages.empty? %>
      <%= dt("Merge") %>
      <%= dd_start %>
        <ul>
<%   @info.merge_messages.each do |message| %>
          <li><%= format_message(message) %></li>
<%   end %>
        </ul>
      </dd>
<% end %>
      <%= dt("Message") %>
      <%= dd(pre(format_message(@info.summary))) %>
<%= format_files("Added",        @info.added_files) %>
<%= format_files("Copied",       @info.copied_files) %>
<%= format_files("Removed",      @info.deleted_files) %>
<%= format_files("Modified",     @info.updated_files) %>
<%= format_files("Renamed",      @info.renamed_files) %>
<%= format_files("Type Changed", @info.type_changed_files) %>
    </dl>

<%= format_diffs %>
  </body>
</html>
      TEMPLATE
    end
th_diff_line_number(&block) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 530
def th_diff_line_number(&block)
  tag("th",
      {
        "class" => "diff-line-number",
        "style" => border_styles,
      },
      &block)
end
tr_diff_header(&block) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 521
def tr_diff_header(&block)
  tag("tr",
      {
        "class" => "diff-header",
        "style" => border_styles,
      },
      &block)
end
user_url_github(name) click to toggle source
# File lib/git-commit-mailer/html-mail-body-formatter.rb, line 372
def user_url_github(name)
  "#{@mailer.github_base_url}/#{name}"
end