Class: HTML::Pipeline::IssueReferenceFilter

Inherits:
Filter
  • Object
show all
Defined in:
lib/html/pipeline/issue_reference_filter.rb

Overview

identify github issue references using a customizable filter pattern

Constant Summary collapse

REPOSITORY_NAME =
%r{[a-z0-9][a-z0-9\-]*/[a-z0-9][a-z0-9\-_]*}ix.freeze
SHORT_PATTERN =

Match references of the form:

  • #123

  • codetree/feedback#123

  • GH-123

See rubular.com/r/zM9MJl8SOC

/
  (?<=^|\W)                    # beginning of string or non-word char
  (
    (?:(#{REPOSITORY_NAME})?    # repository name (optional)
    \#|(?:GH\-))(\d+)           # issue number
  )
  (?=
    \.+[ \t\W]|               # dots followed by space or non-word character
    \.+$|                     # dots at end of line
    [^0-9a-zA-Z_.]|           # non-word character except dot
    $                         # end of line
  )
/ix.freeze
URL_PATTERN =
%r{
  (?:^|\W)                    # beginning of string or non-word char
  https://github.com/
  (#{REPOSITORY_NAME})        # repository name
  /(?:issues|pulls)/
  (\d+)                       # issue number
  (?=
    \.+[ \t\W]|               # dots followed by space or non-word character
    \.+$|                     # dots at end of line
    [^0-9a-zA-Z_.]|           # non-word character except dot
    $                         # end of line
  )
}ix.freeze
IGNORE_PARENTS =

Don’t look for mentions in text nodes that are children of these elements

%w[pre code a style].to_set

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.issue_references_in(text) ⇒ Object



54
55
56
57
58
59
60
# File 'lib/html/pipeline/issue_reference_filter.rb', line 54

def self.issue_references_in(text)
  text.gsub SHORT_PATTERN do |match|
    repository = Regexp.last_match(2)
    number = Regexp.last_match(3)
    yield match, repository, number
  end
end

Instance Method Details

#callObject



66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/html/pipeline/issue_reference_filter.rb', line 66

def call
  doc.search('.//text()').each do |node|
    content = node.to_html
    next if has_ancestor?(node, IGNORE_PARENTS)

    html = issue_reference_filter(content, base_url, default_repo)
    next if html == content

    node.replace(html)
  end

  doc
end

#default_repoObject



62
63
64
# File 'lib/html/pipeline/issue_reference_filter.rb', line 62

def default_repo
  context[:repository]
end

#issue_reference_filter(text, _base_url = '/', default_repo = nil) ⇒ Object



80
81
82
83
84
85
# File 'lib/html/pipeline/issue_reference_filter.rb', line 80

def issue_reference_filter(text, _base_url = '/', default_repo = nil)
  self.class.issue_references_in(text) do |match, referenced_repo, number|
    repo = referenced_repo || default_repo
    repo ? link_to_issue(repo, number, default_repo) : match
  end
end


87
88
89
90
91
92
93
94
95
96
# File 'lib/html/pipeline/issue_reference_filter.rb', line 87

def link_to_issue(repo, number, default_repo)
  content = "##{number}"
  content = "#{repo}#{content}" if repo != default_repo

  url = base_url.dup
  url << '/' unless url =~ %r{[/~]\z}
  url << "#{repo}/issues/#{number}"

  "<a href='#{url}' class='issue-reference'>#{content}</a>"
end