Module: JekyllSupport
- Defined in:
- lib/hooks/a_page.rb,
lib/jekyll_plugin_support.rb,
lib/jekyll_plugin_support.rb,
lib/error/jekyll_custom_error.rb,
lib/helper/jekyll_plugin_helper.rb,
lib/tag/jekyll_plugin_support_tag.rb,
lib/block/jekyll_plugin_support_block.rb,
lib/helper/jekyll_plugin_helper_class.rb,
lib/tag/jekyll_plugin_support_tag_noarg.rb,
lib/block/jekyll_plugin_support_block_noarg.rb,
lib/helper/jekyll_plugin_helper_attribution.rb,
lib/generator/jekyll_plugin_support_generator.rb,
lib/jekyll_plugin_support/jekyll_plugin_support_class.rb
Defined Under Namespace
Classes: APage, CustomError, JekyllBlock, JekyllBlockNoArgParsing, JekyllGenerator, JekyllPluginHelper, JekyllTag, JekyllTagNoArgParsing
Constant Summary collapse
- FIXNUM_MAX =
(2**((0.size * 8) - 2)) - 1
- END_OF_DAYS =
One trillion years in the future
1_000_000_000_000- DISPLAYED_CALLS =
8- JekyllPluginSupportError =
define_error
Class Method Summary collapse
-
.apage_from(collection_name: nil, date: nil, description: nil, draft: false, last_modified: nil, logger: nil, order: nil, title: nil, url: nil) ⇒ Object
Contructor for testing and jekyll_outline.
-
.apages_from_objects(objects, origin) ⇒ Object
Create Array of JekyllSupport::APage from objects.
-
.define_error ⇒ Object
A new StandardError subclass containing the shorten_backtrace method.
- .dump_stack(stack, cycles, interval) ⇒ Object
- .dump_vars(_logger, liquid_context) ⇒ Object
- .error_short_trace(logger, error) ⇒ Object
-
.inject_config_vars(liquid_context) ⇒ Object
Inject variable definitions from _config.yml into liquid_context Modifies liquid_context.scopes in the caller (call by object reference, see stackoverflow.com/a/1872159/553865) See README.md#configuration-variable-definitions See demo/variables.html.
-
.lookup_liquid_variables(logger, liquid_context, markup_original) ⇒ Object
Modifies a clone of markup_original so variable references are replaced by their values.
-
.new_attribute(obj, prop_name, prop_value) ⇒ Object
Defines a new attribute called ‘prop_name` in object `obj` and sets it to `prop_value`.
- .process_included_variables(logger, scope, markup) ⇒ Object
- .process_jekyll_variables(logger, jekyll, markup) ⇒ Object
- .process_layout_variables(logger, layout, markup) ⇒ Object
-
.process_liquid_variables(logger, scope, markup) ⇒ Object
Process assigned, captured and injected variables.
- .process_page_variables(logger, page, markup) ⇒ Object
- .redef_without_warning(const, value) ⇒ Object
-
.sanitize_variable_name(name) ⇒ String
Sanitizes variable names to prevent regex injection attacks.
- .warn_short_trace(logger, error) ⇒ Object
Class Method Details
.apage_from(collection_name: nil, date: nil, description: nil, draft: false, last_modified: nil, logger: nil, order: nil, title: nil, url: nil) ⇒ Object
Contructor for testing and jekyll_outline
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/hooks/a_page.rb', line 7 def self.apage_from( # rubocop:disable Metrics/ParameterLists collection_name: nil, date: nil, description: nil, draft: false, last_modified: nil, logger: nil, order: nil, title: nil, url: nil ) # Jekyll documents have inconsistent date and last_modified property types. date = Time.parse(date) if date.instance_of?(String) unless date.instance_of? Time logger.error { "date is not an instance of Time, it is an instance of #{date.class}" } exit 2 end last_modified = Date.parse(last_modified) if last_modified.instance_of?(String) last_modified = Date.parse(date.strftime('%Y-%m-%d')) if last_modified.nil? unless last_modified.instance_of? Date logger.error { "last_modified is not an instance of Date, it is an instance of #{last_modified.class}" } exit 3 end last_modified = Date.parse(date._to_s) if last_modified.nil? data = { collection: { label: collection_name }, draft: draft, last_modified: last_modified, order: order, title: title, } obj = {} JekyllSupport.new_attribute obj, :data, data JekyllSupport.new_attribute obj, :date, date JekyllSupport.new_attribute obj, :description, description JekyllSupport.new_attribute obj, :draft, draft JekyllSupport.new_attribute obj, :extname, '.html' JekyllSupport.new_attribute obj, :last_modified, last_modified JekyllSupport.new_attribute obj, :logger, PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config) JekyllSupport.new_attribute obj, :title, title JekyllSupport.new_attribute obj, :url, url JekyllSupport::APage.new obj, nil rescue StandardError => e puts e. end |
.apages_from_objects(objects, origin) ⇒ Object
Create Array of JekyllSupport::APage from objects
58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/hooks/a_page.rb', line 58 def self.apages_from_objects(objects, origin) pages = [] objects.each do |object| unless object.respond_to?(:logger) JekyllSupport.new_attribute(object, :logger, PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)) end page = APage.new(object, origin) pages << page unless page.data['exclude_from_all'] || page.path == 'redirect.html' end pages end |
.define_error ⇒ Object
Returns a new StandardError subclass containing the shorten_backtrace method.
23 24 25 |
# File 'lib/jekyll_plugin_support/jekyll_plugin_support_class.rb', line 23 def define_error Class.new ::JekyllSupport::CustomError end |
.dump_stack(stack, cycles, interval) ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/jekyll_plugin_support/jekyll_plugin_support_class.rb', line 75 def self.dump_stack(stack, cycles, interval) stack_depth = stack.length puts "Stack depth is #{stack_depth}" num_entries = cycles * interval return unless stack_depth > interval * 5 stack.last(num_entries).each_with_index do |x, i| msg = " #{i}: #{x}" (i % interval).zero? ? puts(msg.yellow) : puts(msg) end end |
.dump_vars(_logger, liquid_context) ⇒ Object
30 31 32 33 34 35 36 37 38 39 |
# File 'lib/jekyll_plugin_support/jekyll_plugin_support_class.rb', line 30 def self.dump_vars(_logger, liquid_context) page = liquid_context.registers[:page] vars = liquid_context.scopes.map do |scope| scope.map { |name, value| " #{name} = #{value}" }.join("\n") end.join("\n") puts <<~END_MSG #{page['name']} variables after injecting any defined in _config.yml: #{vars} END_MSG end |
.error_short_trace(logger, error) ⇒ Object
16 17 18 19 20 |
# File 'lib/jekyll_plugin_support/jekyll_plugin_support_class.rb', line 16 def self.error_short_trace(logger, error) error.set_backtrace error.backtrace[0..DISPLAYED_CALLS] logger.error { error. } # Are error and logger.error defined? error end |
.inject_config_vars(liquid_context) ⇒ Object
Inject variable definitions from _config.yml into liquid_context Modifies liquid_context.scopes in the caller (call by object reference, see stackoverflow.com/a/1872159/553865) See README.md#configuration-variable-definitions See demo/variables.html
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/jekyll_plugin_support/jekyll_plugin_support_class.rb', line 47 def self.inject_config_vars(liquid_context) site = liquid_context.registers[:site] plugin_variables = site.config['liquid_vars'] scope = liquid_context.scopes.last # Support multiple environment variable keys and fall back to Jekyll's environment env = site.config['env'] @mode = env&.[]('JEKYLL_ENV') || env&.[]('JEKYLL_ENVIRONMENT') || site.config['JEKYLL_ENV'] || site.config['JEKYLL_ENVIRONMENT'] || 'development' # Set default values (support multiple data types) plugin_variables&.each do |name, value| scope[name] = value end # Override with environment-specific values plugin_variables&.[](@mode)&.each do |name, value| scope[name] = value end liquid_context end |
.lookup_liquid_variables(logger, liquid_context, markup_original) ⇒ Object
Modifies a clone of markup_original so variable references are replaced by their values
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/jekyll_plugin_support/jekyll_plugin_support_class.rb', line 90 def self.lookup_liquid_variables(logger, liquid_context, markup_original) markup = markup_original.clone page = liquid_context.registers[:page] envs = liquid_context.environments.first layout = envs[:layout] jekyll = envs[:jekyll] # Process variables in Jekyll's actual priority order: # 1. Page variables (registers[:page]) # 2. Layout variables (environments.first[:layout]) # 3. Jekyll global variables (environments.first[:jekyll]) # 4. Include variables (scopes) # 5. Liquid variables (scopes) markup = process_page_variables logger, page, markup markup = process_layout_variables logger, layout, markup markup = process_jekyll_variables logger, jekyll, markup liquid_context.scopes&.each do |scope| markup = process_included_variables logger, scope, markup markup = process_liquid_variables logger, scope, markup end markup rescue StandardError => e logger.error { e. } end |
.new_attribute(obj, prop_name, prop_value) ⇒ Object
Defines a new attribute called ‘prop_name` in object `obj` and sets it to `prop_value`
73 74 75 76 |
# File 'lib/hooks/a_page.rb', line 73 def self.new_attribute(obj, prop_name, prop_value) obj.class.module_eval { attr_accessor prop_name } obj.instance_variable_set :"@#{prop_name}", prop_value end |
.process_included_variables(logger, scope, markup) ⇒ Object
115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/jekyll_plugin_support/jekyll_plugin_support_class.rb', line 115 def self.process_included_variables(logger, scope, markup) scope['include']&.each do |name, value| raise JekyllPluginSupportError, "include.#{name} is undefined." if name.nil? raise JekyllPluginSupportError, "include.#{name} is a #{name.class}, not a String." unless name.instance_of?(String) raise JekyllPluginSupportError, "include.#{name} has an undefined value." if value.nil? # Sanitize variable name to prevent regex injection sanitized_name = sanitize_variable_name(name) markup.gsub!("{{include.#{sanitized_name}}}", value.to_s) end markup rescue StandardError => e logger.error { e. } end |
.process_jekyll_variables(logger, jekyll, markup) ⇒ Object
171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/jekyll_plugin_support/jekyll_plugin_support_class.rb', line 171 def self.process_jekyll_variables(logger, jekyll, markup) return markup unless jekyll # JekyllDrop provides access to version and environment # Handle known JekyllDrop attributes markup.gsub!('{{jekyll.version}}', jekyll.version.to_s) if jekyll.respond_to?(:version) markup.gsub!('{{jekyll.environment}}', jekyll.environment.to_s) if jekyll.respond_to?(:environment) markup rescue StandardError => e logger.error { e. } end |
.process_layout_variables(logger, layout, markup) ⇒ Object
130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/jekyll_plugin_support/jekyll_plugin_support_class.rb', line 130 def self.process_layout_variables(logger, layout, markup) layout&.each do |name, value| if value.nil? value = '' logger.warn { "layout.#{value} is undefined." } end markup.gsub!("{{layout.#{name}}}", value.to_s) end markup rescue StandardError => e logger.error { e. } end |
.process_liquid_variables(logger, scope, markup) ⇒ Object
Process assigned, captured and injected variables
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/jekyll_plugin_support/jekyll_plugin_support_class.rb', line 144 def self.process_liquid_variables(logger, scope, markup) unless markup.instance_of?(String) logger.warn { "markup is a #{markup.class}, not a String" } return markup end scope&.each do |name, value| next if name.nil? value = '' if value.nil? markup.gsub!("{{#{name}}}", value&.to_s) end markup rescue StandardError => e logger.error { e. } end |
.process_page_variables(logger, page, markup) ⇒ Object
160 161 162 163 164 165 166 167 168 169 |
# File 'lib/jekyll_plugin_support/jekyll_plugin_support_class.rb', line 160 def self.process_page_variables(logger, page, markup) page&.each_key do |key| next if %w[content excerpt next previous output].include? key # Skip problem attributes markup.gsub!("{{page.#{key}}}", page[key].to_s) end markup rescue StandardError => e logger.error { e. } end |
.redef_without_warning(const, value) ⇒ Object
25 26 27 28 |
# File 'lib/jekyll_plugin_support.rb', line 25 def self.redef_without_warning(const, value) send(:remove_const, const) if const_defined?(const) const_set const, value end |
.sanitize_variable_name(name) ⇒ String
Sanitizes variable names to prevent regex injection attacks
188 189 190 191 |
# File 'lib/jekyll_plugin_support/jekyll_plugin_support_class.rb', line 188 def self.sanitize_variable_name(name) # Allow only alphanumeric characters, underscores, and hyphens name.to_s.gsub(/[^a-zA-Z0-9_-]/, '') end |
.warn_short_trace(logger, error) ⇒ Object
193 194 195 196 197 198 199 200 |
# File 'lib/jekyll_plugin_support/jekyll_plugin_support_class.rb', line 193 def self.warn_short_trace(logger, error) remaining = error.backtrace.length - DISPLAYED_CALLS logger.warn do error. + "\n" + error.backtrace.take(DISPLAYED_CALLS).join("\n") + "\n...Remaining #{remaining} call sites elided.\n" end end |