jekyll_flexible_include 2.0.14 → 2.0.18

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: 235134772b0ff492ec61e24e71a8094977ae43e740c338dabfd65e92cd8ac416
4
- data.tar.gz: c89b5985bde7ec87ef12870cf27369d1f2c6194de9ef8459064675f13402d87f
3
+ metadata.gz: d8f07914cb71b0dc833f7735175ef18ccde8357e7fcf14014d954cae6e40c5bc
4
+ data.tar.gz: e077293b1be82f05dedfd02e6326c6c64d4a87895fc4d6f90cc7d532d50df857
5
5
  SHA512:
6
- metadata.gz: '094fae8fef148dd4801710911d8d0bde33e45a3ef0c7b5f5417e0a5baea1cc8d24d975d3b9e02e76ed96fca375651bd06074bf5a21a72ca1ee3343f960ab9aec'
7
- data.tar.gz: 810afd58a9df5f7d7d88f97de0bbbb5547cbe400d0a09a25dff8ada24bdc4ad313cb0a535571388d6990edc125e3fca9d07c3a71bf33f0868a057cc451f47bc6
6
+ metadata.gz: 2a476f8c116c18590acd67e5be96fb1d10889394f3c278cec7bb43d211be7a8f8dcacc158953c4e9bea3de29b6d32668e8d5500ae24a8a0bd405d091219ac6ff
7
+ data.tar.gz: 5bd8341a6eb53a35a520791a32d79ec587169650f56d36c3d4b4aa965f6247867037253d83c677cbdae913d79b19d6a18a901a63013cc49fbc526358583bb238
data/.rubocop.yml CHANGED
@@ -1,16 +1,36 @@
1
- require: rubocop-jekyll
2
- inherit_gem:
3
- rubocop-jekyll: .rubocop.yml
1
+ require:
2
+ # - rubocop-jekyll
3
+ - rubocop-md
4
+ - rubocop-performance
5
+ - rubocop-rake
6
+ - rubocop-rspec
7
+
8
+ # inherit_gem:
9
+ # rubocop-jekyll: .rubocop.yml
4
10
 
5
11
  AllCops:
6
12
  Exclude:
7
- - vendor/**/*
8
- - Gemfile*
13
+ - demo/_site/**/*
14
+ - exe/**/*
15
+ - vendor/**/*
16
+ - Gemfile*
9
17
  NewCops: enable
10
18
  TargetRubyVersion: 2.6
11
19
 
12
- # Gemspec/RequireMFA:
13
- # Enabled: false
20
+ Gemspec/DeprecatedAttributeAssignment:
21
+ Enabled: false
22
+
23
+ Gemspec/RequireMFA:
24
+ Enabled: false
25
+
26
+ Layout/InitialIndentation:
27
+ Exclude:
28
+ - README.md
29
+
30
+ Layout/HashAlignment:
31
+ EnforcedColonStyle: table
32
+ Exclude:
33
+ - jekyll_flexible_include_plugin.gemspec
14
34
 
15
35
  Layout/LineLength:
16
36
  Max: 150
@@ -18,20 +38,68 @@ Layout/LineLength:
18
38
  Layout/MultilineMethodCallIndentation:
19
39
  Enabled: false
20
40
 
41
+ Lint/RedundantCopDisableDirective:
42
+ Exclude:
43
+ - jekyll_flexible_include_plugin.gemspec
44
+
45
+ Metrics/AbcSize:
46
+ Max: 45
47
+
21
48
  Metrics/BlockLength:
22
- Enabled: false
49
+ Exclude:
50
+ - jekyll_flexible_include_plugin.gemspec
51
+ - spec/**/*
52
+
53
+ Metrics/ClassLength:
54
+ Exclude:
55
+ - spec/**/*
56
+
57
+ Metrics/CyclomaticComplexity:
58
+ Max: 20
59
+
60
+ Metrics/MethodLength:
61
+ Max: 40
62
+
63
+ Metrics/PerceivedComplexity:
64
+ Max: 15
65
+
66
+ Naming/FileName:
67
+ Exclude:
68
+ - Rakefile
69
+
70
+ RSpec/ExampleLength:
71
+ Max: 20
72
+
73
+ RSpec/MultipleExpectations:
74
+ Max: 15
23
75
 
24
76
  Style/CommandLiteral:
25
77
  Enabled: false
26
78
 
79
+ Style/CommentedKeyword:
80
+ Enabled: false
81
+
82
+ Style/Documentation:
83
+ Enabled: false
84
+
85
+ Style/FrozenStringLiteralComment:
86
+ Enabled: false
87
+
27
88
  Style/PercentLiteralDelimiters:
28
89
  Enabled: false
29
90
 
30
91
  Style/RegexpLiteral:
31
92
  Enabled: false
32
93
 
94
+ Style/StringConcatenation:
95
+ Exclude:
96
+ - spec/**/*
97
+
33
98
  Style/StringLiterals:
34
99
  Enabled: false
35
100
 
36
101
  Style/StringLiteralsInInterpolation:
37
102
  Enabled: false
103
+
104
+ Style/TrailingCommaInHashLiteral:
105
+ EnforcedStyleForMultiline: comma
data/CHANGELOG.md CHANGED
@@ -1,18 +1,42 @@
1
+ ## 2.0.18 / 2023-03-24
2
+ * The following are now parsed property:
3
+ `die_on_file_error`, `die_on_path_denied`, `die_on_run_error`, `die_on_path_denied`, and `die_on_other_error`.
4
+
5
+ ## 2.0.17 / 2023-03-22
6
+ * Added `repo` and `git_ref` parameters, so files can be retrieved from git repositories at a given commit or tag.
7
+
8
+ ## 2.0.16 / 2023-02-19
9
+ * Replaced hard-coded CSS in `denied` method with `flexible_error` class in
10
+ `demo/assets/css/style.css`.
11
+ * Added `-e` and `-x` options to `demo/_bin/debug`.
12
+ * Added configuration section `flexible_include` with supported parameters
13
+ `die_on_file_error`, `die_on_path_denied`, `die_on_run_error`,
14
+ `die_on_path_denied` and `die_on_other_error`.
15
+ * Fixed `undefined method 'path'` that occurred when `FLEXIBLE_INCLUDE_PATHS` was specified.
16
+
17
+ ## 2.0.15 / 2023-02-18
18
+ * Replaced dependency `key-value-parser` with `jekyll_plugin_support`.
19
+ * Added `demo` website.
20
+ * Improved the documentation.
21
+ * Updated Rubocop configuration.
22
+ * Added `strip` option.
23
+
1
24
  ## 2.0.14 / 2022-09-27
2
- * Added `key-value-parser` as a dependency
25
+ * Added `key-value-parser` as a dependency.
3
26
 
4
27
  ## 2.0.13 / 2022-04-24
5
- * Added `highlight` regex option, for highlighting
6
- * Added `number` option, for numbered lines
28
+ * Added `highlight` regex option, for highlighting.
29
+ * Added `number` option, for numbered lines.
7
30
 
8
31
  ## 2.0.12 / 2022-04-22
9
- * Exits with an error message if an environment variable included in the value of `FLEXIBLE_INCLUDE_PATHS` is undefined.
32
+ * Exits with an error message if an environment variable included in the value
33
+ of `FLEXIBLE_INCLUDE_PATHS` is undefined.
10
34
 
11
35
  ## 2.0.11 / 2022-04-15
12
- * Added & => & to the escaped characters
36
+ * Added & => & to the escaped characters.
13
37
 
14
38
  ## 2.0.10 / 2022-04-15
15
- * Fixed nil pointer
39
+ * Fixed nil pointer.
16
40
 
17
41
  ## 2.0.9 / 2022-04-15
18
42
  * Changed how path matching was implemented.
@@ -40,10 +64,11 @@
40
64
  * Updated to `jekyll_plugin_logger` v2.1.0
41
65
 
42
66
  ## 2.0.0 / 2022-03-11
43
- * Made into a Ruby gem and published on RubyGems.org as [jekyll_flexible_include](https://rubygems.org/gems/jekyll_flexible_include).
44
- * `bin/attach` script added for debugging
45
- * Rubocop standards added
46
- * Proper versioning and CHANGELOG.md added
67
+ * Made into a Ruby gem and published on RubyGems.org as
68
+ [jekyll_flexible_include](https://rubygems.org/gems/jekyll_flexible_include).
69
+ * `bin/attach` script added for debugging.
70
+ * Rubocop standards added.
71
+ * Proper versioning and CHANGELOG.md added.
47
72
 
48
73
  ## 1.1.1 / 2021-05-01
49
74
  * Handles spaces in filenames properly.
@@ -52,14 +77,14 @@
52
77
  * Added `do_not_escape` optional parameter.
53
78
 
54
79
  ## 1.0.0 / 2020-11-28
55
- * Mike Slinn took over the project
56
- * Now supports relative includes
80
+ * Mike Slinn took over the project.
81
+ * Now supports relative includes.
57
82
 
58
83
  ## 2020-11-28
59
- * Renamed include_absolute to flexible_include
84
+ * Mike Slinn renamed `include_absolute` to `flexible_include`.
60
85
 
61
86
  ## 2020-08-23
62
- * Now supports absolute paths
87
+ * Now supports absolute paths.
63
88
 
64
89
  ## 2022-03-11
65
- * Project began
90
+ * Project began.
data/README.md CHANGED
@@ -2,52 +2,115 @@ Jekyll `flexible_include` Plugin
2
2
  [![Gem Version](https://badge.fury.io/rb/jekyll_flexible_include.svg)](https://badge.fury.io/rb/jekyll_flexible_include)
3
3
  ===========
4
4
 
5
- `Flexible_include` is a Jekyll plugin that includes the contents of a file or the result of a process into a generated page. `Flexible_include` is useful because Jekyll's built-in `include` tag only supports the including of files residing within the `_includes/` subfolder of a Jekyll project, and because `flexible_include` offers additional ways of including content.
5
+ `Flexible_include` is a Jekyll plugin that includes the contents of a file
6
+ or the result of a process into a generated page.
7
+ `Flexible_include` is useful because Jekyll's built-in `include` tag only
8
+ supports the including of files residing within the `_includes/` subfolder of a Jekyll project,
9
+ and because `flexible_include` offers additional ways of including content.
6
10
 
7
- Originally called `include_absolute`, this plugin has been renamed to `flexible_include` because it no longer just includes absolute file names.
11
+ Originally called `include_absolute`,
12
+ this plugin has been renamed to `flexible_include` because it no longer just
13
+ includes absolute file names.
8
14
 
9
15
  This plugin is available as a [Ruby gem](https://rubygems.org/gems/jekyll_flexible_include).
10
16
  More information is available on my website about [my Jekyll plugins](https://www.mslinn.com/blog/2020/10/03/jekyll-plugins.html).
11
17
 
12
18
  This plugin supports 4 types of includes:
13
19
 
20
+
14
21
  ### Include Types
15
22
 
16
23
  1. Absolute filenames (recognized by filename paths that start with `/`).
17
- 2. Filenames relative to the top-level directory of the Jekyll web site (relative paths **do not** start with `.` or `/`).
24
+
25
+ 2. Filenames relative to the top-level directory of the Jekyll website (relative paths **do not** start with `.` or `/`).
26
+
18
27
  3. Filenames relative to the user home directory (recognized by filename paths starting with `~/`).
28
+
19
29
  4. Executable filenames on the `PATH` (recognized by filename paths that begin with `!`).
20
30
 
21
31
 
22
- In addition, filenames that require environment expansion because they contain a <code>$</code> character are
23
- expanded according to the environment variables defined when <code>jekyll build</code> executes.
32
+ In addition, filenames that require environment expansion because they contain a
33
+ <code>$</code> character are expanded according to the environment variables
34
+ defined when <code>jekyll build</code> executes.
24
35
 
25
36
 
26
- ### Syntax
27
- The following are equivalent:
37
+ A file from a git repository can also be included.
38
+ Files can be retrieved from at a given commit or tag.
39
+ Two new options are provided for this purpose:
40
+ - `repo` - directory where git repo resides; environment variables are expanded; defaults to current directory.
41
+ - `git_ref` - Git ref of commit or tag to be examined for the file; defaults to `HEAD`.
42
+
43
+
44
+ ### Configuration
45
+ Configuration parameters can be added to a section in `_config.yml` called `flexible_include`, like this:
46
+
47
+ ```yaml
48
+ flexible_include:
49
+ die_on_file_error: true
50
+ die_on_path_denied: true
51
+ die_on_run_error: true
52
+ die_on_other_error: true
28
53
  ```
54
+
55
+ The default values for all of these parameters is `false`,
56
+ except for `die_on_other_error`, which defaults to `true`.
57
+
58
+ - If `die_on_file_error` is enabled, then an attempt to include a file that fails will cause Jekyll to die with an error message.
59
+
60
+ - If `die_on_path_denied` is enabled (see [Restricting Directory Access](#restricting-directory-access)), then an attempt to include a file that should be blocked will cause Jekyll to die with an error message.
61
+
62
+ - If `die_on_run_error` is enabled, then an attempt to run a process that fails will cause Jekyll to die with an error message.
63
+
64
+ - If `die_on_other_error` is enabled, then any other exception will cause Jekyll to die with an error message.
65
+
66
+
67
+ ### Syntax
68
+ The following are all equivalent, however, the first two are recommended:
69
+ ```html
70
+ {% flexible_include file="path" [ OPTIONS ] %}
71
+ {% flexible_include file='path' [ OPTIONS ] %}
29
72
  {% flexible_include path [ OPTIONS ] %}
30
73
  {% flexible_include 'path' [ OPTIONS ] %}
31
74
  {% flexible_include "path" [ OPTIONS ] %}
32
75
  ```
33
76
 
34
- By default, the included file will escape characters <code>&lt;</code>, <code>{</code> and <code>}</code>
35
- unless <code>do_not_escape</code> is specified.
36
- Note that the [square brackets] merely indicate optional parameters and are not intended to be written literally.
77
+ Note that the [square brackets] merely indicate optional parameters
78
+ and are not intended to be written literally.
79
+
37
80
 
38
81
  ### Options
39
- * `do_not_escape` includes the content without HTML escaping it.
40
- * `highlight='regex pattern here'` wraps content matching the regex pattern within a `<span class='bg_yellow'></span>` tag.
41
- * `pre` causes the included file to be wrapped inside a &lt;pre>&lt;/pre> tag, no label is generated. The &lt;pre>&lt;/pre> tag has an `data-lt-active="false"` attribute, so [LanguageTool](https://forum.languagetool.org/t/avoid-spell-check-on-certain-html-inputs-manually/3944) does not check the spelling or grammar of the contents.
82
+ * `do_not_escape` keyword option caused the content to be included without HTML escaping it.
83
+ By default, the included file will escape characters <code>&lt;</code>,
84
+ <code>{</code> and <code>}</code> unless the <code>do_not_escape</code> keyword option is specified.
85
+
86
+ * `highlight='regex pattern here'` wraps content matching the regex pattern within a
87
+ `<span class='bg_yellow'></span>` tag.
88
+ Note that the pattern can simply consist of the exact text that you want to highlight.
89
+
90
+ * `pre` is a keyword option that causes the included file to be wrapped inside a
91
+ &lt;pre>&lt;/pre> tag; no label is generated.
92
+ The &lt;pre>&lt;/pre> tag has an `data-lt-active="false"` attribute, so
93
+ [LanguageTool](https://forum.languagetool.org/t/avoid-spell-check-on-certain-html-inputs-manually/3944)
94
+ will not attempt to check the spelling or grammar of the contents.
42
95
 
43
96
  The following options imply `pre`:
44
- * `dark` applies the `dark` class to the generated &lt;pre>&lt;/pre> tag.
97
+ * `dark` keyword option applies the `dark` class to the generated &lt;pre>&lt;/pre> tag.
45
98
  You can define the `dark` and `darkLabel` classes as desired.
46
99
  [This CSS is a good starting point.](https://www.mslinn.com/blog/2020/10/03/jekyll-plugins.html#pre_css)
47
- * `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.
48
- * `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.
49
- * `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.
50
- * `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.
100
+
101
+ * `download` keyword option uses the name of the file as a label,
102
+ and displays it above the &lt;pre>&lt;/pre> tag.
103
+ Clicking the label causes the file to be downloaded.
104
+
105
+ * `copyButton` keyword option draws an icon at the top right of the &lt;pre>&lt;/pre>
106
+ tag that causes the included contents to be copied to the clipboard.
107
+
108
+ * `label` keyword option specifies that an automatically generated label be placed above the contents.
109
+ There is no need to specify this option if `download` or `copy_button` options are provided.
110
+
111
+ * `label="blah blah"` specifies a label for the contents; this value overrides the default label.
112
+ The value can be enclosed in single or double quotes.
113
+
51
114
 
52
115
  ### Restricting Directory Access
53
116
  By default, `flexible_include` can read from all directories according to the permissions of the user account that launched the `jekyll` process.
@@ -57,70 +120,97 @@ Defining an environment variable called `FLEXIBLE_INCLUDE_PATHS` prior to launch
57
120
  This environment variable consists of a colon-delimited set of
58
121
  [file and directory glob patterns](https://docs.ruby-lang.org/en/2.7.0/Dir.html#method-c-glob).
59
122
  For example, the following restricts access to only the files within:
123
+
60
124
  1. The `~/my_dir` directory tree of the account of the user that launched Jekyll.
125
+
61
126
  2. The directory tree rooted at `/var/files`.
127
+
62
128
  3. The directory tree rooted at the expanded value of the `$work` environment variable.
129
+
63
130
  ```shell
64
131
  export FLEXIBLE_INCLUDE_PATHS='~/.*:$sites/.*:$work/.*'
65
132
  ```
133
+
66
134
  Note that the above matches dot (hidden) files as well as regular files.
67
135
  To just match visible files:
136
+
68
137
  ```shell
69
138
  export FLEXIBLE_INCLUDE_PATHS='~/my_dir/**/*:/var/files/**/*:$work/**/*'
70
139
  ```
71
140
 
72
141
  #### Note
73
- The specified directories are traversed when the plugin starts, and the filenames are stored in memory. Directories with lots of files might take a noticable amount to time to enumerate the files.
142
+ The specified directories are traversed when the plugin starts,
143
+ and the filenames are stored in memory.
144
+ Directories with lots of files might take a noticable amount of
145
+ time to enumerate the files.
74
146
 
75
147
 
76
148
  ### Restricting Arbitrary Processes
77
- By default, `flexible_include` can execute any command. You can disable that by setting the environment variable `DISABLE_FLEXIBLE_INCLUDE` to any non-empty value.
149
+ By default, `flexible_include` can execute any command.
150
+ You can disable that by setting the environment variable `DISABLE_FLEXIBLE_INCLUDE`
151
+ to any non-empty value.
78
152
  ```shell
79
153
  export DISABLE_FLEXIBLE_INCLUDE=true
80
154
  ```
81
155
 
82
- If a potential command execution is intercepted, a big red message will appear on the generated web page that says `Arbitrary command execution denied by DISABLE_FLEXIBLE_INCLUDE value.`, and a red error message will be logged on the console that says something like: `ERROR FlexibleInclude: _posts/2020/2020-10-03-jekyll-plugins.html - Arbitrary command execution denied by DISABLE_FLEXIBLE_INCLUDE value.`
156
+ If a potential command execution is intercepted,
157
+ a big red message will appear on the generated web page that says
158
+ `Arbitrary command execution denied by DISABLE_FLEXIBLE_INCLUDE value.`,
159
+ and a red error message will be logged on the console that says something like:
160
+ `ERROR FlexibleInclude: _posts/2020/2020-10-03-jekyll-plugins.html - Arbitrary command execution denied by DISABLE_FLEXIBLE_INCLUDE value.`
83
161
 
84
162
 
85
163
  ## Installation
164
+ 1. Add the following to `Gemfile`, inside the `jekyll_plugins` group:
165
+ ```ruby
166
+ group :jekyll_plugins do
167
+ gem 'jekyll_flexible_include', '~> 2.0.15'
168
+ end
169
+ ```
86
170
 
87
- Add the following to `Gemfile`, inside the `jekyll_plugins` group:
88
- ```
89
- group :jekyll_plugins do
90
- gem 'jekyll_flexible_include', '~> 2.0.0'
91
- end
92
- ```
171
+ 2. Add the following to `_config.yml`.
172
+ This is necessary because the name of the plugin
173
+ does not match the name of the entry point file:
174
+ ```yaml
175
+ plugins:
176
+ - flexible_include
177
+ ```
93
178
 
94
- Also add it to `_config.yml`:
95
- ```yaml
96
- plugins:
97
- - flexible_include
98
- ```
179
+ 3. Copy `demo/assets/images/clippy.svg` to a directory that resolves to
180
+ `assets/images/` in your Jekyll website.
99
181
 
100
- And then execute:
182
+ 4. Copy the CSS from `demo/assets/css/styles.css` between the comments to your Jekyll project's CSS file:
183
+ ```css
184
+ blah blah blah
101
185
 
102
- $ bundle install
186
+ /* START OF CSS TO COPY */
187
+ Copy this stuff
188
+ /* END OF CSS TO COPY */
103
189
 
104
- Or install it yourself as:
190
+ blah blah blah
191
+ ```
105
192
 
106
- $ gem install jekyll_flexible_include
193
+ 5. Install the `jekyll_flexible_include` Ruby gem as usual:
194
+ ```shell
195
+ $ bundle install
196
+ ```
107
197
 
108
198
 
109
199
  ## Examples
110
200
 
111
- 1. Include files, escaping any HTML markup so it appears as written; all four types of includes are shown.
201
+ 1. Include files, escaping any HTML markup, so it appears as written; all four types of includes are shown.
112
202
  ```
113
203
  {% flexible_include '../../folder/outside/jekyll/site/foo.html' %}
114
204
  {% flexible_include 'folder/within/jekyll/site/bar.js' %}
115
205
  {% flexible_include '/etc/passwd' %}
116
206
  {% flexible_include '~/.ssh/config' %}
117
- {% flexible_include '!jekyll' %}
207
+ {% flexible_include '!jekyll help' %}
118
208
  {% flexible_include '$HOME/.bash_aliases' %}
119
209
  ```
120
210
 
121
211
  2. Include a JSON file (without escaping characters).
122
212
  ```
123
- {% flexible_include '~/folder/under/home/directory/foo.html' do_not_escape %}
213
+ {% flexible_include do_not_escape file='~/folder/under/home/directory/foo.html' %}
124
214
  ```
125
215
 
126
216
  ## Additional Information
@@ -132,37 +222,43 @@ More information is available on
132
222
  GitHub Pages only allows [these plugins](https://pages.github.com/versions/).
133
223
  That means `flexible_include` will not work on GitHub Pages.
134
224
  Following is a workaround.
225
+
135
226
  1. Let's assume your git repository that you want to publish as GitHub Pages is called `mysite`.
136
227
  This repository cannot be the source of your GitHub Pages because you are using the `flexible_include` plugin.
228
+
137
229
  2. Make a new git repository to hold the generated website. Let's call this git repository `generated_site`.
230
+
138
231
  3. Generate `mysite` locally as usual.
232
+
139
233
  4. Copy the generated HTML in the `mysite/_site/` directory to `generated_site`.
234
+
140
235
  5. Run `git commit` on `generated_site`.
236
+
141
237
  6. Tell GitHub that you want the `generated_site` repository to hold your GitHub pages.
238
+
142
239
  7. A moment later, your website will now be visible as GitHub Pages, with the included content, just as you saw it locally.
143
240
 
144
241
 
145
242
  ## Known Issues
146
243
  If the plugin does not work:
147
- 1. Ensure `_config.yml` doesn't have `safe: true`. That prevents all plugins from working.
148
- 2. If you have version older than v2.x.x, delete the file `_plugins/flexible_include.rb` or you will have version conflicts.
149
244
 
245
+ 1. Ensure `_config.yml` doesn't have `safe: true` set.
246
+ That prevents all plugins from working.
150
247
 
151
- ## Development
248
+ 2. If you have version older than v2.x.x,
249
+ delete the file `_plugins/flexible_include.rb`,
250
+ or you will have version conflicts.
152
251
 
153
- After checking out the repo, run `bin/setup` to install dependencies.
252
+
253
+ ## Development
254
+ After checking out the repo, run `bin/setup` to install dependencies as binstubs in the `exe` directory.
154
255
 
155
256
  You can also run `bin/console` for an interactive prompt that will allow you to experiment.
156
257
 
157
258
  ### Build and Install Locally
158
259
  To build and install this gem onto your local machine, run:
159
260
  ```shell
160
- $ rake install:local
161
- ```
162
-
163
- The following also does the same thing:
164
- ```shell
165
- $ bundle exec rake install
261
+ $ rake install
166
262
  ```
167
263
 
168
264
  Examine the newly built gem:
@@ -182,11 +278,59 @@ jekyll_flexible_include (2.0.4)
182
278
  ```
183
279
 
184
280
 
281
+ ## Demo Website
282
+ A test/demo website is provided in the `demo` directory.
283
+ You can run it under a debugger, or let it run free.
284
+
285
+ The `demo/_bin/debug` script can set various parameters for the demo.
286
+ View the help information with the `-h` option:
287
+ ```shell
288
+ $ demo/_bin/debug -h
289
+
290
+ debug - Run the demo Jekyll website.
291
+
292
+ By default the demo Jekyll website runs without restriction under ruby-debug-ide and debase.
293
+ View it at http://localhost:4444
294
+
295
+ Options:
296
+ -e Restrict the allowable directories to read from to the following regexes:
297
+ jekyll_flexible_include_plugin/.*
298
+ /dev/.*
299
+ /proc/.*
300
+ /run/.*
301
+
302
+ -h Show this error message
303
+
304
+ -r Run freely, without a debugger
305
+
306
+ -x Disable the ability to execute arbitrary commands
307
+ ```
308
+
309
+
310
+ ### Debugging the Demo
311
+ To run under a debugger, for example Visual Studio Code:
312
+ 1. Set breakpoints.
313
+
314
+ 2. Initiate a debug session from the command line:
315
+ ```shell
316
+ $ demo/bin/debug
317
+ ```
318
+
319
+ 3. Once the `Fast Debugger` signon appears, launch the Visual Studio Code launch configuration called `Attach rdebug-ide`.
320
+
321
+ 4. View the generated website at [`http://localhost:4444`](http://localhost:4444).
322
+
323
+
185
324
  ### Build and Push to RubyGems
186
325
  To release a new version,
326
+
187
327
  1. Update the version number in `version.rb`.
188
- 2. Commit all changes to git; if you don't the next step might fail with an unexplainable error message.
189
- 3. Run the following:
328
+
329
+ 2. Add a comment to the top of `CHANGELOG.md`.
330
+
331
+ 3. Commit all changes to git; if you don't the next step will fail.
332
+
333
+ 4. Run the following:
190
334
  ```shell
191
335
  $ bundle exec rake release
192
336
  ```
@@ -195,12 +339,14 @@ To release a new version,
195
339
 
196
340
 
197
341
  ## Contributing
198
-
199
342
  1. Fork the project
343
+
200
344
  2. Create a descriptively named feature branch
345
+
201
346
  3. Add your feature
347
+
202
348
  4. Submit a pull request
203
349
 
204
- ## License
205
350
 
351
+ ## License
206
352
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,7 +1,5 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
5
3
 
6
4
  RSpec::Core::RakeTask.new(:spec)
7
- task :default => :spec
5
+ task default: :spec
@@ -1,12 +1,10 @@
1
- # frozen_string_literal: true
1
+ require_relative 'lib/flexible_include/version'
2
2
 
3
- require_relative "lib/flexible_include/version"
3
+ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
4
+ github = 'https://github.com/mslinn/jekyll_flexible_include_plugin'
4
5
 
5
- Gem::Specification.new do |spec|
6
- github = "https://github.com/mslinn/jekyll_flexible_include_plugin"
7
-
8
- spec.authors = ["Mike Slinn", "Tan Nhu", "Maarten Brakkee"]
9
- spec.bindir = "exe"
6
+ spec.authors = ['Mike Slinn', 'Tan Nhu', 'Maarten Brakkee']
7
+ spec.bindir = 'exe'
10
8
  spec.description = <<~END_OF_DESC
11
9
  Jekyll's built-in include tag only supports including files within the _includes folder.
12
10
  This plugin supports 4 types of includes: absolute filenames,
@@ -14,36 +12,29 @@ Gem::Specification.new do |spec|
14
12
  filenames relative to the user home directory,
15
13
  and executable filenames on the PATH.
16
14
  END_OF_DESC
17
- spec.email = ["mslinn@mslinn.com"]
18
- spec.files = Dir[".rubocop.yml", "LICENSE.*", "Rakefile", "{lib,spec}/**/*", "*.gemspec", "*.md"]
19
- spec.homepage = "https://www.mslinn.com/blog/2020/10/03/jekyll-plugins.html#flexibleInclude"
20
- spec.license = "MIT"
15
+ spec.email = ['mslinn@mslinn.com']
16
+ spec.files = Dir['.rubocop.yml', 'LICENSE.*', 'Rakefile', '{lib,spec}/**/*', '*.gemspec', '*.md']
17
+ spec.homepage = 'https://www.mslinn.com/blog/2020/10/03/jekyll-plugins.html#flexibleInclude'
18
+ spec.license = 'MIT'
21
19
  spec.metadata = {
22
- "allowed_push_host" => "https://rubygems.org",
23
- "bug_tracker_uri" => "#{github}/issues",
24
- "changelog_uri" => "#{github}/CHANGELOG.md",
25
- "homepage_uri" => spec.homepage,
26
- "source_code_uri" => github,
20
+ 'allowed_push_host' => 'https://rubygems.org',
21
+ 'bug_tracker_uri' => "#{github}/issues",
22
+ 'changelog_uri' => "#{github}/CHANGELOG.md",
23
+ 'homepage_uri' => spec.homepage,
24
+ 'source_code_uri' => github,
27
25
  }
28
- spec.name = "jekyll_flexible_include"
26
+ spec.name = 'jekyll_flexible_include'
29
27
  spec.post_install_message = <<~END_MESSAGE
30
28
 
31
29
  Thanks for installing #{spec.name}!
32
30
 
33
31
  END_MESSAGE
34
- spec.require_paths = ["lib"]
35
- spec.required_ruby_version = ">= 2.6.0"
36
- spec.summary = "Jekyll plugin supports various ways to include content into the generated site."
32
+ spec.require_paths = ['lib']
33
+ spec.required_ruby_version = '>= 2.6.0'
34
+ spec.summary = 'Jekyll plugin supports various ways to include content into the generated site.'
37
35
  spec.test_files = spec.files.grep(%r!^(test|spec|features)/!)
38
36
  spec.version = JekyllFlexibleIncludePluginVersion::VERSION
39
37
 
40
- spec.add_dependency "jekyll", ">= 3.5.0"
41
- spec.add_dependency "jekyll_plugin_logger", '~> 2.1.0'
42
- spec.add_dependency "key-value-parser"
43
-
44
- # spec.add_development_dependency "debase"
45
- # spec.add_development_dependency "rubocop-jekyll"
46
- # spec.add_development_dependency "rubocop-rake"
47
- # spec.add_development_dependency "rubocop-rspec"
48
- # spec.add_development_dependency "ruby-debug-ide"
38
+ spec.add_dependency 'jekyll_plugin_support', '~> 0.5.1'
39
+ spec.add_dependency 'rugged'
49
40
  end
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module JekyllFlexibleIncludePluginVersion
4
- VERSION = "2.0.14"
2
+ VERSION = '2.0.18'.freeze
5
3
  end
@@ -1,170 +1,224 @@
1
- # frozen_string_literal: true
2
-
3
- require "benchmark"
4
- require "jekyll"
5
- require "jekyll_plugin_logger"
6
- require "securerandom"
7
- require_relative "flexible_include/version"
8
- require_relative "jekyll_tag_helper"
1
+ require 'benchmark'
2
+ require 'jekyll_plugin_support'
3
+ require 'securerandom'
4
+ require_relative 'flexible_include/version'
9
5
 
10
6
  module JekyllFlexibleIncludeName
11
- PLUGIN_NAME = "flexible_include"
12
- end
13
-
14
- class FlexibleError < StandardError
7
+ PLUGIN_NAME = 'flexible_include'.freeze
15
8
  end
16
9
 
17
- class FlexibleInclude < Liquid::Tag
18
- FlexibleIncludeError = Class.new(Liquid::Error)
19
-
20
- @read_regexes = nil
10
+ module FlexibleClassMethods
11
+ def access_allowed(path)
12
+ return true unless @read_regexes
21
13
 
22
- def self.normalize_path(path)
23
- JekyllTagHelper.expand_env(path, die_if_undefined: true)
24
- .gsub("~", Dir.home)
14
+ @read_regexes.find { |regex| regex.match(normalize_path(path)) }
25
15
  end
26
16
 
27
- # If FLEXIBLE_INCLUDE_PATHS='~/lib/.*:.*:$WORK/.*'
28
- # Then @read_regexes will be set to regexes of ["/home/my_user_id/lib/.*", "/pwd/.*", "/work/envar/path/.*"]
29
- def self.security_check
30
- @execution_denied = ENV['DISABLE_FLEXIBLE_INCLUDE']
31
-
32
- unless @read_regexes
33
- flexible_include_paths = ENV['FLEXIBLE_INCLUDE_PATHS']
34
- read_paths = normalize_path(flexible_include_paths) if flexible_include_paths
35
- if read_paths
36
- @read_regexes = read_paths.split(":").map do |path|
37
- abs_path = path.start_with?('/') ? path : (Pathname.new(Dir.pwd) + path).to_s
38
- Regexp.new(abs_path)
39
- end
40
- end
41
- end
17
+ def self.escape_html(string)
18
+ string.gsub("&", "&amp;")
19
+ .gsub("{", "&#123;")
20
+ .gsub("}", "&#125;")
21
+ .gsub("<", "&lt;")
42
22
  end
43
23
 
44
- def self.access_allowed(path)
45
- return true unless @read_regexes
46
-
47
- @read_regexes.find { |regex| regex.match(normalize_path(path)) }
24
+ def normalize_path(path)
25
+ JekyllPluginHelper.expand_env(path, die_if_undefined: true)
26
+ .gsub('~', Dir.home)
48
27
  end
49
28
 
50
- def self.number_content(content)
29
+ def number_content(content)
51
30
  lines = content.split("\n")
52
31
  digits = lines.length.to_s.length
53
32
  i = 0
54
33
  numbered_content = lines.map do |line|
55
34
  i += 1
56
- number = i.to_s.rjust(digits, " ")
35
+ number = i.to_s.rjust(digits, ' ')
57
36
  "<span class='unselectable numbered_line'> #{number}: </span>#{line}"
58
37
  end
59
- result = numbered_content.join("\n")
60
- result += "\n" unless result.end_with?("\n")
38
+ result = numbered_content.join "\n"
39
+ result += "\n" unless result.end_with? "\n"
61
40
  result
62
41
  end
63
42
 
64
- # @param tag_name [String] the name of the tag, which we already know.
65
- # @param markup [String] the arguments from the tag, as a single string.
66
- # @param parse_context [Liquid::ParseContext] hash that stores Liquid options.
67
- # By default it has two keys: :locale and :line_numbers, the first is a Liquid::I18n object, and the second,
68
- # a boolean parameter that determines if error messages should display the line number the error occurred.
69
- # This argument is used mostly to display localized error messages on Liquid built-in Tags and Filters.
70
- # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags
71
- def initialize(tag_name, markup, _parse_context)
72
- super
73
- @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
74
- @helper = JekyllTagHelper.new(tag_name, markup, @logger)
43
+ # If FLEXIBLE_INCLUDE_PATHS='~/lib/.*:.*:$WORK/.*'
44
+ # Then @read_regexes will be set to regexes of ['/home/my_user_id/lib/.*', '/pwd/.*', '/work/envar/path/.*']
45
+ def security_check
46
+ @execution_denied = ENV.fetch('DISABLE_FLEXIBLE_INCLUDE', nil)
75
47
 
76
- self.class.security_check
77
- end
48
+ return if @read_regexes
78
49
 
79
- # @param liquid_context [Liquid::Context]
80
- def render(liquid_context) # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/CyclomaticComplexity
81
- @helper.liquid_context = liquid_context
82
- @do_not_escape = @helper.parameter_specified? "do_not_escape"
83
- @download = @helper.parameter_specified? "download"
84
- @dark = " dark" if @helper.parameter_specified?("dark")
85
- @highlight_pattern = @helper.parameter_specified? "highlight"
86
- @label = @helper.parameter_specified? "label"
87
- @number_lines = @helper.parameter_specified? "number"
88
- @label_specified = @label
89
- @copy_button = @helper.parameter_specified? "copyButton"
90
- @pre = @copy_button || @dark || @download || @label_specified || @number_lines || @helper.parameter_specified?("pre") # Download or label implies pre
50
+ flexible_include_paths = ENV.fetch('FLEXIBLE_INCLUDE_PATHS', nil)
51
+ read_paths = normalize_path(flexible_include_paths) if flexible_include_paths
52
+ return unless read_paths
91
53
 
92
- filename = @helper.parameter_specified? "file"
93
- filename ||= @helper.params.first # Do this after all options have been checked for
94
- @label ||= filename
54
+ @read_regexes = read_paths.split(':').map do |path|
55
+ abs_path = path.start_with?('/') ? path : (Pathname.new(Dir.pwd) + path).to_s
56
+ Regexp.new(abs_path)
57
+ end
58
+ end
59
+ end
95
60
 
96
- # If a label was specified, use it, otherwise concatenate any dangling parameters and use that as the label
97
- @label ||= @helper.params[1..].join(" ")
61
+ FlexibleIncludeError = Class.new(Liquid::Error)
98
62
 
99
- @logger.debug("filename=#{filename}")
63
+ class FlexibleInclude < JekyllSupport::JekyllTag # rubocop: disable Metrics/ClassLength
64
+ include JekyllFlexibleIncludePluginVersion
100
65
 
101
- path = JekyllTagHelper.expand_env(filename)
66
+ def render_impl # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
67
+ setup
68
+ path = JekyllPluginHelper.expand_env(@filename)
102
69
  case path
103
70
  when /\A\// # Absolute path
104
- return denied("Access to #{path} denied by FLEXIBLE_INCLUDE_PATHS value.") unless self.class.access_allowed(path)
71
+ return denied("Access to <code>#{path}</code> denied by <code>FLEXIBLE_INCLUDE_PATHS</code> value.") unless self.class.access_allowed(path)
105
72
 
106
- @logger.debug { "Absolute path=#{path}, filename=#{filename}" }
73
+ @logger.debug { "Absolute path=#{path}, @filename=#{@filename}" }
107
74
  when /\A~/ # Relative path to user's home directory
108
- return denied("Access to #{path} denied by FLEXIBLE_INCLUDE_PATHS value.") unless self.class.access_allowed(path)
75
+ return denied("Access to <code>#{path}</code> denied by <code>FLEXIBLE_INCLUDE_PATHS</code> value.") unless self.class.access_allowed(path)
109
76
 
110
- @logger.debug { "User home start filename=#{filename}, path=#{path}" }
111
- filename.slice! "~/"
112
- path = File.join(ENV['HOME'], filename)
113
- @logger.debug { "User home end filename=#{filename}, path=#{path}" }
77
+ @logger.debug { "User home start @filename=#{@filename}, path=#{path}" }
78
+ @filename = @filename.delete_prefix '~/'
79
+ path = File.join(Dir.home, @filename)
80
+ @logger.debug { "User home end @filename=#{@filename}, path=#{path}" }
114
81
  when /\A!/ # Run command and return response
115
- return denied("Arbitrary command execution denied by DISABLE_FLEXIBLE_INCLUDE value.") if @execution_denied
82
+ return denied('Arbitrary command execution denied by DISABLE_FLEXIBLE_INCLUDE value.') if @execution_denied
116
83
 
117
- filename = JekyllTagHelper.remove_quotes(@helper.argv.first) if @helper.argv.first
118
- filename.slice! "!"
119
- contents = run(filename)
84
+ @filename = JekyllPluginHelper.remove_quotes(@helper.argv.first) if @helper.argv.first
85
+ @filename = @filename.delete_prefix '!'
86
+ contents = run(@filename)
120
87
  else # Relative path
121
- site = liquid_context.registers[:site]
122
- source = File.expand_path(site.config['source']) # website root directory
123
- path = File.join(source, filename) # Fully qualified path of include file from relative path
88
+ source = File.expand_path(@site.config['source']) # website root directory
89
+ path = File.join(source, @filename) # Fully qualified path of include file from relative path
124
90
  @relative = true
125
- @logger.debug { "Relative end filename=#{filename}, path=#{path}" }
91
+ @logger.debug { "Relative end @filename=#{@filename}, path=#{path}" }
126
92
  end
127
93
  render_completion(path, contents)
128
- # rescue StandardError => e
129
- # raise FlexibleIncludeError, e.message.red, [] # Suppress stack trace
94
+ rescue Errno::EACCES => e
95
+ msg = format_error_message e.message
96
+ @logger.error msg
97
+ raise FlexibleIncludeError, msg, [] if @die_on_file_error
98
+
99
+ "<span class='flexible_error'>FlexibleIncludeError: #{msg}</span>"
100
+ rescue Errno::ENOENT => e
101
+ msg = format_error_message e.message
102
+ @logger.error msg
103
+ raise FlexibleIncludeError, msg, [] if @die_on_path_denied
104
+
105
+ "<span class='flexible_error'>FlexibleIncludeError: #{msg}</span>"
106
+ rescue FlexibleIncludeError => e
107
+ @logger.error e.message
108
+ raise e
109
+ rescue StandardError => e
110
+ msg = format_error_message e.message
111
+ @logger.error msg
112
+ raise FlexibleIncludeError, msg, [] if @die_on_other_error
113
+
114
+ "<span class='flexible_error'>FlexibleIncludeError: #{msg}</span>"
130
115
  end
131
116
 
132
117
  private
133
118
 
119
+ class << self
120
+ include FlexibleClassMethods
121
+ end
122
+
134
123
  def denied(msg)
135
- @logger.error("#{@helper.page.path} - #{msg}")
136
- "<p style='color: white; background-color: red; padding: 2pt 1em 2pt 1em;'>#{msg}</p>"
124
+ msg_no_html = remove_html_tags(msg)
125
+ @logger.error("#{@page['path']} - #{msg_no_html}")
126
+ raise FlexibleIncludeError, "#{@page['path']} - #{msg_no_html.red}", [] if @die_on_path_denied
127
+
128
+ "<p class='flexible_error'>#{msg}</p>"
129
+ end
130
+
131
+ def format_error_message(message)
132
+ "#{message} on line #{@line_number} (after front matter) of #{@page['path']}}"
137
133
  end
138
134
 
139
135
  def highlight(content, pattern)
140
- content.gsub(Regexp::new(pattern), "<span class='bg_yellow'>\\0</span>")
136
+ content.gsub(Regexp.new(pattern), "<span class='bg_yellow'>\\0</span>")
141
137
  end
142
138
 
143
- def read_file(file)
144
- File.read(file)
139
+ def parse_args
140
+ @copy_button = @helper.parameter_specified? 'copyButton'
141
+ @dark = ' dark' if @helper.parameter_specified? 'dark'
142
+ @do_not_escape = @helper.parameter_specified? 'do_not_escape'
143
+ @download = @helper.parameter_specified? 'download'
144
+ @highlight_pattern = @helper.parameter_specified? 'highlight'
145
+ @label = @helper.parameter_specified? 'label'
146
+ @label_specified = @label
147
+ @number_lines = @helper.parameter_specified? 'number'
148
+ @strip = @helper.parameter_specified? 'strip'
149
+
150
+ # Download, dark, label or number implies pre
151
+ @pre = @helper.parameter_specified?('pre') || @copy_button || @dark || @download || @label_specified || @number_lines
152
+
153
+ @filename = @helper.parameter_specified? 'file'
154
+ @filename ||= @helper.params.first # Do this after all options have been checked for
155
+ @label ||= @filename
156
+
157
+ # If a label was specified, use it, otherwise concatenate any dangling parameters and use that as the label
158
+ @label ||= @helper.params[1..].join(' ')
159
+
160
+ @logger.debug("@filename=#{@filename}")
145
161
  end
146
162
 
163
+ # Not used, delete
147
164
  def realpath_prefixed_with?(path, dir)
148
165
  File.exist?(path) && File.realpath(path).start_with?(dir)
149
- rescue StandardError
150
- false
166
+ rescue StandardError => _e
167
+ raise FlexibleIncludeError, remove_html_tags(e.message).red, [] if @die_on_file_error
168
+ end
169
+
170
+ def remove_html_tags(string)
171
+ string.gsub(/<[^>]*>/, '')
151
172
  end
152
173
 
153
174
  def render_completion(path, contents)
154
- contents ||= read_file(path)
155
- contents2 = @do_not_escape ? contents : JekyllTagHelper.escape_html(contents)
175
+ contents ||= File.read(path)
176
+ contents.strip! if @strip
177
+ contents2 = @do_not_escape ? contents : FlexibleClassMethods.escape_html(contents)
156
178
  contents2 = highlight(contents2, @highlight_pattern) if @highlight_pattern
157
179
  contents2 = FlexibleInclude.number_content(contents2) if @number_lines
158
180
  @pre ? wrap_in_pre(path, contents2) : contents2
159
181
  end
160
182
 
161
183
  def run(cmd)
162
- @logger.debug { "Executing filename=#{cmd}" }
184
+ if cmd.empty?
185
+ msg = format_error_message 'FlexibleIncludeError: Empty command string'
186
+ @do_not_escape = true
187
+ return "<span class='flexible_error'>#{msg}</span>" unless @die_on_other_error
188
+
189
+ raise FlexibleIncludeError, msg, []
190
+ end
191
+
192
+ @logger.debug { "Executing #{cmd}" }
163
193
  %x[#{cmd}].chomp
194
+ rescue FlexibleIncludeError => e
195
+ raise e
196
+ rescue StandardError => e
197
+ msg = format_error_message "#{e.class}: #{e.message.strip}"
198
+ @logger.error msg
199
+ @do_not_escape = true
200
+ return "<span class='flexible_error'>#{msg}</span>" unless @die_on_run_error
201
+
202
+ e.set_backtrace []
203
+ raise e
204
+ end
205
+
206
+ def setup
207
+ self.class.security_check
208
+
209
+ config = @config[JekyllFlexibleIncludeName::PLUGIN_NAME]
210
+ if config
211
+ @die_on_file_error = config['die_on_file_error'] == true
212
+ @die_on_other_error = config['die_on_other_error'] == true
213
+ @die_on_path_denied = config['die_on_path_denied'] == true
214
+ @die_on_run_error = config['die_on_run_error'] == true
215
+ end
216
+
217
+ parse_args
164
218
  end
165
219
 
166
- PREFIX = "<button class='copyBtn' data-clipboard-target="
167
- SUFFIX = "title='Copy to clipboard'><img src='/assets/images/clippy.svg' alt='Copy to clipboard' style='width: 13px'></button>"
220
+ PREFIX = "<button class='copyBtn' data-clipboard-target=".freeze
221
+ SUFFIX = "title='Copy to clipboard'><img src='/assets/images/clippy.svg' alt='Copy to clipboard' style='width: 13px'></button>".freeze
168
222
 
169
223
  def wrap_in_pre(path, content)
170
224
  basename = File.basename(path)
@@ -178,14 +232,13 @@ class FlexibleInclude < Liquid::Tag
178
232
  @label_specified ? @label : basename
179
233
  end
180
234
  pre_id = "id#{SecureRandom.hex 6}"
181
- copy_button = @copy_button ? "#{PREFIX}'##{pre_id}'#{SUFFIX}" : ""
182
- dark_label = " darkLabel" if @dark
235
+ copy_button = @copy_button ? "#{PREFIX}'##{pre_id}'#{SUFFIX}" : ''
236
+ dark_label = ' darkLabel' if @dark
183
237
  <<~END_PRE
184
238
  <div class="codeLabel#{dark_label}">#{label_or_href}</div>
185
239
  <pre data-lt-active="false" class="maxOneScreenHigh copyContainer#{@dark}" id="#{pre_id}">#{copy_button}#{content}</pre>
186
240
  END_PRE
187
241
  end
188
- end
189
242
 
190
- PluginMetaLogger.instance.info { "Loaded #{JekyllFlexibleIncludeName::PLUGIN_NAME} v#{JekyllFlexibleIncludePluginVersion::VERSION} plugin." }
191
- Liquid::Template.register_tag('flexible_include', FlexibleInclude)
243
+ JekyllPluginHelper.register(self, 'flexible_include')
244
+ end
data/lib/git_util.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'rugged'
2
+
3
+ class GitFileReader
4
+ def initialize(repo_dir = '.')
5
+ @repo = Rugged::Repository.new repo_dir
6
+ end
7
+
8
+ def blob_at(ref, path)
9
+ commit = @repo.rev_parse ref # Rugged::Commit
10
+ @repo.blob_at(commit.oid, path) # Rugged::Blob
11
+ end
12
+
13
+ def commit_for_ref(ref)
14
+ reference = @repo.ref ref # Rugged::Reference
15
+ abort "Error: #{ref} is an invalid ref" if reference.nil?
16
+
17
+ reference_direct = reference.type == :symbolic ? reference.target : reference
18
+ @commit = reference_direct.target # Rugged::Commit
19
+ self
20
+ end
21
+
22
+ # @return content of desired file
23
+ def contents(filename)
24
+ abort('Error: @commit is undefined; invoke commit_for_ref before invoking contents') if @commit.nil?
25
+
26
+ tree = @commit.tree # Rugged::Tree
27
+ entry = tree.get_entry filename # hash
28
+ abort("Error: #{filename} is not present in commit #{commit.oid}") if entry.nil?
29
+
30
+ sha = entry[:oid] # String
31
+ object = @repo.read sha # Rugged::ObdObject; this is a blob
32
+ object.data # String
33
+ end
34
+ end
35
+
36
+ if $PROGRAM_NAME == __FILE__
37
+ puts GitFileReader.new('.').blob_at('HEAD~2', 'README.md').content
38
+ # puts GitFileReader.new('.').commit_for_ref('HEAD^').contents('README.md')
39
+ # puts GitFileReader.new('.').commit_for_ref('HEAD').contents('README.md')
40
+ # puts GitFileReader.new('.').commit_for_ref('refs/heads/master').contents('README.md')
41
+ end
@@ -0,0 +1,18 @@
1
+ require_relative '../lib/flexible_include'
2
+
3
+ RSpec.describe(FlexibleInclude) do
4
+ it 'controls access to files' do
5
+ ENV['FLEXIBLE_INCLUDE_PATHS'] = '~/.*:spec/.*'
6
+
7
+ described_class.send(:new, 'my_tag', '', Liquid::ParseContext.new)
8
+ described_class.security_check
9
+ expect(described_class.access_allowed(__FILE__)).to be_truthy
10
+
11
+ expect(described_class.access_allowed('~/.mem_settings.yaml')).to be_truthy
12
+
13
+ home_file = JekyllTagHelper.expand_env('$HOME/.mem_settings.yaml')
14
+ expect(described_class.access_allowed(home_file)).to be_truthy
15
+
16
+ expect(described_class.access_allowed('/asdf')).to be_falsey
17
+ end
18
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,16 +1,14 @@
1
- # frozen_string_literal: true
1
+ require 'jekyll'
2
2
 
3
- require "jekyll"
4
-
5
- require_relative "../lib/flexible_include"
3
+ require_relative '../lib/flexible_include'
6
4
 
7
5
  Jekyll.logger.log_level = :info
8
6
 
9
7
  RSpec.configure do |config|
10
8
  config.filter_run :focus
11
- config.order = "random"
9
+ config.order = 'random'
12
10
  config.run_all_when_everything_filtered = true
13
11
 
14
12
  # See https://relishapp.com/rspec/rspec-core/docs/command-line/only-failures
15
- config.example_status_persistence_file_path = "spec/status_persistence.txt"
13
+ config.example_status_persistence_file_path = 'spec/status_persistence.txt'
16
14
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll_flexible_include
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.14
4
+ version: 2.0.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Slinn
@@ -10,38 +10,24 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2022-09-27 00:00:00.000000000 Z
13
+ date: 2023-03-24 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
- name: jekyll
17
- requirement: !ruby/object:Gem::Requirement
18
- requirements:
19
- - - ">="
20
- - !ruby/object:Gem::Version
21
- version: 3.5.0
22
- type: :runtime
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- version: 3.5.0
29
- - !ruby/object:Gem::Dependency
30
- name: jekyll_plugin_logger
16
+ name: jekyll_plugin_support
31
17
  requirement: !ruby/object:Gem::Requirement
32
18
  requirements:
33
19
  - - "~>"
34
20
  - !ruby/object:Gem::Version
35
- version: 2.1.0
21
+ version: 0.5.1
36
22
  type: :runtime
37
23
  prerelease: false
38
24
  version_requirements: !ruby/object:Gem::Requirement
39
25
  requirements:
40
26
  - - "~>"
41
27
  - !ruby/object:Gem::Version
42
- version: 2.1.0
28
+ version: 0.5.1
43
29
  - !ruby/object:Gem::Dependency
44
- name: key-value-parser
30
+ name: rugged
45
31
  requirement: !ruby/object:Gem::Requirement
46
32
  requirements:
47
33
  - - ">="
@@ -73,8 +59,8 @@ files:
73
59
  - jekyll_flexible_include_plugin.gemspec
74
60
  - lib/flexible_include.rb
75
61
  - lib/flexible_include/version.rb
76
- - lib/jekyll_tag_helper.rb
77
- - spec/glob_spec.rb
62
+ - lib/git_util.rb
63
+ - spec/flexible_include_spec.rb
78
64
  - spec/spec_helper.rb
79
65
  - spec/status_persistence.txt
80
66
  homepage: https://www.mslinn.com/blog/2020/10/03/jekyll-plugins.html#flexibleInclude
@@ -110,7 +96,7 @@ specification_version: 4
110
96
  summary: Jekyll plugin supports various ways to include content into the generated
111
97
  site.
112
98
  test_files:
113
- - spec/glob_spec.rb
99
+ - spec/flexible_include_spec.rb
114
100
  - spec/spec_helper.rb
115
101
  - spec/status_persistence.txt
116
102
  ...
@@ -1,90 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "shellwords"
4
- require 'key_value_parser'
5
-
6
- class JekyllTagHelper
7
- attr_reader :argv, :liquid_context, :logger, :params, :tag_name
8
-
9
- def self.escape_html(string)
10
- string.gsub("&", "&amp;")
11
- .gsub("{", "&#123;")
12
- .gsub("}", "&#125;")
13
- .gsub("<", "&lt;")
14
- end
15
-
16
- # Expand a environment variable reference
17
- def self.expand_env(str, die_if_undefined=false)
18
- str.gsub(/\$([a-zA-Z_][a-zA-Z0-9_]*)|\${\g<1>}|%\g<1>%/) do
19
- envar = Regexp.last_match(1)
20
- raise FlexibleError, "flexible_include error: #{envar} is undefined".red, [] if !ENV.key?(envar) && die_if_undefined # Suppress stack trace
21
- ENV[envar]
22
- end
23
- end
24
-
25
- # strip leading and trailing quotes if present
26
- def self.remove_quotes(string)
27
- string.strip.gsub(/\A'|\A"|'\Z|"\Z/, '').strip if string
28
- end
29
-
30
- def initialize(tag_name, markup, logger)
31
- @tag_name = tag_name
32
- @argv = Shellwords.split(markup)
33
- @keys_values = KeyValueParser.new.parse(@argv) # Hash[Symbol, String|Boolean]
34
- @logger = logger
35
- @logger.debug { "@keys_values='#{@keys_values}'" }
36
- end
37
-
38
- def delete_parameter(name)
39
- @params.delete(name)
40
- @argv.delete_if { |x| x.start_with? name }
41
- @keys_values.delete(name.to_sym)
42
- end
43
-
44
- # @return if parameter was specified, returns value and removes it from the available tokens
45
- def parameter_specified?(name)
46
- value = @keys_values[name.to_sym]
47
- delete_parameter(name)
48
- value
49
- end
50
-
51
- PREDEFINED_SCOPE_KEYS = [:include, :page].freeze
52
-
53
- # Finds variables defined in an invoking include, or maybe somewhere else
54
- # @return variable value or nil
55
- def dereference_include_variable(name)
56
- @liquid_context.scopes.each do |scope|
57
- next if PREDEFINED_SCOPE_KEYS.include? scope.keys.first
58
-
59
- value = scope[name]
60
- return value if value
61
- end
62
- nil
63
- end
64
-
65
- # @return value of variable, or the empty string
66
- def dereference_variable(name)
67
- value = @liquid_context[name] # Finds variables named like 'include.my_variable', found in @liquid_context.scopes.first
68
- value ||= @page[name] if @page # Finds variables named like 'page.my_variable'
69
- value ||= dereference_include_variable(name)
70
- value ||= ""
71
- value
72
- end
73
-
74
- # Sets @params by replacing any Liquid variable names with their values
75
- def liquid_context=(context)
76
- @liquid_context = context
77
- @params = @keys_values.map { |k, _v| lookup_variable(k) }
78
- end
79
-
80
- def lookup_variable(symbol)
81
- string = symbol.to_s
82
- return string unless string.start_with?("{{") && string.end_with?("}}")
83
-
84
- dereference_variable(string.delete_prefix("{{").delete_suffix("}}"))
85
- end
86
-
87
- def page
88
- @liquid_context.registers[:page]
89
- end
90
- end
data/spec/glob_spec.rb DELETED
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../lib/flexible_include"
4
-
5
- RSpec.describe(FlexibleInclude) do
6
- it "controls access to files" do
7
- ENV['FLEXIBLE_INCLUDE_PATHS'] = '~/.*:spec/.*'
8
-
9
- FlexibleInclude.send(:new, 'my_tag', "", Liquid::ParseContext.new)
10
- FlexibleInclude.security_check
11
- expect(FlexibleInclude.access_allowed(__FILE__)).to be_truthy
12
-
13
- expect(FlexibleInclude.access_allowed("~/.mem_settings.yaml")).to be_truthy
14
-
15
- home_file = JekyllTagHelper.expand_env("$HOME/.mem_settings.yaml")
16
- expect(FlexibleInclude.access_allowed(home_file)).to be_truthy
17
-
18
- expect(FlexibleInclude.access_allowed('/asdf')).to be_falsey
19
- end
20
- end