jekyll_plugin_support 0.7.2 → 0.8.0

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.
@@ -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.msg }
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,33 @@
1
+ # Class methods for JekyllPluginHelper
2
+ class JekyllPluginHelper
3
+ # Expand an environment variable reference
4
+ def self.expand_env(str, die_if_undefined: false)
5
+ str&.gsub(/\$([a-zA-Z_][a-zA-Z0-9_]*)|\${\g<1>}|%\g<1>%/) do
6
+ envar = Regexp.last_match(1)
7
+ raise JekyllPluginSupportError, "jekyll_plugin_support error: #{envar} is undefined".red, [] \
8
+ if !ENV.key?(envar) && die_if_undefined # Suppress stack trace
9
+
10
+ ENV.fetch(envar, nil)
11
+ end
12
+ end
13
+
14
+ def self.register(klass, name)
15
+ abort("Error: The #{name} plugin does not define VERSION") \
16
+ unless klass.const_defined?(:VERSION)
17
+
18
+ version = klass.const_get(:VERSION)
19
+
20
+ abort("Error: The #{name} plugin is not an instance of JekyllSupport::JekyllBlock or JekyllSupport::JekyllTag") \
21
+ unless klass.instance_of?(Class) &&
22
+ (klass.ancestors.include?(JekyllSupport::JekyllBlock) ||
23
+ klass.ancestors.include?(JekyllSupport::JekyllTag))
24
+
25
+ Liquid::Template.register_tag(name, klass)
26
+ PluginMetaLogger.instance.info { "Loaded #{name} v#{version} plugin." }
27
+ end
28
+
29
+ # strip leading and trailing quotes if present
30
+ def self.remove_quotes(string)
31
+ string.strip.gsub(/\A'|\A"|'\Z|"\Z/, '').strip if string
32
+ end
33
+ end
@@ -1,3 +1,3 @@
1
1
  module JekyllPluginSupportVersion
2
- VERSION = '0.7.2'.freeze
2
+ VERSION = '0.8.0'.freeze
3
3
  end
@@ -4,211 +4,14 @@ 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'
@@ -0,0 +1,77 @@
1
+ require_relative 'jekyll_plugin_error_handling'
2
+
3
+ module JekyllSupport
4
+ # Base class for Jekyll block tags
5
+ class JekyllBlock < Liquid::Block
6
+ attr_reader :argument_string, :helper, :line_number, :logger, :page, :site, :text
7
+
8
+ include JekyllSupportErrorHandling
9
+ extend JekyllSupportErrorHandling
10
+
11
+ # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags
12
+ # @param tag_name [String] the name of the tag, which we usually know.
13
+ # @param argument_string [String] the arguments passed to the tag, as a single string.
14
+ # @param parse_context [Liquid::ParseContext] hash that stores Liquid options.
15
+ # By default it has two keys: :locale and :line_numbers, the first is a Liquid::I18n object, and the second,
16
+ # a boolean parameter that determines if error messages should display the line number the error occurred.
17
+ # This argument is used mostly to display localized error messages on Liquid built-in Tags and Filters.
18
+ # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags
19
+ # @return [void]
20
+ def initialize(tag_name, markup, parse_context)
21
+ super
22
+ @tag_name = tag_name
23
+ @argument_string = markup.to_s # Vars in plugin parameters cannot be replaced yet
24
+ @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
25
+ @logger.debug { "#{self.class}: respond_to?(:no_arg_parsing) #{respond_to?(:no_arg_parsing) ? 'yes' : 'no'}." }
26
+ @helper = JekyllPluginHelper.new tag_name, markup, @logger, respond_to?(:no_arg_parsing)
27
+ end
28
+
29
+ # Method prescribed by the Jekyll plugin lifecycle.
30
+ # Defines @config, @envs, @mode, @page and @site
31
+ # @return [String]
32
+ def render(liquid_context)
33
+ @helper.liquid_context = JekyllSupport.inject_vars @logger, liquid_context
34
+ text = super # Liquid variable values in content are looked up and substituted
35
+
36
+ @envs = liquid_context.environments.first
37
+ @page = liquid_context.registers[:page] # hash
38
+ @scopes = liquid_context.scopes
39
+ @site = liquid_context.registers[:site]
40
+
41
+ @config = @site.config
42
+ @tag_config = @config[@tag_name]
43
+
44
+ @layout = @envs[:layout]
45
+ @paginator = @envs[:paginator]
46
+ @theme = @envs[:theme]
47
+
48
+ @mode = @config['env']&.key?('JEKYLL_ENV') ? @config['env']['JEKYLL_ENV'] : 'development'
49
+
50
+ @helper.reinitialize(@markup.strip)
51
+
52
+ @attribution = @helper.parameter_specified?('attribution') || false unless @no_arg_parsing
53
+ @logger.debug { "@keys_values='#{@keys_values}'" }
54
+
55
+ markup = JekyllSupport.lookup_liquid_variables liquid_context, @argument_string
56
+ @helper.reinitialize markup
57
+
58
+ render_impl text
59
+ rescue StandardError => e
60
+ e.shorten_backtrace
61
+ msg = format_error_message e.full_message
62
+ @logger.error msg
63
+ raise e if @die_on_standard_error
64
+
65
+ "<div class='standard_error'>#{e.class}: #{msg}</div>"
66
+ end
67
+
68
+ # Jekyll plugins should override this method, not render,
69
+ # so they can be tested more easily.
70
+ # The following variables are predefined:
71
+ # @argument_string, @config, @envs, @helper, @layout, @logger, @mode, @page, @paginator, @site, @tag_name and @theme
72
+ # @return [String] The result to be rendered to the invoking page
73
+ def render_impl(text)
74
+ text
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,30 @@
1
+ require_relative 'jekyll_plugin_error_handling'
2
+
3
+ module JekyllSupport
4
+ class JekyllBlockNoArgParsing < JekyllBlock
5
+ attr_reader :argument_string, :helper, :line_number, :logger, :page, :site
6
+
7
+ include JekyllSupportErrorHandling
8
+ extend JekyllSupportErrorHandling
9
+
10
+ def initialize(tag_name, argument_string, parse_context)
11
+ class << self
12
+ include NoArgParsing
13
+ end
14
+
15
+ super
16
+ @logger.debug { "#{self.class}: respond_to?(:o_arg_parsing) #{respond_to?(:no_arg_parsing) ? 'yes' : 'no'}." }
17
+ rescue StandardError => e
18
+ e.shorten_backtrace
19
+ @logger.error { e.full_message }
20
+ JekyllSupport.error_short_trace(@logger, e)
21
+ end
22
+
23
+ # Jekyll plugins must override this method, not render, so their plugin can be tested more easily
24
+ # The following variables are predefined:
25
+ # @argument_string, @config, @envs, @helper, @layout, @logger, @mode, @page, @paginator, @site, @tag_name and @theme
26
+ def render_impl
27
+ abort "#{self.class}.render_impl for tag #{@tag_name} must be overridden, but it was not."
28
+ end
29
+ end
30
+ end