isodoc 3.7.3 → 3.7.4.pre.alpha.1
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/.gitignore +25 -0
- data/README.adoc +15 -0
- data/isodoc.gemspec +12 -5
- data/lib/isodoc/gem_tasks.rb +3 -2
- data/lib/isodoc/metadata.rb +15 -2
- data/lib/isodoc/metadata_bibdata.rb +35 -1
- data/lib/isodoc/presentation_function/docid.rb +13 -1
- data/lib/isodoc/presentation_function/docid_semantic.rb +12 -0
- data/lib/isodoc/presentation_function/refs.rb +7 -1
- data/lib/isodoc/spec_helpers/canon_html_input_guard.rb +108 -16
- data/lib/isodoc/version.rb +1 -1
- data/lib/relaton/render-isodoc/general.rb +4 -8
- data/lib/relaton/render-isodoc/styles/isodoc.yml +23 -0
- metadata +15 -9
- data/lib/relaton/render-isodoc/config.yml +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f9eca206080376f0d963170e2c45ec57945a257fda3ab170217b9719fb8c25a6
|
|
4
|
+
data.tar.gz: 10fa45dadb8322115235ab358ada67bb86a64ede4f25d05a10e8f6485773f035
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3e360b76748e8e03283b2b280363c7bf7a7b0c696e2bba62f9daf621e0006dfd791bc8ae5989d3a8229b9445fd02559f644ce6460ed31a9ca77ae495e6fe7323
|
|
7
|
+
data.tar.gz: 91162667360c2a04cd6142e78297c13d4c256f6bc908c1fdd1fc43e35da9e7ac1b4c75ba0cd96abf4e382239823bb5fee41e1fd2b1958fe069e335616d7ce3e0
|
data/.gitignore
CHANGED
|
@@ -1 +1,26 @@
|
|
|
1
1
|
spec/assets/img.svg
|
|
2
|
+
|
|
3
|
+
# Generated test output
|
|
4
|
+
test.doc
|
|
5
|
+
test.err.html
|
|
6
|
+
test.html
|
|
7
|
+
test.presentation.xml
|
|
8
|
+
test_*_files/
|
|
9
|
+
test_*_htmlimages/
|
|
10
|
+
_test_attachments/
|
|
11
|
+
spec/test.html
|
|
12
|
+
spec/test_*_htmlimages/
|
|
13
|
+
spec/assets/iso.doc
|
|
14
|
+
spec/assets/iso.headless.html
|
|
15
|
+
spec/assets/odf1.emf
|
|
16
|
+
spec/assets/test.html
|
|
17
|
+
|
|
18
|
+
# Tooling
|
|
19
|
+
coverage/
|
|
20
|
+
pkg/
|
|
21
|
+
.rspec_status
|
|
22
|
+
.rubocop-https---*
|
|
23
|
+
.rubocop-remote-*
|
|
24
|
+
|
|
25
|
+
# Gem library: resolve at install time
|
|
26
|
+
Gemfile.lock
|
data/README.adoc
CHANGED
|
@@ -85,3 +85,18 @@ NOTE: In the HTML stylesheets specific to standards, the Cover page and Intro pa
|
|
|
85
85
|
This gem relies on https://github.com/metanorma/html2doc[html2doc] to generate Microsoft Word documents.
|
|
86
86
|
|
|
87
87
|
Please see https://github.com/metanorma/html2doc#converting-document-output-to-native-word-docx[this post-processing procedure] to convert output into a native-`docx` document.
|
|
88
|
+
|
|
89
|
+
== Stylesheet compilation and `sassc-embedded`
|
|
90
|
+
|
|
91
|
+
The `.scss` stylesheets under `lib/` are **precompiled to `.css` when this gem is packaged**, not at consumer render time:
|
|
92
|
+
|
|
93
|
+
* `lib/isodoc/gem_tasks.rb` enhances the standard `rake build` with a `build_scss` step: every `lib/**/*.scss` is compiled to a sibling `.css` (using `sassc-embedded`), the compiled files are packed into the released `.gem`, and are then removed from the git working tree. Compiled stylesheets are never committed.
|
|
94
|
+
|
|
95
|
+
At runtime, `lib/isodoc/css.rb#precompiled_style_or_original` prefers the sibling `.css` shipped inside the installed gem. **Consumers of released isodoc gems therefore never load `sassc-embedded`** — which is why the gemspec does not declare it.
|
|
96
|
+
|
|
97
|
+
The runtime SCSS compilation path (`css.rb#convert_scss`, which `require`s `sassc-embedded`) only runs when the sibling `.css` is absent, which is the case when:
|
|
98
|
+
|
|
99
|
+
* working from a git checkout of this repository (no compiled `.css` on disk), or
|
|
100
|
+
* a downstream project resolves isodoc from git (e.g. `gem "isodoc", github: "metanorma/isodoc"`): bundler installs the gemspec's file list, which carries only `.scss`
|
|
101
|
+
|
|
102
|
+
NOTE: Downstream maintainers: if your Gemfile pins isodoc from git, your HTML renders will `require "sassc-embedded"` at runtime even though released-gem consumers never do. A downstream `gem "sassc-embedded"` line in that setup is load-bearing, not dead weight — and it becomes droppable once you revert to a released isodoc gem.
|
data/isodoc.gemspec
CHANGED
|
@@ -28,15 +28,22 @@ Gem::Specification.new do |spec|
|
|
|
28
28
|
end
|
|
29
29
|
spec.required_ruby_version = Gem::Requirement.new(">= 3.3.0")
|
|
30
30
|
|
|
31
|
-
spec.add_dependency "base64"
|
|
31
|
+
spec.add_dependency "base64", ">= 0.1.0"
|
|
32
32
|
spec.add_dependency "bigdecimal"
|
|
33
33
|
spec.add_dependency "html2doc", "~> 1.12"
|
|
34
|
-
# spec.add_dependency "isodoc-i18n", "~> 1.
|
|
35
|
-
spec.add_dependency "relaton-cli", ">=
|
|
36
|
-
# spec.add_dependency "metanorma-utils", "~>
|
|
34
|
+
# spec.add_dependency "isodoc-i18n", "~> 1.5" # already in relaton-render and mn-requirements
|
|
35
|
+
spec.add_dependency "relaton-cli", ">= 3.0.0.pre.alpha", "< 3.1.0"
|
|
36
|
+
# spec.add_dependency "metanorma-utils", "~> 2.0" # already in isodoc-i18n
|
|
37
37
|
spec.add_dependency "mn2pdf", ">= 2.13"
|
|
38
38
|
spec.add_dependency "mn-requirements", "~> 0.5.0"
|
|
39
|
-
|
|
39
|
+
# Allowance for the relaton 3.0.0.pre family (mirrors the relaton-cli
|
|
40
|
+
# allowance in #824): relaton 3.0.0.pre requires relaton-render
|
|
41
|
+
# 3.0.0.pre, which joins the family's versioning and restores the 1.x
|
|
42
|
+
# leaves as deprecated shims, so flavor stacks boot against it.
|
|
43
|
+
# Released isodoc lines keep resolving relaton-render 1.3.0; only a
|
|
44
|
+
# stack that explicitly adopts the relaton prerelease co-resolves
|
|
45
|
+
# 3.0.0.pre.
|
|
46
|
+
spec.add_dependency "relaton-render", "~> 3.0.0.pre.alpha", "< 5"
|
|
40
47
|
spec.add_dependency "roman-numerals"
|
|
41
48
|
spec.add_dependency "rouge", "~> 4.0"
|
|
42
49
|
spec.add_dependency "thread_safe"
|
data/lib/isodoc/gem_tasks.rb
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
# sassc-embedded / sassc_importer load lazily in load_scss_paths: every
|
|
4
|
+
# flavor Rakefile requires this file, but only scss compilation needs the
|
|
5
|
+
# (undeclared) sassc dependency.
|
|
5
6
|
require "rake/clean"
|
|
6
7
|
require "tmpdir"
|
|
7
8
|
|
data/lib/isodoc/metadata.rb
CHANGED
|
@@ -141,14 +141,27 @@ module IsoDoc
|
|
|
141
141
|
set(:edition_display,
|
|
142
142
|
isoxml.at(ns("//bibdata/edition#{currlang}"))&.text)
|
|
143
143
|
set(:docyear, isoxml.at(ns("//bibdata/copyright/from"))&.text)
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
ver = isoxml.at(ns("//bibdata/version"))
|
|
145
|
+
set(:draft, draft_from_version(ver))
|
|
146
|
+
revdate = ver&.at(ns("./revision-date"))&.text ||
|
|
147
|
+
isoxml.at(ns("//bibdata/date[@type='updated']/on"))&.text
|
|
146
148
|
set(:revdate, revdate)
|
|
147
149
|
set(:revdate_monthyear, monthyr(revdate))
|
|
148
150
|
set(:draftinfo,
|
|
149
151
|
draftinfo(get[:draft], get[:revdate]))
|
|
150
152
|
end
|
|
151
153
|
|
|
154
|
+
# <version> carries either its draft directly (legacy hand-built
|
|
155
|
+
# documents) or revision-date/draft children (the semantic
|
|
156
|
+
# pipeline's serialization).
|
|
157
|
+
def draft_from_version(ver)
|
|
158
|
+
return nil if ver.nil?
|
|
159
|
+
|
|
160
|
+
draft = ver.at(ns("./draft"))&.text
|
|
161
|
+
draft ||= ver.children.select(&:text?).join.strip
|
|
162
|
+
draft&.empty? ? nil : draft
|
|
163
|
+
end
|
|
164
|
+
|
|
152
165
|
def title(isoxml, _out)
|
|
153
166
|
main = isoxml.at(ns("//bibdata/title[@language='#{@lang}']"))
|
|
154
167
|
&.children and set(:doctitle, to_xml(main))
|
|
@@ -16,7 +16,10 @@ module IsoDoc
|
|
|
16
16
|
|
|
17
17
|
def bibdata_from_xml(model, node)
|
|
18
18
|
node or return
|
|
19
|
-
|
|
19
|
+
# Cli.parse_xml's contract is a Nokogiri::XML::Document
|
|
20
|
+
# (remove_namespaces!, at); under the moxml/leptris adapter the
|
|
21
|
+
# mapping node's native is not Nokogiri. Convert via markup.
|
|
22
|
+
model.bibdata = Relaton::Cli.parse_xml(Nokogiri::XML(node.to_xml))
|
|
20
23
|
end
|
|
21
24
|
|
|
22
25
|
def bibdata_to_xml(model, parent, doc); end
|
|
@@ -60,6 +63,7 @@ module IsoDoc
|
|
|
60
63
|
# meta[:bibdata] with the resolved docidentifier.
|
|
61
64
|
# See https://github.com/metanorma/metanorma/issues/558.
|
|
62
65
|
stripped.xpath("//docidentifier[@boilerplate = 'true']").each(&:remove)
|
|
66
|
+
collapse_lang_variants!(stripped.root)
|
|
63
67
|
bib = BibdataConfig.from_xml(
|
|
64
68
|
"<metanorma>#{stripped.root.to_xml}</metanorma>",
|
|
65
69
|
).bibdata or return nil
|
|
@@ -72,6 +76,36 @@ module IsoDoc
|
|
|
72
76
|
nil
|
|
73
77
|
end
|
|
74
78
|
|
|
79
|
+
# Relaton models these fields as singular. Presentation i18n
|
|
80
|
+
# (PresentationXMLConvert#tag_translate, JIS #edition_integer?)
|
|
81
|
+
# intentionally emits language-variant siblings — language="",
|
|
82
|
+
# language="ja", numberonly="true", … — for rendering; feeding them
|
|
83
|
+
# to Relaton yields an Array and CollectionTrueMissingError /
|
|
84
|
+
# IncorrectModelError. Keep the canonical node (no @language, not
|
|
85
|
+
# @numberonly) so Liquid still sees the source value, matching
|
|
86
|
+
# Metadata#edition / #docstatus which read the NOLANG node.
|
|
87
|
+
SINGULAR_LANG_VARIANT_XPATHS = [
|
|
88
|
+
"./edition",
|
|
89
|
+
"./status/stage",
|
|
90
|
+
"./status/substage",
|
|
91
|
+
"./ext/doctype",
|
|
92
|
+
].freeze
|
|
93
|
+
|
|
94
|
+
def collapse_lang_variants!(root)
|
|
95
|
+
SINGULAR_LANG_VARIANT_XPATHS.each do |xpath|
|
|
96
|
+
collapse_singular_nodes!(root, xpath)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def collapse_singular_nodes!(root, xpath)
|
|
101
|
+
nodes = root.xpath(xpath)
|
|
102
|
+
nodes.size > 1 or return
|
|
103
|
+
keep = nodes.find { |n| n["language"].to_s.empty? && n["numberonly"] != "true" } ||
|
|
104
|
+
nodes.find { |n| n["language"].to_s.empty? } ||
|
|
105
|
+
nodes.first
|
|
106
|
+
nodes.each { |n| n.remove unless n.equal?(keep) }
|
|
107
|
+
end
|
|
108
|
+
|
|
75
109
|
# The Liquid `bibdata` object is built by round-tripping //bibdata through
|
|
76
110
|
# the Relaton object model, which represents bibliographic-item fields but
|
|
77
111
|
# not the Metanorma-document extension metadata under bibdata/ext
|
|
@@ -10,7 +10,7 @@ module IsoDoc
|
|
|
10
10
|
bib["suppress_identifier"] == "true" and return nil
|
|
11
11
|
ret = bib.xpath(ns("./docidentifier[@scope = 'biblio-tag']"))
|
|
12
12
|
ret.empty? or return ret.map { |x| to_xml(x.children) }
|
|
13
|
-
ret = pref_ref_code_parse(bib) or return nil
|
|
13
|
+
ret = pref_ref_code_markup(bib) || pref_ref_code_parse(bib) or return nil
|
|
14
14
|
ins = bib.at(ns("./docidentifier[last()]"))
|
|
15
15
|
ret.reverse_each do |r|
|
|
16
16
|
id = docid_l10n(r, citation: false)
|
|
@@ -19,6 +19,18 @@ module IsoDoc
|
|
|
19
19
|
ret
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
# Markup-preserving identifier: when the source docidentifier itself
|
|
23
|
+
# carries inline structure (semx, sup, sub...), keep that markup for
|
|
24
|
+
# the biblio-tag instead of the renderer's flat text, which would
|
|
25
|
+
# drop presentation structure like the sup in "ISO 712<sup>1</sup>".
|
|
26
|
+
def pref_ref_code_markup(bib)
|
|
27
|
+
ids = bib.xpath(ns("./docidentifier[not(@scope)]"))
|
|
28
|
+
.reject { |x| %w(metanorma metanorma-ordinal).include?(x["type"]) }
|
|
29
|
+
.select { |x| x.elements.any? }
|
|
30
|
+
ids.empty? and return nil
|
|
31
|
+
[to_xml(ids.first.children)]
|
|
32
|
+
end
|
|
33
|
+
|
|
22
34
|
def pref_ref_code_parse(bib)
|
|
23
35
|
data, = @bibrender.parse(bib)
|
|
24
36
|
ret = data[:authoritative_identifier] or return nil
|
|
@@ -51,6 +51,8 @@ module IsoDoc
|
|
|
51
51
|
|
|
52
52
|
begin
|
|
53
53
|
parsed = flavor.parse(string)
|
|
54
|
+
next if publisher_replaced?(string, parsed)
|
|
55
|
+
|
|
54
56
|
parsed_any = true
|
|
55
57
|
if parsed.to_s == string
|
|
56
58
|
annotated = parsed.to_s(annotated: true)
|
|
@@ -76,6 +78,16 @@ module IsoDoc
|
|
|
76
78
|
string.tr("—", "-").gsub("--", "-")
|
|
77
79
|
end
|
|
78
80
|
|
|
81
|
+
# A parser that replaces the input's own leading publisher token
|
|
82
|
+
# with its own (ASHRAE parsing "IETF 6281" as "ASHRAE Standard
|
|
83
|
+
# 6281") has not parsed the identifier at all: keep trying, so the
|
|
84
|
+
# identifier reaches the regex fallback rather than the
|
|
85
|
+
# plain-string refusal
|
|
86
|
+
def publisher_replaced?(string, parsed)
|
|
87
|
+
own = string[/\A[A-Za-z][A-Za-z.-]*(?=\s)/] or return false
|
|
88
|
+
parsed.to_s[/\A[A-Za-z][A-Za-z.-]*(?=\s)/] != own
|
|
89
|
+
end
|
|
90
|
+
|
|
79
91
|
# Regex-based fallback when Pubid::Registry cannot parse the id. Emits
|
|
80
92
|
# the same generic class names that Pubid uses (publisher, docnumber,
|
|
81
93
|
# part, year) so that flavors' `std_docid_span_classes` remaps work
|
|
@@ -14,6 +14,11 @@ module IsoDoc
|
|
|
14
14
|
bib["suppress_identifier"] == true and
|
|
15
15
|
bib.xpath(ns("./docidentifier")).each(&:remove)
|
|
16
16
|
bib["type"] ||= "standard"
|
|
17
|
+
# The renderer takes flat identifier text; inline markup (semx, sup)
|
|
18
|
+
# in the source docidentifier yields an empty composition.
|
|
19
|
+
bib.xpath("./docidentifier").each do |d|
|
|
20
|
+
d.elements.any? and d.children = d.text
|
|
21
|
+
end
|
|
17
22
|
end
|
|
18
23
|
|
|
19
24
|
def bibitem(bib, renderings)
|
|
@@ -50,7 +55,8 @@ module IsoDoc
|
|
|
50
55
|
def bibrender_formattedref(formattedref, bib); end
|
|
51
56
|
|
|
52
57
|
def bibrender_relaton(bib, renderings)
|
|
53
|
-
|
|
58
|
+
r = renderings[bib["id"]] or return
|
|
59
|
+
f = r[:formattedref] or return
|
|
54
60
|
f &&= "<formattedref>#{f}</formattedref>"
|
|
55
61
|
if x = bib.at(ns("./formattedref"))
|
|
56
62
|
x.replace(f)
|
|
@@ -1,25 +1,45 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "canon"
|
|
4
|
+
require "nokogiri"
|
|
4
5
|
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
6
|
+
# Guards Canon's serialization matchers against input shapes that
|
|
7
|
+
# Canon's XML pretty-printer (preprocessing: :format in the metanorma
|
|
8
|
+
# profile) and the moxml/leptris backend cannot digest.
|
|
8
9
|
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
10
|
+
# 1. Leading "<?xml ?>" processing instructions in HTML input strings
|
|
11
|
+
# passed to Canon's be_html_equivalent_to / be_html4_equivalent_to /
|
|
12
|
+
# be_html5_equivalent_to matchers.
|
|
13
|
+
#
|
|
14
|
+
# WHY: Nokogiri::HTML5.fragment parses a leading "<?xml ?>" as a
|
|
15
|
+
# bogus Nokogiri::XML::Comment at index 0 of the fragment. In
|
|
16
|
+
# Canon's verbose mode (used by the matchers) comments are
|
|
17
|
+
# intentionally not filtered, so the bogus comment shifts fragment
|
|
18
|
+
# child indices and causes Canon's diff report to blame elements at
|
|
19
|
+
# the tail of the document for an offence at the head — an
|
|
20
|
+
# "uninterpretable report" remote from the actual cause. Canon's
|
|
21
|
+
# maintainer has chosen not to normalise this at the input boundary
|
|
22
|
+
# (closed PR lutaml/canon#124); this guard is the local defence.
|
|
23
|
+
#
|
|
24
|
+
# 2. XML fragments (zero or many top-level nodes) and recoverable
|
|
25
|
+
# malformations (unclosed tags) passed to be_xml_equivalent_to.
|
|
26
|
+
# IsoDoc specs routinely compare such input — e.g. "<span>…</span>
|
|
27
|
+
# <semx>…</semx>" anchor labels, a Word <body> extract with the
|
|
28
|
+
# closing tag stripped, or an empty string for "nothing left after
|
|
29
|
+
# stripping Word chrome". Canon.format / PrettyPrinter::Xml#moxml_format
|
|
30
|
+
# runs Moxml::Context#parse in strict mode, which raises
|
|
31
|
+
# Moxml::ParseError ("malformed input" at the second root, "empty
|
|
32
|
+
# input", or an unclosed tag) instead of comparing the fragments.
|
|
33
|
+
# Wrapping both sides in a synthetic root makes them
|
|
34
|
+
# single-document inputs; when the wrapped form is still not
|
|
35
|
+
# well-formed, a Nokogiri recover-mode round-trip closes the
|
|
36
|
+
# unclosed tags. The transformation is identical on both sides, so
|
|
37
|
+
# equivalence of the original fragments is preserved.
|
|
18
38
|
#
|
|
19
39
|
# WHEN: required for the side effect. Requiring this file installs a
|
|
20
|
-
# Module#prepend on Canon::RSpecMatchers::SerializationMatcher
|
|
21
|
-
#
|
|
22
|
-
#
|
|
40
|
+
# Module#prepend on Canon::RSpecMatchers::SerializationMatcher that
|
|
41
|
+
# raises IsoDoc::SpecHelpers::CanonGuardError on the HTML PI condition
|
|
42
|
+
# and wraps XML-fragment inputs before comparison.
|
|
23
43
|
#
|
|
24
44
|
# REUSE: downstream gems that build on isodoc's spec idioms (metanorma
|
|
25
45
|
# family, mn2pdf, etc.) can opt in by adding a single line to their
|
|
@@ -34,10 +54,16 @@ module IsoDoc
|
|
|
34
54
|
class CanonGuardError < StandardError; end
|
|
35
55
|
|
|
36
56
|
# Prepended onto Canon::RSpecMatchers::SerializationMatcher to
|
|
37
|
-
# intercept matches? before Canon's own
|
|
57
|
+
# intercept matches? / compute_equivalent before Canon's own
|
|
58
|
+
# implementation runs.
|
|
38
59
|
module CanonHtmlInputGuard
|
|
39
60
|
ILLEGAL_HTML_PREFIX = /\A\s*<\?xml\b/i.freeze
|
|
40
61
|
|
|
62
|
+
# Synthetic root used to give multi-node / empty XML fragments a
|
|
63
|
+
# single document element. Deliberately ugly so it cannot be
|
|
64
|
+
# confused with real IsoDoc vocabulary.
|
|
65
|
+
XML_FRAG_ROOT = "canon-xml-frag-root"
|
|
66
|
+
|
|
41
67
|
def matches?(target)
|
|
42
68
|
if html_format? &&
|
|
43
69
|
(illegal_prefix?(@expected) || illegal_prefix?(target))
|
|
@@ -47,8 +73,74 @@ module IsoDoc
|
|
|
47
73
|
super
|
|
48
74
|
end
|
|
49
75
|
|
|
76
|
+
# This prepend's frames sit between the spec and canon's matcher;
|
|
77
|
+
# canon's rebaseliner resolves its rewrite target from the first
|
|
78
|
+
# non-rspec/non-canon frame, which would land here. Drop these
|
|
79
|
+
# frames so resolution reaches the actual spec call site.
|
|
80
|
+
def attempt_rebaseline
|
|
81
|
+
if Canon::Rebaseliner.enabled? && @rebaseliner_caller
|
|
82
|
+
@rebaseliner_caller = @rebaseliner_caller.drop_while do |loc|
|
|
83
|
+
(loc.absolute_path || loc.path).to_s.end_with?(
|
|
84
|
+
"canon_html_input_guard.rb",
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
super
|
|
89
|
+
end
|
|
90
|
+
|
|
50
91
|
private
|
|
51
92
|
|
|
93
|
+
# Canon's Comparison already understands DocumentFragment nodes,
|
|
94
|
+
# but NodeParser parses strings as full documents — a multi-root
|
|
95
|
+
# fragment or an empty string then blows up in the :format
|
|
96
|
+
# preprocessing pretty-printer (strict Moxml parse) before the
|
|
97
|
+
# comparator ever runs. Wrap both sides so they parse as one
|
|
98
|
+
# document; the wrapper is shared, so it cannot create false
|
|
99
|
+
# equivalences.
|
|
100
|
+
def compute_equivalent(target)
|
|
101
|
+
if xml_format?
|
|
102
|
+
@expected = wrap_xml_fragment(@expected)
|
|
103
|
+
target = wrap_xml_fragment(target)
|
|
104
|
+
end
|
|
105
|
+
super(target)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def xml_format?
|
|
109
|
+
@format == :xml
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def wrap_xml_fragment(value)
|
|
113
|
+
return value unless value.is_a?(String)
|
|
114
|
+
return value if already_wrapped?(value)
|
|
115
|
+
|
|
116
|
+
wrapped = "<#{XML_FRAG_ROOT}>#{value}</#{XML_FRAG_ROOT}>"
|
|
117
|
+
strict_parse_ok?(wrapped) ? wrapped : recover_wrap(wrapped)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Nokogiri's recover-mode parse closes unclosed tags (Word body
|
|
121
|
+
# extracts routinely omit "</body>"). Applied only when the
|
|
122
|
+
# wrapped input is not already well-formed, because the recover
|
|
123
|
+
# round-trip also rewrites entities and can add xml:lang — both
|
|
124
|
+
# harmless when the input is already broken, both destructive
|
|
125
|
+
# when it is not.
|
|
126
|
+
def recover_wrap(wrapped)
|
|
127
|
+
Nokogiri::XML(wrapped).to_xml
|
|
128
|
+
rescue StandardError
|
|
129
|
+
wrapped
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def strict_parse_ok?(xml)
|
|
133
|
+
Canon::XmlParsing.moxml_context.parse(xml, readonly: true, strict: true)
|
|
134
|
+
true
|
|
135
|
+
rescue StandardError
|
|
136
|
+
false
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def already_wrapped?(value)
|
|
140
|
+
value.include?("<#{XML_FRAG_ROOT}") ||
|
|
141
|
+
value.match?(/\A\s*<\?xml\b[^>]*>\s*<#{XML_FRAG_ROOT}/)
|
|
142
|
+
end
|
|
143
|
+
|
|
52
144
|
def html_format?
|
|
53
145
|
%i[html html4 html5].include?(@format)
|
|
54
146
|
end
|
data/lib/isodoc/version.rb
CHANGED
|
@@ -5,15 +5,11 @@ module Relaton
|
|
|
5
5
|
module Render
|
|
6
6
|
module IsoDoc
|
|
7
7
|
class General < ::Relaton::Render::General
|
|
8
|
-
|
|
8
|
+
STYLE_PATH = File.join(__dir__, "styles/isodoc.yml")
|
|
9
9
|
|
|
10
|
-
def
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def read_config
|
|
16
|
-
super.deep_merge(config_loc)
|
|
10
|
+
def initialize(options = {})
|
|
11
|
+
options[:style] ||= STYLE_PATH
|
|
12
|
+
super
|
|
17
13
|
end
|
|
18
14
|
end
|
|
19
15
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# The IsoDoc presentation citation style: the author-date reference
|
|
2
|
+
# composition with (a) markup delimiters instead of plain-text
|
|
3
|
+
# emphasis — IsoDoc references embed into PresentationXML, where
|
|
4
|
+
# emphasis is an element (<em>), not the plain-text convention — and
|
|
5
|
+
# (b) no authoritative identifier in the reference composition: the
|
|
6
|
+
# identifier renders as the biblio-tag ahead of the formattedref
|
|
7
|
+
# ("ISO 712, _Cereals_ ..."), never duplicated inside it. Patents
|
|
8
|
+
# keep theirs: the patent number is the citation itself.
|
|
9
|
+
name: "IsoDoc (ISO 690, presentation markup)"
|
|
10
|
+
extends: author-date
|
|
11
|
+
templates:
|
|
12
|
+
titleOpen: "<em>"
|
|
13
|
+
titleClose: "</em>"
|
|
14
|
+
reference: "{{creator}}. {{title}}. {{medium}}. {{edition}}. {{series}}. {{production}}, {{date}}. {{location}}."
|
|
15
|
+
perType:
|
|
16
|
+
- type: monograph
|
|
17
|
+
template: "{{creator}}. {{title}}. {{edition}}. {{series}}. {{production}}, {{date}}. {{location}}."
|
|
18
|
+
- type: report
|
|
19
|
+
template: "{{creator}}. {{title}}. {{numeration}}. {{edition}}. {{series}}. {{production}}, {{date}}. {{location}}."
|
|
20
|
+
- type: continuing
|
|
21
|
+
template: "{{creator}}. {{title}}. {{componentPart}}. {{medium}}. {{edition}}. {{production}}, {{date}}. {{numeration}}. {{location}}."
|
|
22
|
+
- type: online
|
|
23
|
+
template: "{{creator}}. {{title}}. {{date}}. {{location}}."
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: isodoc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.7.
|
|
4
|
+
version: 3.7.4.pre.alpha.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base64
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 0.1.0
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: 0.1.0
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: bigdecimal
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -58,7 +58,7 @@ dependencies:
|
|
|
58
58
|
requirements:
|
|
59
59
|
- - ">="
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
61
|
+
version: 3.0.0.pre.alpha
|
|
62
62
|
- - "<"
|
|
63
63
|
- !ruby/object:Gem::Version
|
|
64
64
|
version: 3.1.0
|
|
@@ -68,7 +68,7 @@ dependencies:
|
|
|
68
68
|
requirements:
|
|
69
69
|
- - ">="
|
|
70
70
|
- !ruby/object:Gem::Version
|
|
71
|
-
version:
|
|
71
|
+
version: 3.0.0.pre.alpha
|
|
72
72
|
- - "<"
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
74
|
version: 3.1.0
|
|
@@ -106,14 +106,20 @@ dependencies:
|
|
|
106
106
|
requirements:
|
|
107
107
|
- - "~>"
|
|
108
108
|
- !ruby/object:Gem::Version
|
|
109
|
-
version:
|
|
109
|
+
version: 3.0.0.pre.alpha
|
|
110
|
+
- - "<"
|
|
111
|
+
- !ruby/object:Gem::Version
|
|
112
|
+
version: '5'
|
|
110
113
|
type: :runtime
|
|
111
114
|
prerelease: false
|
|
112
115
|
version_requirements: !ruby/object:Gem::Requirement
|
|
113
116
|
requirements:
|
|
114
117
|
- - "~>"
|
|
115
118
|
- !ruby/object:Gem::Version
|
|
116
|
-
version:
|
|
119
|
+
version: 3.0.0.pre.alpha
|
|
120
|
+
- - "<"
|
|
121
|
+
- !ruby/object:Gem::Version
|
|
122
|
+
version: '5'
|
|
117
123
|
- !ruby/object:Gem::Dependency
|
|
118
124
|
name: roman-numerals
|
|
119
125
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -329,8 +335,8 @@ files:
|
|
|
329
335
|
- lib/metanorma/output/base.rb
|
|
330
336
|
- lib/metanorma/output/utils.rb
|
|
331
337
|
- lib/metanorma/output/xslfo.rb
|
|
332
|
-
- lib/relaton/render-isodoc/config.yml
|
|
333
338
|
- lib/relaton/render-isodoc/general.rb
|
|
339
|
+
- lib/relaton/render-isodoc/styles/isodoc.yml
|
|
334
340
|
homepage: https://github.com/metanorma/isodoc
|
|
335
341
|
licenses:
|
|
336
342
|
- BSD-2-Clause
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
template:
|
|
2
|
-
# skip authoritative identifier, it is inserted in front of formattedref within metanorma
|
|
3
|
-
standard: "{% if creatornames %}{{ creatornames }} ({{ role}}){%else%}{{publisher}}{%endif%} $$$ <em>{{ title }}</em> $$$ {{ medium | capitalize }}$$$ {{ edition | capitalize_first }}$$$ {{date}}$$$ {{place}}: {%if creatornames %}{{publisher}}{% endif %} $$$ {{size}}$$$ {{ extent }}$$$ {{ uri }}$$$ {{ labels['at_url'] | capitalize}}:_{{ access_location }}$$$ [{{ labels['viewed'] }}:_{{date_accessed}}]"
|
|
4
|
-
|