jekyll-carve 0.1.1 → 0.1.2
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 +4 -4
- data/README.md +47 -29
- data/lib/jekyll/carve/version.rb +1 -1
- data/lib/jekyll-carve.rb +121 -3
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1fd1b876054b8355dc08cdf7569c46cafd968c9e8874c65cd4e6e2866f29d6e7
|
|
4
|
+
data.tar.gz: c4866d9b82ff1d2bf963eb8945fa4a67b70b94aaa4d3e78b300229d369cefc4d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b0c225c70722c0ed014f0ade97aae1b534992dd6830b02acf47a27b1914fe92208f478aefb72ec071794be0fd9e33f75be25a365fe55ef5f3b7be0b8e23b1f0a
|
|
7
|
+
data.tar.gz: 6c86ca36aec167aa996d1b01df87113e9e0ef8796f97a0cde5c4a1e4f6badc6b0edbad271886c7cd192a7e1167f7c23042952e74641907cae0e1a87f7e65f2e2
|
data/README.md
CHANGED
|
@@ -130,6 +130,52 @@ reaches the output.
|
|
|
130
130
|
> front matter, from a comment system, or from anything else a visitor can
|
|
131
131
|
> influence.
|
|
132
132
|
|
|
133
|
+
### `carve.includes` - pulling one file into another
|
|
134
|
+
|
|
135
|
+
A Carve page can pull another file in with `{{ path }}`. It stays literal until
|
|
136
|
+
the site asks:
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
carve:
|
|
140
|
+
includes: true
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Includes need carve-lang 0.1.4 or later. On an older engine, a page that
|
|
144
|
+
reaches them stops the build with a message naming the upgrade.
|
|
145
|
+
|
|
146
|
+
Paths resolve relative to the file that wrote them, and nothing resolves outside
|
|
147
|
+
the containment root. The root is Jekyll's source directory unless
|
|
148
|
+
`carve.include_root` names another one, and an include that would leave it is
|
|
149
|
+
not expanded.
|
|
150
|
+
|
|
151
|
+
```yaml
|
|
152
|
+
carve:
|
|
153
|
+
includes: true
|
|
154
|
+
include_root: /srv/shared/fragments
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`carve.include_root` must be an **absolute** path. A relative one is refused
|
|
158
|
+
rather than resolved, because resolving it lands on whatever directory the build
|
|
159
|
+
ran from, which is not a root anyone chose. The page being rendered has to sit
|
|
160
|
+
inside the root too.
|
|
161
|
+
|
|
162
|
+
A target that cannot be read is reported against the page that asked for it, and
|
|
163
|
+
the directive is left as written. The message does not say whether the file was
|
|
164
|
+
missing or refused by containment: both report `include-unresolved`, so a page
|
|
165
|
+
cannot be used to probe the filesystem. The class is at `--verbose`.
|
|
166
|
+
|
|
167
|
+
Under `jekyll serve`, a page is rebuilt when a target it read changes, because
|
|
168
|
+
every resolved target is registered with Jekyll's regeneration path.
|
|
169
|
+
|
|
170
|
+
A conversion with no page behind it - the converter called directly on a String -
|
|
171
|
+
leaves the directive literal, since there is no file for a relative path to
|
|
172
|
+
resolve against.
|
|
173
|
+
|
|
174
|
+
> [!NOTE]
|
|
175
|
+
> Fragments under the source directory are pages in their own right, so Jekyll
|
|
176
|
+
> will publish them. Exclude them in `_config.yml`, or keep them outside the
|
|
177
|
+
> source and point `include_root` at the tree above both.
|
|
178
|
+
|
|
133
179
|
## Usage
|
|
134
180
|
|
|
135
181
|
Create a page with a `.crv` extension. It MUST begin with Jekyll
|
|
@@ -193,32 +239,4 @@ has already removed the leading block by the time Carve runs.
|
|
|
193
239
|
|
|
194
240
|
## Development
|
|
195
241
|
|
|
196
|
-
|
|
197
|
-
bundle install
|
|
198
|
-
bundle exec rspec # run the converter unit tests
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### Which engine you are testing against
|
|
202
|
-
|
|
203
|
-
`bundle install` here does **not** resolve `carve-lang` from RubyGems. `Gemfile`
|
|
204
|
-
pins the engine to a carve-rb revision, so a development run measures one exact
|
|
205
|
-
engine build rather than whatever the registry serves that day, and
|
|
206
|
-
`script/verify_engine_pin.rb` refuses when the Gemfile, the resolved bundle and
|
|
207
|
-
the loaded library disagree. CI runs it before the suite:
|
|
208
|
-
|
|
209
|
-
```sh
|
|
210
|
-
bundle exec ruby script/verify_engine_pin.rb
|
|
211
|
-
# carve-lang 0.1.2 from carve-rb b7f3a91a... (Gemfile pins b7f3a91a4192)
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
An installed copy of this gem resolves differently, through the range
|
|
215
|
-
`jekyll-carve.gemspec` declares - today `>= 0.1.1, < 0.2.0`. The two are
|
|
216
|
-
deliberately not the same engine, and both are checked:
|
|
217
|
-
`spec/engine_floor_spec.rb` asks whether the engine under `bundle exec rspec`
|
|
218
|
-
still does what the floor claims, and `script/consumer_engine_probe.rb` asks the
|
|
219
|
-
same of an actual `gem install`, daily in `Engine drift` and again before every
|
|
220
|
-
release.
|
|
221
|
-
|
|
222
|
-
There is no committed `Gemfile.lock`, and that is deliberate - the reasoning,
|
|
223
|
-
including why a lockfile would be a weaker pin here and what it would cost the
|
|
224
|
-
Ruby 3.1 job, is written at the top of `Gemfile`.
|
|
242
|
+
Contributor setup, testing, and maintenance notes are in the [development guide](docs/development.md).
|
data/lib/jekyll/carve/version.rb
CHANGED
data/lib/jekyll-carve.rb
CHANGED
|
@@ -59,9 +59,52 @@ module Jekyll
|
|
|
59
59
|
#
|
|
60
60
|
# Returns the rendered HTML String.
|
|
61
61
|
def convert(content)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
document = Rendering.current
|
|
63
|
+
root = include_root
|
|
64
|
+
if root.nil? || document.nil? || document.path.to_s.empty?
|
|
65
|
+
return ::Carve.to_html(content.to_s,
|
|
66
|
+
extensions: carve_extensions,
|
|
67
|
+
symbols: carve_symbols)
|
|
68
|
+
end
|
|
69
|
+
# carve-lang added this entry point in 0.1.4; the floor stays lower for sites without includes.
|
|
70
|
+
unless ::Carve.respond_to?(:to_html_with_includes)
|
|
71
|
+
raise ArgumentError,
|
|
72
|
+
"carve.includes: the installed carve-lang (#{::Carve::VERSION}) has no " \
|
|
73
|
+
"to_html_with_includes; upgrade it to 0.1.4 or later, or set carve.includes: false"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
begin
|
|
77
|
+
result = ::Carve.to_html_with_includes(content.to_s,
|
|
78
|
+
root: root,
|
|
79
|
+
source_path: document.path,
|
|
80
|
+
extensions: carve_extensions,
|
|
81
|
+
symbols: carve_symbols)
|
|
82
|
+
rescue ArgumentError => e
|
|
83
|
+
# A relative root, or a page outside it. Both are decided by the
|
|
84
|
+
# engine; what this adds is the key and the page to look at.
|
|
85
|
+
raise ArgumentError,
|
|
86
|
+
"carve.include_root: #{document.relative_path || document.path}: #{e.message}"
|
|
87
|
+
end
|
|
88
|
+
report_includes(result, document, root)
|
|
89
|
+
result[:value]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# The containment root configured under `carve.include_root`, or nil when
|
|
93
|
+
# `carve.includes` is off.
|
|
94
|
+
#
|
|
95
|
+
# A configured value is handed to the engine exactly as written. The
|
|
96
|
+
# engine refuses a relative root, and that refusal is what keeps
|
|
97
|
+
# containment off whatever directory the build ran from; expanding it
|
|
98
|
+
# here would mean it never fires. The default is Jekyll's own source
|
|
99
|
+
# directory, which this package derives rather than reads, so that one is
|
|
100
|
+
# expanded.
|
|
101
|
+
def include_root
|
|
102
|
+
return nil unless carve_config["includes"]
|
|
103
|
+
|
|
104
|
+
configured = carve_config["include_root"]
|
|
105
|
+
return configured.to_s if configured.is_a?(String) && !configured.empty?
|
|
106
|
+
|
|
107
|
+
File.expand_path(site_source)
|
|
65
108
|
end
|
|
66
109
|
|
|
67
110
|
# Carve extensions configured under `carve.extensions` in _config.yml.
|
|
@@ -129,6 +172,48 @@ module Jekyll
|
|
|
129
172
|
|
|
130
173
|
private
|
|
131
174
|
|
|
175
|
+
# Surface what expansion degraded, and record what it read.
|
|
176
|
+
def report_includes(result, document, root)
|
|
177
|
+
page = document.relative_path || document.path
|
|
178
|
+
Array(result[:warnings]).each do |warning|
|
|
179
|
+
origin = warning[:file]
|
|
180
|
+
where = origin && origin != page ? "#{page} (#{origin})" : page
|
|
181
|
+
Jekyll.logger.warn "Carve:", "#{where}: #{warning[:rule]}: #{warning[:message]}"
|
|
182
|
+
end
|
|
183
|
+
suppressed = result[:suppressedWarnings].to_i
|
|
184
|
+
if suppressed.positive?
|
|
185
|
+
Jekyll.logger.warn "Carve:",
|
|
186
|
+
"#{page}: #{suppressed} further include warnings suppressed"
|
|
187
|
+
end
|
|
188
|
+
Array(result[:dependencies]).each do |dependency|
|
|
189
|
+
# A containment refusal and a missing file are the same warning, so a
|
|
190
|
+
# page cannot probe the filesystem (spec I7). The class that was
|
|
191
|
+
# collapsed is here, for the build's own log.
|
|
192
|
+
if dependency[:denial]
|
|
193
|
+
Jekyll.logger.debug "Carve:",
|
|
194
|
+
"#{page}: include #{dependency[:path]}: #{dependency[:denial]}"
|
|
195
|
+
next
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
register_dependency(document, File.join(root, dependency[:path].to_s))
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Tell Jekyll the page has to be rebuilt when this target changes.
|
|
203
|
+
#
|
|
204
|
+
# Only a RESOLVED target is registered. An unresolved dependency reports
|
|
205
|
+
# the directive as written rather than a path relative to the root, so
|
|
206
|
+
# joining it onto the root names the wrong file: a nested `missing.crv`
|
|
207
|
+
# would be recorded against the root rather than against the directory
|
|
208
|
+
# its parent sits in. A fragment appearing later is covered by Jekyll's
|
|
209
|
+
# own watch over the source directory.
|
|
210
|
+
def register_dependency(document, target)
|
|
211
|
+
regenerator = document.site&.regenerator
|
|
212
|
+
return unless regenerator.respond_to?(:add_dependency)
|
|
213
|
+
|
|
214
|
+
regenerator.add_dependency(document.path, target)
|
|
215
|
+
end
|
|
216
|
+
|
|
132
217
|
# The `carve` table from _config.yml, or an empty Hash.
|
|
133
218
|
def carve_config
|
|
134
219
|
config = @config.is_a?(Hash) ? @config["carve"] : nil
|
|
@@ -247,9 +332,42 @@ module Jekyll
|
|
|
247
332
|
end
|
|
248
333
|
end
|
|
249
334
|
end
|
|
335
|
+
|
|
336
|
+
# Which document Jekyll is rendering right now.
|
|
337
|
+
#
|
|
338
|
+
# `Jekyll::Converter#convert` is handed a String and nothing else, so a
|
|
339
|
+
# converter cannot see the file the body came from - and an include has to
|
|
340
|
+
# resolve against that file. The `:pre_render` hook carries it, and Jekyll
|
|
341
|
+
# renders documents one at a time, so the current one is a thread-local
|
|
342
|
+
# rather than a queue.
|
|
343
|
+
module Rendering
|
|
344
|
+
KEY = :jekyll_carve_document
|
|
345
|
+
|
|
346
|
+
module_function
|
|
347
|
+
|
|
348
|
+
def current
|
|
349
|
+
Thread.current[KEY]
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
def with(document)
|
|
353
|
+
Thread.current[KEY] = document
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def clear
|
|
357
|
+
Thread.current[KEY] = nil
|
|
358
|
+
end
|
|
359
|
+
end
|
|
250
360
|
end
|
|
251
361
|
end
|
|
252
362
|
|
|
363
|
+
Jekyll::Hooks.register %i[pages documents], :pre_render do |document|
|
|
364
|
+
Jekyll::Carve::Rendering.with(document)
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
Jekyll::Hooks.register %i[pages documents], :post_render do |_document|
|
|
368
|
+
Jekyll::Carve::Rendering.clear
|
|
369
|
+
end
|
|
370
|
+
|
|
253
371
|
# Resolve the symbol map once per build rather than once per process.
|
|
254
372
|
#
|
|
255
373
|
# `Site#reset` runs at the top of every `Site#process`, including every rebuild
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jekyll-carve
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- markup-carve
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-09-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: carve-lang
|