gollum-lib 5.0.a.4-java → 5.0.5-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -1
- data/HISTORY.md +4 -0
- data/README.md +12 -7
- data/Rakefile +8 -7
- data/gemspec.rb +17 -10
- data/gollum-lib.gemspec +8 -6
- data/gollum-lib_java.gemspec +2 -2
- data/lib/gollum-lib.rb +9 -9
- data/lib/gollum-lib/blob_entry.rb +2 -8
- data/lib/gollum-lib/committer.rb +23 -61
- data/lib/gollum-lib/file.rb +105 -82
- data/lib/gollum-lib/file_view.rb +8 -4
- data/lib/gollum-lib/filter.rb +12 -0
- data/lib/gollum-lib/filter/code.rb +9 -13
- data/lib/gollum-lib/filter/critic_markup.rb +97 -0
- data/lib/gollum-lib/filter/emoji.rb +11 -8
- data/lib/gollum-lib/filter/macro.rb +5 -2
- data/lib/gollum-lib/filter/plantuml.rb +1 -1
- data/lib/gollum-lib/filter/remote_code.rb +3 -2
- data/lib/gollum-lib/filter/render.rb +25 -2
- data/lib/gollum-lib/filter/sanitize.rb +1 -8
- data/lib/gollum-lib/filter/tags.rb +57 -46
- data/lib/gollum-lib/filter/toc.rb +17 -21
- data/lib/gollum-lib/filter/yaml.rb +1 -1
- data/lib/gollum-lib/git_access.rb +0 -25
- data/lib/gollum-lib/helpers.rb +13 -3
- data/lib/gollum-lib/macro.rb +4 -0
- data/lib/gollum-lib/macro/audio.rb +9 -0
- data/lib/gollum-lib/macro/global_toc.rb +2 -1
- data/lib/gollum-lib/macro/navigation.rb +8 -6
- data/lib/gollum-lib/macro/note.rb +19 -0
- data/lib/gollum-lib/macro/octicon.rb +12 -0
- data/lib/gollum-lib/macro/series.rb +2 -2
- data/lib/gollum-lib/macro/warn.rb +11 -0
- data/lib/gollum-lib/markup.rb +17 -32
- data/lib/gollum-lib/markups.rb +13 -8
- data/lib/gollum-lib/page.rb +80 -166
- data/lib/gollum-lib/pagination.rb +7 -6
- data/lib/gollum-lib/redirects.rb +42 -0
- data/lib/gollum-lib/sanitization.rb +32 -357
- data/lib/gollum-lib/version.rb +1 -1
- data/lib/gollum-lib/wiki.rb +216 -404
- metadata +65 -27
- data/ROADMAP +0 -6
data/lib/gollum-lib/file.rb
CHANGED
@@ -2,55 +2,125 @@
|
|
2
2
|
|
3
3
|
module Gollum
|
4
4
|
class File
|
5
|
-
|
5
|
+
|
6
|
+
# Does the filesystem support reading symlinks?
|
7
|
+
FS_SUPPORT_SYMLINKS = !Gem.win_platform?
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
# For use with self.find: returns true if the given query corresponds to the in-repo path of the BlobEntry.
|
12
|
+
#
|
13
|
+
# query - The String path to match.
|
14
|
+
# entry - The BlobEntry to check against.
|
15
|
+
# global_match - (Not implemented for File, see Page.path_match)
|
16
|
+
# hyphened_tags - If true, replace spaces in match_path with hyphens.
|
17
|
+
# case_insensitive - If true, compare query and match_path case-insensitively
|
18
|
+
def path_match(query, entry, global_match = false, hyphened_tags = false, case_insensitive = false)
|
19
|
+
path_compare(query, ::File.join('/', entry.path), hyphened_tags, case_insensitive)
|
20
|
+
end
|
21
|
+
|
22
|
+
# For use with self.path_match: returns true if 'query' and 'match_path' match, strictly or taking account of the following parameters:
|
23
|
+
# hyphened_tags - If true, replace spaces in match_path with hyphens.
|
24
|
+
# case_insensitive - If true, compare query and match_path case-insensitively
|
25
|
+
def path_compare(query, match_path, hyphened_tags, case_insensitive)
|
26
|
+
if hyphened_tags
|
27
|
+
final_query = query.gsub(' ', '-')
|
28
|
+
final_match = match_path.gsub(' ', '-')
|
29
|
+
else
|
30
|
+
final_query = query
|
31
|
+
final_match = match_path
|
32
|
+
end
|
33
|
+
final_match.send(case_insensitive ? :casecmp? : :==, final_query)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Find a file in the given Gollum wiki.
|
38
|
+
#
|
39
|
+
# wiki - The wiki.
|
40
|
+
# path - The full String path.
|
41
|
+
# version - The String version ID to find.
|
42
|
+
# try_on_disk - If true, try to return just a reference to a file
|
43
|
+
# that exists on the disk.
|
44
|
+
# global_match - If true, find a File matching path's filename, but not it's directory (so anywhere in the repo)
|
45
|
+
#
|
46
|
+
# Returns a Gollum::File or nil if the file could not be found. Note
|
47
|
+
# that if you specify try_on_disk=true, you may or may not get a file
|
48
|
+
# for which on_disk? is actually true.
|
49
|
+
def self.find(wiki, path, version, try_on_disk = false, global_match = false)
|
50
|
+
map = wiki.tree_map_for(version.to_s)
|
51
|
+
|
52
|
+
query_path = Pathname.new(::File.join(['/', wiki.page_file_dir, path].compact)).cleanpath.to_s
|
53
|
+
query_path.sub!(/^\/\//, '/') if Gem.win_platform? # On Windows, Pathname#cleanpath will leave double slashes at the start of a path intact, so sub them out.
|
54
|
+
|
55
|
+
begin
|
56
|
+
entry = map.detect do |entry|
|
57
|
+
path_match(query_path, entry, global_match, wiki.hyphened_tag_lookup, wiki.case_insensitive_tag_lookup)
|
58
|
+
end
|
59
|
+
entry ? self.new(wiki, entry.blob(wiki.repo), entry.dir, version, try_on_disk) : nil
|
60
|
+
rescue Gollum::Git::NoSuchShaFound
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
end
|
6
64
|
|
7
65
|
# Public: Initialize a file.
|
8
66
|
#
|
9
|
-
# wiki - The Gollum::Wiki
|
67
|
+
# wiki - The Gollum::Wiki
|
68
|
+
# blob - The Gollum::Git::Blob
|
69
|
+
# path - The String path
|
70
|
+
# version - The String SHA or Gollum::Git::Commit version
|
71
|
+
# try_on_disk - If true, try to get an on disk reference for this file.
|
10
72
|
#
|
11
73
|
# Returns a newly initialized Gollum::File.
|
12
|
-
def initialize(wiki)
|
74
|
+
def initialize(wiki, blob, path, version, try_on_disk = false)
|
13
75
|
@wiki = wiki
|
14
|
-
@blob =
|
15
|
-
@path =
|
16
|
-
@
|
17
|
-
|
76
|
+
@blob = blob
|
77
|
+
@path = "#{path}/#{blob.name}"[1..-1]
|
78
|
+
@version = version.is_a?(Gollum::Git::Commit) ? version : @wiki.commit_for(version)
|
79
|
+
get_disk_reference if try_on_disk
|
18
80
|
end
|
19
81
|
|
20
|
-
# Public: The
|
82
|
+
# Public: The path of the page within the repo.
|
21
83
|
#
|
22
|
-
# Returns the String
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
84
|
+
# Returns the String path.
|
85
|
+
attr_reader :path
|
86
|
+
|
87
|
+
# Public: The Gollum::Git::Commit version of the file.
|
88
|
+
attr_accessor :version
|
28
89
|
|
29
|
-
# Public:
|
90
|
+
# Public: Whether the file can be read from disk.
|
91
|
+
attr_accessor :on_disk
|
92
|
+
|
93
|
+
# Public: The SHA hash identifying this page
|
30
94
|
#
|
31
95
|
# Returns the String SHA.
|
32
96
|
def sha
|
33
97
|
@blob && @blob.id
|
34
98
|
end
|
35
99
|
|
36
|
-
# Public: The
|
100
|
+
# Public: The on-disk filename of the page including extension.
|
37
101
|
#
|
38
|
-
# Returns the String
|
39
|
-
def
|
40
|
-
|
102
|
+
# Returns the String name.
|
103
|
+
def filename
|
104
|
+
@blob && @blob.name
|
41
105
|
end
|
106
|
+
alias :name :filename
|
42
107
|
|
43
|
-
# Public: The
|
108
|
+
# Public: The url path required to reach this file within the repo.
|
44
109
|
#
|
45
|
-
# Returns the String
|
46
|
-
def
|
47
|
-
|
48
|
-
@
|
110
|
+
# Returns the String url_path
|
111
|
+
def url_path
|
112
|
+
# Chop off the page_file_dir and first slash if necessary
|
113
|
+
@wiki.page_file_dir ? self.path[@wiki.page_file_dir.length+1..-1] : self.path
|
49
114
|
end
|
50
115
|
|
51
|
-
|
116
|
+
# Public: The url_path, but URL encoded.
|
117
|
+
#
|
118
|
+
# Returns the String url_path
|
119
|
+
def escaped_url_path
|
120
|
+
ERB::Util.url_encode(self.url_path).gsub('%2F', '/').force_encoding('utf-8')
|
121
|
+
end
|
52
122
|
|
53
|
-
# Public: The raw contents of the
|
123
|
+
# Public: The raw contents of the file.
|
54
124
|
#
|
55
125
|
# Returns the String data.
|
56
126
|
def raw_data
|
@@ -69,7 +139,7 @@ module Gollum
|
|
69
139
|
#
|
70
140
|
# Returns true if this is a pointer to an on-disk file
|
71
141
|
def on_disk?
|
72
|
-
|
142
|
+
!!@on_disk
|
73
143
|
end
|
74
144
|
|
75
145
|
# Public: The path to this file on disk
|
@@ -79,48 +149,29 @@ module Gollum
|
|
79
149
|
@on_disk_path
|
80
150
|
end
|
81
151
|
|
82
|
-
# Public: The Gollum::Git::Commit version of the file.
|
83
|
-
attr_accessor :version
|
84
|
-
|
85
|
-
# Public: The String path of the file.
|
86
|
-
attr_reader :path
|
87
|
-
|
88
152
|
# Public: The String mime type of the file.
|
89
153
|
def mime_type
|
90
154
|
@blob && @blob.mime_type
|
91
155
|
end
|
92
156
|
|
93
|
-
|
94
|
-
|
95
|
-
# blob - The Gollum::Git::Blob that contains the info.
|
96
|
-
# path - The String directory path of the file.
|
97
|
-
#
|
98
|
-
# Returns the populated Gollum::File.
|
99
|
-
def populate(blob, path = nil)
|
100
|
-
@blob = blob
|
101
|
-
@path = "#{path}/#{blob.name}"[1..-1]
|
102
|
-
@on_disk = false
|
103
|
-
@on_disk_path = nil
|
104
|
-
self
|
157
|
+
def self.protected_files
|
158
|
+
['custom.css', 'custom.js', '.redirects.gollum']
|
105
159
|
end
|
106
160
|
|
107
|
-
|
108
|
-
#
|
109
|
-
# Internal Methods
|
110
|
-
#
|
111
|
-
#########################################################################
|
161
|
+
private
|
112
162
|
|
113
163
|
# Return the file path to this file on disk, if available.
|
114
164
|
#
|
115
165
|
# Returns nil if the file isn't available on disk. This can occur if the
|
116
166
|
# repo is bare, if the commit isn't the HEAD, or if there are problems
|
117
167
|
# resolving symbolic links.
|
118
|
-
def get_disk_reference
|
168
|
+
def get_disk_reference
|
119
169
|
return false if @wiki.repo.bare
|
120
|
-
return false if
|
170
|
+
return false if @version.sha != @wiki.repo.head.commit.sha
|
171
|
+
return false if @blob.is_symlink && !FS_SUPPORT_SYMLINKS
|
121
172
|
|
122
173
|
# This will try to resolve symbolic links, as well
|
123
|
-
pathname = Pathname.new(::File.expand_path(::File.join(@wiki.repo.path, '..',
|
174
|
+
pathname = Pathname.new(::File.expand_path(::File.join(@wiki.repo.path, '..', @path)))
|
124
175
|
if pathname.symlink?
|
125
176
|
source = ::File.readlink(pathname.to_path)
|
126
177
|
realpath = ::File.join(::File.dirname(pathname.to_path), source)
|
@@ -129,36 +180,8 @@ module Gollum
|
|
129
180
|
else
|
130
181
|
@on_disk_path = pathname.to_path
|
131
182
|
end
|
132
|
-
true
|
183
|
+
@on_disk = true
|
133
184
|
end
|
134
185
|
|
135
|
-
# Find a file in the given Gollum repo.
|
136
|
-
#
|
137
|
-
# name - The full String path.
|
138
|
-
# version - The String version ID to find.
|
139
|
-
# try_on_disk - If true, try to return just a reference to a file
|
140
|
-
# that exists on the disk.
|
141
|
-
#
|
142
|
-
# Returns a Gollum::File or nil if the file could not be found. Note
|
143
|
-
# that if you specify try_on_disk=true, you may or may not get a file
|
144
|
-
# for which on_disk? is actually true.
|
145
|
-
def find(name, version, try_on_disk = false)
|
146
|
-
checked = name.downcase
|
147
|
-
map = @wiki.tree_map_for(version)
|
148
|
-
commit = version.is_a?(Gollum::Git::Commit) ? version : @wiki.commit_for(version)
|
149
|
-
|
150
|
-
if (result = map.detect { |entry| entry.path.downcase == checked })
|
151
|
-
@path = name
|
152
|
-
@version = commit
|
153
|
-
|
154
|
-
if try_on_disk && get_disk_reference(name, commit)
|
155
|
-
@on_disk = true
|
156
|
-
else
|
157
|
-
@blob = result.blob(@wiki.repo)
|
158
|
-
end
|
159
|
-
|
160
|
-
self
|
161
|
-
end
|
162
|
-
end
|
163
186
|
end
|
164
187
|
end
|
data/lib/gollum-lib/file_view.rb
CHANGED
@@ -10,12 +10,13 @@ module Gollum
|
|
10
10
|
# set pages to wiki.pages + wiki.files and show_all to true
|
11
11
|
def initialize(pages, options = {})
|
12
12
|
@pages = pages
|
13
|
+
@wiki = @pages.first ? @pages.first.wiki : nil
|
13
14
|
@show_all = options[:show_all] || false
|
14
15
|
@checked = options[:collapse_tree] ? '' : "checked"
|
15
16
|
end
|
16
17
|
|
17
18
|
def enclose_tree(string)
|
18
|
-
%Q(<ol class="tree">\n) + string + %Q(</ol>)
|
19
|
+
sanitize_html(%Q(<ol class="tree">\n) + string + %Q(</ol>))
|
19
20
|
end
|
20
21
|
|
21
22
|
def new_page(page)
|
@@ -96,7 +97,7 @@ module Gollum
|
|
96
97
|
</li>
|
97
98
|
HTML
|
98
99
|
|
99
|
-
return enclose_tree
|
100
|
+
return enclose_tree(html)
|
100
101
|
end
|
101
102
|
|
102
103
|
sorted_folders = []
|
@@ -153,8 +154,11 @@ module Gollum
|
|
153
154
|
changed = false
|
154
155
|
end
|
155
156
|
|
156
|
-
|
157
|
-
enclose_tree html
|
157
|
+
enclose_tree(html)
|
158
158
|
end # end render_files
|
159
|
+
|
160
|
+
def sanitize_html(data)
|
161
|
+
@wiki ? @wiki.sanitizer.clean(data) : data
|
162
|
+
end
|
159
163
|
end # end FileView class
|
160
164
|
end # end Gollum module
|
data/lib/gollum-lib/filter.rb
CHANGED
@@ -47,14 +47,21 @@ module Gollum
|
|
47
47
|
class Filter
|
48
48
|
include Gollum::Helpers
|
49
49
|
|
50
|
+
PLACEHOLDER_PATTERN = /%(\S+)%.+=\1=/
|
51
|
+
|
50
52
|
# Setup the object. Sets `@markup` to be the instance of Gollum::Markup that
|
51
53
|
# is running this filter chain, and sets `@map` to be an empty hash (for use
|
52
54
|
# in your extract/process operations).
|
55
|
+
|
53
56
|
def initialize(markup)
|
54
57
|
@markup = markup
|
55
58
|
@map = {}
|
59
|
+
@open_pattern = "%#{self.class.to_s.split('::').last}%"
|
60
|
+
@close_pattern = "=#{self.class.to_s.split('::').last}="
|
56
61
|
end
|
57
62
|
|
63
|
+
attr_reader :open_pattern, :close_pattern
|
64
|
+
|
58
65
|
def extract(data)
|
59
66
|
raise RuntimeError,
|
60
67
|
"#{self.class} has not implemented ##extract!"
|
@@ -66,6 +73,11 @@ module Gollum
|
|
66
73
|
end
|
67
74
|
|
68
75
|
protected
|
76
|
+
|
77
|
+
def sanitize(data)
|
78
|
+
@markup.wiki.sanitizer.clean(data, @markup.historical)
|
79
|
+
end
|
80
|
+
|
69
81
|
# Render a (presumably) non-fatal error as HTML
|
70
82
|
#
|
71
83
|
def html_error(message)
|
@@ -14,31 +14,27 @@ class Gollum::Filter::Code < Gollum::Filter
|
|
14
14
|
org_headers = %r{([ \t]*#\+HEADER[S]?:[^\r\n]*\n)*}
|
15
15
|
org_name = %r{([ \t]*#\+NAME:[^\r\n]*\n)?}
|
16
16
|
org_lang = %r{[ ]*([^\n \r]*)[ ]*[^\r\n]*}
|
17
|
-
org_begin = %r{[ \t]
|
18
|
-
org_end = %r{\n[ \t]*#\+END_SRC[ \t]*}
|
17
|
+
org_begin = %r{([ \t]*)#\+BEGIN_SRC#{org_lang}\r?\n}
|
18
|
+
org_end = %r{\r?\n[ \t]*#\+END_SRC[ \t\r]*}
|
19
19
|
data.gsub!(/^#{org_headers}#{org_name}#{org_begin}(.+?)#{org_end}$/mi) do
|
20
|
-
cache_codeblock(Regexp.last_match[
|
20
|
+
"#{Regexp.last_match[3]}#{cache_codeblock(Regexp.last_match[4], Regexp.last_match[5])}"
|
21
21
|
end
|
22
22
|
when :markdown
|
23
|
-
data.gsub!(/^([
|
23
|
+
data.gsub!(/^([ ]{0,3})(~~~+) ?([^\r\n]+)?\r?\n(.+?)\r?\n[ ]{0,3}(~~~+)[ \t\r]*$/m) do
|
24
24
|
m_indent = Regexp.last_match[1]
|
25
25
|
m_start = Regexp.last_match[2] # ~~~
|
26
26
|
m_lang = Regexp.last_match[3]
|
27
27
|
m_code = Regexp.last_match[4]
|
28
28
|
m_end = Regexp.last_match[5] # ~~~
|
29
|
-
#
|
30
|
-
next '' if
|
31
|
-
lang = m_lang ? m_lang.strip : nil
|
32
|
-
if lang
|
33
|
-
lang = lang.match(/\.([^}\s]+)/)
|
34
|
-
lang = lang[1] unless lang.nil?
|
35
|
-
end
|
29
|
+
# The closing code fence must be at least as long as the opening fence
|
30
|
+
next '' if m_end.length < m_start.length
|
31
|
+
lang = m_lang ? m_lang.strip.split.first : nil
|
36
32
|
"#{m_indent}#{cache_codeblock(lang, m_code, m_indent)}"
|
37
33
|
end
|
38
34
|
end
|
39
35
|
|
40
36
|
|
41
|
-
data.gsub!(/^([
|
37
|
+
data.gsub!(/^([ ]{0,3})``` ?([^\r\n]+)?\r?\n(.+?)\r?\n[ ]{0,3}```[ \t]*\r?$/m) do
|
42
38
|
"#{Regexp.last_match[1]}#{cache_codeblock(Regexp.last_match[2].to_s.strip, Regexp.last_match[3], Regexp.last_match[1])}" # print the SHA1 ID with the proper indentation
|
43
39
|
end
|
44
40
|
data
|
@@ -133,7 +129,7 @@ class Gollum::Filter::Code < Gollum::Filter
|
|
133
129
|
|
134
130
|
def cache_codeblock(language, code, indent = "")
|
135
131
|
language = language.to_s.empty? ? nil : language
|
136
|
-
id = Digest::SHA1.hexdigest("#{language}.#{code}")
|
132
|
+
id = "#{open_pattern}#{Digest::SHA1.hexdigest("#{language}.#{code}")}#{close_pattern}"
|
137
133
|
cached = @markup.check_cache(:code, id)
|
138
134
|
@map[id] = cached ?
|
139
135
|
{ :output => cached } :
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# ~*~ encoding: utf-8 ~*~
|
2
|
+
|
3
|
+
# CriticMarkup
|
4
|
+
#
|
5
|
+
# Render CriticMarkup
|
6
|
+
|
7
|
+
class Gollum::Filter::CriticMarkup < Gollum::Filter
|
8
|
+
|
9
|
+
# Patterns inspired by https://github.com/DivineDominion/criticmarkup.tmbundle/blob/master/Syntaxes/criticmarkup.tmLanguage
|
10
|
+
# All patterns use multiline matching (m flag)
|
11
|
+
# Logic inspired by https://github.com/CriticMarkup/CriticMarkup-toolkit/blob/master/CLI/criticParser_CLI.py
|
12
|
+
|
13
|
+
ADDITION_PATTERN = %r|{\+\+(?<content>.*?)\+\+[ \t]*(\[(.*?)\])?[ \t]*\}|m
|
14
|
+
DELETION_PATTERN = %r|{--(?<content>.*?)--[ \t]*(\[(.*?)\])?[ \t]*\}|m
|
15
|
+
SUBSTITUTION_PATTERN = %r|{~~(?<oldcontent>.*?)~>(?<newcontent>.*?)~~}|m
|
16
|
+
HIGHLIGHT_PATTERN = %r|{\=\=(?<content>.*?)[ \t]*(\[(.*?)\])?[ \t]*\=\=\}{>>(?<comment>.*?)<<}|m
|
17
|
+
COMMENT_PATTERN = %r|{>>(?<content>.*?)<<}|m
|
18
|
+
|
19
|
+
def extract(data)
|
20
|
+
data.gsub! ADDITION_PATTERN do
|
21
|
+
content = $~[:content]
|
22
|
+
placeholder = generate_placeholder("#{content}#{@map.size}")
|
23
|
+
# Is there a new paragraph followed by new text
|
24
|
+
if content.start_with?("\n\n") && content != "\n\n"
|
25
|
+
html = "\n\n<ins class='critic break'> </ins>\n\n<ins>#{content.gsub('\n', ' ')}</ins>"
|
26
|
+
# Is the addition just a single new paragraph
|
27
|
+
elsif content == "\n\n"
|
28
|
+
html = "\n\n<ins class='critic break'> </ins>\n\n"
|
29
|
+
# Is it added text followed by a new paragraph?
|
30
|
+
elsif content.end_with?("\n\n") && content != "\n\n"
|
31
|
+
html = "<ins>#{content.gsub('\n', ' ')}</ins>\n\n<ins class='critic break'> </ins>\n\n"
|
32
|
+
else
|
33
|
+
html = "<ins>#{content.gsub('\n', ' ')}</ins>"
|
34
|
+
end
|
35
|
+
@map[placeholder] = html
|
36
|
+
placeholder
|
37
|
+
end
|
38
|
+
|
39
|
+
data.gsub! DELETION_PATTERN do
|
40
|
+
content = $~[:content]
|
41
|
+
placeholder = generate_placeholder("#{content}#{@map.size}")
|
42
|
+
if content == "\n\n"
|
43
|
+
html = "<del> </del>"
|
44
|
+
else
|
45
|
+
html = "<del>#{content.gsub('\n\n', ' ')}</del>"
|
46
|
+
end
|
47
|
+
@map[placeholder] = html
|
48
|
+
placeholder
|
49
|
+
end
|
50
|
+
|
51
|
+
data.gsub! SUBSTITUTION_PATTERN do
|
52
|
+
oldcontent = $~[:oldcontent]
|
53
|
+
newcontent = $~[:newcontent]
|
54
|
+
placeholder = generate_placeholder("#{oldcontent}#{newcontent}#{@map.size}")
|
55
|
+
html = "<del>#{oldcontent}</del><ins>#{newcontent}</ins>"
|
56
|
+
@map[placeholder] = html
|
57
|
+
placeholder
|
58
|
+
end
|
59
|
+
|
60
|
+
data.gsub! HIGHLIGHT_PATTERN do
|
61
|
+
content = $~[:content]
|
62
|
+
comment = $~[:comment]
|
63
|
+
placeholder = generate_placeholder("#{content}#{@map.size}")
|
64
|
+
html = "<mark>#{content}</mark><span class='critic comment'>#{comment}</span>"
|
65
|
+
@map[placeholder] = html
|
66
|
+
placeholder
|
67
|
+
end
|
68
|
+
|
69
|
+
data.gsub! COMMENT_PATTERN do
|
70
|
+
content = $~[:content]
|
71
|
+
placeholder = generate_placeholder("#{content}#{@map.size}")
|
72
|
+
html = "<span class='critic comment'>#{content}</span>"
|
73
|
+
@map[placeholder] = html
|
74
|
+
placeholder
|
75
|
+
end
|
76
|
+
|
77
|
+
data
|
78
|
+
end
|
79
|
+
|
80
|
+
def process(data)
|
81
|
+
data.gsub! process_pattern do
|
82
|
+
@map[$~[:placeholder]]
|
83
|
+
end
|
84
|
+
data
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def process_pattern
|
90
|
+
/(?<placeholder>#{open_pattern}\h{40}#{close_pattern})/
|
91
|
+
end
|
92
|
+
|
93
|
+
def generate_placeholder(content)
|
94
|
+
"#{open_pattern}#{Digest::SHA1.hexdigest(content)}#{close_pattern}"
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|