jekyll_plugin_support 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 522c54334332d7fda1dc57bfa90647d419f458ff6153a7afe8bc8a60b0be7bca
4
- data.tar.gz: 6ce396d28eefd925fa8a7a367fbca3991b2ca3625b85c0720bc9eb295a107b03
3
+ metadata.gz: cbe2d54d363697f10987c73cdd5e7f1f901f170109747f4319553b37251d14a5
4
+ data.tar.gz: 454e854eec50272cbb21bb107e9095585ea9dc4acaf066ee738cf322bdf6465a
5
5
  SHA512:
6
- metadata.gz: 65ca01eb7f2a017675220b352ee4f041a87df21cf435ca280acb19e512c547f68004be72e9f8dcd51aaad099a1beaefc3544261a63eae0f44fc9b8a5e636f58a
7
- data.tar.gz: 1049865b366c17bdc3b4d6b2e88e9826e3dfa849ff6b35f03b65b5c6d9b4367ccfe0477a4497ffab2cfea3e3210512ae2d8bf163f71450a05e5c5963d5960883
6
+ metadata.gz: 58712d203762e16b5ed848f4bff32cdfb43494871c69482b3a29b5d76180dc3b67406fe42b0662e14ded8174bf4d7a49eab16c1c81c66721402d38be4a24ecd4
7
+ data.tar.gz: 10782bbeb291185bdb17a0d0cd5e37ab999f3c74569b415bc5d3892221bf8e43426cd2244be37b4a5ebc90ae2aa3d9d0327f8f5e3c5b0c7da9d9b06cc1cc3546
data/.rubocop.yml CHANGED
@@ -30,7 +30,7 @@ Layout/LineLength:
30
30
  Max: 150
31
31
 
32
32
  Metrics/AbcSize:
33
- Max: 45
33
+ Max: 55
34
34
 
35
35
  Metrics/BlockLength:
36
36
  Exclude:
@@ -64,6 +64,9 @@ RSpec/IndexedLet:
64
64
  RSpec/MultipleExpectations:
65
65
  Max: 15
66
66
 
67
+ Style/ClassVars:
68
+ Enabled: false
69
+
67
70
  Style/Documentation:
68
71
  Enabled: false
69
72
 
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Change Log
2
2
 
3
+
4
+ ## 0.8.2 / 2024-01-03
5
+
6
+ * `JekyllSupport::JekyllBlock` and `JekyllSupport::JekyllTag` subclasses now have automatically created error classes,
7
+ named after the subclass.
8
+ * Error class methods have been provided for standardized and convenient error handling:
9
+ * `shorten_backtrace`
10
+ * `logger_message`
11
+ * `html_message`
12
+ * Tags now self-report when registered.
13
+
14
+
15
+ ## 0.8.1 / 2023-12-10
16
+
17
+ * Added the `JekyllPluginHelper.remove_html_tags` method.
18
+
19
+
3
20
  ## 0.8.0 / 2023-11-14
4
21
 
5
22
  * Restructured for better support of Liquid variables.
data/README.md CHANGED
@@ -199,6 +199,70 @@ both [`demo/_plugins/demo_inline_tag.rb`](demo/_plugins/demo_inline_tag.rb) and
199
199
  ```
200
200
 
201
201
 
202
+ ### Automatically Created Error Classes
203
+
204
+ `JekyllSupport::JekyllBlock` and `JekyllSupport::JekyllTag` subclasses
205
+ automatically create error classes, named after the subclass.
206
+
207
+ For example, if you create a `JekyllSupport::JekyllBlock` subclass called `DemoBlockTag`,
208
+ the automatically generated error class will be called `DemoBlockTagError`.
209
+
210
+ Although you could use it as you would any other error class, `JekyllPluginSupport` provides some helper methods.
211
+ These methods fill in the page path and line number that caused the error, shorten the stack trace,
212
+ log an error message, and can be used to return an HTML-friendly version of the message to the web page.
213
+
214
+ The following example is a shortened version of `demo/_plugins/demo_block_tag.rb`.
215
+ You might want to write similar code in your `rescue` blocks.
216
+
217
+ ```ruby
218
+ class DemoBlock < JekyllSupport::JekyllBlock
219
+ VERSION = '0.1.2'.freeze
220
+
221
+ def render_impl(text)
222
+ raise DemoBlockTagError, 'Fall down, go boom.'
223
+ rescue DemoBlockTagError => e
224
+ e.shorten_backtrace
225
+ @logger.error e.logger_message
226
+ raise e if @die_on_demo_block_error
227
+
228
+ e.html_message
229
+ end
230
+ end
231
+ ```
232
+
233
+ Error class methods have been provided for standardized and convenient error handling:
234
+
235
+ * `shorten_backtrace` - most of the lines that spew from a Jekyll backtrace are uninteresting.
236
+ * `logger_message` - The message is constructed from the string provided when the error was raised,
237
+ with the page path and line number added.
238
+ * `html_message` - The same as `logger_message`, but constructed with HTML.
239
+
240
+
241
+ ### Self-Reporting Upon Registration
242
+
243
+ When each tag is registered, it self-reports, for example:
244
+
245
+ ```text
246
+ INFO PluginMetaLogger: Loaded plugin demo_inline_tag v0.1.2. It has:
247
+ Error class: DemoTagError
248
+ CSS class for error messages: demo_tag_error
249
+
250
+ _config.yml contains the following configuration for this plugin:
251
+ {"die_on_demo_tag_error"=>false, "die_on_standard_error"=>false}
252
+
253
+
254
+ INFO PluginMetaLogger: Loaded plugin demo_inline_tag_no_arg v0.1.0. It has:
255
+ Error class: DemoTagNoArgsError
256
+ CSS class for error messages: demo_tag_no_args_error
257
+
258
+ _config.yml does not contain configuration information for this plugin.
259
+ You could add a section containing default values by specifying a section for the tag name,
260
+ and an entry whose name starts with `die_on_`, followed by a snake_case version of the error name.
261
+
262
+ demo_inline_tag_no_arg:
263
+ die_on_demo_tag_no_args_error: false
264
+ ```
265
+
202
266
  ### Example
203
267
 
204
268
  [`demo/index.html`](demo/index.html), contains the following inline tag invocation:
@@ -0,0 +1,54 @@
1
+ require 'facets/string/camelcase'
2
+ require 'facets/string/snakecase'
3
+
4
+ module Jekyll
5
+ # Use like this:
6
+ # CustomError.new(:MyError, 'blah', 'asdf')
7
+ class CustomError < StandardError
8
+ def self.factory(error_class_name)
9
+ return if Object.const_defined? "::#{error_class_name}"
10
+
11
+ Object.const_set error_class_name, Class.new(CustomError)
12
+ end
13
+
14
+ def error_name
15
+ self.class.name.split('::').last
16
+ end
17
+
18
+ def calling_file
19
+ file_fq, _line_number, _extra = backtrace[0].split(':')
20
+ file_fq
21
+ end
22
+
23
+ # @return HTML <div> tag with class set to the snake_case version of the error class name.
24
+ def html_message
25
+ shorten_backtrace
26
+ line_number = self.class.class_variable_get :@@line_number
27
+ path = self.class.class_variable_get :@@path
28
+ <<~END_MSG
29
+ <div class='#{error_name.snakecase}'>
30
+ #{self.class} raised in #{calling_file} while processing line #{line_number} (after front matter) of #{path}
31
+ #{message}
32
+ </div>
33
+ END_MSG
34
+ end
35
+
36
+ def logger_message
37
+ shorten_backtrace
38
+ kaller = caller(1..1).first
39
+ line_number = self.class.class_variable_get :@@line_number
40
+ path = self.class.class_variable_get :@@path
41
+ <<~END_MSG
42
+ #{error_name} raised in #{kaller} while processing line #{line_number} (after front matter) of #{path}
43
+ #{message}
44
+ END_MSG
45
+ end
46
+
47
+ def shorten_backtrace(backtrace_element_count = 3)
48
+ b = backtrace[0..backtrace_element_count - 1].map do |x|
49
+ x.gsub(Dir.pwd + '/', './')
50
+ end
51
+ set_backtrace b
52
+ end
53
+ end
54
+ end
@@ -19,20 +19,23 @@ module JekyllSupportErrorHandling
19
19
  rescue StandardError => e
20
20
  file, line_number, caller = e.backtrace[caller_index].split(':')
21
21
  caller = caller.tr('`', "'")
22
- warn "#{error.msg} #{caller} on line #{line_number} (after front matter) of #{file}".red
22
+ warn "#{error.message} #{caller} on line #{line_number} (after front matter) of #{file}".red
23
23
  # Process.kill('HUP', Process.pid) # generates huge stack trace
24
24
  exec "echo ''"
25
25
  end
26
26
 
27
+ # TODO: Delete this
27
28
  def format_error_message(message)
28
29
  page = " of #{@page['path']}" if @page
29
30
  remove_ansi_color "on line #{line_number} (after front matter)#{page}.\n#{message}"
30
31
  end
31
32
 
33
+ # TODO: Delete this
32
34
  def remove_ansi_color(string)
33
35
  string.gsub(/\e\[([;\d]+)?m/, '')
34
36
  end
35
37
 
38
+ # TODO: Delete this
36
39
  def maybe_reraise_error(error, throw_error: true)
37
40
  fmsg = format_error_message "#{error.class}: #{error.message.strip}"
38
41
  @logger.error { fmsg }
@@ -25,7 +25,7 @@ class JekyllPluginHelper
25
25
  @markup = markup
26
26
  rescue StandardError => e
27
27
  e.shorten_backtrace
28
- @logger.error { e.msg }
28
+ @logger.error { e.message }
29
29
  end
30
30
 
31
31
  # @return undefined if parameter was specified, removes it from the available tokens and returns value
@@ -1,3 +1,7 @@
1
+ require 'facets/string/camelcase'
2
+ require 'facets/string/snakecase'
3
+ require 'yaml'
4
+
1
5
  # Class methods for JekyllPluginHelper
2
6
  class JekyllPluginHelper
3
7
  # Expand an environment variable reference
@@ -11,19 +15,56 @@ class JekyllPluginHelper
11
15
  end
12
16
  end
13
17
 
14
- def self.register(klass, name)
15
- abort("Error: The #{name} plugin does not define VERSION") \
18
+ def self.generate_message(klass, tag_name, version)
19
+ error_name_stub = klass.name.include?('::') ? klass.name.split('::')[1] : klass.name
20
+ error_ruby_class_name = "#{error_name_stub.camelcase(:upper)}Error"
21
+ config_die_key = "die_on_#{error_ruby_class_name.snakecase}"
22
+ error_css_class_name = error_ruby_class_name.split('::').last.snakecase
23
+ config = YAML.load_file('_config.yml')
24
+ tag_config = config[tag_name]
25
+ tag_config_msg = if tag_config.nil?
26
+ <<~END_MSG
27
+ _config.yml does not contain configuration information for this plugin.
28
+ You could add a section containing default values by specifying a section for the tag name,
29
+ and an entry whose name starts with `die_on_`, followed by a snake_case version of the error name.
30
+
31
+ #{tag_name}:
32
+ #{config_die_key}: false
33
+ END_MSG
34
+ else
35
+ <<~END_MSG
36
+ _config.yml contains the following configuration for this plugin:
37
+ #{tag_config}
38
+ END_MSG
39
+ end
40
+
41
+ <<~END_MSG
42
+ Loaded plugin #{tag_name} v#{version}. It has:
43
+ Error class: #{error_ruby_class_name}
44
+ CSS class for error messages: #{error_css_class_name}
45
+
46
+ #{tag_config_msg}
47
+ END_MSG
48
+ end
49
+
50
+ def self.register(klass, tag_name)
51
+ abort("Error: The #{tag_name} plugin does not define VERSION") \
16
52
  unless klass.const_defined?(:VERSION)
17
53
 
18
54
  version = klass.const_get(:VERSION)
19
55
 
20
- abort("Error: The #{name} plugin is not an instance of JekyllSupport::JekyllBlock or JekyllSupport::JekyllTag") \
56
+ abort("Error: The #{tag_name} plugin is not an instance of JekyllSupport::JekyllBlock or JekyllSupport::JekyllTag") \
21
57
  unless klass.instance_of?(Class) &&
22
58
  (klass.ancestors.include?(JekyllSupport::JekyllBlock) ||
23
59
  klass.ancestors.include?(JekyllSupport::JekyllTag))
24
60
 
25
- Liquid::Template.register_tag(name, klass)
26
- PluginMetaLogger.instance.info { "Loaded #{name} v#{version} plugin." }
61
+ Liquid::Template.register_tag(tag_name, klass)
62
+ msg = generate_message(klass, tag_name, version)
63
+ PluginMetaLogger.instance.info { msg }
64
+ end
65
+
66
+ def self.remove_html_tags(string)
67
+ string.gsub(/<[^>]*>/, '').strip
27
68
  end
28
69
 
29
70
  # strip leading and trailing quotes if present
@@ -1,3 +1,3 @@
1
1
  module JekyllPluginSupportVersion
2
- VERSION = '0.8.0'.freeze
2
+ VERSION = '0.8.2'.freeze
3
3
  end
@@ -15,3 +15,4 @@ require_relative 'jekyll_plugin_support_block'
15
15
  require_relative 'jekyll_plugin_support_block_noarg'
16
16
  require_relative 'jekyll_plugin_support_tag'
17
17
  require_relative 'jekyll_plugin_support_tag_noarg'
18
+ require_relative 'jekyll_custom_error'
@@ -24,6 +24,9 @@ module JekyllSupport
24
24
  @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
25
25
  @logger.debug { "#{self.class}: respond_to?(:no_arg_parsing) #{respond_to?(:no_arg_parsing) ? 'yes' : 'no'}." }
26
26
  @helper = JekyllPluginHelper.new tag_name, markup, @logger, respond_to?(:no_arg_parsing)
27
+
28
+ @error_name = "#{tag_name.camelcase(:upper)}Error"
29
+ Jekyll::CustomError.factory @error_name
27
30
  end
28
31
 
29
32
  # Method prescribed by the Jekyll plugin lifecycle.
@@ -41,6 +44,8 @@ module JekyllSupport
41
44
  @config = @site.config
42
45
  @tag_config = @config[@tag_name]
43
46
 
47
+ set_error_context
48
+
44
49
  @layout = @envs[:layout]
45
50
  @paginator = @envs[:paginator]
46
51
  @theme = @envs[:theme]
@@ -58,11 +63,15 @@ module JekyllSupport
58
63
  render_impl text
59
64
  rescue StandardError => e
60
65
  e.shorten_backtrace
61
- msg = format_error_message e.full_message
62
- @logger.error msg
66
+ @logger.error { "#{e.class} on line #{@line_number} of #{e.backtrace[0].split(':').first} by #{tag_name} - #{e.message}" }
67
+ binding.pry if @pry_on_standard_error # rubocop:disable Lint/Debugger
63
68
  raise e if @die_on_standard_error
64
69
 
65
- "<div class='standard_error'>#{e.class}: #{msg}</div>"
70
+ <<~END_MSG
71
+ <div class='standard_error'>
72
+ #{e.class} on line #{@line_number} of #{e.backtrace[0].split(':').first} by #{tag_name}: #{e.message}
73
+ </div>
74
+ END_MSG
66
75
  end
67
76
 
68
77
  # Jekyll plugins should override this method, not render,
@@ -73,5 +82,15 @@ module JekyllSupport
73
82
  def render_impl(text)
74
83
  text
75
84
  end
85
+
86
+ def set_error_context
87
+ return unless Object.const_defined? @error_name
88
+
89
+ error_class = Object.const_get @error_name
90
+ error_class.class_variable_set(:@@argument_string, @argument_string)
91
+ error_class.class_variable_set(:@@line_number, @line_number)
92
+ error_class.class_variable_set(:@@path, @page['path'])
93
+ error_class.class_variable_set(:@@tag_name, @tag_name)
94
+ end
76
95
  end
77
96
  end
@@ -1,3 +1,5 @@
1
+ require_relative 'jekyll_custom_error'
2
+
1
3
  # Monkey patch StandardError so a new method called shorten_backtrace is added.
2
4
  class StandardError
3
5
  def shorten_backtrace(backtrace_element_count = 3)
@@ -20,7 +22,7 @@ module JekyllSupport
20
22
 
21
23
  # @return a new StandardError subclass containing the shorten_backtrace method
22
24
  def define_error
23
- Class.new StandardError
25
+ Class.new Jekyll::CustomError
24
26
  end
25
27
  module_function :define_error
26
28
 
@@ -78,7 +80,7 @@ module JekyllSupport
78
80
  def self.warn_short_trace(logger, error)
79
81
  remaining = error.backtrace.length - DISPLAYED_CALLS
80
82
  logger.warn do
81
- error.msg + "\n" +
83
+ error.message + "\n" +
82
84
  error.backtrace.take(DISPLAYED_CALLS).join("\n") +
83
85
  "\n...Remaining #{remaining} call sites elided.\n"
84
86
  end
@@ -27,6 +27,9 @@ module JekyllSupport
27
27
  @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
28
28
  @logger.debug { "#{self.class}: respond_to?(:no_arg_parsing) #{respond_to?(:no_arg_parsing) ? 'yes' : 'no'}." }
29
29
  @helper = JekyllPluginHelper.new(tag_name, @argument_string, @logger, respond_to?(:no_arg_parsing))
30
+
31
+ @error_name = "#{tag_name.camelcase(:upper)}Error"
32
+ Jekyll::CustomError.factory @error_name
30
33
  end
31
34
 
32
35
  # Method prescribed by the Jekyll plugin lifecycle.
@@ -45,6 +48,8 @@ module JekyllSupport
45
48
  @jps = @config['jekyll_plugin_support']
46
49
  @pry_on_standard_error = @jps['pry_on_standard_error'] || false if @jps
47
50
 
51
+ set_error_context
52
+
48
53
  # @envs.keys are :content, :highlighter_prefix, :highlighter_suffix, :jekyll, :layout, :page, :paginator, :site, :theme
49
54
  @layout = @envs[:layout]
50
55
  @paginator = @envs[:paginator]
@@ -57,12 +62,15 @@ module JekyllSupport
57
62
  render_impl
58
63
  rescue StandardError => e
59
64
  e.shorten_backtrace
60
- msg = format_error_message e.full_message
61
- @logger.error msg
65
+ @logger.error { "#{e.class} on line #{@line_number} of #{e.backtrace[0].split(':').first} while processing #{tag_name} - #{e.message}" }
62
66
  binding.pry if @pry_on_standard_error # rubocop:disable Lint/Debugger
63
67
  raise e if @die_on_standard_error
64
68
 
65
- "<div class='standard_error'>#{e.class}: #{msg}</div>"
69
+ <<~END_MSG
70
+ <div class='standard_error'>
71
+ #{e.class} on line #{@line_number} of #{e.backtrace[0].split(':').first} while processing #{tag_name}: #{e.message}
72
+ </div>
73
+ END_MSG
66
74
  end
67
75
 
68
76
  # Jekyll plugins must override this method, not render, so their plugin can be tested more easily
@@ -71,5 +79,15 @@ module JekyllSupport
71
79
  def render_impl
72
80
  abort "#{self.class}.render_impl for tag #{@tag_name} must be overridden, but it was not."
73
81
  end
82
+
83
+ def set_error_context
84
+ return unless Object.const_defined? @error_name
85
+
86
+ error_class = Object.const_get @error_name
87
+ error_class.class_variable_set(:@@argument_string, @argument_string)
88
+ error_class.class_variable_set(:@@line_number, @line_number)
89
+ error_class.class_variable_set(:@@path, @page['path'])
90
+ error_class.class_variable_set(:@@tag_name, @tag_name)
91
+ end
74
92
  end
75
93
  end
@@ -0,0 +1,39 @@
1
+ require_relative '../lib/jekyll_custom_error'
2
+ require_relative '../lib/jekyll_plugin_support_class'
3
+
4
+ class Dummy
5
+ def just_for_testing; end
6
+ end
7
+
8
+ class CustomErrorSpec
9
+ tag_name = 'test_tag'
10
+ argument_string = 'This is the argument string'
11
+ AnError = JekyllSupport.define_error
12
+ AnError.class_variable_set(:@@tag_name, tag_name)
13
+ AnError.class_variable_set(:@@argument_string, argument_string)
14
+
15
+ puts "AnError is a #{AnError.class}; StandardError is a #{StandardError.class}"
16
+ begin
17
+ raise AnError, 'Oops'
18
+ rescue AnError => e
19
+ puts "Caught AnError: #{e.message}"
20
+ rescue Jekyll::CustomError => e
21
+ puts "Caught CustomError: #{e.message}"
22
+ end
23
+
24
+ RSpec.describe JekyllPluginHelper do
25
+ it 'generates messages' do
26
+ msg = described_class.generate_message(Dummy, tag_name, '0.1.0')
27
+ puts msg
28
+ expect(msg).to include(match(/Error class. DummyError/))
29
+ expect(msg).to include(match(/CSS class for error messages. dummy_error/))
30
+ expect(msg).to include(match(/die_on_dummy_error. false/))
31
+ end
32
+ end
33
+
34
+ RSpec.describe Jekyll::CustomError do
35
+ it 'can create custom errors' do
36
+ expect { raise AnError, 'Oops' }.to raise_error(AnError)
37
+ end
38
+ end
39
+ end
@@ -1,7 +1,9 @@
1
1
  example_id | status | run_time |
2
2
  ------------------------------------------------ | ------ | --------------- |
3
- ./spec/jekyll_plugin_helper_options_spec.rb[1:1] | failed | 0.00009 seconds |
4
- ./spec/jekyll_plugin_helper_options_spec.rb[1:2] | failed | 0.00004 seconds |
5
- ./spec/jekyll_plugin_helper_options_spec.rb[1:3] | failed | 0.00002 seconds |
6
- ./spec/jekyll_plugin_helper_options_spec.rb[1:4] | failed | 0.00002 seconds |
3
+ ./spec/custom_error_spec.rb[1:1] | failed | 0.00772 seconds |
4
+ ./spec/custom_error_spec.rb[2:1] | passed | 0.0011 seconds |
5
+ ./spec/jekyll_plugin_helper_options_spec.rb[1:1] | failed | 0.00005 seconds |
6
+ ./spec/jekyll_plugin_helper_options_spec.rb[1:2] | failed | 0.00003 seconds |
7
+ ./spec/jekyll_plugin_helper_options_spec.rb[1:3] | failed | 0.00003 seconds |
8
+ ./spec/jekyll_plugin_helper_options_spec.rb[1:4] | failed | 0.00003 seconds |
7
9
  ./spec/liquid_variable_parsing_spec.rb[1:1] | failed | 0.00003 seconds |
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll_plugin_support
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Slinn
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-22 00:00:00.000000000 Z
11
+ date: 2024-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: facets
@@ -94,6 +94,7 @@ files:
94
94
  - README.md
95
95
  - Rakefile
96
96
  - jekyll_plugin_support.gemspec
97
+ - lib/jekyll_custom_error.rb
97
98
  - lib/jekyll_plugin_error_handling.rb
98
99
  - lib/jekyll_plugin_helper.rb
99
100
  - lib/jekyll_plugin_helper_attribution.rb
@@ -106,6 +107,7 @@ files:
106
107
  - lib/jekyll_plugin_support_spec_support.rb
107
108
  - lib/jekyll_plugin_support_tag.rb
108
109
  - lib/jekyll_plugin_support_tag_noarg.rb
110
+ - spec/custom_error_spec.rb
109
111
  - spec/jekyll_plugin_helper_options_spec.rb
110
112
  - spec/liquid_variable_parsing_spec.rb
111
113
  - spec/spec_helper.rb
@@ -142,6 +144,7 @@ signing_key:
142
144
  specification_version: 4
143
145
  summary: Provides a framework for writing and testing Jekyll plugins
144
146
  test_files:
147
+ - spec/custom_error_spec.rb
145
148
  - spec/jekyll_plugin_helper_options_spec.rb
146
149
  - spec/liquid_variable_parsing_spec.rb
147
150
  - spec/spec_helper.rb