metanorma-core 0.2.2 → 0.2.3
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 41c7086b0f760b06a87c99ce115f66d31c1a8e30a6f43a182e1ed81a076b0ee6
|
|
4
|
+
data.tar.gz: a55d956d5122b77c0078b9d48adb4c4c3b6c97b1c7638498a8a9d31d342b799b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c37685805cfcff21fe4bb18e2a17661242c36a7605aa257736875c5735870e875fcfeb399f3769c25cd8ec4515a68561f8bcc8a503b970c805fe04251e2c2f6f
|
|
7
|
+
data.tar.gz: 4ce50e2bba70f304654640489d89a8d3e9fe45b2e42c3b34f634985b8d79db23bdb5f9e2f2da15bda5fdd6da9b0089b344657e9cbc131ce26d80a0011662ac82
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
= Implementing STS output for a Metanorma flavour
|
|
2
|
+
:toc: macro
|
|
3
|
+
:toclevels: 3
|
|
4
|
+
|
|
5
|
+
toc::[]
|
|
6
|
+
|
|
7
|
+
== Purpose and audience
|
|
8
|
+
|
|
9
|
+
This is a developer guide for implementing https://www.niso.org/standards-committees/sts[NISO STS] /
|
|
10
|
+
ISO STS output for a Metanorma flavour *from scratch*, using the metanorma-core
|
|
11
|
+
_document-model output leg_.
|
|
12
|
+
|
|
13
|
+
It is written for metanorma-core maintainers and flavour/taste contributors — the
|
|
14
|
+
people who add a new semantic-XML-to-STS output format to a flavour. It is not an
|
|
15
|
+
author guide: authors selecting STS output for an existing flavour need only the
|
|
16
|
+
document attribute (e.g. `:output-extensions:`) documented on metanorma.org.
|
|
17
|
+
|
|
18
|
+
The mechanism described here is the *Feature B* document-model convergence
|
|
19
|
+
(metanorma-core#12): a flavour or taste declares two classes — a *reader* and a
|
|
20
|
+
*transformer* — and metanorma-core drives the read/transform/serialise chain. No
|
|
21
|
+
flavour re-implements the output plumbing, and metanorma-core never depends on the
|
|
22
|
+
STS artefact gem.
|
|
23
|
+
|
|
24
|
+
The worked examples are the two production adoptions:
|
|
25
|
+
|
|
26
|
+
* *OIML* — STS contributed by the OIML *taste* over the ISO base flavour
|
|
27
|
+
(metanorma-oiml + metanorma-taste).
|
|
28
|
+
* *ISO* — STS native to the *flavour* (metanorma-iso).
|
|
29
|
+
|
|
30
|
+
== The big picture
|
|
31
|
+
|
|
32
|
+
Metanorma builds a document in stages:
|
|
33
|
+
|
|
34
|
+
[source]
|
|
35
|
+
----
|
|
36
|
+
input.adoc --> semantic XML --> (presentation XML) --> output (HTML/PDF/DOCX/STS/...)
|
|
37
|
+
----
|
|
38
|
+
|
|
39
|
+
Most rendered outputs (HTML, PDF, DOCX) are generated from *presentation XML* — the
|
|
40
|
+
semantic XML enriched with rendering metadata. STS can be generated from *either*
|
|
41
|
+
leg, depending on what your STS transformer consumes. metanorma-core's default treats
|
|
42
|
+
STS as a *semantic*-leg format, and ISO's native `isosts` does exactly that; but a
|
|
43
|
+
flavour or taste whose STS transformer needs the rendered presentation XML can opt
|
|
44
|
+
into the *presentation* leg, as the OIML taste's `oimlsts` does. You declare the leg
|
|
45
|
+
(see <<step-3-make-the-format-selectable>>).
|
|
46
|
+
|
|
47
|
+
The document-model output leg turns that "semantic XML -> STS XML" step into a
|
|
48
|
+
declarative contract. A flavour declares, per output format:
|
|
49
|
+
|
|
50
|
+
* a *reader* that parses the input XML string into a document model, and
|
|
51
|
+
* a *transformer* that maps that model to the STS model and serialises it.
|
|
52
|
+
|
|
53
|
+
metanorma-core's `Processor#output` recognises the format and runs the chain
|
|
54
|
+
(`Processor#render_via_document_model`), so the flavour ships two classes instead of
|
|
55
|
+
bespoke output code.
|
|
56
|
+
|
|
57
|
+
== The contract
|
|
58
|
+
|
|
59
|
+
The contract is `Metanorma::Processor#document_transformers`
|
|
60
|
+
(`metanorma-core/lib/metanorma/processor/processor.rb`). It returns a hash mapping an
|
|
61
|
+
output-format symbol to a spec:
|
|
62
|
+
|
|
63
|
+
[source,ruby]
|
|
64
|
+
----
|
|
65
|
+
def document_transformers
|
|
66
|
+
{
|
|
67
|
+
myflavoursts: {
|
|
68
|
+
reader: MyFlavour::Sts::SourceDocument, # required
|
|
69
|
+
transformer: MyFlavour::Sts::Standard, # required
|
|
70
|
+
to_xml_options: {}, # default {}
|
|
71
|
+
strip_default_namespace: false, # default false
|
|
72
|
+
post_process: nil, # default identity
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
----
|
|
77
|
+
|
|
78
|
+
Spec keys (metanorma-core contract):
|
|
79
|
+
|
|
80
|
+
`:reader`:: (required) responds to `.from_xml(String) -> model`. Parses the input
|
|
81
|
+
XML into a document model.
|
|
82
|
+
|
|
83
|
+
`:transformer`:: (required) responds to `.new(model, options)`; the instance responds
|
|
84
|
+
to `#transform -> target`, and the target responds to `#to_xml`. See
|
|
85
|
+
<<the-adapter-pattern>>.
|
|
86
|
+
|
|
87
|
+
`:to_xml_options`:: hash splatted into `target.to_xml(**opts)` (default `{}`).
|
|
88
|
+
|
|
89
|
+
`:strip_default_namespace`:: strip `xmlns="..."` from the input XML before
|
|
90
|
+
`from_xml` (default `false`). Set `true` when your reader's model does not expect the
|
|
91
|
+
Metanorma default namespace on the root.
|
|
92
|
+
|
|
93
|
+
`:post_process`:: a callable `(xml, transformer, options) -> xml` run on the
|
|
94
|
+
serialised string (default identity). Use it for namespace / processing-metadata /
|
|
95
|
+
language fix-ups that must happen on the serialised output.
|
|
96
|
+
|
|
97
|
+
Two further keys are read by the *metanorma compile driver* (not by metanorma-core)
|
|
98
|
+
to make the format selectable; see <<step-3-make-the-format-selectable>>:
|
|
99
|
+
|
|
100
|
+
`:suffix`:: the output filename suffix, e.g. `"oiml.sts.xml"`.
|
|
101
|
+
|
|
102
|
+
`:presentation`:: `true` if the format is generated from *presentation* XML;
|
|
103
|
+
omit/`false` for the *semantic* leg. Per-transformer choice: OIML's `oimlsts` sets
|
|
104
|
+
`true`, ISO's native `isosts` uses the semantic leg.
|
|
105
|
+
|
|
106
|
+
=== How metanorma-core drives it
|
|
107
|
+
|
|
108
|
+
`Processor#output` routes any registered format through the document-model leg:
|
|
109
|
+
|
|
110
|
+
[source,ruby]
|
|
111
|
+
----
|
|
112
|
+
def output(isodoc_node, inname, outname, format, options = {})
|
|
113
|
+
options_preprocess(options)
|
|
114
|
+
transformers = effective_document_transformers(options)
|
|
115
|
+
if transformers.key?(format)
|
|
116
|
+
render_via_document_model(isodoc_node, inname, outname, format,
|
|
117
|
+
options, transformers.fetch(format))
|
|
118
|
+
else
|
|
119
|
+
File.open(outname, "w:UTF-8") { |f| f.write(isodoc_node) }
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
----
|
|
123
|
+
|
|
124
|
+
`render_via_document_model` is the whole chain, duck-typed — it never names a
|
|
125
|
+
concrete reader/transformer/model gem, so those stay out of metanorma-core's
|
|
126
|
+
dependencies:
|
|
127
|
+
|
|
128
|
+
[source,ruby]
|
|
129
|
+
----
|
|
130
|
+
xml = document_model_input_xml(isodoc_node, inname) # semantic or presentation leg
|
|
131
|
+
xml = xml.gsub(/\sxmlns="[^"]*"/, "") if spec[:strip_default_namespace]
|
|
132
|
+
transformer = spec.fetch(:transformer)
|
|
133
|
+
.new(spec.fetch(:reader).from_xml(xml), options)
|
|
134
|
+
out = transformer.transform.to_xml(**(spec[:to_xml_options] || {}))
|
|
135
|
+
out = spec[:post_process].call(out, transformer, options) if spec[:post_process]
|
|
136
|
+
----
|
|
137
|
+
|
|
138
|
+
The input XML comes from `isodoc_node` (the semantic leg) or, when that is nil, from
|
|
139
|
+
reading `inname` (the presentation leg). Which leg fires is governed by
|
|
140
|
+
`use_presentation_xml`. The metanorma-core default treats STS and RFC as semantic-leg
|
|
141
|
+
formats:
|
|
142
|
+
|
|
143
|
+
[source,ruby]
|
|
144
|
+
----
|
|
145
|
+
def use_presentation_xml(ext) # metanorma-core default
|
|
146
|
+
case ext
|
|
147
|
+
when :html, :doc, :pdf then true
|
|
148
|
+
else false # STS, RFC, ... default to the semantic leg
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
----
|
|
152
|
+
|
|
153
|
+
A flavour overrides this per format. ISO keeps `isosts` on the semantic leg when its
|
|
154
|
+
native STS is enabled (and falls back to the presentation leg for the legacy path):
|
|
155
|
+
|
|
156
|
+
[source,ruby]
|
|
157
|
+
----
|
|
158
|
+
def use_presentation_xml(ext) # metanorma-iso
|
|
159
|
+
return false if ext == :isosts && Metanorma::Iso::Sts.enabled? # native STS: semantic
|
|
160
|
+
return true if %i[html_alt sts isosts].include?(ext) # legacy path: presentation
|
|
161
|
+
super
|
|
162
|
+
end
|
|
163
|
+
----
|
|
164
|
+
|
|
165
|
+
A *taste* declares the leg instead through the `:presentation` key of its spec (Route
|
|
166
|
+
B); OIML sets `presentation: true`, putting `oimlsts` on the presentation leg. Pick
|
|
167
|
+
the leg your transformer actually consumes.
|
|
168
|
+
|
|
169
|
+
[#the-adapter-pattern]
|
|
170
|
+
== Step 1 — Build the STS transformer (in the artefact gem)
|
|
171
|
+
|
|
172
|
+
The reader and transformer live in the flavour's *artefact gem* (e.g.
|
|
173
|
+
metanorma-oiml), never in metanorma-core.
|
|
174
|
+
|
|
175
|
+
=== The reader
|
|
176
|
+
|
|
177
|
+
The reader responds to `.from_xml(String) -> model`. In practice this is a thin
|
|
178
|
+
entry point on your source-document model:
|
|
179
|
+
|
|
180
|
+
[source,ruby]
|
|
181
|
+
----
|
|
182
|
+
module Metanorma::Oiml::Sts::Transformer
|
|
183
|
+
class SourceDocument
|
|
184
|
+
def self.from_xml(input)
|
|
185
|
+
parse(input) # -> a SourceDocument model instance
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
----
|
|
190
|
+
|
|
191
|
+
=== The transformer (adapter)
|
|
192
|
+
|
|
193
|
+
The transformer must satisfy: `.new(model, options)`, `#transform -> target`, and
|
|
194
|
+
`target#to_xml`. The cleanest way to meet this while reusing an existing conversion
|
|
195
|
+
pipeline is the *adapter-is-its-own-target* pattern from metanorma-oiml
|
|
196
|
+
(`lib/metanorma/oiml/sts/transformer/standard.rb`):
|
|
197
|
+
|
|
198
|
+
[source,ruby]
|
|
199
|
+
----
|
|
200
|
+
class Standard
|
|
201
|
+
def initialize(model, options = {})
|
|
202
|
+
@model = model
|
|
203
|
+
@options = options
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def transform
|
|
207
|
+
@document_transformer = DocumentTransformer.new(Context.new(@model))
|
|
208
|
+
self # the adapter is its own #to_xml target
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def to_xml(**_options)
|
|
212
|
+
@document_transformer.transform_to_xml(@model) # full existing pipeline
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
----
|
|
216
|
+
|
|
217
|
+
`#to_xml` runs the *full* existing conversion pipeline (model build plus the
|
|
218
|
+
namespace / processing-metadata / language post-processing on the serialised
|
|
219
|
+
string), so the driven output is byte-identical to the gem's standalone converter
|
|
220
|
+
(`Metanorma::Oiml::Sts::Transformer.convert`). Returning the raw `#transform` model
|
|
221
|
+
instead would drop that post-processing — a common trap.
|
|
222
|
+
|
|
223
|
+
TIP: If your gem already has a standalone `convert` (or an `oiml-sts`-style CLI),
|
|
224
|
+
make the adapter's output byte-equal to it and add a byte-equivalence test. That is
|
|
225
|
+
your safety net that the unified path did not change behaviour.
|
|
226
|
+
|
|
227
|
+
== Step 2 — Register the format
|
|
228
|
+
|
|
229
|
+
There are two registration routes. Choose by *what owns the flavour*.
|
|
230
|
+
|
|
231
|
+
=== Route A — flavour-native (the flavour has its own Processor)
|
|
232
|
+
|
|
233
|
+
If STS belongs to the flavour itself (ISO), override `document_transformers` on the
|
|
234
|
+
flavour's `Metanorma::Processor` subclass:
|
|
235
|
+
|
|
236
|
+
[source,ruby]
|
|
237
|
+
----
|
|
238
|
+
module Metanorma::Iso
|
|
239
|
+
class Processor < Metanorma::Processor
|
|
240
|
+
def document_transformers
|
|
241
|
+
{
|
|
242
|
+
isosts: {
|
|
243
|
+
reader: Metanorma::Iso::Sts::SourceDocument,
|
|
244
|
+
transformer: Metanorma::Iso::Sts::Standard,
|
|
245
|
+
},
|
|
246
|
+
}
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
----
|
|
251
|
+
|
|
252
|
+
This is zero-arg and static: the flavour always offers the format.
|
|
253
|
+
|
|
254
|
+
=== Route B — taste-contributed (a taste over a base flavour)
|
|
255
|
+
|
|
256
|
+
If STS belongs to a *taste* over a base flavour (OIML is a taste over ISO), the taste
|
|
257
|
+
contributes the spec through the per-taste hook in metanorma-taste, *without*
|
|
258
|
+
metanorma-taste depending on the artefact gem.
|
|
259
|
+
|
|
260
|
+
Declare a `data/<taste>/transformers.rb` shim in the taste gem
|
|
261
|
+
(metanorma-taste/data/oiml/transformers.rb):
|
|
262
|
+
|
|
263
|
+
[source,ruby]
|
|
264
|
+
----
|
|
265
|
+
Metanorma::TasteRegister.register_document_transformers(:oiml) do
|
|
266
|
+
require "metanorma/oiml/sts" # loaded lazily — only for OIML builds
|
|
267
|
+
|
|
268
|
+
{
|
|
269
|
+
oimlsts: {
|
|
270
|
+
reader: Metanorma::Oiml::Sts::Transformer::SourceDocument,
|
|
271
|
+
transformer: Metanorma::Oiml::Sts::Transformer::Standard,
|
|
272
|
+
strip_default_namespace: false,
|
|
273
|
+
to_xml_options: {},
|
|
274
|
+
suffix: "oiml.sts.xml", # compile-driver keys (Step 3)
|
|
275
|
+
presentation: true,
|
|
276
|
+
},
|
|
277
|
+
}
|
|
278
|
+
end
|
|
279
|
+
----
|
|
280
|
+
|
|
281
|
+
How the hook works (`metanorma-taste/lib/metanorma/taste_register.rb`):
|
|
282
|
+
|
|
283
|
+
* `register_document_transformers(taste, &block)` stores the block, keyed by taste.
|
|
284
|
+
* `document_transformers_for(taste)` is memoised: on first use it requires the taste's
|
|
285
|
+
`data/<taste>/transformers.rb` shim (`load_transformer_hook`), then calls the block.
|
|
286
|
+
* Because the `require "metanorma/oiml/sts"` sits *inside* the block, the artefact gem
|
|
287
|
+
loads only for builds that use the taste. metanorma-taste keeps no hard dependency
|
|
288
|
+
on it. If the shim declares transformers but the artefact gem is not in the bundle,
|
|
289
|
+
the hook raises `UnknownTasteError` telling the user to add it.
|
|
290
|
+
|
|
291
|
+
The taste-aware `Processor#effective_document_transformers` then merges the taste's
|
|
292
|
+
specs onto the flavour's `document_transformers`, keyed by `options[:supplied_type]`
|
|
293
|
+
(the active taste). Base flavours and tastes without the hook are unaffected:
|
|
294
|
+
|
|
295
|
+
[source,ruby]
|
|
296
|
+
----
|
|
297
|
+
def effective_document_transformers(options = {})
|
|
298
|
+
base = document_transformers
|
|
299
|
+
taste = options[:supplied_type]
|
|
300
|
+
unless taste && defined?(Metanorma::TasteRegister) &&
|
|
301
|
+
Metanorma::TasteRegister.respond_to?(:document_transformers_for)
|
|
302
|
+
return base
|
|
303
|
+
end
|
|
304
|
+
base.merge(Metanorma::TasteRegister.document_transformers_for(taste) || {})
|
|
305
|
+
end
|
|
306
|
+
----
|
|
307
|
+
|
|
308
|
+
NOTE: `supplied_type` is the seam that carries taste identity to the shared, stateless
|
|
309
|
+
processor. No per-build state is kept on the processor instance.
|
|
310
|
+
|
|
311
|
+
[#step-3-make-the-format-selectable]
|
|
312
|
+
== Step 3 — Make the format selectable in the compile driver
|
|
313
|
+
|
|
314
|
+
For a user to request the format (e.g. `:output-extensions: oimlsts`), the metanorma
|
|
315
|
+
compile driver must know its suffix and which leg it uses. This is threaded via
|
|
316
|
+
`supplied_type` (`metanorma/lib/metanorma/compile/compile_options.rb`):
|
|
317
|
+
|
|
318
|
+
* `supplied_type` originates from `options[:type]` and is copied into the isodoc
|
|
319
|
+
options (`copy_isodoc_options_attrs`: `ret[:supplied_type] = options[:supplied_type]`),
|
|
320
|
+
so the taste-aware processor sees it.
|
|
321
|
+
* `effective_output_formats` merges the processor's `output_formats` with the
|
|
322
|
+
`:suffix` of each taste-contributed format, so the format passes extension
|
|
323
|
+
validation and gets an output filename:
|
|
324
|
+
+
|
|
325
|
+
[source,ruby]
|
|
326
|
+
----
|
|
327
|
+
def effective_output_formats(options)
|
|
328
|
+
@processor.output_formats.merge(
|
|
329
|
+
taste_transformers(options).transform_values { |s| s[:suffix] }.compact,
|
|
330
|
+
)
|
|
331
|
+
end
|
|
332
|
+
----
|
|
333
|
+
* `uses_presentation_xml?` honours both the processor's answer and the taste spec's
|
|
334
|
+
`:presentation` flag:
|
|
335
|
+
+
|
|
336
|
+
[source,ruby]
|
|
337
|
+
----
|
|
338
|
+
def uses_presentation_xml?(ext, options)
|
|
339
|
+
@processor.use_presentation_xml(ext) ||
|
|
340
|
+
(taste_transformers(options)[ext] || {})[:presentation] == true
|
|
341
|
+
end
|
|
342
|
+
----
|
|
343
|
+
|
|
344
|
+
For a *flavour-native* format (Route A), the compile driver reads the same keys off
|
|
345
|
+
the flavour's own `document_transformers`; set `:suffix` there too if the format is
|
|
346
|
+
user-selectable, and override `use_presentation_xml` to pick the leg (ISO's `isosts`
|
|
347
|
+
returns `false` for the semantic leg).
|
|
348
|
+
|
|
349
|
+
== Step 4 — Deprecate the standalone converter (optional)
|
|
350
|
+
|
|
351
|
+
If the artefact gem had a standalone STS converter or CLI (e.g. `oiml-sts convert`),
|
|
352
|
+
deprecate it in favour of the unified path once the driver is in place. Keep the code
|
|
353
|
+
(the adapter delegates to it) but emit a deprecation notice from the old CLI entry
|
|
354
|
+
points, and document the metanorma-driven path as canonical. metanorma-oiml#24 is the
|
|
355
|
+
reference.
|
|
356
|
+
|
|
357
|
+
== Conforming to the official STS specifications
|
|
358
|
+
|
|
359
|
+
The transformer must emit *conformant* STS. Source the normative models from:
|
|
360
|
+
|
|
361
|
+
* *NISO STS* — ANSI/NISO Z39.102, the NISO Standards Tag Suite.
|
|
362
|
+
* *ISO STS* — the ISO profile/extension of NISO STS.
|
|
363
|
+
|
|
364
|
+
Model the transformer's output against these tag sets (element/attribute names,
|
|
365
|
+
allowed content models, metadata blocks). Validate generated output against the STS
|
|
366
|
+
DTD/schema as part of your test suite; do not rely on visual inspection of the PDF/
|
|
367
|
+
HTML, which can look correct while the STS XML is non-conformant.
|
|
368
|
+
|
|
369
|
+
== Testing (smoke tests)
|
|
370
|
+
|
|
371
|
+
At minimum:
|
|
372
|
+
|
|
373
|
+
. *Build test* — compile a small document requesting the new format and assert the
|
|
374
|
+
output file is produced with the expected suffix and a well-formed STS root.
|
|
375
|
+
. *Byte-equivalence test* — assert the driven output equals the standalone converter's
|
|
376
|
+
output (guards the adapter, per <<the-adapter-pattern>>).
|
|
377
|
+
. *Registration test* — for a taste, assert `document_transformers_for(:yourtaste)`
|
|
378
|
+
returns the spec and that `effective_document_transformers` merges it under
|
|
379
|
+
`supplied_type`.
|
|
380
|
+
. *Schema validation* — validate the generated STS against the NISO/ISO STS schema.
|
|
381
|
+
|
|
382
|
+
The OIML and ISO STS specs in metanorma-oiml / metanorma-iso are the templates.
|
|
383
|
+
|
|
384
|
+
== Checklist
|
|
385
|
+
|
|
386
|
+
[cols="1,3"]
|
|
387
|
+
|===
|
|
388
|
+
| Artefact gem | `reader` (`.from_xml`) + `transformer` (`Standard` adapter, byte-equal to standalone `convert`)
|
|
389
|
+
| Registration | Route A: override `document_transformers` on the flavour Processor. Route B: `data/<taste>/transformers.rb` shim with a lazy `require`
|
|
390
|
+
| Selectable | `:suffix` (+ `:presentation` only if presentation-leg) so the compile driver exposes it
|
|
391
|
+
| Leg | Declare it per what your transformer consumes: semantic (`use_presentation_xml` `false`, e.g. ISO `isosts`) or presentation (`presentation: true`, e.g. OIML `oimlsts`)
|
|
392
|
+
| Deprecate | old standalone converter/CLI emits a deprecation notice
|
|
393
|
+
| Conformance | output validated against NISO/ISO STS schema
|
|
394
|
+
| Tests | build + byte-equivalence + registration + schema
|
|
395
|
+
|===
|
|
396
|
+
|
|
397
|
+
== Reference
|
|
398
|
+
|
|
399
|
+
* metanorma-core#12 — Feature B document-model convergence (design: Decision + Alignment)
|
|
400
|
+
* metanorma-core#13 — taste-aware `Processor#effective_document_transformers`
|
|
401
|
+
* metanorma/metanorma#589 — compile-driver output selection (`supplied_type`, `effective_output_formats`, `uses_presentation_xml?`)
|
|
402
|
+
* metanorma/metanorma-iso#1610 — mature STS-ISO transformer adoption (flavour-native, Route A)
|
|
403
|
+
* metanorma/metanorma-oiml#24 — STS core-driver adapter + `oiml-sts` CLI deprecation (Route B artefact)
|
|
404
|
+
* metanorma/metanorma-taste#188 — per-taste hook + OIML `:oimlsts` registration
|
|
405
|
+
* NISO STS (ANSI/NISO Z39.102) and ISO STS official specifications
|
|
@@ -70,6 +70,29 @@ module Metanorma
|
|
|
70
70
|
{}
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
+
# The flavor's own {#document_transformers}, merged with the document-model
|
|
74
|
+
# specs contributed by the active taste (+options[:supplied_type]+). Those
|
|
75
|
+
# specs come from +Metanorma::TasteRegister+ when it supports the per-taste
|
|
76
|
+
# hook; base flavors (no taste), and installed tastes without the hook, are
|
|
77
|
+
# unaffected -- the base map is returned unchanged. {#document_transformers}
|
|
78
|
+
# stays zero-arg (flavors override it) and the taste specs are merged on
|
|
79
|
+
# top. No per-build state is kept on the shared processor instance: the
|
|
80
|
+
# taste identity rides entirely on +options[:supplied_type]+.
|
|
81
|
+
#
|
|
82
|
+
# @param options [Hash] processor options; reads +:supplied_type+.
|
|
83
|
+
# @return [Hash{Symbol => Hash}] merged format symbol -> spec.
|
|
84
|
+
def effective_document_transformers(options = {})
|
|
85
|
+
base = document_transformers
|
|
86
|
+
taste = options[:supplied_type]
|
|
87
|
+
unless taste && defined?(Metanorma::TasteRegister) &&
|
|
88
|
+
Metanorma::TasteRegister.respond_to?(:document_transformers_for)
|
|
89
|
+
return base
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
contributed = Metanorma::TasteRegister.document_transformers_for(taste)
|
|
93
|
+
base.merge(contributed || {})
|
|
94
|
+
end
|
|
95
|
+
|
|
73
96
|
# Convert an input file to Metanorma semantic XML by routing it
|
|
74
97
|
# through the {Metanorma::Input::Asciidoc} processor with this
|
|
75
98
|
# processor's Asciidoctor backend. Override for non-Asciidoc
|
|
@@ -131,9 +154,10 @@ module Metanorma
|
|
|
131
154
|
# string (document-model leg).
|
|
132
155
|
def output(isodoc_node, inname, outname, format, options = {})
|
|
133
156
|
options_preprocess(options)
|
|
134
|
-
|
|
157
|
+
transformers = effective_document_transformers(options)
|
|
158
|
+
if transformers.key?(format)
|
|
135
159
|
render_via_document_model(isodoc_node, inname, outname, format,
|
|
136
|
-
options)
|
|
160
|
+
options, transformers.fetch(format))
|
|
137
161
|
else
|
|
138
162
|
File.open(outname, "w:UTF-8") { |f| f.write(isodoc_node) }
|
|
139
163
|
end
|
|
@@ -155,9 +179,13 @@ module Metanorma
|
|
|
155
179
|
# {#document_transformers}.
|
|
156
180
|
# @param options [Hash] processor options, passed to the transformer and
|
|
157
181
|
# post-processor.
|
|
182
|
+
# @param spec [Hash, nil] pre-resolved transformer spec; when nil it is
|
|
183
|
+
# resolved from {#effective_document_transformers} (so callers that pass
|
|
184
|
+
# the old five-argument signature still work).
|
|
158
185
|
# @return [String] the serialised (and post-processed) output XML.
|
|
159
|
-
def render_via_document_model(isodoc_node, inname, outname, format, options
|
|
160
|
-
|
|
186
|
+
def render_via_document_model(isodoc_node, inname, outname, format, options,
|
|
187
|
+
spec = nil)
|
|
188
|
+
spec ||= effective_document_transformers(options).fetch(format)
|
|
161
189
|
xml = document_model_input_xml(isodoc_node, inname)
|
|
162
190
|
xml = xml.gsub(/\sxmlns="[^"]*"/, "") if spec[:strip_default_namespace]
|
|
163
191
|
transformer = spec.fetch(:transformer)
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: metanorma-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: asciidoctor
|
|
@@ -164,6 +163,7 @@ files:
|
|
|
164
163
|
- Gemfile
|
|
165
164
|
- LICENSE
|
|
166
165
|
- README.adoc
|
|
166
|
+
- docs/implementing-sts-output-for-a-flavour.adoc
|
|
167
167
|
- lib/metanorma-core.rb
|
|
168
168
|
- lib/metanorma/asciidoctor_extensions.rb
|
|
169
169
|
- lib/metanorma/asciidoctor_extensions/glob_include_processor.rb
|
|
@@ -184,7 +184,6 @@ homepage: https://github.com/metanorma/metanorma-core
|
|
|
184
184
|
licenses:
|
|
185
185
|
- BSD-2-Clause
|
|
186
186
|
metadata: {}
|
|
187
|
-
post_install_message:
|
|
188
187
|
rdoc_options: []
|
|
189
188
|
require_paths:
|
|
190
189
|
- lib
|
|
@@ -199,8 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
199
198
|
- !ruby/object:Gem::Version
|
|
200
199
|
version: '0'
|
|
201
200
|
requirements: []
|
|
202
|
-
rubygems_version:
|
|
203
|
-
signing_key:
|
|
201
|
+
rubygems_version: 4.0.16
|
|
204
202
|
specification_version: 4
|
|
205
203
|
summary: Metanorma Core
|
|
206
204
|
test_files: []
|