asciisourcerer 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.adoc +355 -35
- data/lib/asciidoctor/extensions/source-skim-tree-processor/extension.rb +55 -0
- data/lib/asciisourcerer.rb +1 -0
- data/lib/sourcerer/asciidoc.rb +13 -9
- data/lib/sourcerer/attributes_filter.rb +72 -0
- data/lib/sourcerer/rendering.rb +29 -0
- data/lib/sourcerer/source_skim/config.rb +53 -0
- data/lib/sourcerer/source_skim/skimmer.rb +298 -0
- data/lib/sourcerer/source_skim.rb +76 -0
- data/lib/sourcerer/sync/block_parser.rb +245 -0
- data/lib/sourcerer/sync/cast.rb +274 -0
- data/lib/sourcerer/sync.rb +33 -0
- data/lib/sourcerer/util/list_amend.rb +63 -0
- data/lib/sourcerer/util/pathifier.rb +101 -0
- data/lib/sourcerer/version.rb +1 -1
- data/lib/sourcerer.rb +3 -0
- metadata +13 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3ed8f8523d54a5f1627241552ea3ed79513e7721d4b615622f37c149f797b236
|
|
4
|
+
data.tar.gz: 8a926eac14aa811b7b573bd61cd5eb209900fa77551c5330c4581133148a3faa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5467d009399728b3e251ee96cace5279a99c27aa5eaa45605dddbdd10ec2758da39e741212fb9d193db9480ad7029d429150832c8d33391839e5fa2ad719e38d
|
|
7
|
+
data.tar.gz: c592774a5427067c102ade751fbbc8e77e899afec0d327bce0ae8a2c0101d684f0b27e818f778fa4a065a93a756bb887e976d1e7352ba1eae21a8bbb6cd9fd96
|
data/README.adoc
CHANGED
|
@@ -1,38 +1,52 @@
|
|
|
1
|
-
:page-layout: default
|
|
2
|
-
:page-permalink: /docs
|
|
3
|
-
:page-nav_order: 1
|
|
4
1
|
= AsciiSourcerer
|
|
5
2
|
// tag::ai-prompt[]
|
|
6
3
|
// Collects AsciiDoc content for presenting to a generative AI prompt
|
|
7
4
|
// Other AI-only prompt matter could go here
|
|
8
|
-
// tag::
|
|
9
|
-
:
|
|
10
|
-
:
|
|
11
|
-
|
|
12
|
-
:
|
|
13
|
-
|
|
14
|
-
:
|
|
15
|
-
:
|
|
16
|
-
:
|
|
17
|
-
:
|
|
18
|
-
:
|
|
19
|
-
:
|
|
20
|
-
|
|
21
|
-
:
|
|
5
|
+
// tag::global-settings[]
|
|
6
|
+
:this_proj_slug: asciisourcerer
|
|
7
|
+
:this_proj_name: AsciiSourcerer
|
|
8
|
+
// tag::universal-settings[]
|
|
9
|
+
// ALL changes within this block must be made in prime template:
|
|
10
|
+
// DocOps/lab/gems/docopslab-dev/templates/README.asciidoc
|
|
11
|
+
:docopslab_src_www_url: https://github.com/DocOps
|
|
12
|
+
:docopslab_domain: docopslab.org
|
|
13
|
+
:docopslab_www_url: https://{docopslab_domain}
|
|
14
|
+
:docopslab_io_www_url: https://docopslab.github.io
|
|
15
|
+
:docopslab_ruby_version: 3.2.7
|
|
16
|
+
:docopslab_src_www_url: https://raw.githubusercontent.com/DocOps
|
|
17
|
+
:docopslab_git_src_uri: git@github.com:DocOps
|
|
18
|
+
:this_proj_src_www_url: {docopslab_src_www_url}/{this_proj_slug}
|
|
19
|
+
:this_proj_src_raw_url: https://raw.githubusercontent.com/DocOps/{this_proj_slug}/main
|
|
20
|
+
:this_proj_src_main_files_url: {this_proj_src_www_url}/blob/main
|
|
21
|
+
:this_proj_src_git_uri: {docopslab_git_src_uri}/{this_proj_slug}.git
|
|
22
|
+
:this_proj_ruby_version: {docopslab_ruby_version}
|
|
23
|
+
// tag::env-settings[]
|
|
24
|
+
:docs_extn:
|
|
22
25
|
ifdef::env-github[]
|
|
23
26
|
:docs_extn: .adoc
|
|
24
|
-
:
|
|
25
|
-
:
|
|
26
|
-
:
|
|
27
|
-
:
|
|
27
|
+
:icons: font
|
|
28
|
+
:caution-caption: :fire:
|
|
29
|
+
:important-caption: :exclamation:
|
|
30
|
+
:note-caption: :paperclip:
|
|
31
|
+
:tip-caption: :bulb:
|
|
32
|
+
:warning-caption: :warning:
|
|
28
33
|
endif::[]
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
// end::env-settings[]
|
|
35
|
+
// Settings likely to be overridden locally
|
|
36
|
+
:this_prod_slug: {this_proj_slug}
|
|
37
|
+
:this_prod_name: {this_proj_name}
|
|
38
|
+
// end::universal-settings[]
|
|
39
|
+
:this_prod_vrsn_major: 0
|
|
40
|
+
:this_prod_vrsn_minor: 2
|
|
41
|
+
:this_prod_vrsn_majmin: {this_prod_vrsn_major}.{this_prod_vrsn_minor}
|
|
42
|
+
:this_prod_vrsn_patch: 0
|
|
43
|
+
:this_prod_vrsn: {this_prod_vrsn_majmin}.{this_prod_vrsn_patch}
|
|
44
|
+
:next_prod_vrsn: 0.3.0
|
|
45
|
+
// end::global-settings[]
|
|
33
46
|
:toc: macro
|
|
34
|
-
:toclevels:
|
|
35
|
-
|
|
47
|
+
:toclevels: 4
|
|
48
|
+
:this_prod_repo_files_path: {this_proj_src_www_url}/tree/main
|
|
49
|
+
:imagesdir: ./specs/docs
|
|
36
50
|
|
|
37
51
|
AsciiSourcerer is a Ruby library for radical single-sourcing of documentation and product data, primarily from AsciiDoc, YAML, and Liquid templating operations.
|
|
38
52
|
|
|
@@ -47,31 +61,51 @@ Its end user base is expected to be Ruby developers; for user-friendlier applica
|
|
|
47
61
|
The core module is canonically called `Sourcerer` and is usually referred to as such in documentation.
|
|
48
62
|
The module `AsciiSourcerer` serves as an alias to `Sourcerer` in case of namespace conflicts.
|
|
49
63
|
|
|
64
|
+
toc::[]
|
|
65
|
+
|
|
50
66
|
[[capabilities]]
|
|
51
67
|
=== Capabilities
|
|
52
68
|
|
|
53
69
|
The API focuses on a small set of robust primitives that downstream tools can compose.
|
|
54
70
|
|
|
71
|
+
[qanda]
|
|
55
72
|
AsciiDoc extraction::
|
|
56
73
|
Load attributes, transclude tagged snippets, extract tagged regions, and convert documents from AsciiDoc source files.
|
|
57
74
|
|
|
58
75
|
Tag-aware YAML loading::
|
|
59
76
|
Load YAML files while preserving custom tags and optionally resolving embedded AsciiDoc attributes and Liquid/ERB template syntax.
|
|
60
77
|
|
|
78
|
+
Text syncing in source files::
|
|
79
|
+
Synchronise canonical tagged blocks from a prime template into project-local files.
|
|
80
|
+
Supports one-time bootstrapping, ongoing sync, Liquid rendering within managed blocks, and dry-run diffing.
|
|
81
|
+
See <<sync-cast>>.
|
|
82
|
+
|
|
61
83
|
Templating and rendering::
|
|
62
84
|
Render Liquid or ERB templates against YAML data or AsciiDoc attributes.
|
|
63
85
|
|
|
64
86
|
Liquid runtime integration::
|
|
65
87
|
Initialize a Jekyll-routed Liquid runtime with DocOps Lab filters and tags, so Jekyll-compatible templates behave predictably.
|
|
88
|
+
See <<templating-liquid-runtime>>.
|
|
66
89
|
|
|
67
90
|
Build-time generation::
|
|
68
91
|
Generate prebuild artifacts (attributes, snippets, regions) for downstream builds and runtime access.
|
|
92
|
+
See <<pipelines>>.
|
|
69
93
|
|
|
70
94
|
AsciiDoc-to-manpage conversion::
|
|
71
95
|
Build manpages for apps from the docs.
|
|
72
96
|
|
|
73
97
|
AsciiDoc-to-Markdown conversion::
|
|
74
98
|
Convert AsciiDoc documents to Markdown for agentic consumption, with a focus on preserving semantic structure and document frontmatter.
|
|
99
|
+
See <<markdowngrade>>.
|
|
100
|
+
|
|
101
|
+
AsciiDoc source inspection::
|
|
102
|
+
Skim AsciiDoc documents to produce machine-oriented outlines of sections, code blocks, tables, and other semantic elements for tooling and agent consumption.
|
|
103
|
+
See <<source-skim>>.
|
|
104
|
+
|
|
105
|
+
General-purpose utilities::
|
|
106
|
+
Small, dependency-light primitives for list amendment and path classification/enumeration, available under `Sourcerer::Util`.
|
|
107
|
+
Not required internally; useful for downstream callers and scripts.
|
|
108
|
+
See <<utilities>>.
|
|
75
109
|
|
|
76
110
|
All of these operations are meant to be available even before resources like SchemaGraphy and LiquiDoc are loaded.
|
|
77
111
|
Most are best invoked via a <<integrations,downstream API or utility>>, where robust services for _input_ (file read), _output_ (file write), _configuration_, _scripting_, and contextual _enrichment_ may be available via CLI or API.
|
|
@@ -89,6 +123,7 @@ AsciiDoc attributes are key-value pairs defined in AsciiDoc documents that can b
|
|
|
89
123
|
|
|
90
124
|
tagged regions::
|
|
91
125
|
Sections of source files demarcated by `tag::` and `end::` markers, which can be extracted as content snippets for reuse in documentation or other outputs.
|
|
126
|
+
Tagged regions can also be used by <<sync-cast>> to identify content blocks for synchronization across _source_ files.
|
|
92
127
|
|
|
93
128
|
YAML tags::
|
|
94
129
|
Custom YAML tags (ex: `!liquid`, `!attribute`) that provide special processing instructions during YAML loading.
|
|
@@ -114,6 +149,10 @@ Extract attributes and tagged content from AsciiDoc into artifacts that are load
|
|
|
114
149
|
Converter flow::
|
|
115
150
|
Use a custom converter (callable or constant name) to produce specialized output without embedding converter logic into the core rendering pipeline.
|
|
116
151
|
|
|
152
|
+
Source inspection flow::
|
|
153
|
+
Skim an AsciiDoc source document to produce a structured, JSON-ready outline of its sections and key block elements for tooling and agents.
|
|
154
|
+
See <<source-skim>>.
|
|
155
|
+
|
|
117
156
|
[[quickstart]]
|
|
118
157
|
=== Quickstart
|
|
119
158
|
|
|
@@ -122,7 +161,7 @@ Add `asciisourcerer` to your application using Bundler.
|
|
|
122
161
|
.Gemfile addition
|
|
123
162
|
[source,ruby,subs=+attributes]
|
|
124
163
|
----
|
|
125
|
-
gem 'asciisourcerer', '~> {
|
|
164
|
+
gem 'asciisourcerer', '~> {this_prod_vrsn_majmin}'
|
|
126
165
|
----
|
|
127
166
|
|
|
128
167
|
Then require and use it in your Ruby code.
|
|
@@ -137,6 +176,7 @@ Primary API namespaces:
|
|
|
137
176
|
* `Sourcerer::Yaml` for YAML loading with tag preservation and optional attribute resolution.
|
|
138
177
|
* `Sourcerer::Yaml::TagUtils` for tag helper methods (`detag`, `tag_of`, `tag?`).
|
|
139
178
|
* `Sourcerer::Rendering` for template rendering and output orchestration.
|
|
179
|
+
* `Sourcerer::Sync` for canonical block synchronization (<<sync-cast>>).
|
|
140
180
|
|
|
141
181
|
The top-level `Sourcerer.*` methods remain as compatibility delegators.
|
|
142
182
|
This layer is actually *deprecated* and will be removed in AsciiSourcerer 1.0.
|
|
@@ -169,7 +209,7 @@ Sourcerer::AsciiDoc.generate_html(
|
|
|
169
209
|
|
|
170
210
|
If `asciidoctor-html5s` is unavailable at runtime, Sourcerer falls back to the standard `html5` backend.
|
|
171
211
|
|
|
172
|
-
[[
|
|
212
|
+
[[markdowngrade]]
|
|
173
213
|
=== MarkDownGrade (AsciiDoc -> Markdown)
|
|
174
214
|
|
|
175
215
|
`Sourcerer::MarkDownGrade` handles HTML-to-Markdown adaptation.
|
|
@@ -217,8 +257,8 @@ markdown = Sourcerer::MarkDownGrade.convert_html(
|
|
|
217
257
|
puts(markdown)
|
|
218
258
|
----
|
|
219
259
|
|
|
220
|
-
[[
|
|
221
|
-
|
|
260
|
+
[[markdowngrade-migration]]
|
|
261
|
+
==== Migration Mini-Guide (DocOps Lab)
|
|
222
262
|
|
|
223
263
|
For consumers currently using `DocOps/lab/scripts/mark_down_grade.rb`, migrate to Sourcerer in two steps.
|
|
224
264
|
|
|
@@ -235,7 +275,99 @@ Step 2: Verify parity, then remove duplicate script::
|
|
|
235
275
|
Recommended follow-through::
|
|
236
276
|
* Redirect or retire `lab/scripts/README-mark_down_grade.adoc` so AsciiSourcerer remains source-of-truth.
|
|
237
277
|
|
|
238
|
-
[[
|
|
278
|
+
[[sync-cast]]
|
|
279
|
+
=== Sync/Cast: Canonical Block Synchronization
|
|
280
|
+
|
|
281
|
+
Sync/Cast keeps a set of _canonical blocks_ consistent across multiple files.
|
|
282
|
+
Here are some feature-specific terms.
|
|
283
|
+
|
|
284
|
+
prime template::
|
|
285
|
+
A source file containing canonical blocks intended to be synchronised into one or more project-local target files.
|
|
286
|
+
|
|
287
|
+
target file::
|
|
288
|
+
A project-local file that receives synchronised content from a prime template.
|
|
289
|
+
All content outside canonical blocks is preserved verbatim.
|
|
290
|
+
|
|
291
|
+
canonical block::
|
|
292
|
+
A tagged region whose content is owned by the synchronization system.
|
|
293
|
+
Identified by a configurable prefix; the default is `universal-`.
|
|
294
|
+
Override it per call with the `canonical_prefix:` keyword argument.
|
|
295
|
+
|
|
296
|
+
[[sync-cast-tag-syntax]]
|
|
297
|
+
==== Tag syntax
|
|
298
|
+
|
|
299
|
+
Canonical blocks use AsciiDoc-style `tag::`/`end::` markers embedded inside comments.
|
|
300
|
+
Three comment styles are recognized so the same prime can manage files of any type:
|
|
301
|
+
|
|
302
|
+
[cols="3m,5m",options="header"]
|
|
303
|
+
|===
|
|
304
|
+
| Style | Example
|
|
305
|
+
| HTML / Markdown comment
|
|
306
|
+
| <!-- tag::universal-intro[] -->
|
|
307
|
+
| AsciiDoc line comment
|
|
308
|
+
| // tag::universal-intro[]
|
|
309
|
+
| Shell / Ruby / YAML comment
|
|
310
|
+
| # tag::universal-intro[]
|
|
311
|
+
|===
|
|
312
|
+
|
|
313
|
+
The trailing `[]` is optional in all three styles.
|
|
314
|
+
|
|
315
|
+
A tag whose name begins with the configured prefix (default `universal-`) is treated as canonical and managed by Sync/Cast.
|
|
316
|
+
All other tagged regions in a target file are left entirely alone, and their presence beside a canonical block never triggers a warning.
|
|
317
|
+
|
|
318
|
+
[[sync-cast-operations]]
|
|
319
|
+
==== Operations
|
|
320
|
+
|
|
321
|
+
init::
|
|
322
|
+
One-time operation that renders the prime template (the whole file, not just canonical blocks) through Liquid and writes the result as a new target file.
|
|
323
|
+
Use this to bootstrap a repo-local copy of a project template.
|
|
324
|
+
|
|
325
|
+
sync::
|
|
326
|
+
Ongoing operation that scans for canonical blocks, replaces their content with the prime version (after optional Liquid rendering), and leaves everything else verbatim.
|
|
327
|
+
|
|
328
|
+
dry_run: true::
|
|
329
|
+
Pass `dry_run: true` to either operation to compute the result without writing any file.
|
|
330
|
+
The `result.diff` file contains the rendered content (`init`) or a unified diff (`sync`).
|
|
331
|
+
|
|
332
|
+
[NOTE]
|
|
333
|
+
====
|
|
334
|
+
If a canonical block is absent from a target file, `sync` emits a warning.
|
|
335
|
+
That warning is suppressed when the target contains a non-canonical tag sharing the same suffix — for example, `local-intro` alongside canonical `universal-intro` — indicating a deliberate project-local override.
|
|
336
|
+
====
|
|
337
|
+
|
|
338
|
+
[[sync-cast-liquid]]
|
|
339
|
+
==== Liquid variables in blocks
|
|
340
|
+
|
|
341
|
+
Pass a plain Ruby `Hash` as `data:` and its top-level keys become Liquid variables inside every canonical block.
|
|
342
|
+
Nested values follow Liquid dot notation.
|
|
343
|
+
|
|
344
|
+
During `sync`, only canonical block content is rendered.
|
|
345
|
+
During `init`, the entire prime template is rendered.
|
|
346
|
+
Local content in target files is never rendered.
|
|
347
|
+
|
|
348
|
+
[source,markdown]
|
|
349
|
+
----
|
|
350
|
+
<!-- tag::universal-intro[] -->
|
|
351
|
+
This is {{ data.variables.name }} version {{ data.variables.version }}.
|
|
352
|
+
<!-- end::universal-intro[] -->
|
|
353
|
+
----
|
|
354
|
+
|
|
355
|
+
[[sync-cast-bootstrap]]
|
|
356
|
+
==== Bootstrap example
|
|
357
|
+
|
|
358
|
+
[source,ruby]
|
|
359
|
+
----
|
|
360
|
+
Sourcerer::Sync.init(
|
|
361
|
+
'templates/AGENTS.markdown',
|
|
362
|
+
'AGENTS.md',
|
|
363
|
+
data: { 'project' => 'my-gem', 'org' => 'DocOps' }
|
|
364
|
+
)
|
|
365
|
+
----
|
|
366
|
+
|
|
367
|
+
Parent directories are created automatically.
|
|
368
|
+
Pass `dry_run: true` to return the rendered content in `result.diff` without writing any file.
|
|
369
|
+
|
|
370
|
+
[[templating-liquid-runtime]]
|
|
239
371
|
=== Templating and Liquid Runtime
|
|
240
372
|
|
|
241
373
|
Sourcerer supports Liquid and ERB, but its Liquid support is intentionally aligned with Jekyll’s runtime.
|
|
@@ -284,6 +416,169 @@ Downstream filter responsibility::
|
|
|
284
416
|
Sourcerer ships generic Liquid utility filters only.
|
|
285
417
|
Schema-aware filters (including SGYML-specific classification filters) should be provided by downstream tooling such as SchemaGraphy and/or ReleaseHx.
|
|
286
418
|
|
|
419
|
+
[[source-skim]]
|
|
420
|
+
=== SourceSkim
|
|
421
|
+
|
|
422
|
+
`Sourcerer::SourceSkim` generates machine-oriented _skims_ of AsciiDoc source documents.
|
|
423
|
+
|
|
424
|
+
A skim is a structured, JSON/YAML-ready outline of selected source elements:
|
|
425
|
+
sections, code blocks, definition lists, tables, images, and more.
|
|
426
|
+
Skims are intended to help tooling and agents inspect documentation source without ingesting full file contents.
|
|
427
|
+
|
|
428
|
+
.Example: Skim a file for sections and code blocks
|
|
429
|
+
[source,ruby]
|
|
430
|
+
----
|
|
431
|
+
# Tree sections by default
|
|
432
|
+
skim = Sourcerer::SourceSkim.skim_file('docs/install.adoc')
|
|
433
|
+
|
|
434
|
+
# Both tree and flat section shapes
|
|
435
|
+
skim = Sourcerer::SourceSkim.skim_file('docs/install.adoc', forms: [:tree, :flat])
|
|
436
|
+
|
|
437
|
+
# Restrict to specific categories
|
|
438
|
+
skim = Sourcerer::SourceSkim.skim_file('docs/install.adoc', categories: [:code_blocks, :tables])
|
|
439
|
+
|
|
440
|
+
# Skim inline content
|
|
441
|
+
skim = Sourcerer::SourceSkim.skim_string(raw_adoc_content)
|
|
442
|
+
----
|
|
443
|
+
|
|
444
|
+
Section shapes::
|
|
445
|
+
Pass `forms: [:tree]` (default), `forms: [:flat]`, or both.
|
|
446
|
+
Tree shape preserves nesting; flat shape adds `parent_id` and expresses child section IDs as an array.
|
|
447
|
+
|
|
448
|
+
Categories::
|
|
449
|
+
Default output includes `attributes_custom`, `definition_lists`, `code_blocks`, `literal_blocks`, `examples`, `sidebars`, `tables`, and `images`.
|
|
450
|
+
Opt-in only (excluded by default): `attributes_builtin`, `admonitions`, `quotes`.
|
|
451
|
+
Pass `categories:` with an explicit array of symbols to restrict or expand output.
|
|
452
|
+
|
|
453
|
+
Output reference::
|
|
454
|
+
The skim output schema is at `specs/data/asciidoc-source-skim.schema.json` and a YAML model reference at `specs/data/asciidoc-source-skim-model.yaml`.
|
|
455
|
+
|
|
456
|
+
[[skim-asciidoctor-extension]]
|
|
457
|
+
==== Asciidoctor extension
|
|
458
|
+
`Sourcerer::SourceSkim::TreeProcessorExtension` integrates SourceSkim into Asciidoctor parsing pipelines.
|
|
459
|
+
It stores the result as the `source-skim-result` document attribute and reads `source-skim-forms` and `source-skim-categories` document attributes for per-document configuration.
|
|
460
|
+
|
|
461
|
+
.Register the extension
|
|
462
|
+
[source,ruby]
|
|
463
|
+
----
|
|
464
|
+
require 'asciidoctor/extensions/source-skim-tree-processor/extension'
|
|
465
|
+
Asciidoctor::Extensions.register Sourcerer::SourceSkim::TreeProcessorExtension
|
|
466
|
+
----
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
[[utilities]]
|
|
470
|
+
=== Utilities
|
|
471
|
+
|
|
472
|
+
`Sourcerer::Util` hosts small, dependency-light primitives intended for use by downstream callers and scripts.
|
|
473
|
+
They are not required internally; require the appropriate file explicitly when you need it.
|
|
474
|
+
|
|
475
|
+
Neither utility carries any new runtime dependencies beyond the standard library.
|
|
476
|
+
|
|
477
|
+
[[util-list-amend]]
|
|
478
|
+
==== `Sourcerer::Util::ListAmend`
|
|
479
|
+
|
|
480
|
+
Merges a user-supplied list into a default list using `+`/`-` amendment tokens.
|
|
481
|
+
|
|
482
|
+
.Require
|
|
483
|
+
[source,ruby]
|
|
484
|
+
----
|
|
485
|
+
require 'sourcerer/util/list_amendment'
|
|
486
|
+
----
|
|
487
|
+
|
|
488
|
+
.API
|
|
489
|
+
[source,ruby]
|
|
490
|
+
----
|
|
491
|
+
Sourcerer::Util::ListAmend.apply(default_list, custom_list, normalize: nil) -> Array<String>
|
|
492
|
+
----
|
|
493
|
+
|
|
494
|
+
Behavior::
|
|
495
|
+
`nil` / empty custom:::
|
|
496
|
+
Returns `default_list` (stringified) unchanged.
|
|
497
|
+
Fixed-list mode:::
|
|
498
|
+
If `custom_list` contains *no* tokens starting with `+` or `-`, it fully replaces `default_list`.
|
|
499
|
+
Amendment mode:::
|
|
500
|
+
If `custom_list` contains *any* `+`/`-` token:
|
|
501
|
+
`-slug` removes `slug` from the working set (or no-op if absent). +
|
|
502
|
+
`+slug` adds `slug` if not already present. +
|
|
503
|
+
bare `slug` is treated as `+slug`.
|
|
504
|
+
|
|
505
|
+
`normalize` (optional)::
|
|
506
|
+
A callable used to compare items during deduplication and removal, for example `->(s) { s.downcase }`.
|
|
507
|
+
|
|
508
|
+
.Examples
|
|
509
|
+
[source,ruby]
|
|
510
|
+
----
|
|
511
|
+
defaults = %w[a b c]
|
|
512
|
+
|
|
513
|
+
# nil → unchanged
|
|
514
|
+
Sourcerer::Util::ListAmend.apply(defaults, nil) # => ["a", "b", "c"]
|
|
515
|
+
|
|
516
|
+
# fixed list
|
|
517
|
+
Sourcerer::Util::ListAmend.apply(defaults, "b c") # => ["b", "c"]
|
|
518
|
+
|
|
519
|
+
# amendment: remove b, add d
|
|
520
|
+
Sourcerer::Util::ListAmend.apply(defaults, "-b +d") # => ["a", "c", "d"]
|
|
521
|
+
|
|
522
|
+
# amendment: bare token treated as addition
|
|
523
|
+
Sourcerer::Util::ListAmend.apply(defaults, "-b d") # => ["a", "c", "d"]
|
|
524
|
+
----
|
|
525
|
+
|
|
526
|
+
[[util-pathifier]]
|
|
527
|
+
==== `Sourcerer::Util::Pathifier`
|
|
528
|
+
|
|
529
|
+
Classifies an input string as `:file`, `:dir`, `:glob`, or `:missing` and provides a lazy enumerator of matching paths.
|
|
530
|
+
Directory traversal is enumerator-based to avoid materializing large path arrays.
|
|
531
|
+
|
|
532
|
+
.Require
|
|
533
|
+
[source,ruby]
|
|
534
|
+
----
|
|
535
|
+
require 'sourcerer/util/path_matcher'
|
|
536
|
+
----
|
|
537
|
+
|
|
538
|
+
.API
|
|
539
|
+
[source,ruby]
|
|
540
|
+
----
|
|
541
|
+
result = Sourcerer::Util::Pathifier.match(input, recursive: true, include_dirs: false, follow_symlinks: false)
|
|
542
|
+
# result.type -> :file | :dir | :glob | :missing
|
|
543
|
+
# result.input -> original input string
|
|
544
|
+
# result.enum -> Enumerator<String> of matching paths
|
|
545
|
+
----
|
|
546
|
+
|
|
547
|
+
Classification rules::
|
|
548
|
+
`:file`::: `File.file?(input)` is true.
|
|
549
|
+
`:dir`::: `File.directory?(input)` is true.
|
|
550
|
+
`:glob`::: Input contains glob metacharacters (`* ? [ ] { }`).
|
|
551
|
+
`:missing`::: None of the above.
|
|
552
|
+
|
|
553
|
+
Options::
|
|
554
|
+
`recursive`::: Traverse directories recursively via `Find.find` (default: `true`).
|
|
555
|
+
`include_dirs`::: Also yield directory paths during traversal (default: `false`).
|
|
556
|
+
`follow_symlinks`::: Follow symlink directories during recursion (default: `false`).
|
|
557
|
+
|
|
558
|
+
.Examples
|
|
559
|
+
[source,ruby]
|
|
560
|
+
----
|
|
561
|
+
# File
|
|
562
|
+
r = Sourcerer::Util::Pathifier.match('docs/install.adoc')
|
|
563
|
+
r.type # => :file
|
|
564
|
+
r.enum.to_a # => ["/absolute/path/docs/install.adoc"]
|
|
565
|
+
|
|
566
|
+
# Directory (lazy recursive)
|
|
567
|
+
r = Sourcerer::Util::Pathifier.match('docs/')
|
|
568
|
+
r.type # => :dir
|
|
569
|
+
r.enum.select { |p| p.end_with?('.adoc') } # lazy filter
|
|
570
|
+
|
|
571
|
+
# Glob
|
|
572
|
+
r = Sourcerer::Util::Pathifier.match('docs/**/*.adoc')
|
|
573
|
+
r.type # => :glob
|
|
574
|
+
r.enum.to_a # => all matching files
|
|
575
|
+
|
|
576
|
+
# Missing
|
|
577
|
+
r = Sourcerer::Util::Pathifier.match('no/such/path')
|
|
578
|
+
r.type # => :missing
|
|
579
|
+
r.enum.to_a # => []
|
|
580
|
+
----
|
|
581
|
+
|
|
287
582
|
|
|
288
583
|
[[integrations]]
|
|
289
584
|
== Integrations (Implemented and Planned)
|
|
@@ -291,6 +586,9 @@ Schema-aware filters (including SGYML-specific classification filters) should be
|
|
|
291
586
|
These notes describe how AsciiSourcerer relates to existing and future downstream tools.
|
|
292
587
|
For most users, these tools are the recommended way to access AsciiSourcerer’s capabilities, since they provide a richer context for configuration, input/output management, and workflow orchestration.
|
|
293
588
|
|
|
589
|
+
https://github.com/DocOps/lab/tree/main/gems/docopslab-dev[docopslab-dev]::
|
|
590
|
+
A harness for DocOps Lab developer tasks and operations.
|
|
591
|
+
|
|
294
592
|
SchemaGraphy::
|
|
295
593
|
SchemaGraphy's API is the schema-aware layer in the DocOps Lab ecosystem.
|
|
296
594
|
Sourcerer provides it with primitives such as YAML loading, templating, and Liquid runtime setup, while SchemaGraphy handles schema validation and templated-field interpretation.
|
|
@@ -306,6 +604,28 @@ Jekyll Extensions::
|
|
|
306
604
|
DocOps Labs maintains plugins, themes, and even a utility for generating technical documentation with the Jekyll static-site generator.
|
|
307
605
|
All the benefits of extended YAML ingest and Liquid processing are available via these extensions, along with and usually through SchemaGraphy.
|
|
308
606
|
|
|
607
|
+
[[alpha-scripts]]
|
|
608
|
+
=== Alpha Scripts/CLIs
|
|
609
|
+
|
|
610
|
+
The AsciiSourcerer repo does host some CLI utilities and scripts that make direct usage of APIs hosted in the `asciisourcerer` gem.
|
|
611
|
+
These are largely prototype utilities that will eventually make it into official DocOps Lab applications with proper I/O surfaces.
|
|
612
|
+
|
|
613
|
+
[WARNING]
|
|
614
|
+
These scripts are *neither* rigorously tested *nor* officially supported.
|
|
615
|
+
They may be altered, deprecated, or dropped in backward-incompatible ways.
|
|
616
|
+
Use them as examples but do not rely on them in production.
|
|
617
|
+
|
|
618
|
+
To use such a script, copy it from the repo's `scripts/` directory into your project, then run it with `ruby` or `bundle exec ruby` as appropriate.
|
|
619
|
+
|
|
620
|
+
Current scripts include::
|
|
621
|
+
`skim_asciidoc.rb`:::
|
|
622
|
+
For AsciiDoc source inspection.
|
|
623
|
+
Generates YAML or JSON versions of `Sourcerer::SourceSkim` output for a given AsciiDoc document or collection of documents.
|
|
624
|
+
|
|
625
|
+
`mark_down_grade.rb`:::
|
|
626
|
+
For AsciiDoc-to-Markdown conversion.
|
|
627
|
+
This script orchestrates `Sourcerer::AsciiDoc.mark_down_grade` and is a recommended starting point for users needing this functionality without building their own Ruby integration.
|
|
628
|
+
|
|
309
629
|
|
|
310
630
|
[[development]]
|
|
311
631
|
== Development
|
|
@@ -343,13 +663,13 @@ Special developer Rake tasks and libraries are available via the `docopslab-dev`
|
|
|
343
663
|
[.prompt]
|
|
344
664
|
bundle exec rake --tasks | grep labdev:
|
|
345
665
|
|
|
346
|
-
The link:{
|
|
666
|
+
The link:{docopslab_src_www_url}/lab/tree/main/gems/docopslab-dev/README.adoc[DocOps Lab Devtool] or see `.agent/docs/topics/docpslab-devtool.md`.
|
|
347
667
|
|
|
348
668
|
[[api]]
|
|
349
669
|
=== API Design
|
|
350
670
|
|
|
351
671
|
The API is designed to be stable and backward-compatible, with a clear deprecation path for any breaking changes.
|
|
352
|
-
The top-level `Sourcerer.*` methods are deprecated in favor of direct namespace usage (`Sourcerer::Yaml`, `Sourcerer::AsciiDoc`, `Sourcerer::Rendering`), which will be removed in version 1.0.
|
|
672
|
+
The top-level `Sourcerer.*` methods are deprecated in favor of direct namespace usage (`Sourcerer::Yaml`, `Sourcerer::AsciiDoc`, `Sourcerer::Rendering`, `Sourcerer::Sync`), which will be removed in version 1.0.
|
|
353
673
|
|
|
354
674
|
Do not add new public methods directly to the `Sourcerer` namespace;
|
|
355
675
|
instead, add them to the appropriate submodule.
|
|
@@ -368,7 +688,7 @@ Avoid exporting helper methods as accidental public API.
|
|
|
368
688
|
[[tests]]
|
|
369
689
|
=== Tests
|
|
370
690
|
|
|
371
|
-
See the full testing documentation at link:{
|
|
691
|
+
See the full testing documentation at link:{this_prod_repo_files_url}/specs/tests/README.adoc[`specs/tests/README.adoc`]
|
|
372
692
|
|
|
373
693
|
Run the RSpec suite:
|
|
374
694
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'asciidoctor/extensions'
|
|
4
|
+
require_relative '../../../sourcerer/source_skim'
|
|
5
|
+
|
|
6
|
+
module Sourcerer
|
|
7
|
+
module SourceSkim
|
|
8
|
+
# Asciidoctor TreeProcessor extension that runs a SourceSkim pass on the
|
|
9
|
+
# document immediately after parsing and stores the result as the document
|
|
10
|
+
# attribute +source-skim-result+.
|
|
11
|
+
#
|
|
12
|
+
# The skim is keyed by symbol (+:title+, +:sections_tree+, etc.) so it is
|
|
13
|
+
# ready for direct use in Ruby without a JSON round-trip.
|
|
14
|
+
#
|
|
15
|
+
# == Configuration via document attributes
|
|
16
|
+
#
|
|
17
|
+
# +source-skim-forms+:: Comma-separated list of section shapes to emit.
|
|
18
|
+
# Recognized values: +tree+, +flat+. Default: +tree+.
|
|
19
|
+
# +source-skim-categories+:: Comma-separated list of element categories to
|
|
20
|
+
# include. Omit to use the default set (everything except
|
|
21
|
+
# +attributes_builtin+).
|
|
22
|
+
#
|
|
23
|
+
# == Usage
|
|
24
|
+
#
|
|
25
|
+
# === API
|
|
26
|
+
#
|
|
27
|
+
# require 'asciidoctor/extensions/source-skim-tree-processor/extension'
|
|
28
|
+
#
|
|
29
|
+
# Asciidoctor::Extensions.register Sourcerer::SourceSkim::TreeProcessorExtension
|
|
30
|
+
#
|
|
31
|
+
# doc = Asciidoctor.load_file('my.adoc', safe: :safe, sourcemap: true)
|
|
32
|
+
# skim = doc.attr('source-skim-result')
|
|
33
|
+
#
|
|
34
|
+
# === With asciidoctor CLI
|
|
35
|
+
#
|
|
36
|
+
# asciidoctor -r ./lib/asciidoctor/extensions/source-skim-tree-processor/extension.rb \
|
|
37
|
+
# -a source-skim-forms=tree,flat \
|
|
38
|
+
# -a source-skim-categories=sections,code_blocks,admonitions \
|
|
39
|
+
# my.adoc
|
|
40
|
+
class TreeProcessorExtension < Asciidoctor::Extensions::TreeProcessor
|
|
41
|
+
def process document
|
|
42
|
+
raw_forms = document.attr('source-skim-forms', 'tree')
|
|
43
|
+
forms = raw_forms.split(',').map { |f| f.strip.to_sym }
|
|
44
|
+
|
|
45
|
+
raw_cats = document.attr('source-skim-categories')
|
|
46
|
+
categories = raw_cats&.split(',')&.map { |c| c.strip.to_sym }
|
|
47
|
+
|
|
48
|
+
config = Config.new(forms: forms, categories: categories)
|
|
49
|
+
skim = Skimmer.new.process(document, config: config)
|
|
50
|
+
document.set_attr('source-skim-result', skim)
|
|
51
|
+
nil
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
data/lib/asciisourcerer.rb
CHANGED
data/lib/sourcerer/asciidoc.rb
CHANGED
|
@@ -208,7 +208,8 @@ module Sourcerer
|
|
|
208
208
|
source_path,
|
|
209
209
|
conversion_source_text,
|
|
210
210
|
backend: selected_backend,
|
|
211
|
-
header_footer: options[:header_footer]
|
|
211
|
+
header_footer: options[:header_footer],
|
|
212
|
+
attributes: options[:attributes])
|
|
212
213
|
|
|
213
214
|
frontmatter = options[:include_frontmatter] ? extract_frontmatter(source_text, document.attributes) : {}
|
|
214
215
|
html_body = document.convert
|
|
@@ -239,7 +240,7 @@ module Sourcerer
|
|
|
239
240
|
|
|
240
241
|
# @api private
|
|
241
242
|
def self.normalize_mark_down_grade_options options
|
|
242
|
-
supported_option_keys = %i[html_output_path backend header_footer include_frontmatter markdown_options]
|
|
243
|
+
supported_option_keys = %i[html_output_path backend header_footer include_frontmatter markdown_options attributes]
|
|
243
244
|
unknown_option_keys = options.keys - supported_option_keys
|
|
244
245
|
raise ArgumentError, "unknown option(s): #{unknown_option_keys.join(', ')}" unless unknown_option_keys.empty?
|
|
245
246
|
|
|
@@ -248,7 +249,8 @@ module Sourcerer
|
|
|
248
249
|
backend: options.fetch(:backend, 'asciidoctor-html5s'),
|
|
249
250
|
header_footer: options.fetch(:header_footer, false),
|
|
250
251
|
include_frontmatter: options.fetch(:include_frontmatter, true),
|
|
251
|
-
markdown_options: options.fetch(:markdown_options, { github_flavored: true })
|
|
252
|
+
markdown_options: options.fetch(:markdown_options, { github_flavored: true }),
|
|
253
|
+
attributes: options.fetch(:attributes, {})
|
|
252
254
|
}
|
|
253
255
|
end
|
|
254
256
|
|
|
@@ -375,8 +377,9 @@ module Sourcerer
|
|
|
375
377
|
# @param source_text [String]
|
|
376
378
|
# @param backend [String]
|
|
377
379
|
# @param header_footer [Boolean]
|
|
380
|
+
# @param attributes [Hash]
|
|
378
381
|
# @return [Asciidoctor::Document]
|
|
379
|
-
def self.load_document_for_markdown_grade source_path, source_text, backend:, header_footer:
|
|
382
|
+
def self.load_document_for_markdown_grade source_path, source_text, backend:, header_footer:, attributes: {}
|
|
380
383
|
expanded_source_path = File.expand_path(source_path)
|
|
381
384
|
Asciidoctor.load(
|
|
382
385
|
source_text,
|
|
@@ -385,11 +388,12 @@ module Sourcerer
|
|
|
385
388
|
backend: backend,
|
|
386
389
|
header_footer: header_footer,
|
|
387
390
|
base_dir: File.dirname(source_path),
|
|
388
|
-
attributes:
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
391
|
+
attributes: attributes.merge(
|
|
392
|
+
{
|
|
393
|
+
'docfile' => expanded_source_path,
|
|
394
|
+
'docdir' => File.dirname(expanded_source_path),
|
|
395
|
+
'docname' => File.basename(source_path, File.extname(source_path))
|
|
396
|
+
}))
|
|
393
397
|
end
|
|
394
398
|
|
|
395
399
|
# Extracts commands from listing and literal blocks with a specific role.
|