jekyll_flexible_include 2.0.4 → 2.0.5

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: 60cf6d0ee5123d82f4a0ae31d85db6ffcbb7326693af3dc457dc64110de42d88
4
- data.tar.gz: b06fcc1ef1439efdf98effed553c714583bbe600707719a7252c93079e8e7a5e
3
+ metadata.gz: 7728aa7304d9fef053bb7b6f0e5adb59938a13711764f5ec1615497d54e23845
4
+ data.tar.gz: 1ef45a4764e136856e80e9a874cfa6e30ac1a9bc2523a10a024fa79bafc1b3d5
5
5
  SHA512:
6
- metadata.gz: 2eab4ce0e37112c0499703ecd30211b01ae2b38e1ec89f01f94b188dfdf539ec7dd1a5f8aa4f4be7a3d9dae7d30d71797687a8a00c916e1cf948d6b1326403ba
7
- data.tar.gz: ab036ab986241031929f7f4ac335312e4fcb81a66019f196278c38d247292f22c69b009fe269b7e19633ea5a6645e1b86db81a2b60e172a16b3a6d4cb5791f96
6
+ metadata.gz: 33c164b768d259e680458b14fab226d7fe038685a8dc98b459140a812628c8e9978e200e1ea3da414be678ebaca5f73e3b42957f26879162d6ce9c874f5346d2
7
+ data.tar.gz: 43b56da5e19d31a4aa51c87ba21d284c57f1f242a2f25f16bf71d3524ad620df09ba98faf18b234992073ddb2b09fbe89a912a6a15877d9ce1b71608eaa6ea33
data/.rubocop.yml CHANGED
@@ -9,6 +9,9 @@ AllCops:
9
9
  NewCops: enable
10
10
  TargetRubyVersion: 2.6
11
11
 
12
+ # Gemspec/RequireMFA:
13
+ # Enabled: false
14
+
12
15
  Layout/LineLength:
13
16
  Max: 150
14
17
 
@@ -18,6 +21,9 @@ Layout/MultilineMethodCallIndentation:
18
21
  Metrics/BlockLength:
19
22
  Enabled: false
20
23
 
24
+ Style/CommandLiteral:
25
+ Enabled: false
26
+
21
27
  Style/PercentLiteralDelimiters:
22
28
  Enabled: false
23
29
 
@@ -29,6 +35,3 @@ Style/StringLiterals:
29
35
 
30
36
  Style/StringLiteralsInInterpolation:
31
37
  Enabled: false
32
-
33
- Gemspec/RequireMFA:
34
- Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 2.0.5 / 2022-04-11
2
+ * Now using <code>Shellwords</code> and <code>KeyValueParser</code> instead of a homegrown parser.
3
+ * Refactored helper methods to jekyll_tag_helper.rb
4
+ * Looks up values for liquid variable references from several scopes.
5
+ * Suppresses stack dump when an error occurs.
6
+ * Deleted a lot of old cruft.
7
+ * Added pre, label and copy_button optional parameters
8
+
1
9
  ## 2.0.4 / 2022-04-05
2
10
  * Updated to `jekyll_plugin_logger` v2.1.0
3
11
 
data/README.md CHANGED
@@ -22,14 +22,27 @@ This plugin supports 4 types of includes:
22
22
  In addition, filenames that require environment expansion because they contain a <code>$</code> character are
23
23
  expanded according to the environment variables defined when <code>jekyll build</code> executes.
24
24
 
25
- ### Syntax:
25
+ ### Syntax
26
+ The following are equivalent:
26
27
  ```
27
- {% flexible_include path [ do_not_escape='true' ] %}
28
+ {% flexible_include path [ OPTIONS ] %}
29
+ {% flexible_include 'path' [ OPTIONS ] %}
30
+ {% flexible_include "path" [ OPTIONS ] %}
28
31
  ```
29
32
 
30
- The included file will escape characters <code>&lt;</code>, <code>{</code> and <code>}</code> unless <code>do_not_escape</code>
31
- is specified with a value other than <code>false</code>.
32
- Note that the [square brackets] merely indicate an optional parameter and are not intended to be literally written.
33
+ By default, the included file will escape characters <code>&lt;</code>, <code>{</code> and <code>}</code>
34
+ unless <code>do_not_escape</code> is specified.
35
+ Note that the [square brackets] merely indicate optional parameters and are not intended to be written literally.
36
+
37
+ ### Options
38
+ * `do_not_escape` includes the content without HTML escaping it.
39
+ * `pre` causes the included file to be wrapped inside a &lt;pre>&lt;/pre> tag, no label is generated.
40
+
41
+ The following options imply `pre`:
42
+ * `download` uses the name of the file as a label, and displays it above the &lt;pre>&lt;/pre> tag. Clicking the label causes the file to be downloaded.
43
+ * `copy_button` draws an icon at the top right of the &lt;pre>&lt;/pre> tag that causes the included contents to be copied to the clipboard.
44
+ * `label` specifies that an automatically generated label be placed above the contents. There is no need to specify this option if `download` or `copy_button` options are provided.
45
+ * `label="blah blah"` specifies a label for the contents; this value overrides the default label. The value can be enclosed in single or double quotes.
33
46
 
34
47
 
35
48
  ### Additional Information
@@ -62,7 +75,7 @@ Or install it yourself as:
62
75
 
63
76
  ## Examples
64
77
 
65
- 1. Include files without parameters; all four types of includes are shown.
78
+ 1. Include files, escaping any HTML markup so it appears as written; all four types of includes are shown.
66
79
  ```
67
80
  {% flexible_include '../../folder/outside/jekyll/site/foo.html' %}
68
81
  {% flexible_include 'folder/within/jekyll/site/bar.js' %}
@@ -74,7 +87,7 @@ Or install it yourself as:
74
87
 
75
88
  2. Include a JSON file (without escaping characters).
76
89
  ```
77
- {% flexible_include '~/folder/under/home/directory/foo.html' do_not_escape='true' %}
90
+ {% flexible_include '~/folder/under/home/directory/foo.html' do_not_escape %}
78
91
  ```
79
92
 
80
93
  ## Additional Information
@@ -125,14 +138,14 @@ $ gem info jekyll_flexible_include
125
138
 
126
139
  *** LOCAL GEMS ***
127
140
 
128
- jekyll_flexible_include (1.0.0)
129
- Author: Mike Slinn
130
- Homepage:
131
- https://github.com/mslinn/jekyll_flexible_include
141
+ jekyll_flexible_include (2.0.4)
142
+ Authors: Mike Slinn, Tan Nhu, Maarten Brakkee
143
+ Homepage: https://www.mslinn.com/blog/2020/10/03/jekyll-plugins.html#flexibleInclude
132
144
  License: MIT
133
- Installed at: /home/mslinn/.gems
145
+ Installed at (2.0.4): /home/mslinn/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0
134
146
 
135
- Generates Jekyll logger with colored output.
147
+ Jekyll plugin supports various ways to include content into the
148
+ generated site.
136
149
  ```
137
150
 
138
151
 
@@ -5,7 +5,7 @@ require_relative "lib/flexible_include/version"
5
5
  Gem::Specification.new do |spec|
6
6
  github = "https://github.com/mslinn/jekyll_flexible_include_plugin"
7
7
 
8
- spec.authors = ["Mike Slinn"]
8
+ spec.authors = ["Mike Slinn", "Tan Nhu", "Maarten Brakkee"]
9
9
  spec.bindir = "exe"
10
10
  spec.description = <<~END_OF_DESC
11
11
  Jekyll's built-in include tag only supports including files within the _includes folder.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JekyllFlexibleIncludePluginVersion
4
- VERSION = "2.0.4"
4
+ VERSION = "2.0.5"
5
5
  end
@@ -2,139 +2,74 @@
2
2
 
3
3
  require "jekyll"
4
4
  require "jekyll_plugin_logger"
5
+ require "securerandom"
5
6
  require_relative "flexible_include/version"
7
+ require_relative "jekyll_tag_helper"
6
8
 
7
9
  module JekyllFlexibleIncludeName
8
10
  PLUGIN_NAME = "flexible_include"
9
11
  end
10
12
 
11
- class FlexibleIncludeError < StandardError
12
- attr_accessor :path
13
-
14
- def initialize(msg, path)
15
- super
16
- @path = path
17
- end
18
- end
19
-
20
13
  class FlexibleInclude < Liquid::Tag
21
- VALID_SYNTAX = %r!
22
- ([\w-]+)\s*=\s*
23
- (?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w.-]+))
24
- !x.freeze
25
- VARIABLE_SYNTAX = %r!
26
- (?<variable>[^{]*(\{\{\s*[\w\-.]+\s*(\|.*)?\}\}[^\s{}]*)+)
27
- (?<params>.*)
28
- !mx.freeze
29
-
30
- FULL_VALID_SYNTAX = %r!\A\s*(?:#{VALID_SYNTAX}(?=\s|\z)\s*)*\z!.freeze
31
- VALID_FILENAME_CHARS = %r!^[\w/\.-]+$!.freeze
32
-
33
- def initialize(tag_name, markup, parse_context)
14
+ FlexibleIncludeError = Class.new(Liquid::Error)
15
+
16
+ # @param tag_name [String] the name of the tag, which we already know.
17
+ # @param markup [String] the arguments from the tag, as a single string.
18
+ # @param parse_context [Liquid::ParseContext] hash that stores Liquid options.
19
+ # By default it has two keys: :locale and :line_numbers, the first is a Liquid::I18n object, and the second,
20
+ # a boolean parameter that determines if error messages should display the line number the error occurred.
21
+ # This argument is used mostly to display localized error messages on Liquid built-in Tags and Filters.
22
+ # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags
23
+ def initialize(tag_name, markup, _parse_context)
34
24
  super
35
25
  @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
36
- matched = markup.strip.match(VARIABLE_SYNTAX)
37
- if matched
38
- @file = matched["variable"].strip
39
- @params = matched["params"].strip
40
- else
41
- @file, @params = markup.strip.split(%r!\s+!, 2)
26
+ @helper = JekyllTagHelper.new(tag_name, markup, @logger)
27
+ end
28
+
29
+ # @param liquid_context [Liquid::Context]
30
+ def render(liquid_context) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
31
+ @helper.liquid_context = liquid_context
32
+ @do_not_escape = @helper.parameter_specified? "do_not_escape"
33
+ @download = @helper.parameter_specified? "download"
34
+ @label = @helper.parameter_specified? "label"
35
+ @label_specified = @label
36
+ @copy_button = @helper.parameter_specified? "copyButton"
37
+ @pre = @copy_button || @download || @label_specified || @helper.parameter_specified?("pre") # Download or label implies pre
38
+ filename = @helper.params.first # Do this after all options have been checked for
39
+ @label ||= filename
40
+
41
+ # If a label was specified, use it, otherwise concatenate any dangling parameters and use that as the label
42
+ @label ||= @helper.params[1..].join(" ")
43
+
44
+ @logger.debug("filename=#{filename}")
45
+
46
+ path = JekyllTagHelper.expand_env(filename)
47
+ case path
48
+ when /\A\// # Absolute path
49
+ @logger.debug { "Absolute path=#{path}, filename=#{filename}" }
50
+ when /\A~/ # Relative path to user's home directory
51
+ @logger.debug { "User home start filename=#{filename}, path=#{path}" }
52
+ filename.slice! "~/"
53
+ path = File.join(ENV['HOME'], filename)
54
+ @logger.debug { "User home end filename=#{filename}, path=#{path}" }
55
+ when /\A!/ # Run command and return response
56
+ filename = JekyllTagHelper.remove_quotes(@helper.argv.first)
57
+ filename.slice! "!"
58
+ contents = run(filename)
59
+ else # Relative path
60
+ site = liquid_context.registers[:site]
61
+ source = File.expand_path(site.config['source']) # website root directory
62
+ path = File.join(source, filename) # Fully qualified path of include file from relative path
63
+ @relative = true
64
+ @logger.debug { "Relative end filename=#{filename}, path=#{path}" }
42
65
  end
43
- @markup = markup
44
- @logger.debug("initialize: @markup=#{@markup}")
45
- @parse_context = parse_context
46
- end
47
-
48
- # @param context [Liquid::Context]
49
- def render(context) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
50
- markup = @markup
51
- @logger.debug { "markup='#{markup}'" }
52
- markup = sanitize_parameter(markup)
53
- markup = expand_env(markup)
54
- path = markup
55
- if /\A\//.match(markup) # Is the file absolute?
56
- @logger.debug { "Absolute path=#{path}, markup=#{markup}" }
57
- elsif /\A~/.match(markup) # Relative path to user's home directory?
58
- @logger.debug { "Relative start markup=#{markup}, path=#{path}" }
59
- markup.slice! "~/"
60
- path = File.join(ENV['HOME'], markup)
61
- @logger.debug { "Relative end markup=#{markup}, path=#{path}" }
62
- elsif /\A\!/.match(markup) # Run command and return response
63
- markup.slice! "!"
64
- @logger.debug { "Execute markup=#{markup}" }
65
- contents = run(markup)
66
- else # The file is relative or it was passed as a parameter to an include and was not noticed before, e.g. @file='{{include.file}}'
67
- @logger.debug { "Catchall start @file=#{@file}, markup=#{markup}, path=#{path}" }
68
- file = render_variable(context)
69
- markup = file if file
70
- markup = expand_env(markup)
71
- markup = sanitize_parameter(markup)
72
- if /\A\//.match(markup) # Absolute path
73
- path = markup
74
- elsif /\A\!/.match(markup)
75
- markup.slice! "!"
76
- @logger.debug { "Execute markup=#{markup}" }
77
- contents = run(markup)
78
- elsif /\A~/.match(markup) # Relative path to user's home directory?
79
- markup.slice! "~/"
80
- path = File.join(ENV['HOME'], markup)
81
- else # Relative path
82
- site = context.registers[:site]
83
- source = File.expand_path(site.config['source']) # website root directory
84
- path = File.join(source, markup) # Fully qualified path of include file from relative path
85
- end
86
- @logger.debug { "Catchall end markup=#{markup}, path=#{path}" }
87
- end
88
- render_completion(context, path, contents)
66
+ render_completion(path, contents)
67
+ # rescue StandardError => e
68
+ # raise FlexibleIncludeError, e.message.red, [] # Suppress stack trace
89
69
  end
90
70
 
91
71
  private
92
72
 
93
- def escape_html?(context)
94
- do_not_escape = false
95
- if @params
96
- context["include"] = parse_params(context)
97
- @logger.debug { "context['include']['do_not_escape'] = #{context['include']['do_not_escape']}" }
98
- do_not_escape = context['include'].fetch('do_not_escape', 'false')
99
- @logger.debug { "do_not_escape=#{do_not_escape}" }
100
- @logger.debug { "do_not_escape=='false' = #{do_not_escape=='false'}" }
101
- end
102
- do_not_escape
103
- end
104
-
105
- def escape_html(string)
106
- string.gsub("{", "&#123;").gsub("}", "&#125;").gsub("<", "&lt;")
107
- end
108
-
109
- def expand_env(str)
110
- str.gsub(/\$([a-zA-Z_][a-zA-Z0-9_]*)|\${\g<1>}|%\g<1>%/) { ENV[$1] }
111
- end
112
-
113
- # Grab file read opts in the context
114
- def file_read_opts(context)
115
- context.registers[:site].file_read_opts
116
- end
117
-
118
- def parse_params(context)
119
- params = {}
120
- markup = @params
121
-
122
- while (match = VALID_SYNTAX.match(markup))
123
- markup = markup[match.end(0)..-1]
124
-
125
- value = if match[2]
126
- match[2].gsub(%r!\\"!, '"')
127
- elsif match[3]
128
- match[3].gsub(%r!\\'!, "'")
129
- elsif match[4]
130
- context[match[4]]
131
- end
132
-
133
- params[match[1]] = value
134
- end
135
- params
136
- end
137
-
138
73
  def read_file(file)
139
74
  File.read(file)
140
75
  end
@@ -145,72 +80,37 @@ class FlexibleInclude < Liquid::Tag
145
80
  false
146
81
  end
147
82
 
148
- def render_completion(context, path, contents)
149
- begin
150
- contents = read_file(path) unless contents
151
- rescue StandardError => e
152
- puts "flexible_include.rb error: #{e.message}".red
153
- $stderr.reopen(IO::NULL)
154
- $stdout.reopen(IO::NULL)
155
- exit
156
- end
157
- escaped_contents = escape_html?(context) ? escape_html(contents) : contents
158
- context.stack do # Temporarily push a new local scope onto the variable stack
159
- begin
160
- partial = Liquid::Template.parse(escaped_contents) # Type Liquid::Template
161
- rescue StandardError => e
162
- puts "flexible_include.rb error: #{e.message}".red
163
- $stderr.reopen(IO::NULL)
164
- $stdout.reopen(IO::NULL)
165
- exit
166
- end
167
-
168
- begin
169
- partial.render!(context)
170
- rescue Liquid::Error => e
171
- e.template_name = path
172
- e.markup_context = "included " if e.markup_context.nil?
173
- raise e
174
- end
175
- end
176
- end
177
-
178
- # @return setvalue of 'file' variable if defined
179
- def render_variable(context)
180
- if @file.match VARIABLE_SYNTAX
181
- partial = context.registers[:site]
182
- .liquid_renderer
183
- .file("(variable)")
184
- .parse(@file)
185
- partial.render!(context)
186
- end
83
+ def render_completion(path, contents)
84
+ contents ||= read_file(path)
85
+ contents2 = @do_not_escape ? contents : JekyllTagHelper.escape_html(contents)
86
+ @pre ? wrap_in_pre(path, contents2) : contents2
187
87
  end
188
88
 
189
89
  def run(cmd)
190
- %x[ #{cmd} ].chomp
191
- end
192
-
193
- # strip leading and trailing quotes if present
194
- def sanitize_parameter(parameter)
195
- parameter.strip.gsub(/\A'|'\Z/, '').strip if parameter
196
- end
197
-
198
- def valid_include_file?(path, dir, safe)
199
- !outside_site_source?(path, dir, safe) && File.file?(path)
200
- end
201
-
202
- def outside_site_source?(path, dir, safe)
203
- safe && !realpath_prefixed_with?(path, dir)
204
- end
205
-
206
- def could_not_locate_message(file, includes_dirs, safe)
207
- message = "Could not locate the included file '#{file}' in any of "\
208
- "#{includes_dirs}. Ensure it exists in one of those directories and"
209
- message + if safe
210
- " is not a symlink as those are not allowed in safe mode."
211
- else
212
- ", if it is a symlink, does not point outside your site source."
213
- end
90
+ @logger.debug { "Executing filename=#{cmd}" }
91
+ %x[#{cmd}].chomp
92
+ end
93
+
94
+ PREFIX = "<button class='copyBtn' data-clipboard-target="
95
+ SUFFIX = "title='Copy to clipboard'><img src='/assets/images/clippy.svg' alt='Copy to clipboard' style='width: 13px'></button>"
96
+
97
+ def wrap_in_pre(path, content)
98
+ basename = File.basename(path)
99
+ label_or_href = if @download
100
+ label = @label_specified ? @label : basename
101
+ <<~END_HREF
102
+ <a href='data:text/plain;charset=UTF-8,#{basename}' download='#{basename}'
103
+ title='Click on the file name to download the file'>#{label}</a>
104
+ END_HREF
105
+ else
106
+ @label_specified ? @label : basename
107
+ end
108
+ pre_id = "id#{SecureRandom.hex 6}"
109
+ copy_button = @copy_button ? "#{PREFIX}'##{pre_id}'#{SUFFIX}" : ""
110
+ <<~END_PRE
111
+ <div class="codeLabel">#{label_or_href}</div>
112
+ <pre data-lt-active="false" class="maxOneScreenHigh copyContainer" id="#{pre_id}">#{copy_button}#{content}</pre>
113
+ END_PRE
214
114
  end
215
115
  end
216
116
 
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "shellwords"
4
+
5
+ class JekyllTagHelper
6
+ attr_reader :argv, :liquid_context, :logger, :params, :tag_name
7
+
8
+ def self.escape_html(string)
9
+ string.gsub("{", "&#123;").gsub("}", "&#125;").gsub("<", "&lt;")
10
+ end
11
+
12
+ # Expand environment variable references
13
+ def self.expand_env(str)
14
+ str.gsub(/\$([a-zA-Z_][a-zA-Z0-9_]*)|\${\g<1>}|%\g<1>%/) { ENV[Regexp.last_match(1)] }
15
+ end
16
+
17
+ # strip leading and trailing quotes if present
18
+ def self.remove_quotes(string)
19
+ string.strip.gsub(/\A'|\A"|'\Z|"\Z/, '').strip if string
20
+ end
21
+
22
+ def initialize(tag_name, markup, logger)
23
+ @tag_name = tag_name
24
+ @argv = Shellwords.split(markup)
25
+ @keys_values = KeyValueParser.new.parse(@argv) # Hash[Symbol, String|Boolean]
26
+ @logger = logger
27
+ @logger.debug { "@keys_values='#{@keys_values}'" }
28
+ end
29
+
30
+ def delete_parameter(name)
31
+ @params.delete(name)
32
+ @argv.delete_if { |x| x.start_with? name }
33
+ @keys_values.delete(name.to_sym)
34
+ end
35
+
36
+ # @return if parameter was specified, returns value and removes it from the available tokens
37
+ def parameter_specified?(name)
38
+ value = @keys_values[name.to_sym]
39
+ delete_parameter(name)
40
+ value
41
+ end
42
+
43
+ PREDEFINED_SCOPE_KEYS = [:include, :page].freeze
44
+
45
+ # Finds variables defined in an invoking include, or maybe somewhere else
46
+ # @return variable value or nil
47
+ def dereference_include_variable(name)
48
+ @liquid_context.scopes.each do |scope|
49
+ next if PREDEFINED_SCOPE_KEYS.include? scope.keys.first
50
+
51
+ value = scope[name]
52
+ return value if value
53
+ end
54
+ nil
55
+ end
56
+
57
+ # @return value of variable, or the empty string
58
+ def dereference_variable(name)
59
+ @liquid_context[name] || # Finds variables named like 'include.my_variable', found in @liquid_context.scopes.first
60
+ @page[name] || # Finds variables named like 'page.my_variable'
61
+ dereference_include_variable(name) ||
62
+ ""
63
+ end
64
+
65
+ # Sets @params by replacing any Liquid variable names with their values
66
+ def liquid_context=(context)
67
+ @liquid_context = context
68
+ @params = @keys_values.map { |k, _v| lookup_variable(k) }
69
+ end
70
+
71
+ def lookup_variable(symbol)
72
+ string = symbol.to_s
73
+ return string unless string.start_with?("{{") && string.end_with?("}}")
74
+
75
+ dereference_variable(string.delete_prefix("{{").delete_suffix("}}"))
76
+ end
77
+
78
+ def page
79
+ @liquid_context.registers[:page]
80
+ end
81
+ end
metadata CHANGED
@@ -1,14 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll_flexible_include
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.4
4
+ version: 2.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Slinn
8
+ - Tan Nhu
9
+ - Maarten Brakkee
8
10
  autorequire:
9
11
  bindir: exe
10
12
  cert_chain: []
11
- date: 2022-04-06 00:00:00.000000000 Z
13
+ date: 2022-04-13 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: jekyll
@@ -85,6 +87,7 @@ files:
85
87
  - jekyll_flexible_include_plugin.gemspec
86
88
  - lib/flexible_include.rb
87
89
  - lib/flexible_include/version.rb
90
+ - lib/jekyll_tag_helper.rb
88
91
  homepage: https://www.mslinn.com/blog/2020/10/03/jekyll-plugins.html#flexibleInclude
89
92
  licenses:
90
93
  - MIT