Skip to content

Commit b039a16

Browse files
committed
GFM refactor: Move the actual parsing to a class under the Gitlab module
1 parent e31a9dd commit b039a16

File tree

2 files changed

+101
-59
lines changed

2 files changed

+101
-59
lines changed
Lines changed: 3 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,4 @@
11
module GitlabMarkdownHelper
2-
REFERENCE_PATTERN = %r{
3-
([^\w&;])? # Prefix (1)
4-
( # Reference (2)
5-
@([\w\._]+) | # User name (3)
6-
[#!$](\d+) | # Issue/MR/Snippet ID (4)
7-
[\h]{6,40} # Commit ID (2)
8-
)
9-
([^\w&;])? # Suffix (5)
10-
}x.freeze
11-
122
def gfm(text, html_options = {})
133
return text if text.nil?
144
return text if @project.nil?
@@ -22,21 +12,10 @@ def gfm(text, html_options = {})
2212
"{gfm-extraction-#{md5}}"
2313
end
2414

25-
text.gsub!(REFERENCE_PATTERN) do |match|
26-
vals = {
27-
prefix: $1,
28-
reference: $2,
29-
user_name: $3,
30-
reference_id: $4,
31-
suffix: $5
32-
}
15+
# TODO: add popups with additional information
3316

34-
if ref_link = reference_link(vals, html_options)
35-
sprintf('%s%s%s', vals[:prefix], ref_link, vals[:suffix])
36-
else
37-
match
38-
end
39-
end
17+
parser = Gitlab::Markdown.new(@project, html_options)
18+
text = parser.parse(text)
4019

4120
# Insert pre block extractions
4221
text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
@@ -71,39 +50,4 @@ def markdown(text)
7150

7251
@__renderer.render(text).html_safe
7352
end
74-
75-
private
76-
77-
def reference_link(vals, html_options)
78-
# TODO: add popups with additional information
79-
case vals[:reference]
80-
81-
# team member: @foo
82-
when /^@/
83-
user = @project.users.where(name: vals[:user_name]).first
84-
member = @project.users_projects.where(user_id: user).first if user
85-
link_to("@#{user.name}", project_team_member_path(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member
86-
87-
# issue: #123
88-
when /^#/
89-
issue = @project.issues.where(id: vals[:reference_id]).first
90-
link_to("##{issue.id}", project_issue_path(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}")) if issue
91-
92-
# merge request: !123
93-
when /^!/
94-
merge_request = @project.merge_requests.where(id: vals[:reference_id]).first
95-
link_to("!#{merge_request.id}", project_merge_request_path(@project, merge_request), html_options.merge(title: "Merge Request: #{merge_request.title}", class: "gfm gfm-merge_request #{html_options[:class]}")) if merge_request
96-
97-
# snippet: $123
98-
when /^\$/
99-
snippet = @project.snippets.where(id: vals[:reference_id]).first
100-
link_to("$#{snippet.id}", project_snippet_path(@project, snippet), html_options.merge(title: "Snippet: #{snippet.title}", class: "gfm gfm-snippet #{html_options[:class]}")) if snippet
101-
102-
# commit: 123456...
103-
when /^\h/
104-
commit = @project.commit(vals[:reference])
105-
link_to(vals[:reference], project_commit_path(@project, id: commit.id), html_options.merge(title: "Commit: #{commit.author_name} - #{CommitDecorator.new(commit).title}", class: "gfm gfm-commit #{html_options[:class]}")) if commit
106-
107-
end
108-
end
10953
end

lib/gitlab/markdown.rb

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
module Gitlab
2+
# Custom parsing for Gitlab-flavored Markdown
3+
#
4+
# Examples
5+
#
6+
# >> m = Markdown.new(...)
7+
#
8+
# >> m.parse("Hey @david, can you fix this?")
9+
# => "Hey <a href="/gitlab/team_members/1">@david</a>, can you fix this?"
10+
#
11+
# >> m.parse("Commit 35d5f7c closes #1234")
12+
# => "Commit <a href="/gitlab/commits/35d5f7c">35d5f7c</a> closes <a href="/gitlab/issues/1234">#1234</a>"
13+
class Markdown
14+
include Rails.application.routes.url_helpers
15+
include ActionView::Helpers
16+
17+
REFERENCE_PATTERN = %r{
18+
([^\w&;])? # Prefix (1)
19+
( # Reference (2)
20+
@([\w\._]+) # User name (3)
21+
|[#!$](\d+) # Issue/MR/Snippet ID (4)
22+
|([\h]{6,40}) # Commit ID (5)
23+
)
24+
([^\w&;])? # Suffix (6)
25+
}x.freeze
26+
27+
attr_reader :html_options
28+
29+
def initialize(project, html_options = {})
30+
@project = project
31+
@html_options = html_options
32+
end
33+
34+
def parse(text)
35+
text.gsub(REFERENCE_PATTERN) do |match|
36+
prefix = $1 || ''
37+
reference = $2
38+
identifier = $3 || $4 || $5
39+
suffix = $6 || ''
40+
41+
if ref_link = reference_link(reference, identifier)
42+
prefix + ref_link + suffix
43+
else
44+
match
45+
end
46+
end
47+
end
48+
49+
private
50+
51+
# Private: Dispatches to a dedicated processing method based on reference
52+
#
53+
# reference - Object reference ("@1234", "!567", etc.)
54+
# identifier - Object identifier (Issue ID, SHA hash, etc.)
55+
#
56+
# Returns string rendered by the processing method
57+
def reference_link(reference, identifier)
58+
case reference
59+
when /^@/ then reference_user(identifier)
60+
when /^#/ then reference_issue(identifier)
61+
when /^!/ then reference_merge_request(identifier)
62+
when /^\$/ then reference_snippet(identifier)
63+
when /^\h/ then reference_commit(identifier)
64+
end
65+
end
66+
67+
def reference_user(identifier)
68+
if user = @project.users.where(name: identifier).first
69+
member = @project.users_projects.where(user_id: user).first
70+
link_to("@#{user.name}", project_team_member_path(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member
71+
end
72+
end
73+
74+
def reference_issue(identifier)
75+
if issue = @project.issues.where(id: identifier).first
76+
link_to("##{issue.id}", project_issue_path(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}"))
77+
end
78+
end
79+
80+
def reference_merge_request(identifier)
81+
if merge_request = @project.merge_requests.where(id: identifier).first
82+
link_to("!#{merge_request.id}", project_merge_request_path(@project, merge_request), html_options.merge(title: "Merge Request: #{merge_request.title}", class: "gfm gfm-merge_request #{html_options[:class]}"))
83+
end
84+
end
85+
86+
def reference_snippet(identifier)
87+
if snippet = @project.snippets.where(id: identifier).first
88+
link_to("$#{snippet.id}", project_snippet_path(@project, snippet), html_options.merge(title: "Snippet: #{snippet.title}", class: "gfm gfm-snippet #{html_options[:class]}"))
89+
end
90+
end
91+
92+
def reference_commit(identifier)
93+
if commit = @project.commit(identifier)
94+
link_to(identifier, project_commit_path(@project, id: commit.id), html_options.merge(title: "Commit: #{commit.author_name} - #{CommitDecorator.new(commit).title}", class: "gfm gfm-commit #{html_options[:class]}"))
95+
end
96+
end
97+
end
98+
end

0 commit comments

Comments
 (0)