jekyll_plugin_support 0.7.2 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,51 @@
1
+ module JekyllSupportErrorHandling
2
+ attr_reader :logger, :page
3
+
4
+ # If a Jekyll plugin needs to crash exit, and stop Jekyll, call this method.
5
+ # It does not generate a stack trace.
6
+ # This method does not return because the process is abruptly terminated.
7
+ #
8
+ # @param error StandardError or a subclass of StandardError is required
9
+ #
10
+ # Do not raise the error before calling this method, just create it via 'new', like this:
11
+ # exit_without_stack_trace StandardError.new('This is my error message')
12
+ #
13
+ # If you want to call this method from a handler method, the default index for the backtrace array must be specified.
14
+ # The default backtrace index is 1, which means the calling method.
15
+ # To specify the calling method's caller, pass in 2, like this:
16
+ # exit_without_stack_trace StandardError.new('This is my error message'), 2
17
+ def exit_without_stack_trace(error, caller_index = 1)
18
+ raise error
19
+ rescue StandardError => e
20
+ file, line_number, caller = e.backtrace[caller_index].split(':')
21
+ caller = caller.tr('`', "'")
22
+ warn "#{error.message} #{caller} on line #{line_number} (after front matter) of #{file}".red
23
+ # Process.kill('HUP', Process.pid) # generates huge stack trace
24
+ exec "echo ''"
25
+ end
26
+
27
+ # TODO: Delete this
28
+ def format_error_message(message)
29
+ page = " of #{@page['path']}" if @page
30
+ remove_ansi_color "on line #{line_number} (after front matter)#{page}.\n#{message}"
31
+ end
32
+
33
+ # TODO: Delete this
34
+ def remove_ansi_color(string)
35
+ string.gsub(/\e\[([;\d]+)?m/, '')
36
+ end
37
+
38
+ # TODO: Delete this
39
+ def maybe_reraise_error(error, throw_error: true)
40
+ fmsg = format_error_message "#{error.class}: #{error.message.strip}"
41
+ @logger.error { fmsg }
42
+ return "<span class='jekyll_plugin_support_error'>#{fmsg}</span>" unless throw_error
43
+
44
+ error.set_backtrace error.backtrace[0..9]
45
+ raise error
46
+ end
47
+
48
+ def warn_short_trace(error)
49
+ JekyllSupport.warn_short_trace(@logger, error)
50
+ end
51
+ end
@@ -1,45 +1,14 @@
1
1
  require 'facets/string/interpolate'
2
2
  require 'key_value_parser'
3
3
  require 'shellwords'
4
- require_relative 'gem_support'
4
+ require_relative 'jekyll_plugin_helper_class'
5
+ require_relative 'jekyll_plugin_helper_attribution'
5
6
 
6
- # Base class for all types of Jekyll plugin helpers
7
- class JekyllPluginHelper # rubocop:disable Metrics/ClassLength
7
+ class JekyllPluginHelper
8
8
  attr_accessor :liquid_context
9
9
  attr_reader :argv, :attribution, :keys_values, :logger, :markup, :no_arg_parsing, :params, :tag_name,
10
10
  :argv_original, :excerpt_caller, :keys_values_original, :params_original, :jpsh_subclass_caller
11
11
 
12
- # Expand an environment variable reference
13
- def self.expand_env(str, die_if_undefined: false)
14
- str.gsub(/\$([a-zA-Z_][a-zA-Z0-9_]*)|\${\g<1>}|%\g<1>%/) do
15
- envar = Regexp.last_match(1)
16
- raise HrefError, "jekyll_href error: #{envar} is undefined".red, [] \
17
- if !ENV.key?(envar) && die_if_undefined # Suppress stack trace
18
-
19
- ENV.fetch(envar, nil)
20
- end
21
- end
22
-
23
- def self.register(klass, name)
24
- abort("Error: The #{name} plugin does not define VERSION") \
25
- unless klass.const_defined?(:VERSION)
26
-
27
- version = klass.const_get(:VERSION)
28
-
29
- abort("Error: The #{name} plugin is not an instance of JekyllSupport::JekyllBlock or JekyllSupport::JekyllTag") \
30
- unless klass.instance_of?(Class) &&
31
- (klass.ancestors.include?(JekyllSupport::JekyllBlock) ||
32
- klass.ancestors.include?(JekyllSupport::JekyllTag))
33
-
34
- Liquid::Template.register_tag(name, klass)
35
- PluginMetaLogger.instance.info { "Loaded #{name} v#{version} plugin." }
36
- end
37
-
38
- # strip leading and trailing quotes if present
39
- def self.remove_quotes(string)
40
- string.strip.gsub(/\A'|\A"|'\Z|"\Z/, '').strip if string
41
- end
42
-
43
12
  # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags
44
13
  # @param tag_name [String] the name of the tag, which we already know.
45
14
  # @param argument_string [String] the arguments from the tag, as a single string.
@@ -53,51 +22,18 @@ class JekyllPluginHelper # rubocop:disable Metrics/ClassLength
53
22
  @tag_name = tag_name
54
23
  @logger = logger
55
24
  @no_arg_parsing = no_arg_parsing
56
- reinitialize(markup.strip)
57
-
58
- @attribution = parameter_specified?('attribution') || false unless no_arg_parsing
59
- @logger.debug { "@keys_values='#{@keys_values}'" }
25
+ @markup = markup
60
26
  rescue StandardError => e
61
- @logger.error { "#{self.class} died with a #{e.full_message}" }
62
- end
63
-
64
- def attribute
65
- return unless @current_gem
66
-
67
- <<~END_OUTPUT
68
- <div id="jps_attribute_#{rand(999_999)}" class="jps_attribute">
69
- <div>
70
- <a href="#{@homepage}" target="_blank" rel="nofollow">
71
- #{attribution_string}
72
- </a>
73
- </div>
74
- </div>
75
- END_OUTPUT
76
- end
77
-
78
- def default_attribution
79
- authors = @authors&.join(', ')
80
- result = "Generated by the \#{@name} v\#{@version} Jekyll plugin"
81
- result << ", written by #{authors}" if authors
82
- result << " \#{@published_date}" if @published_date
83
- result << '.'
84
- result
85
- end
86
-
87
- # Sets @current_gem if file points at a uniquely named file within a gem.
88
- # @param file must be a fully qualified file name in a gem, for example: __FILE__
89
- def gem_file(file)
90
- @current_gem = GemSupport.current_spec file
91
- @logger.debug "No gem found for '#{file} was found." unless @current_gem
92
- annotate_globals if @attribution && @current_gem
27
+ e.shorten_backtrace
28
+ @logger.error { e.message }
93
29
  end
94
30
 
95
31
  # @return undefined if parameter was specified, removes it from the available tokens and returns value
96
32
  def parameter_specified?(name, delete_param: true)
97
- return if @keys_values.empty?
33
+ return false if @keys_values.to_s.empty?
98
34
 
99
35
  key = name
100
- key = name.to_sym if @keys_values.first.first.instance_of?(Symbol)
36
+ key = name.to_sym if @keys_values&.first&.first.instance_of?(Symbol)
101
37
  value = @keys_values[key]
102
38
  delete_parameter(name) if delete_param
103
39
  value
@@ -112,18 +48,21 @@ class JekyllPluginHelper # rubocop:disable Metrics/ClassLength
112
48
  define_singleton_method(:params) { warn_fetch :params }
113
49
  define_singleton_method(:parameter_specified?) { |_name| warn_parse(:parameter_specified?) }
114
50
  define_singleton_method(:delete_parameter) { |_name| warn_parse(:delete_parameter) }
51
+ @attribution = false
115
52
  else
116
53
  parse markup
54
+ @attribution = parameter_specified?('attribution') || false
55
+ @logger.debug { "@keys_values='#{@keys_values}'" }
117
56
  end
118
57
  end
119
58
 
120
59
  # Call this method to return the remaining markup after `parameter_specified?` has been invoked.
121
60
  def remaining_markup
122
- @argv.join(' ')
61
+ @argv&.join(' ')
123
62
  end
124
63
 
125
64
  def remaining_markup_original
126
- @argv_original.join(' ')
65
+ @argv_original&.join(' ')
127
66
  end
128
67
 
129
68
  def warn_fetch(variable)
@@ -134,27 +73,6 @@ class JekyllPluginHelper # rubocop:disable Metrics/ClassLength
134
73
  abort "Error: Argument parsing was suppressed, but an attempt to invoke #{meth} was made"
135
74
  end
136
75
 
137
- private
138
-
139
- def attribution_string
140
- string = if @attribution == true
141
- default_attribution
142
- else
143
- @attribution
144
- end
145
- String.interpolate { string }
146
- end
147
-
148
- def annotate_globals
149
- return unless @current_gem
150
-
151
- @name = @current_gem.name
152
- @authors = @current_gem.authors
153
- @homepage = @current_gem.homepage
154
- @published_date = @current_gem.date.to_date.to_s
155
- @version = @current_gem.version
156
- end
157
-
158
76
  def delete_parameter(key)
159
77
  return if @keys_values.empty? || @params.nil?
160
78
 
@@ -167,58 +85,26 @@ class JekyllPluginHelper # rubocop:disable Metrics/ClassLength
167
85
  @keys_values_original.delete(key)
168
86
  end
169
87
 
170
- PREDEFINED_SCOPE_KEYS = %i[include page].freeze
171
-
172
- # Finds variables defined in an invoking include, or maybe somewhere else
173
- # @return variable value or nil
174
- def dereference_include_variable(name)
175
- @liquid_context.scopes.each do |scope|
176
- next if PREDEFINED_SCOPE_KEYS.include? scope.keys.first
177
-
178
- value = scope[name]
179
- return value if value
180
- end
181
- nil
182
- end
183
-
184
- # @return value of variable, or the empty string
185
- def dereference_variable(name)
186
- value = @liquid_context[name] # Finds variables named like 'include.my_variable', found in @liquid_context.scopes.first
187
- value ||= @page[name] if @page # Finds variables named like 'page.my_variable'
188
- value ||= dereference_include_variable(name)
189
- value ||= ''
190
- value
191
- end
192
-
193
- def lookup_variable(symbol)
194
- string = symbol.to_s
195
- return string unless string.start_with?('{{') && string.end_with?('}}')
196
-
197
- dereference_variable(string.delete_prefix('{{').delete_suffix('}}'))
198
- end
88
+ private
199
89
 
200
90
  def page
201
91
  @liquid_context.registers[:page]
202
92
  end
203
93
 
204
- # rubocop:disable Style/IfUnlessModifier
205
94
  def parse(markup)
206
95
  @argv_original = Shellwords.split(markup)
207
96
  @keys_values_original = KeyValueParser
208
- .new({}, { array_values: false, normalize_keys: false, separator: /=/ })
209
- .parse(@argv_original)
210
- unless respond_to?(:no_arg_parsing) && no_arg_parsing
211
- @params_original = @keys_values_original.map { |k, _v| lookup_variable(k) }
212
- end
97
+ .new({}, { array_values: false, normalize_keys: false, separator: /=/ })
98
+ .parse(@argv_original)
99
+ @params_original = @keys_values_original unless respond_to?(:no_arg_parsing) && no_arg_parsing
213
100
 
214
101
  @argv = Shellwords.split(self.class.expand_env(markup))
215
102
  @keys_values = KeyValueParser
216
- .new({}, { array_values: false, normalize_keys: false, separator: /=/ })
217
- .parse(@argv)
103
+ .new({}, { array_values: false, normalize_keys: false, separator: /=/ })
104
+ .parse(@argv)
218
105
 
219
106
  return if respond_to?(:no_arg_parsing) && no_arg_parsing
220
107
 
221
- @params = @keys_values.map { |k, _v| lookup_variable(k) }
108
+ @params = @keys_values # TODO: @keys_values should be deleted
222
109
  end
223
- # rubocop:enable Style/IfUnlessModifier
224
110
  end
@@ -0,0 +1,72 @@
1
+ # Attribution aspect of JekyllPluginHelper
2
+ class JekyllPluginHelper
3
+ # @param file must be a fully qualified file name that points to a file within a gem.
4
+ # @return Gem::Specification of gem that file points into, or nil if not called from a gem
5
+ # See https://stackoverflow.com/a/75890279/553865
6
+ def self.current_spec(file)
7
+ abort 'JekyllPluginHelper::current_spec: file is nil' if file.nil?
8
+ return nil unless File.exist?(file)
9
+
10
+ searcher = if Gem::Specification.respond_to?(:find)
11
+ Gem::Specification
12
+ elsif Gem.respond_to?(:searcher)
13
+ Gem.searcher.init_gemspecs
14
+ end
15
+
16
+ searcher&.find do |spec|
17
+ file.start_with? spec.full_gem_path
18
+ end
19
+ end
20
+
21
+ def attribute
22
+ return unless @current_gem
23
+
24
+ <<~END_OUTPUT
25
+ <div id="jps_attribute_#{rand(999_999)}" class="jps_attribute">
26
+ <div>
27
+ <a href="#{@homepage}" target="_blank" rel="nofollow">
28
+ #{attribution_string}
29
+ </a>
30
+ </div>
31
+ </div>
32
+ END_OUTPUT
33
+ end
34
+
35
+ def default_attribution
36
+ authors = @authors&.join(', ')
37
+ result = "Generated by the \#{@name} v\#{@version} Jekyll plugin"
38
+ result << ", written by #{authors}" if authors
39
+ result << " \#{@published_date}" if @published_date
40
+ result << '.'
41
+ result
42
+ end
43
+
44
+ # Sets @current_gem if file points at a uniquely named file within a gem.
45
+ # @param file must be a fully qualified file name in a gem, for example: __FILE__
46
+ def gem_file(file)
47
+ @current_gem = JekyllPluginHelper.current_spec file
48
+ @logger.debug "No gem found for '#{file} was found." unless @current_gem
49
+ annotate_globals if @attribution && @current_gem
50
+ end
51
+
52
+ private
53
+
54
+ def annotate_globals
55
+ return unless @current_gem
56
+
57
+ @name = @current_gem.name
58
+ @authors = @current_gem.authors
59
+ @homepage = @current_gem.homepage
60
+ @published_date = @current_gem.date.to_date.to_s
61
+ @version = @current_gem.version
62
+ end
63
+
64
+ def attribution_string
65
+ string = if @attribution == true
66
+ default_attribution
67
+ else
68
+ @attribution
69
+ end
70
+ String.interpolate { string }
71
+ end
72
+ end
@@ -0,0 +1,73 @@
1
+ require 'facets/string/camelcase'
2
+ require 'facets/string/snakecase'
3
+ require 'yaml'
4
+
5
+ # Class methods for JekyllPluginHelper
6
+ class JekyllPluginHelper
7
+ # Expand an environment variable reference
8
+ def self.expand_env(str, die_if_undefined: false)
9
+ str&.gsub(/\$([a-zA-Z_][a-zA-Z0-9_]*)|\${\g<1>}|%\g<1>%/) do
10
+ envar = Regexp.last_match(1)
11
+ raise JekyllPluginSupportError, "jekyll_plugin_support error: #{envar} is undefined".red, [] \
12
+ if !ENV.key?(envar) && die_if_undefined # Suppress stack trace
13
+
14
+ ENV.fetch(envar, nil)
15
+ end
16
+ end
17
+
18
+ def self.generate_message(klass, tag_name, version)
19
+ error_ruby_class_name = "#{klass.name.camelcase(:upper)}Error"
20
+ config_die_key = "die_on_#{error_ruby_class_name.snakecase}"
21
+ error_css_class_name = error_ruby_class_name.split('::').last.snakecase
22
+ # config_file_fq = File.realpath 'demo/_config.yml'
23
+ config = YAML.load_file('demo/_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 like this:
29
+
30
+ #{tag_name}:
31
+ #{config_die_key}: false
32
+ END_MSG
33
+ else
34
+ <<~END_MSG
35
+ _config.yml contains the following configuration for this plugin is:
36
+ #{tag_config}
37
+ END_MSG
38
+ end
39
+
40
+ <<~END_MSG
41
+ Loaded plugin #{tag_name} v#{version}. It has:
42
+ Error class: #{error_ruby_class_name}
43
+ CSS class for error messages: #{error_css_class_name}
44
+
45
+ #{tag_config_msg}
46
+ END_MSG
47
+ end
48
+
49
+ def self.register(klass, tag_name)
50
+ abort("Error: The #{tag_name} plugin does not define VERSION") \
51
+ unless klass.const_defined?(:VERSION)
52
+
53
+ version = klass.const_get(:VERSION)
54
+
55
+ abort("Error: The #{tag_name} plugin is not an instance of JekyllSupport::JekyllBlock or JekyllSupport::JekyllTag") \
56
+ unless klass.instance_of?(Class) &&
57
+ (klass.ancestors.include?(JekyllSupport::JekyllBlock) ||
58
+ klass.ancestors.include?(JekyllSupport::JekyllTag))
59
+
60
+ Liquid::Template.register_tag(tag_name, klass)
61
+ msg = generate_message(klass, tag_name, version)
62
+ PluginMetaLogger.instance.info msg
63
+ end
64
+
65
+ def self.remove_html_tags(string)
66
+ string.gsub(/<[^>]*>/, '').strip
67
+ end
68
+
69
+ # strip leading and trailing quotes if present
70
+ def self.remove_quotes(string)
71
+ string.strip.gsub(/\A'|\A"|'\Z|"\Z/, '').strip if string
72
+ end
73
+ end
@@ -1,3 +1,3 @@
1
1
  module JekyllPluginSupportVersion
2
- VERSION = '0.7.2'.freeze
2
+ VERSION = '0.8.1'.freeze
3
3
  end
@@ -4,211 +4,15 @@ require 'jekyll_plugin_logger'
4
4
  require_relative 'jekyll_plugin_helper'
5
5
  require_relative 'jekyll_plugin_support/version'
6
6
 
7
- # @author Copyright 2022 Michael Slinn
8
- # @license SPDX-License-Identifier: Apache-2.0``
9
7
  module NoArgParsing
10
8
  attr_accessor :no_arg_parsing
11
9
 
12
10
  @no_arg_parsing = true
13
11
  end
14
12
 
15
- module JekyllSupport
16
- DISPLAYED_CALLS = 8
17
-
18
- def self.error_short_trace(logger, error)
19
- remaining = error.backtrace.length - DISPLAYED_CALLS
20
- logger.error do
21
- error.message + "\n" + # rubocop:disable Style/StringConcatenation
22
- error.backtrace.take(DISPLAYED_CALLS).join("\n") +
23
- "\n...Remaining #{remaining} call sites elided.\n"
24
- end
25
- end
26
-
27
- def self.warn_short_trace(logger, error)
28
- remaining = error.backtrace.length - DISPLAYED_CALLS
29
- logger.warn do
30
- error.message + "\n" + # rubocop:disable Style/StringConcatenation
31
- error.backtrace.take(DISPLAYED_CALLS).join("\n") +
32
- "\n...Remaining #{remaining} call sites elided.\n"
33
- end
34
- end
35
-
36
- # Base class for Jekyll block tags
37
- class JekyllBlock < Liquid::Block
38
- attr_reader :argument_string, :helper, :line_number, :logger, :page, :site, :text
39
-
40
- # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags
41
- # @param tag_name [String] the name of the tag, which we usually know.
42
- # @param argument_string [String] the arguments passed to the tag, as a single string.
43
- # @param parse_context [Liquid::ParseContext] hash that stores Liquid options.
44
- # By default it has two keys: :locale and :line_numbers, the first is a Liquid::I18n object, and the second,
45
- # a boolean parameter that determines if error messages should display the line number the error occurred.
46
- # This argument is used mostly to display localized error messages on Liquid built-in Tags and Filters.
47
- # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags
48
- # @return [void]
49
- def initialize(tag_name, argument_string, parse_context)
50
- super
51
- @tag_name = tag_name
52
- @argument_string = argument_string
53
- @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
54
- @logger.debug { "#{self.class}: respond_to?(:no_arg_parsing) #{respond_to?(:no_arg_parsing) ? 'yes' : 'no'}." }
55
- @helper = JekyllPluginHelper.new tag_name, argument_string, @logger, respond_to?(:no_arg_parsing)
56
- end
57
-
58
- # @return line number where tag or block was found, relative to the start of the page
59
- def jekyll_line_number
60
- @page['front_matter'].count("\n") + @line_number
61
- end
62
-
63
- # Method prescribed by the Jekyll plugin lifecycle.
64
- # Defines @config, @envs, @mode, @page and @site
65
- # @return [String]
66
- def render(liquid_context)
67
- text = super
68
- @helper.liquid_context = liquid_context
69
-
70
- @page = liquid_context.registers[:page] # hash
71
- @site = liquid_context.registers[:site]
72
- @config = @site.config
73
- @envs = liquid_context.environments.first
74
-
75
- @layout = @envs[:layout]
76
- @paginator = @envs[:paginator]
77
- @theme = @envs[:theme]
78
-
79
- @mode = @config['env']&.key?('JEKYLL_ENV') ? @config['env']['JEKYLL_ENV'] : 'development'
80
-
81
- render_impl text
82
- rescue StandardError => e
83
- @logger.error { "#{self.class} died with a #{e.full_message}" }
84
- JekyllSupport.error_short_trace(@logger, e)
85
- end
86
-
87
- # Jekyll plugins should override this method, not render,
88
- # so they can be tested more easily.
89
- # The following variables are predefined:
90
- # @argument_string, @config, @envs, @helper, @layout, @logger, @mode, @page, @paginator, @site, @tag_name and @theme
91
- # @return [String] The result to be rendered to the invoking page
92
- def render_impl(text)
93
- text
94
- end
95
-
96
- def warn_short_trace(error)
97
- JekyllSupport.warn_short_trace(@logger, error)
98
- end
99
- end
100
-
101
- class JekyllBlockNoArgParsing < JekyllBlock
102
- def initialize(tag_name, argument_string, parse_context)
103
- class << self
104
- include NoArgParsing
105
- end
106
-
107
- super
108
- @logger.debug { "#{self.class}: respond_to?(:o_arg_parsing) #{respond_to?(:no_arg_parsing) ? 'yes' : 'no'}." }
109
- rescue StandardError => e
110
- @logger.error { "#{self.class} died with a #{e.full_message}" }
111
- JekyllSupport.error_short_trace(@logger, e)
112
- end
113
-
114
- def warn_short_trace(error)
115
- JekyllSupport.warn_short_trace(@logger, error)
116
- end
117
- end
118
-
119
- # Base class for Jekyll tags
120
- class JekyllTag < Liquid::Tag
121
- attr_reader :argument_string, :helper, :line_number, :logger, :page, :site
122
-
123
- # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags
124
- # @param tag_name [String] the name of the tag, which we usually know.
125
- # @param argument_string [String] the arguments passed to the tag, as a single string.
126
- # @param parse_context [Liquid::ParseContext] hash that stores Liquid options.
127
- # By default it has two keys: :locale and :line_numbers, the first is a Liquid::I18n object, and the second,
128
- # a boolean parameter that determines if error messages should display the line number the error occurred.
129
- # This argument is used mostly to display localized error messages on Liquid built-in Tags and Filters.
130
- # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags
131
- # @return [void]
132
- def initialize(tag_name, argument_string, parse_context)
133
- super
134
- @tag_name = tag_name
135
- @argument_string = argument_string
136
- @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
137
- @logger.debug { "#{self.class}: respond_to?(:no_arg_parsing) #{respond_to?(:no_arg_parsing) ? 'yes' : 'no'}." }
138
- @helper = JekyllPluginHelper.new(tag_name, argument_string, @logger, respond_to?(:no_arg_parsing))
139
- end
140
-
141
- # If a Jekyll plugin needs to crash exit, and stop Jekyll, call this method.
142
- # It does not generate a stack trace.
143
- # This method does not return because the process is abruptly terminated.
144
- #
145
- # @param error StandardError or a subclass of StandardError is required
146
- #
147
- # Do not raise the error before calling this method, just create it via 'new', like this:
148
- # exit_without_stack_trace StandardError.new('This is my error message')
149
- #
150
- # If you want to call this method from a handler method, the default index for the backtrace array must be specified.
151
- # The default backtrace index is 1, which means the calling method.
152
- # To specify the calling method's caller, pass in 2, like this:
153
- # exit_without_stack_trace StandardError.new('This is my error message'), 2
154
- def exit_without_stack_trace(error, caller_index = 1)
155
- raise error
156
- rescue StandardError => e
157
- file, line_number, caller = e.backtrace[caller_index].split(':')
158
- caller = caller.tr('`', "'")
159
- warn "#{self.class} died with a '#{error.message}' #{caller} on line #{line_number} of #{file}".red
160
- # Process.kill('HUP', Process.pid) # generates huge stack trace
161
- exec "echo ''"
162
- end
163
-
164
- # @return line number where tag or block was found, relative to the start of the page
165
- def jekyll_line_number
166
- @page['front_matter'].count("\n") + @line_number
167
- end
168
-
169
- # Method prescribed by the Jekyll plugin lifecycle.
170
- def render(liquid_context)
171
- return if @helper.excerpt_caller
172
-
173
- @helper.liquid_context = liquid_context
174
-
175
- @envs = liquid_context.environments.first
176
-
177
- @layout = @envs[:layout]
178
- @paginator = @envs[:paginator]
179
- @theme = @envs[:theme]
180
-
181
- @page = liquid_context.registers[:page]
182
- @site = liquid_context.registers[:site]
183
-
184
- @config = @site.config
185
- @mode = @config['env']&.key?('JEKYLL_ENV') ? @config['env']['JEKYLL_ENV'] : 'development'
186
-
187
- render_impl
188
- rescue StandardError => e
189
- JekyllSupport.error_short_trace(@logger, e)
190
- end
191
-
192
- # Jekyll plugins must override this method, not render, so their plugin can be tested more easily
193
- # The following variables are predefined:
194
- # @argument_string, @config, @envs, @helper, @layout, @logger, @mode, @page, @paginator, @site, @tag_name and @theme
195
- def render_impl
196
- abort "#{self.class}.render_impl for tag #{@tag_name} must be overridden, but it was not."
197
- end
198
-
199
- def warn_short_trace(error)
200
- JekyllSupport.warn_short_trace(@logger, error)
201
- end
202
- end
203
-
204
- class JekyllTagNoArgParsing < JekyllTag
205
- def initialize(tag_name, argument_string, parse_context)
206
- class << self
207
- include NoArgParsing
208
- end
209
-
210
- super
211
- @logger.debug { "#{self.class}: respond_to?(:no_arg_parsing) #{respond_to?(:no_arg_parsing) ? 'yes' : 'no'}." }
212
- end
213
- end
214
- end
13
+ require_relative 'jekyll_plugin_support_class'
14
+ require_relative 'jekyll_plugin_support_block'
15
+ require_relative 'jekyll_plugin_support_block_noarg'
16
+ require_relative 'jekyll_plugin_support_tag'
17
+ require_relative 'jekyll_plugin_support_tag_noarg'
18
+ require_relative 'jekyll_custom_error'