jekyll-spaceship 0.9.3 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 993252decbad6e7d20ed20245f3ba7c7858eb5845402b06605a8b05d6268225f
4
- data.tar.gz: 45012fc8ca11671a98d36b1e1c6dfbfef67cc1c12f01f265ed507760e96f40fd
3
+ metadata.gz: feae82926b331a1fc32b0ed226447d3d58b6721c7187035ae3d82f297970e979
4
+ data.tar.gz: c34eef77784ba8087689780e75548318a91e188073995bbe0922d27abee1d0bc
5
5
  SHA512:
6
- metadata.gz: 139508a04521719d9160e2a0cff09a75600dffc5cae80c9dd75ec047495be87a1a7b786b859d5e335df9226d35617aa9e6470a4905fb497799f2c0c9981d6da2
7
- data.tar.gz: 00b615b28c36a335749d5b3dcd7a60e55b8639b2d86ae8e027243985c939e75333fd4c882ed84999f3de07b43ff07c632db62f88f3641dc4634c744f91a2b279
6
+ metadata.gz: b5e6ed122db069ffdc833eec1a360ee90257b356632ba4732a0b47a49a2ef9a41934d7e7de7eb23a03f61cf49d9347183d9d3cad88f1d9b6b79735cf100651a2
7
+ data.tar.gz: 8fca41fbf22600014b6c5b87f31b31b744447854effdf0099d446293e78d032bbdcc102a222c58a9fd05c7dd7f6088cea28575181e2e337488bd993c23504f93
@@ -1,6 +1,6 @@
1
1
  # These are supported funding model platforms
2
2
 
3
- github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
3
+ github: jeffreytse # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4
4
  patreon: jeffreytse
5
5
  open_collective: # Replace with a single Open Collective username
6
6
  ko_fi: jeffreytse
data/README.md CHANGED
@@ -177,8 +177,15 @@ jekyll-spaceship:
177
177
  inlineMath:
178
178
  - ['$','$']
179
179
  - ['\(','\)']
180
+ displayMath:
181
+ - ['$$','$$']
182
+ - ['\[','\]']
180
183
  svg:
181
184
  fontCache: 'global'
185
+ optimize: # optimization on building stage to check and add mathjax scripts
186
+ enabled: true # value `false` for adding to all pages
187
+ include: [] # include patterns for math expressions checking (regexp)
188
+ exclude: [] # exclude patterns for math expressions checking (regexp)
182
189
  plantuml-processor:
183
190
  mode: default # mode value 'pre-fetch' for fetching image at building stage
184
191
  css:
@@ -31,6 +31,16 @@ module Jekyll::Spaceship
31
31
  first.merge(second.to_h, &merger)
32
32
  end
33
33
 
34
+ def self.deep_dig(obj, key)
35
+ if obj.respond_to?(:key?) && obj.key?(key)
36
+ obj[key]
37
+ elsif obj.respond_to?(:each)
38
+ result = nil
39
+ obj.find { |*a| result = self.deep_dig(a.last, key) }
40
+ result
41
+ end
42
+ end
43
+
34
44
  def self.store(section, default)
35
45
  return @@store[section] if default.nil?
36
46
  @@store[section] = deep_merge(default, @@store[section])
@@ -25,7 +25,11 @@ module Jekyll::Spaceship
25
25
  attr_accessor :handled
26
26
 
27
27
  def name
28
- self.class.name.split('::').last
28
+ self.class.class_name
29
+ end
30
+
31
+ def self.class_name
32
+ self.name.split('::').last
29
33
  end
30
34
 
31
35
  def filename
@@ -212,6 +216,7 @@ module Jekyll::Spaceship
212
216
  'body' => content_body
213
217
  }
214
218
  rescue StandardError => msg
219
+ logger = Logger.new(self.class_name)
215
220
  logger.log msg
216
221
  end
217
222
  end
@@ -16,31 +16,67 @@ module Jekyll::Spaceship
16
16
  end
17
17
 
18
18
  def on_handle_html(content)
19
- # handle emoji markup
20
- content.scan(/:([\w\d+-]+):/) do |match|
19
+ emoji_filter(content, 'pre code') do |emoji|
20
+ # mark current file has been handled
21
+ self.handled = true
22
+
23
+ # here is the replacement content
24
+ "<img class=\"#{config['css']['class']}\""\
25
+ " title=\":#{emoji.name}:\""\
26
+ " alt=\":#{emoji.name}:\""\
27
+ " raw=\"#{emoji.raw}\""\
28
+ " src=\"#{config['src']}#{emoji.image_filename}\""\
29
+ " style=\"vertical-align: middle; display: inline;"\
30
+ " max-width: 1em; visibility: hidden;\""\
31
+ " onload=\"this.style.visibility='visible'\""\
32
+ " onerror=\"this.replaceWith(this.getAttribute('raw'))\">"\
33
+ "</img>"
34
+ end
35
+ end
36
+
37
+ def emoji_filter(content, selector)
38
+ # use nokogiri to parse html
39
+ doc = Nokogiri::HTML(content)
40
+ body = doc.at('body')
41
+
42
+ # filter nodes (pre, code)
43
+ nodes = body.css(selector)
44
+ nodes.each do |node|
45
+ # handle emoji markup
46
+ node.inner_html = node.inner_html.gsub(
47
+ /:([\w\d+-]+?):/, '\:\1\:'
48
+ )
49
+ end
50
+
51
+ # parse the emoji
52
+ content = body.inner_html
53
+ content.scan(/(?<!\\):([\w\d+-]+?)(?<!\\):/) do |match|
54
+ # Skip invalid emoji name
21
55
  emoji = Emoji.find_by_alias match[0]
22
56
  next if emoji.nil?
23
- self.handled = true
24
57
 
25
58
  # escape plus sign
26
59
  emoji_name = emoji.name.gsub('+', '\\\+')
27
- css_class = self.config['css']['class']
60
+
61
+ result = yield emoji
62
+ next if result.nil?
28
63
 
29
64
  content = content.gsub(
30
65
  /(?<!\=")\s*:#{emoji_name}:\s*(?!"\s)/,
31
- "<img class=\"#{css_class}\""\
32
- " title=\":#{emoji.name}:\""\
33
- " alt=\":#{emoji.name}:\""\
34
- " raw=\"#{emoji.raw}\""\
35
- " src=\"#{config['src']}#{emoji.image_filename}\""\
36
- " style=\"vertical-align: middle; display: inline;"\
37
- " max-width: 1em; visibility: hidden;\""\
38
- " onload=\"this.style.visibility='visible'\""\
39
- " onerror=\"this.replaceWith(this.getAttribute('raw'))\">"\
40
- "</img>"
66
+ result)
67
+ end
68
+
69
+ body.inner_html = content
70
+
71
+ # restore nodes (pre, code)
72
+ nodes.each do |node|
73
+ # handle emoji markup
74
+ node.inner_html = node.inner_html.gsub(
75
+ /\\:([\w\d+-]+?)\\:/, ':\1:'
41
76
  )
42
77
  end
43
- content
78
+
79
+ doc.to_html
44
80
  end
45
81
  end
46
82
  end
@@ -11,14 +11,45 @@ module Jekyll::Spaceship
11
11
  'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js',
12
12
  ],
13
13
  'config' => {
14
- 'tex' => { 'inlineMath' => [['$','$'], ['\\(','\\)']] },
14
+ 'tex' => {
15
+ 'inlineMath' => [['$','$'], ['\\(','\\)']],
16
+ 'displayMath' => [['$$','$$'], ['\\[','\\]']]
17
+ },
15
18
  'svg': { 'fontCache': 'global' }
19
+ },
20
+ 'optimize' => {
21
+ 'enabled' => true,
22
+ 'include' => [],
23
+ 'exclude' => []
16
24
  }
17
25
  }
18
26
  end
19
27
 
20
28
  def process?
21
- return true if Type.html?(output_ext)
29
+ return true if Type.html?(output_ext) or Type.markdown?(output_ext)
30
+ end
31
+
32
+ def on_handle_markdown(content)
33
+ # pre-handle mathjax expressions in markdown
34
+ patterns = get_math_patterns()
35
+ patterns['include'].each do |pattern|
36
+ content.scan(pattern) do |result|
37
+ expr = result[0]
38
+ body = result[1]
39
+ next if body.size.zero?
40
+ is_excluded = false
41
+ patterns['exclude'].each do |pe|
42
+ break is_excluded = true if expr.match(/#{pe}/)
43
+ end
44
+ next if is_excluded
45
+ escaped_expr = expr
46
+ .gsub(/(?<!^)\\(?!\S$)/, '\\\\\\\\')
47
+ .gsub(/(?<!\\)\$\$/, '\\\$\\\$')
48
+ .gsub(/\\ /, '\\\\\\ ')
49
+ content = content.gsub(expr, escaped_expr)
50
+ end
51
+ end
52
+ content
22
53
  end
23
54
 
24
55
  def on_handle_html(content)
@@ -45,22 +76,62 @@ module Jekyll::Spaceship
45
76
  end
46
77
 
47
78
  def has_mathjax_expression?(doc)
48
- doc.css('*').each do |node|
49
- if node.content.match(/(?<!\\)\$.+(?<!\\)\$/)
50
- return true
51
- end
52
- if node.content.match(/(?<!\\)\\\(.+(?<!\\)\\\)/)
53
- return true
79
+ return true unless config['optimize']['enabled'] == true
80
+ scan_mathjax_expression(doc) do
81
+ return true
82
+ end
83
+ false
84
+ end
85
+
86
+ def get_math_patterns()
87
+ patterns = []
88
+ math_patterns = []
89
+ ['tex', 'tex2jax'].each do |t|
90
+ ['inlineMath', 'displayMath'].each do |m|
91
+ r = config.dig('config', t, m)
92
+ r&.each do |i|
93
+ btag = Regexp.escape(i[0])
94
+ etag = Regexp.escape(i[1])
95
+ patterns <<= /((?<!\\\\)#{btag}(.*?)(?<!\\\\)#{etag})/
96
+ end
54
97
  end
55
98
  end
99
+ config['optimize']['include'].each do |pattern|
100
+ patterns <<= /(#{pattern})/
101
+ end
102
+ {
103
+ 'include' => patterns,
104
+ 'exclude' => config['optimize']['exclude']
105
+ }
106
+ end
56
107
 
57
- doc.css('script').each do |node|
58
- type = node['type']
59
- if type and type.match(/math\/tex/)
60
- return true
108
+ def scan_mathjax_expression(doc, &block)
109
+ patterns = get_math_patterns()
110
+ doc.css('*').each do |node|
111
+ next if ['code', 'pre', 'figure'].include? node.name
112
+ next if node.ancestors('code, pre, figure').size > 0
113
+ next if node.children.size > 1
114
+ patterns['include'].each do |pattern|
115
+ # check scripting mathjax expression
116
+ if node.name == 'script'
117
+ type = node['type']
118
+ next unless type
119
+ next unless type.match(/math\/tex/)
120
+ end
121
+ # check normal mathjax expression
122
+ node.content.scan(pattern) do |result|
123
+ expr = result[0]
124
+ body = result[1]
125
+ next if body.size.zero?
126
+ is_excluded = false
127
+ patterns['exclude'].each do |pe|
128
+ break is_excluded = true if expr.match(/#{pe}/)
129
+ end
130
+ next if is_excluded
131
+ block.call(node, expr)
132
+ end
61
133
  end
62
134
  end
63
- false
64
135
  end
65
136
  end
66
137
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'uri'
4
+ require "nokogiri"
4
5
 
5
6
  module Jekyll::Spaceship
6
7
  class MediaProcessor < Processor
@@ -18,23 +19,29 @@ module Jekyll::Spaceship
18
19
  }
19
20
  end
20
21
 
21
- def on_handle_markdown(content)
22
- content = handle_normal_audio(content)
23
- content = handle_normal_video(content)
24
- content = handle_youtube(content)
25
- content = handle_vimeo(content)
26
- content = handle_dailymotion(content)
27
- content = handle_spotify(content)
28
- content = handle_soundcloud(content)
22
+ def on_handle_html(content)
23
+ # use nokogiri to parse html content
24
+ doc = Nokogiri::HTML(content)
25
+ # handle each img tag
26
+ doc.css('img').each do |element|
27
+ handle_normal_audio(element)
28
+ handle_normal_video(element)
29
+ handle_youtube(element)
30
+ handle_vimeo(element)
31
+ handle_dailymotion(element)
32
+ handle_spotify(element)
33
+ handle_soundcloud(element)
34
+ end
35
+ doc.to_html
29
36
  end
30
37
 
31
38
  # Examples:
32
39
  # ![audio](//www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3)
33
40
  # ![audio](//www.expample.com/examples/t-rex-roar.mp3?autoplay=true&loop=true)
34
- def handle_normal_audio(content)
35
- handle_media(content, {
41
+ def handle_normal_audio(element)
42
+ handle_media(element, {
36
43
  media_type: 'audio',
37
- host: '(https?:)?\\/\\/.*\\/',
44
+ host: '(https?:\\/\\/)?.*\\/',
38
45
  id: '(.+?\\.(mp3|wav|ogg|mid|midi|aac|wma))',
39
46
  })
40
47
  end
@@ -44,10 +51,10 @@ module Jekyll::Spaceship
44
51
  # ![video](//www.html5rocks.com/en/tutorials/video/basics/devstories.webm)
45
52
  # ![video](//techslides.com/demos/sample-videos/small.ogv?allow=autoplay)
46
53
  # ![video](//techslides.com/demos/sample-videos/small.mp4?width=400)
47
- def handle_normal_video(content)
48
- handle_media(content, {
54
+ def handle_normal_video(element)
55
+ handle_media(element, {
49
56
  media_type: 'iframe',
50
- host: '(https?:)?\\/\\/.*\\/',
57
+ host: '(https?:\\/\\/)?.*\\/',
51
58
  id: '(.+?\\.(avi|mp4|webm|ogg|ogv|flv|mkv|mov|wmv|3gp|rmvb|asf))'
52
59
  })
53
60
  end
@@ -56,8 +63,8 @@ module Jekyll::Spaceship
56
63
  # ![youtube](https://www.youtube.com/watch?v=XA2WjJbmmoM "title")
57
64
  # ![youtube](http://www.youtube.com/embed/w-m_yZCLF5Q)
58
65
  # ![youtube](//youtu.be/mEP3YXaSww8?height=100%&width=400)
59
- def handle_youtube(content)
60
- handle_media(content, {
66
+ def handle_youtube(element)
67
+ handle_media(element, {
61
68
  media_type: 'iframe',
62
69
  host: '(https?:)?\\/\\/.*youtu.*',
63
70
  id: '(?<=\\?v\\=|embed\\/|\\.be\\/)([a-zA-Z0-9\\_\\-]+)',
@@ -68,8 +75,8 @@ module Jekyll::Spaceship
68
75
  # Examples:
69
76
  # ![vimeo](https://vimeo.com/263856289)
70
77
  # ![vimeo](https://vimeo.com/263856289?height=100%&width=400)
71
- def handle_vimeo(content)
72
- handle_media(content, {
78
+ def handle_vimeo(element)
79
+ handle_media(element, {
73
80
  media_type: 'iframe',
74
81
  host: '(https?:)?\\/\\/vimeo\\.com\\/',
75
82
  id: '([0-9]+)',
@@ -80,8 +87,8 @@ module Jekyll::Spaceship
80
87
  # Examples:
81
88
  # ![dailymotion](https://www.dailymotion.com/video/x7tgcev)
82
89
  # ![dailymotion](https://dai.ly/x7tgcev?height=100%&width=400)
83
- def handle_dailymotion(content)
84
- handle_media(content, {
90
+ def handle_dailymotion(element)
91
+ handle_media(element, {
85
92
  media_type: 'iframe',
86
93
  host: '(https?:)?\\/\\/.*dai.?ly.*',
87
94
  id: '(?<=video\\/|\\/)([a-zA-Z0-9\\_\\-]+)',
@@ -92,8 +99,8 @@ module Jekyll::Spaceship
92
99
  # Examples:
93
100
  # ![spotify](//open.spotify.com/track/4Dg5moVCTqxAb7Wr8Dq2T5)
94
101
  # ![spotify](//open.spotify.com/track/37mEkAaqCE7FXMvnlVA8pp?width=400)
95
- def handle_spotify(content)
96
- handle_media(content, {
102
+ def handle_spotify(element)
103
+ handle_media(element, {
97
104
  media_type: 'iframe',
98
105
  host: '(https?:)?\\/\\/open\\.spotify\\.com\\/track\\/',
99
106
  id: '(?<=track\\/)([a-zA-Z0-9\\_\\-]+)',
@@ -104,8 +111,8 @@ module Jekyll::Spaceship
104
111
 
105
112
  # Examples:
106
113
  # ![soundcloud](//soundcloud.com/aviciiofficial/preview-avicii-vs-lenny)
107
- def handle_soundcloud(content)
108
- handle_media(content, {
114
+ def handle_soundcloud(element)
115
+ handle_media(element, {
109
116
  media_type: 'iframe',
110
117
  id_from: 'html',
111
118
  host: '(https?:)?\\/\\/soundcloud\\.com\\/.+\\/[^\\?]+',
@@ -116,71 +123,53 @@ module Jekyll::Spaceship
116
123
  })
117
124
  end
118
125
 
119
- def handle_media(content, data)
126
+ def handle_media(element, data)
120
127
  host = data[:host]
121
- return content if content.sub(/#{host}/, '').nil?
128
+ src = element.get_attribute('src')
129
+ title = element.get_attribute('title')
130
+ id = data[:id_from] === 'html' ? '()' : data[:id]
131
+ match_data = src.match(/#{host}#{id}\S*/)
132
+ return if match_data.nil?
122
133
 
123
134
  media_type = data[:media_type]
124
135
  base_url = data[:base_url]
125
- id = data[:id_from] === 'html' ? '()' : data[:id]
126
- url = "(#{host}#{id}\\S*)"
127
- title = '("(.*)".*){0,1}'
128
-
129
- # pre-handle reference-style links
130
- regex = /(\[(.*)\]:\s*(#{url}\s*#{title}))/
131
- content.scan regex do |match_data|
132
- match = match_data[0]
133
- ref_name = match_data[1]
134
- ref_value = match_data[2]
135
- content = content.gsub(match, '')
136
- .gsub(/\!\[(.*)\]\s*\[#{ref_name}\]/,
137
- "![\1](#{ref_value})")
136
+ id = data[:id_from] === 'html' \
137
+ ? get_id_from_html(src, data[:id]) \
138
+ : match_data[2]
139
+ qs = src.match(/(?<=\?)(\S*?)$/)
140
+ qs = Hash[URI.decode_www_form(qs.to_s)].reject do |k, v|
141
+ next true if v == id or v == ''
138
142
  end
139
143
 
140
- # handle inline-style links
141
- regex = /(\!\[(.*)\]\(.*#{url}\s*#{title}\))/
142
- content.scan regex do |match_data|
143
- url = match_data[2]
144
- id = data[:id_from] === 'html' \
145
- ? get_id_from_html(url, data[:id]) \
146
- : match_data[4]
147
- title = match_data[6]
148
- qs = url.match(/(?<=\?)(\S*?)$/)
149
- qs = Hash[URI.decode_www_form(qs.to_s)].reject do |k, v|
150
- next true if v == id or v == ''
151
- end
152
-
153
- cfg = self.config['default'].clone
154
- cfg['id'] = qs['id'] || cfg['id']
155
- cfg['class'] = qs['class'] || cfg['class']
156
- cfg['style'] = qs['style'] || cfg['style']
157
- cfg['id'] = cfg['id'].gsub('{id}', id)
158
- cfg['class'] = cfg['class'].gsub('{id}', id)
144
+ cfg = self.config['default'].clone
145
+ cfg['id'] = qs['id'] || cfg['id']
146
+ cfg['class'] = qs['class'] || cfg['class']
147
+ cfg['style'] = qs['style'] || cfg['style']
148
+ cfg['id'] = cfg['id'].gsub('{id}', id)
149
+ cfg['class'] = cfg['class'].gsub('{id}', id)
159
150
 
160
- cfg['src'] = URI(base_url ? "#{base_url}#{id}" : url).tap do |v|
161
- v.query = URI.encode_www_form(qs) if qs.size > 0
162
- end
151
+ cfg['src'] = URI(base_url ? "#{base_url}#{id}" : src).tap do |v|
152
+ v.query = URI.encode_www_form(qs) if qs.size > 0
153
+ end
163
154
 
164
- case media_type
165
- when 'audio'
166
- cfg['autoplay'] = qs['autoplay'] || data[:autoplay] || cfg['autoplay']
167
- cfg['loop'] = qs['loop'] || data[:loop] || cfg['loop']
168
- cfg['style'] += ';display: none;' if qs['hidden']
169
- content = handle_audio(content, { target: match_data[0], cfg: cfg })
170
- when 'iframe'
171
- cfg['title'] = title
172
- cfg['width'] = qs['width'] || data[:width] || cfg['width']
173
- cfg['height'] = qs['height'] || data[:height] || cfg['height']
174
- cfg['frameborder'] = qs['frameborder'] || cfg['frameborder']
175
- cfg['allow'] ||= cfg['allow']
176
- content = handle_iframe(content, { target: match_data[0], cfg: cfg })
177
- end
178
- self.handled = true
155
+ case media_type
156
+ when 'audio'
157
+ cfg['autoplay'] = qs['autoplay'] || data[:autoplay] || cfg['autoplay']
158
+ cfg['loop'] = qs['loop'] || data[:loop] || cfg['loop']
159
+ cfg['style'] += ';display: none;' if qs['hidden']
160
+ handle_audio(element, { cfg: cfg })
161
+ when 'iframe'
162
+ cfg['title'] = title
163
+ cfg['width'] = qs['width'] || data[:width] || cfg['width']
164
+ cfg['height'] = qs['height'] || data[:height] || cfg['height']
165
+ cfg['frameborder'] = qs['frameborder'] || cfg['frameborder']
166
+ cfg['allow'] ||= cfg['allow']
167
+ handle_iframe(element, { cfg: cfg })
179
168
  end
180
- content
169
+ self.handled = true
181
170
  end
182
171
 
183
- def handle_audio(content, data)
172
+ def handle_audio(element, data)
184
173
  cfg = data[:cfg]
185
174
  html = "<audio"\
186
175
  " id=\"#{cfg['id']}\""\
@@ -194,10 +183,11 @@ module Jekyll::Spaceship
194
183
  " Here is a <a href=\"#{cfg['src']}\">link to download the audio</a>"\
195
184
  "instead. </p>"\
196
185
  "</audio>"
197
- content.gsub(data[:target], html)
186
+ doc = Nokogiri::XML(html)
187
+ element.replace(doc.children.first)
198
188
  end
199
189
 
200
- def handle_iframe(content, data)
190
+ def handle_iframe(element, data)
201
191
  cfg = data[:cfg]
202
192
  html = "<iframe"\
203
193
  " id=\"#{cfg['id']}\""\
@@ -211,7 +201,8 @@ module Jekyll::Spaceship
211
201
  " frameborder=\"#{cfg['frameborder']}\""\
212
202
  " allowfullscreen>"\
213
203
  "</iframe>"
214
- content.gsub(data[:target], html)
204
+ doc = Nokogiri::XML(html)
205
+ element.replace(doc.children.first)
215
206
  end
216
207
 
217
208
  def get_id_from_html(url, pattern)
@@ -60,6 +60,9 @@ module Jekyll::Spaceship
60
60
  end
61
61
 
62
62
  def handle_mermaid(code)
63
+ # Handle extra empty lines, otherwise it would cause error
64
+ code = code.gsub(/\n\s*\n/, "\n%%-\n")
65
+
63
66
  # encode to UTF-8
64
67
  code = code.encode('UTF-8')
65
68
  url = get_url(code)
@@ -43,7 +43,7 @@ module Jekyll::Spaceship
43
43
  .gsub(/((?<!\\)\${1,2})[^\n]*?\1/, '')
44
44
  .match(/(?<!\\)\|/)
45
45
  replace = result.gsub(
46
- /(?<!(?<!\\)\\)(\*|\$|\[|\(|\"|_)/, '\\\\\\\\\1')
46
+ /(?<!(?<!\\)\\)(\*|\$|\[(?!\^)|\(|\"|_)/, '\\\\\\\\\1')
47
47
  next if result == replace
48
48
  content = content.gsub(result, replace)
49
49
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jekyll
4
4
  module Spaceship
5
- VERSION = "0.9.3"
5
+ VERSION = "0.9.8"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-spaceship
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - jeffreytse
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-07 00:00:00.000000000 Z
11
+ date: 2021-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll