metanorma 1.0.5 → 1.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/macos.yml +8 -8
- data/.github/workflows/ubuntu.yml +20 -16
- data/.github/workflows/windows.yml +8 -8
- data/.gitignore +4 -0
- data/.rubocop.yml +0 -4
- data/lib/metanorma.rb +6 -1
- data/lib/metanorma/collection.rb +182 -0
- data/lib/metanorma/collection_manifest.rb +111 -0
- data/lib/metanorma/collection_renderer.rb +312 -0
- data/lib/metanorma/compile.rb +65 -22
- data/lib/metanorma/document.rb +75 -5
- data/lib/metanorma/input/asciidoc.rb +5 -2
- data/lib/metanorma/output/xslfo.rb +7 -1
- data/lib/metanorma/processor.rb +16 -3
- data/lib/metanorma/registry.rb +11 -2
- data/lib/metanorma/version.rb +1 -1
- data/metanorma.gemspec +4 -2
- metadata +41 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb71b62025d938d52251d5bfb6d1911b3de32299500e12b8fa414a63520a86c3
|
4
|
+
data.tar.gz: df9deea25ea6e374426ad40b3146c63610251873ec652142acffc9274af5856c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6404a68d6371fb24f27e36cc69dc0479da638ec79ef3bb48edf1939d6ec3beffb36c5b86f1402bc238a01ed05481dac255a30ac043cf8a806b24d464e5a16592
|
7
|
+
data.tar.gz: 1881fb5c6c4e3c1d6239b1a4c34dca109f4bc489d33942d42c8e09c9177aef29ce557219aeff7656458bd6e2de918859155728b908ba64c7d6c68c8f1bbdb942
|
data/.github/workflows/macos.yml
CHANGED
@@ -6,33 +6,33 @@ on:
|
|
6
6
|
push:
|
7
7
|
branches: [ master ]
|
8
8
|
pull_request:
|
9
|
+
paths-ignore:
|
10
|
+
- .github/workflows/ubuntu.yml
|
11
|
+
- .github/workflows/windows.yml
|
9
12
|
|
10
13
|
jobs:
|
11
14
|
test-macos:
|
12
15
|
name: Test on Ruby ${{ matrix.ruby }} macOS
|
13
16
|
runs-on: macos-latest
|
17
|
+
continue-on-error: ${{ matrix.experimental }}
|
14
18
|
strategy:
|
15
19
|
fail-fast: false
|
16
20
|
matrix:
|
17
21
|
ruby: [ '2.6', '2.5', '2.4' ]
|
22
|
+
experimental: [false]
|
23
|
+
include:
|
24
|
+
- ruby: '2.7'
|
25
|
+
experimental: true
|
18
26
|
steps:
|
19
27
|
- uses: actions/checkout@master
|
20
28
|
- name: Use Ruby
|
21
29
|
uses: actions/setup-ruby@v1
|
22
30
|
with:
|
23
31
|
ruby-version: ${{ matrix.ruby }}
|
24
|
-
architecture: 'x64'
|
25
32
|
- name: Update gems
|
26
33
|
run: |
|
27
34
|
sudo gem install bundler --force
|
28
35
|
bundle install --jobs 4 --retry 3
|
29
|
-
- name: Use Node
|
30
|
-
uses: actions/setup-node@v1
|
31
|
-
with:
|
32
|
-
node-version: '12'
|
33
|
-
- name: Install Puppeteer
|
34
|
-
run: |
|
35
|
-
npm install -g puppeteer@3.0.1
|
36
36
|
- name: Run specs
|
37
37
|
run: |
|
38
38
|
bundle exec rake
|
@@ -5,48 +5,52 @@ name: ubuntu
|
|
5
5
|
on:
|
6
6
|
push:
|
7
7
|
branches: [ master ]
|
8
|
+
tags:
|
9
|
+
- '*'
|
8
10
|
pull_request:
|
11
|
+
paths-ignore:
|
12
|
+
- .github/workflows/macos.yml
|
13
|
+
- .github/workflows/windows.yml
|
9
14
|
|
10
15
|
jobs:
|
11
16
|
test-linux:
|
12
17
|
name: Test on Ruby ${{ matrix.ruby }} Ubuntu
|
13
18
|
runs-on: ubuntu-latest
|
19
|
+
continue-on-error: ${{ matrix.experimental }}
|
14
20
|
strategy:
|
15
21
|
fail-fast: false
|
16
22
|
matrix:
|
17
23
|
ruby: [ '2.6', '2.5', '2.4' ]
|
24
|
+
experimental: [false]
|
25
|
+
include:
|
26
|
+
- ruby: '2.7'
|
27
|
+
experimental: true
|
18
28
|
steps:
|
19
29
|
- uses: actions/checkout@master
|
20
30
|
- name: Use Ruby
|
21
31
|
uses: actions/setup-ruby@v1
|
22
32
|
with:
|
23
33
|
ruby-version: ${{ matrix.ruby }}
|
24
|
-
architecture: 'x64'
|
25
34
|
- name: Update gems
|
26
35
|
run: |
|
27
36
|
gem install bundler
|
28
37
|
bundle install --jobs 4 --retry 3
|
29
|
-
- name: Use Node
|
30
|
-
uses: actions/setup-node@v1
|
31
|
-
with:
|
32
|
-
node-version: '12'
|
33
|
-
- name: Install Puppeteer
|
34
|
-
run: |
|
35
|
-
sudo apt-get update
|
36
|
-
sudo apt-get install libgbm1
|
37
|
-
npm install -g puppeteer@3.0.1
|
38
38
|
- name: Run specs
|
39
39
|
run: |
|
40
40
|
bundle exec rake
|
41
|
-
- name: Trigger
|
42
|
-
if:
|
41
|
+
- name: Trigger repositories
|
42
|
+
if: matrix.ruby == '2.6'
|
43
43
|
env:
|
44
|
-
GH_USERNAME:
|
45
|
-
GH_ACCESS_TOKEN: ${{ secrets.
|
44
|
+
GH_USERNAME: metanorma-ci
|
45
|
+
GH_ACCESS_TOKEN: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
|
46
46
|
run: |
|
47
47
|
curl -LO --retry 3 https://raw.githubusercontent.com/metanorma/metanorma-build-scripts/master/trigger-gh-actions.sh
|
48
48
|
[[ -f ".github/workflows/dependent_repos.env" ]] && source .github/workflows/dependent_repos.env
|
49
|
-
|
49
|
+
CLIENT_PAYLOAD=$(cat <<EOF
|
50
|
+
"{ "ref": "${GITHUB_REF}", "repo": "${GITHUB_REPOSITORY}" }"
|
51
|
+
EOF
|
52
|
+
)
|
53
|
+
for repo in $REPOS
|
50
54
|
do
|
51
|
-
sh trigger-gh-actions.sh $ORGANISATION $repo $GH_USERNAME $GH_ACCESS_TOKEN $GITHUB_REPOSITORY
|
55
|
+
sh trigger-gh-actions.sh $ORGANISATION $repo $GH_USERNAME $GH_ACCESS_TOKEN $GITHUB_REPOSITORY "$CLIENT_PAYLOAD"
|
52
56
|
done
|
@@ -6,35 +6,35 @@ on:
|
|
6
6
|
push:
|
7
7
|
branches: [ master ]
|
8
8
|
pull_request:
|
9
|
+
paths-ignore:
|
10
|
+
- .github/workflows/macos.yml
|
11
|
+
- .github/workflows/ubuntu.yml
|
9
12
|
|
10
13
|
jobs:
|
11
14
|
test-windows:
|
12
15
|
name: Test on Ruby ${{ matrix.ruby }} Windows
|
13
16
|
runs-on: windows-latest
|
17
|
+
continue-on-error: ${{ matrix.experimental }}
|
14
18
|
strategy:
|
15
19
|
fail-fast: false
|
16
20
|
matrix:
|
17
21
|
ruby: [ '2.6', '2.5', '2.4' ]
|
22
|
+
experimental: [false]
|
23
|
+
include:
|
24
|
+
- ruby: '2.7'
|
25
|
+
experimental: true
|
18
26
|
steps:
|
19
27
|
- uses: actions/checkout@master
|
20
28
|
- name: Use Ruby
|
21
29
|
uses: actions/setup-ruby@v1
|
22
30
|
with:
|
23
31
|
ruby-version: ${{ matrix.ruby }}
|
24
|
-
architecture: 'x64'
|
25
32
|
- name: Update gems
|
26
33
|
shell: pwsh
|
27
34
|
run: |
|
28
35
|
gem install bundler
|
29
36
|
bundle config --local path vendor/bundle
|
30
37
|
bundle install --jobs 4 --retry 3
|
31
|
-
- name: Use Node
|
32
|
-
uses: actions/setup-node@v1
|
33
|
-
with:
|
34
|
-
node-version: '12'
|
35
|
-
- name: Install Puppeteer
|
36
|
-
run: |
|
37
|
-
npm install -g puppeteer@3.0.1
|
38
38
|
- name: Run specs
|
39
39
|
run: |
|
40
40
|
bundle exec rake
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/lib/metanorma.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "metanorma/version"
|
2
4
|
require "asciidoctor"
|
3
5
|
require "metanorma/util"
|
@@ -8,7 +10,10 @@ require "metanorma/registry"
|
|
8
10
|
require "metanorma/processor"
|
9
11
|
require "metanorma/asciidoctor_extensions"
|
10
12
|
require "metanorma/compile"
|
13
|
+
require "metanorma/collection"
|
14
|
+
require "metanorma/collection_renderer"
|
15
|
+
require "metanorma/document"
|
11
16
|
|
17
|
+
# Metanorma module
|
12
18
|
module Metanorma
|
13
|
-
|
14
19
|
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "relaton"
|
4
|
+
require "relaton/cli"
|
5
|
+
require "metanorma/collection_manifest"
|
6
|
+
|
7
|
+
module Metanorma
|
8
|
+
# Metanorma collection of documents
|
9
|
+
class Collection
|
10
|
+
# @return [String]
|
11
|
+
attr_reader :file
|
12
|
+
|
13
|
+
# @return [Array<String>] documents-inline to inject the XML into
|
14
|
+
# the collection manifest; documents-external to keeps them outside
|
15
|
+
attr_reader :directives
|
16
|
+
|
17
|
+
# @return [Hash<String, Metanorma::Document>]
|
18
|
+
attr_reader :documents
|
19
|
+
|
20
|
+
# @param file [String] path to source file
|
21
|
+
# @param directives [Array<String>] documents-inline to inject the XML into
|
22
|
+
# the collection manifest; documents-external to keeps them outside
|
23
|
+
# @param bibdata [RelatonBib::BibliographicItem]
|
24
|
+
# @param manifest [Metanorma::CollectionManifest]
|
25
|
+
# @param documents [Hash<String, Metanorma::Document>]
|
26
|
+
# @param prefatory [String]
|
27
|
+
# @param final [String]
|
28
|
+
# rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
29
|
+
def initialize(**args)
|
30
|
+
@file = args[:file]
|
31
|
+
@directives = args[:directives] || []
|
32
|
+
@bibdata = args[:bibdata]
|
33
|
+
@manifest = args[:manifest]
|
34
|
+
@manifest.collection = self
|
35
|
+
@documents = args[:documents] || {}
|
36
|
+
if @documents.any? && !@directives.include?("documents-inline")
|
37
|
+
@directives << "documents-inline"
|
38
|
+
end
|
39
|
+
@documents.merge! @manifest.documents(File.dirname(@file))
|
40
|
+
@prefatory = args[:prefatory]
|
41
|
+
@final = args[:final]
|
42
|
+
end
|
43
|
+
# rubocop:enable Metrics/AbcSize,Metrics/MethodLength
|
44
|
+
|
45
|
+
# @return [String] XML
|
46
|
+
def to_xml
|
47
|
+
Nokogiri::XML::Builder.new do |xml|
|
48
|
+
xml.send("metanorma-collection",
|
49
|
+
"xmlns" => "http://metanorma.org") do |mc|
|
50
|
+
@bibdata.to_xml mc, bibdata: true, date_format: :full
|
51
|
+
@manifest.to_xml mc
|
52
|
+
content_to_xml "prefatory", mc
|
53
|
+
doccontainer mc
|
54
|
+
content_to_xml "final", mc
|
55
|
+
end
|
56
|
+
end.to_xml
|
57
|
+
end
|
58
|
+
|
59
|
+
def render(opts)
|
60
|
+
CollectionRenderer.render self, opts
|
61
|
+
end
|
62
|
+
|
63
|
+
class << self
|
64
|
+
# @param file [String]
|
65
|
+
# @return [RelatonBib::BibliographicItem,
|
66
|
+
# RelatonIso::IsoBibliographicItem]
|
67
|
+
def parse(file)
|
68
|
+
case file
|
69
|
+
when /\.xml$/ then parse_xml(file)
|
70
|
+
when /.ya?ml$/ then parse_yaml(file)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def parse_xml(file)
|
77
|
+
xml = Nokogiri::XML File.read(file, encoding: "UTF-8")
|
78
|
+
if (b = xml.at("/xmlns:metanorma-collection/xmlns:bibdata"))
|
79
|
+
bd = Relaton::Cli.parse_xml b
|
80
|
+
end
|
81
|
+
mnf_xml = xml.at("/xmlns:metanorma-collection/xmlns:manifest")
|
82
|
+
mnf = CollectionManifest.from_xml mnf_xml
|
83
|
+
pref = pref_final_content xml.at("//xmlns:prefatory-content")
|
84
|
+
fnl = pref_final_content xml.at("//xmlns:final-content")
|
85
|
+
new(file: file, bibdata: bd, manifest: mnf,
|
86
|
+
documents: docs_from_xml(xml, mnf), prefatory: pref, final: fnl)
|
87
|
+
end
|
88
|
+
|
89
|
+
def parse_yaml(file)
|
90
|
+
yaml = YAML.load_file file
|
91
|
+
if yaml["bibdata"]
|
92
|
+
bd = Relaton::Cli::YAMLConvertor.convert_single_file yaml["bibdata"]
|
93
|
+
end
|
94
|
+
mnf = CollectionManifest.from_yaml yaml["manifest"]
|
95
|
+
dirs = yaml["directives"]
|
96
|
+
pref = yaml["prefatory-content"]
|
97
|
+
fnl = yaml["final-content"]
|
98
|
+
new(file: file, directives: dirs, bibdata: bd, manifest: mnf,
|
99
|
+
prefatory: pref, final: fnl)
|
100
|
+
end
|
101
|
+
|
102
|
+
# @param xml [Nokogiri::XML::Document]
|
103
|
+
# @parma mnf [Metanorma::CollectionManifest]
|
104
|
+
# @return [Hash{String=>Metanorma::Document}]
|
105
|
+
def docs_from_xml(xml, mnf)
|
106
|
+
xml.xpath("//xmlns:doc-container/*/xmlns:bibdata")
|
107
|
+
.each_with_object({}) do |b, m|
|
108
|
+
bd = Relaton::Cli.parse_xml b
|
109
|
+
docref = mnf.docref_by_id bd.docidentifier.first.id
|
110
|
+
m[docref["identifier"]] = Document.new bd, docref["fileref"]
|
111
|
+
m
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# @param xml [Nokogiri::XML::Element, nil]
|
116
|
+
# @return [String, nil]
|
117
|
+
def pref_final_content(xml)
|
118
|
+
return unless xml
|
119
|
+
|
120
|
+
<<~CONT
|
121
|
+
|
122
|
+
== #{xml.at('title')&.text}
|
123
|
+
#{xml.at('p')&.text}
|
124
|
+
CONT
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
# @return [String, nil]
|
131
|
+
attr_reader :prefatory, :final
|
132
|
+
|
133
|
+
# @return [String]
|
134
|
+
def dummy_header
|
135
|
+
<<~DUMMY
|
136
|
+
= X
|
137
|
+
A
|
138
|
+
|
139
|
+
DUMMY
|
140
|
+
end
|
141
|
+
|
142
|
+
# @param elm [String] 'prefatory' or 'final'
|
143
|
+
# @param builder [Nokogiri::XML::Builder]
|
144
|
+
def content_to_xml(elm, builder)
|
145
|
+
return unless (cnt = send(elm))
|
146
|
+
|
147
|
+
require "metanorma-#{doctype}"
|
148
|
+
out = sections(dummy_header + cnt)
|
149
|
+
builder.send(elm + "-content") { |b| b << out }
|
150
|
+
end
|
151
|
+
|
152
|
+
# @param cnt [String] prefatory/final content
|
153
|
+
# @return [String] XML
|
154
|
+
def sections(cnt)
|
155
|
+
c = Asciidoctor.convert(cnt, backend: doctype.to_sym, header_footer: true)
|
156
|
+
Nokogiri::XML(c).at("//xmlns:sections").children.to_xml
|
157
|
+
end
|
158
|
+
|
159
|
+
# @param builder [Nokogiri::XML::Builder]
|
160
|
+
def doccontainer(builder)
|
161
|
+
return unless Array(@directives).include? "documents-inline"
|
162
|
+
|
163
|
+
documents.each_with_index do |(_, d), i|
|
164
|
+
id = format("doc%<index>09d", index: i)
|
165
|
+
builder.send("doc-container", id: id) { |b| d.to_xml b }
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# @return [String]
|
170
|
+
def doctype
|
171
|
+
@doctype ||= fetch_doctype || "standoc"
|
172
|
+
end
|
173
|
+
|
174
|
+
# @return [String]
|
175
|
+
def fetch_doctype
|
176
|
+
docid = @bibdata.docidentifier.first
|
177
|
+
return unless docid
|
178
|
+
|
179
|
+
docid.type&.downcase || docid.id&.sub(/\s.*$/, "")&.downcase
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Metanorma
|
4
|
+
# Metanorma collection's manifest
|
5
|
+
class CollectionManifest
|
6
|
+
# @return [Metanorma::Collection]
|
7
|
+
attr_reader :collection
|
8
|
+
|
9
|
+
# @param level [String]
|
10
|
+
# @param title [String, nil]
|
11
|
+
# @param docref [Array<Hash{String=>String}>]
|
12
|
+
# @param manifest [Array<Metanorma::CollectionManifest>]
|
13
|
+
def initialize(level, title = nil, docref = [], manifest = [])
|
14
|
+
@level = level
|
15
|
+
@title = title
|
16
|
+
@docref = docref
|
17
|
+
@manifest = manifest
|
18
|
+
end
|
19
|
+
|
20
|
+
class << self
|
21
|
+
# @param mnf [Nokogiri::XML::Element]
|
22
|
+
# @return [Metanorma::CollectionManifest]
|
23
|
+
def from_yaml(mnf)
|
24
|
+
manifest = RelatonBib::HashConverter.array(mnf["manifest"]).map do |m|
|
25
|
+
from_yaml m
|
26
|
+
end
|
27
|
+
docref = RelatonBib::HashConverter.array mnf["docref"]
|
28
|
+
new(mnf["level"], mnf["title"], docref, manifest)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param mnf [Nokogiri::XML::Element]
|
32
|
+
# @return [Metanorma::CollectionManifest]
|
33
|
+
def from_xml(mnf)
|
34
|
+
level = mnf.at("level").text
|
35
|
+
title = mnf.at("title")&.text
|
36
|
+
manifest = mnf.xpath("xmlns:manifest").map { |m| from_xml(m) }
|
37
|
+
new(level, title, parse_docref(mnf), manifest)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# @param mnf [Nokogiri::XML::Element]
|
43
|
+
# @return [Hash{String=>String}]
|
44
|
+
def parse_docref(mnf)
|
45
|
+
mnf.xpath("xmlns:docref").map do |dr|
|
46
|
+
h = { "identifier" => dr.at("identifier").text }
|
47
|
+
h["fileref"] = dr[:fileref] if dr[:fileref]
|
48
|
+
h
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# @param col [Metanorma::Collection]
|
54
|
+
def collection=(col)
|
55
|
+
@collection = col
|
56
|
+
@manifest.each { |mnf| mnf.collection = col }
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param dir [String] path to coolection
|
60
|
+
# @return [Hash<String, Metanorma::Document>]
|
61
|
+
def documents(dir = "")
|
62
|
+
docs = @docref.each_with_object({}) do |dr, m|
|
63
|
+
next m unless dr["fileref"]
|
64
|
+
|
65
|
+
m[dr["identifier"]] = Document.parse_file File.join(dir, dr["fileref"])
|
66
|
+
m
|
67
|
+
end
|
68
|
+
@manifest.reduce(docs) do |mem, mnf|
|
69
|
+
mem.merge mnf.documents(dir)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# @param builder [Nokogiri::XML::Builder]
|
74
|
+
def to_xml(builder)
|
75
|
+
builder.manifest do |b|
|
76
|
+
b.level @level
|
77
|
+
b.title @title if @title
|
78
|
+
docref_to_xml b
|
79
|
+
@manifest.each { |m| m.to_xml b }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [Array<Hash{String=>String}>]
|
84
|
+
def docrefs
|
85
|
+
return @docrefs if @docrefs
|
86
|
+
|
87
|
+
drfs = @docref.map { |dr| dr }
|
88
|
+
@manifest.reduce(drfs) { |mem, mnf| mem + mnf.docrefs }
|
89
|
+
end
|
90
|
+
|
91
|
+
def docref_by_id(docid)
|
92
|
+
refs = docrefs
|
93
|
+
dref = refs.detect { |k| k["identifier"] == docid }
|
94
|
+
dref || docrefs.detect { |k| /^#{k["identifier"]}/ =~ docid }
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
# @param builder [Nokogiri::XML::Builder]
|
100
|
+
def docref_to_xml(builder)
|
101
|
+
@docref.each do |dr|
|
102
|
+
drf = builder.docref { |b| b.identifier dr["identifier"] }
|
103
|
+
drf[:fileref] = dr["fileref"]
|
104
|
+
if collection.directives.include?("documents-inline")
|
105
|
+
id = collection.documents.find_index { |k, _| k == dr["identifier"] }
|
106
|
+
drf[:id] = format("doc%<index>09d", index: id)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,312 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "isodoc"
|
4
|
+
|
5
|
+
module Metanorma
|
6
|
+
# XML collection renderer
|
7
|
+
class CollectionRenderer
|
8
|
+
FORMATS = %i[html xml doc pdf].freeze
|
9
|
+
|
10
|
+
# This is only going to render the HTML collection
|
11
|
+
# @param xml [Metanorma::Collection] input XML collection
|
12
|
+
# @param folder [String] input folder
|
13
|
+
# @param options [Hash]
|
14
|
+
# @option options [String] :coverpage cover page HTML (Liquid template)
|
15
|
+
# @option options [Array<Symbol>] :format list of formats (xml,html,doc,pdf)
|
16
|
+
# @option options [String] :ourput_folder output directory
|
17
|
+
#
|
18
|
+
# We presuppose that the bibdata of the document is equivalent to that of
|
19
|
+
# the collection, and that the flavour gem can sensibly process it. We may
|
20
|
+
# need to enhance metadata in the flavour gems isodoc/metadata.rb with
|
21
|
+
# collection metadata
|
22
|
+
def initialize(xml, folder, options = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
23
|
+
check_options options
|
24
|
+
@xml = Nokogiri::XML xml # @xml is the collection manifest
|
25
|
+
@lang = @xml&.at(ns("//bibdata/language"))&.text || "en"
|
26
|
+
@script = @xml&.at(ns("//bibdata/script"))&.text || "Latn"
|
27
|
+
@doctype = doctype
|
28
|
+
require "metanorma-#{@doctype}"
|
29
|
+
|
30
|
+
# output processor for flavour
|
31
|
+
@isodoc = isodoc
|
32
|
+
|
33
|
+
@outdir = options[:output_folder]
|
34
|
+
@coverpage = options[:coverpage]
|
35
|
+
@format = options[:format]
|
36
|
+
|
37
|
+
# list of files in the collection
|
38
|
+
@files = read_files folder
|
39
|
+
FileUtils.rm_rf @outdir
|
40
|
+
FileUtils.mkdir_p @outdir
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param col [Metanorma::Collection] XML collection
|
44
|
+
# @param options [Hash]
|
45
|
+
# @option options [String] :coverpage cover page HTML (Liquid template)
|
46
|
+
# @option options [Array<Synbol>] :format list of formats
|
47
|
+
# @option options [Strong] :ourput_folder output directory
|
48
|
+
def self.render(col, options = {})
|
49
|
+
folder = File.dirname col.file
|
50
|
+
cr = new(col.to_xml, folder, options)
|
51
|
+
cr.files
|
52
|
+
cr.coverpage if options[:format]&.include?(:html)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Dummy class
|
56
|
+
class Dummy
|
57
|
+
def attr(_xyz); end
|
58
|
+
end
|
59
|
+
|
60
|
+
# The isodoc class for the metanorma flavour we are using
|
61
|
+
def isodoc # rubocop:disable Metrics/MethodLength
|
62
|
+
x = Asciidoctor.load nil, backend: @doctype.to_sym
|
63
|
+
isodoc = x.converter.html_converter(Dummy.new)
|
64
|
+
isodoc.i18n_init(@lang, @script) # read in internationalisation
|
65
|
+
# create the @meta class of isodoc, with "navigation" set to the index bar
|
66
|
+
# extracted from the manifest
|
67
|
+
nav = indexfile(@xml.at(ns("//manifest")))
|
68
|
+
i18n = isodoc.i18n
|
69
|
+
i18n.set(:navigation, nav)
|
70
|
+
isodoc.metadata_init(@lang, @script, i18n)
|
71
|
+
# populate the @meta class of isodoc with the various metadata fields
|
72
|
+
# native to the flavour; used to populate Liquid
|
73
|
+
isodoc.info(@xml, nil)
|
74
|
+
isodoc
|
75
|
+
end
|
76
|
+
|
77
|
+
# infer the flavour from the first document identifier; relaton does that
|
78
|
+
def doctype
|
79
|
+
if (docid = @xml&.at(ns("//bibdata/docidentifier/@type"))&.text)
|
80
|
+
dt = docid.downcase
|
81
|
+
elsif (docid = @xml&.at(ns("//bibdata/docidentifier"))&.text)
|
82
|
+
dt = docid.sub(/\s.*$/, "").lowercase
|
83
|
+
else return "standoc"
|
84
|
+
end
|
85
|
+
@registry = Metanorma::Registry.instance
|
86
|
+
@registry.alias(dt.to_sym)&.to_s || dt
|
87
|
+
end
|
88
|
+
|
89
|
+
def ns(xpath)
|
90
|
+
IsoDoc::Convert.new({}).ns(xpath)
|
91
|
+
end
|
92
|
+
|
93
|
+
# hash for each document in collection of document identifier to:
|
94
|
+
# document reference (fileref or id), type of document reference,
|
95
|
+
# and bibdata entry for that file
|
96
|
+
# @param path [String] path to collection
|
97
|
+
# @return [Hash{String=>Hash}]
|
98
|
+
def read_files(path) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
99
|
+
files = {}
|
100
|
+
@xml.xpath(ns("//docref")).each do |d|
|
101
|
+
identifier = d.at(ns("./identifier")).text
|
102
|
+
files[identifier] = if d["fileref"]
|
103
|
+
{ type: "fileref",
|
104
|
+
ref: File.join(path, d["fileref"]) }
|
105
|
+
else { type: "id", ref: d["id"] }
|
106
|
+
end
|
107
|
+
file, _filename = targetfile(files[identifier], true)
|
108
|
+
xml = Nokogiri::XML(file)
|
109
|
+
files[identifier][:anchors] = read_anchors(xml)
|
110
|
+
files[identifier][:bibdata] = xml.at(ns("//bibdata"))
|
111
|
+
end
|
112
|
+
files
|
113
|
+
end
|
114
|
+
|
115
|
+
# map locality type and label (e.g. "clause" "1") to id = anchor for
|
116
|
+
# a document
|
117
|
+
def read_anchors(xml)
|
118
|
+
ret = {}
|
119
|
+
xrefs = @isodoc.xref_init(@lang, @script, @isodoc, @isodoc.i18n, {})
|
120
|
+
xrefs.parse xml
|
121
|
+
xrefs.get.each do |k, v|
|
122
|
+
v[:label] && v[:type] || next
|
123
|
+
ret[v[:type]] ||= {}
|
124
|
+
ret[v[:type]][v[:label]] = k
|
125
|
+
end
|
126
|
+
ret
|
127
|
+
end
|
128
|
+
|
129
|
+
# populate liquid template of ARGV[1] with metadata extracted from
|
130
|
+
# collection manifest
|
131
|
+
def coverpage
|
132
|
+
File.open(File.join(@outdir, "index.html"), "w:UTF-8") do |f|
|
133
|
+
f.write @isodoc.populate_template(File.read(@coverpage))
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# @param elm [Nokogiri::XML::Element]
|
138
|
+
# @return [String]
|
139
|
+
def indexfile_title(elm)
|
140
|
+
lvl = elm&.at(ns("./level"))&.text&.capitalize
|
141
|
+
lbl = elm&.at(ns("./title"))&.text
|
142
|
+
"#{lvl}#{lvl && lbl ? ': ' : ''}#{lbl}"
|
143
|
+
end
|
144
|
+
|
145
|
+
# uses the identifier to label documents; other attributes (title) can be
|
146
|
+
# looked up in @files[id][:bibdata]
|
147
|
+
#
|
148
|
+
# @param elm [Nokogiri::XML::Element]
|
149
|
+
# @param builder [Nokogiri::XML::Builder]
|
150
|
+
def indexfile_docref(elm, builder)
|
151
|
+
return "" unless elm.at(ns("./docref"))
|
152
|
+
|
153
|
+
builder.ul { |b| docrefs(elm, b) }
|
154
|
+
end
|
155
|
+
|
156
|
+
# @param elm [Nokogiri::XML::Element]
|
157
|
+
# @param builder [Nokogiri::XML::Builder]
|
158
|
+
def docrefs(elm, builder)
|
159
|
+
elm.xpath(ns("./docref")).each do |d|
|
160
|
+
identifier = d.at(ns("./identifier")).text
|
161
|
+
link = if d["fileref"] then d["fileref"].sub(/\.xml$/, ".html")
|
162
|
+
else d["id"] + ".html"
|
163
|
+
end
|
164
|
+
builder.li { builder.a identifier, href: link }
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# single level navigation list, with hierarchical nesting
|
169
|
+
# if multiple lists are needed as separate HTML fragments, multiple
|
170
|
+
# instances of this function will be needed,
|
171
|
+
# and associated to different variables in the call to @isodoc.metadata_init
|
172
|
+
# (including possibly an array of HTML fragments)
|
173
|
+
#
|
174
|
+
# @param elm [Nokogiri::XML::Element]
|
175
|
+
# @return [String] XML
|
176
|
+
def indexfile(elm)
|
177
|
+
Nokogiri::HTML::Builder.new do |b|
|
178
|
+
b.ul do
|
179
|
+
b.li indexfile_title(elm)
|
180
|
+
indexfile_docref(elm, b)
|
181
|
+
elm.xpath(ns("./manifest")).each do |d|
|
182
|
+
b << indexfile(d)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end.doc.root.to_html
|
186
|
+
end
|
187
|
+
|
188
|
+
# return file contents + output filename for each file in the collection,
|
189
|
+
# given a docref entry
|
190
|
+
# @param data [Hash]
|
191
|
+
# @param read [Boolean]
|
192
|
+
# @return [Array<String, nil>]
|
193
|
+
def targetfile(data, read = false)
|
194
|
+
if data[:type] == "fileref" then ref_file data[:ref], read
|
195
|
+
else xml_file data[:id], read
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# @param ref [String]
|
200
|
+
# @param read [Boolean]
|
201
|
+
# @return [Array<String, nil>]
|
202
|
+
def ref_file(ref, read)
|
203
|
+
file = File.read(ref, encoding: "utf-8") if read
|
204
|
+
filename = ref.sub(/\.xml$/, ".html")
|
205
|
+
[file, filename]
|
206
|
+
end
|
207
|
+
|
208
|
+
# @param id [String]
|
209
|
+
# @param read [Boolean]
|
210
|
+
# @return [Array<String, nil>]
|
211
|
+
def xml_file(id, read)
|
212
|
+
file = @xml.at(ns("//doc-container[@id = '#{id}']")).to_xml if read
|
213
|
+
filename = id + ".html"
|
214
|
+
[file, filename]
|
215
|
+
end
|
216
|
+
|
217
|
+
# @param bib [Nokogiri::XML::Element]
|
218
|
+
# @param identifier [String]
|
219
|
+
def update_bibitem(bib, identifier) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
220
|
+
docid = bib&.at(ns("./docidentifier"))&.text
|
221
|
+
unless @files[docid]
|
222
|
+
warn "Cannot find crossreference to document #{docid} in document "\
|
223
|
+
"#{identifier}!"
|
224
|
+
abort
|
225
|
+
end
|
226
|
+
id = bib["id"]
|
227
|
+
newbib = bib.replace(@files[docid][:bibdata])
|
228
|
+
newbib.name = "bibitem"
|
229
|
+
newbib["id"] = id
|
230
|
+
newbib&.at(ns("./ext"))&.remove
|
231
|
+
_file, url = targetfile(@files[docid], false)
|
232
|
+
uri_node = Nokogiri::XML::Node.new "uri", newbib
|
233
|
+
uri_node[:type] = "citation"
|
234
|
+
uri_node.content = url
|
235
|
+
newbib.at(ns("./docidentifier")).previous = uri_node
|
236
|
+
end
|
237
|
+
|
238
|
+
# TODO: update crossreferences to other files in the selection
|
239
|
+
# repo(current-metanorma-collection/ISO 17301-1:2016)
|
240
|
+
# replaced by
|
241
|
+
# bibdata of "ISO 17301-1:2016" in situ as bibitem
|
242
|
+
# Any erefs to that bibitem id are replaced with relative URL
|
243
|
+
# Preferably with anchor, and is a job to realise dynamic lookup of
|
244
|
+
# localities
|
245
|
+
# @param file [String] XML content
|
246
|
+
# @param identifier [String] docid
|
247
|
+
# @return [String] XML content
|
248
|
+
def update_xrefs(file, identifier)
|
249
|
+
docxml = Nokogiri::XML(file)
|
250
|
+
docxml.xpath(ns("//bibitem[not(ancestor::bibitem)]")).each do |b|
|
251
|
+
docid = b&.at(ns("./docidentifier[@type = 'repository']"))&.text
|
252
|
+
next unless docid && %r{^current-metanorma-collection/}.match(docid)
|
253
|
+
|
254
|
+
update_bibitem(b, identifier)
|
255
|
+
update_anchors(b, docxml, docid)
|
256
|
+
end
|
257
|
+
docxml.to_xml
|
258
|
+
end
|
259
|
+
|
260
|
+
# if there is a crossref to another document, with no anchor, retrieve the
|
261
|
+
# anchor given the locality, and insert it into the crossref
|
262
|
+
def update_anchors(bib, docxml, _id) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
263
|
+
docid = bib&.at(ns("./docidentifier"))&.text
|
264
|
+
docxml.xpath("//xmlns:eref[@citeas = '#{docid}']").each do |e|
|
265
|
+
e.at(ns(".//locality[@type = 'anchor']")).nil? || next
|
266
|
+
ins = e.at(ns("./localityStack")) || next
|
267
|
+
type = ins&.at(ns("./locality/@type"))&.text
|
268
|
+
ref = ins&.at(ns("./locality/referenceFrom"))&.text
|
269
|
+
(anchor = @files[docid][:anchors][type][ref]) || next
|
270
|
+
ref_from = Nokogiri::XML::Node.new "referenceFrom", bib
|
271
|
+
ref_from.content = anchor.sub(/^_/, "")
|
272
|
+
locality = Nokogiri::XML::Node.new "locality", bib
|
273
|
+
locality[:type] = "anchor"
|
274
|
+
locality.add_child ref_from
|
275
|
+
ins << locality
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# process each file in the collection
|
280
|
+
# files are held in memory, and altered as postprocessing
|
281
|
+
def files # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
282
|
+
@files.each do |identifier, x|
|
283
|
+
file, filename = targetfile(x, true)
|
284
|
+
file = update_xrefs(file, identifier)
|
285
|
+
Tempfile.open(["collection", ".xml"], encoding: "utf-8") do |f|
|
286
|
+
f.write(file)
|
287
|
+
f.close
|
288
|
+
# warn "metanorma compile -x html #{f.path}"
|
289
|
+
c = Compile.new
|
290
|
+
c.compile f.path, format: :asciidoc, extension_keys: @format
|
291
|
+
@format.each do |ext|
|
292
|
+
fn = File.basename(filename).sub(/(?<=\.)[^\.]+$/, ext.to_s)
|
293
|
+
FileUtils.mv f.path.sub(/\.xml$/, ".#{ext}"), File.join(@outdir, fn)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
private
|
300
|
+
|
301
|
+
# @param options [Hash]
|
302
|
+
# @raise [ArgumentError]
|
303
|
+
def check_options(options)
|
304
|
+
unless options[:format].is_a?(Array) && (FORMATS & options[:format]).any?
|
305
|
+
raise ArgumentError, "Need to specify formats (xml,html,pdf,doc)"
|
306
|
+
end
|
307
|
+
return if !options[:format].include?(:html) || options[:coverpage]
|
308
|
+
|
309
|
+
raise ArgumentError, "Need to specify a coverpage to render HTML"
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
data/lib/metanorma/compile.rb
CHANGED
@@ -4,14 +4,18 @@ require "htmlentities"
|
|
4
4
|
|
5
5
|
module Metanorma
|
6
6
|
class Compile
|
7
|
+
# @return [Array<String>]
|
8
|
+
attr_reader :errors
|
9
|
+
|
7
10
|
def initialize
|
8
11
|
@registry = Metanorma::Registry.instance
|
12
|
+
@errors = []
|
9
13
|
end
|
10
14
|
|
11
15
|
def compile(filename, options = {})
|
12
16
|
require_libraries(options)
|
13
17
|
options = options_extract(filename, options)
|
14
|
-
|
18
|
+
validate_type(options) && validate_format(options) || (return nil)
|
15
19
|
@processor = @registry.find_processor(options[:type].to_sym)
|
16
20
|
extensions = get_extensions(options) or return nil
|
17
21
|
(file, isodoc = process_input(filename, options)) or return nil
|
@@ -43,6 +47,7 @@ module Metanorma
|
|
43
47
|
o = Metanorma::Input::Asciidoc.new.extract_metanorma_options(content)
|
44
48
|
o = o.merge(xml_options_extract(content))
|
45
49
|
options[:type] ||= o[:type]&.to_sym
|
50
|
+
t = @registry.alias(options[:type]) and options[:type] = t
|
46
51
|
dir = filename.sub(%r(/[^/]+$), "/")
|
47
52
|
options[:relaton] ||= "#{dir}/#{o[:relaton]}" if o[:relaton]
|
48
53
|
options[:sourcecode] ||= "#{dir}/#{o[:sourcecode]}" if o[:sourcecode]
|
@@ -53,10 +58,6 @@ module Metanorma
|
|
53
58
|
options
|
54
59
|
end
|
55
60
|
|
56
|
-
def validate(options)
|
57
|
-
validate_type(options) && validate_format(options)
|
58
|
-
end
|
59
|
-
|
60
61
|
def validate_type(options)
|
61
62
|
unless options[:type]
|
62
63
|
Util.log("[metanorma] Error: Please specify a standard type: #{@registry.supported_backends}.", :error)
|
@@ -89,14 +90,22 @@ module Metanorma
|
|
89
90
|
end
|
90
91
|
|
91
92
|
def get_extensions(options)
|
92
|
-
options[:extension_keys] ||= @processor.output_formats.
|
93
|
-
memo << k
|
93
|
+
options[:extension_keys] ||= @processor.output_formats.reduce([]) do |memo, (k, _)|
|
94
|
+
memo << k
|
94
95
|
end
|
95
|
-
extensions = options[:extension_keys].
|
96
|
-
@processor.output_formats[e]
|
97
|
-
|
98
|
-
|
96
|
+
extensions = options[:extension_keys].reduce([]) do |memo, e|
|
97
|
+
if @processor.output_formats[e]
|
98
|
+
memo << e
|
99
|
+
else
|
100
|
+
message = "[metanorma] Error: #{e} format is not supported for this standard."
|
101
|
+
@errors << message
|
102
|
+
Util.log(message, :error)
|
103
|
+
memo
|
104
|
+
end
|
99
105
|
end
|
106
|
+
if !extensions.include?(:presentation) and extensions.any? { |e| @processor.use_presentation_xml(e) }
|
107
|
+
extensions << :presentation
|
108
|
+
end
|
100
109
|
extensions
|
101
110
|
end
|
102
111
|
|
@@ -110,7 +119,7 @@ module Metanorma
|
|
110
119
|
dir = File.dirname(filename)
|
111
120
|
dir != '.' and
|
112
121
|
file.gsub!(/^include::/, "include::#{dir}/")
|
113
|
-
[file, @processor.input_to_isodoc(file, filename)]
|
122
|
+
[file, @processor.input_to_isodoc(file, filename, options)]
|
114
123
|
when ".xml"
|
115
124
|
Util.log("[metanorma] Processing: Metanorma XML input.", :info)
|
116
125
|
# TODO NN: this is a hack -- we should provide/bridge the
|
@@ -195,28 +204,62 @@ module Metanorma
|
|
195
204
|
end
|
196
205
|
end
|
197
206
|
|
207
|
+
# dependency ordering
|
208
|
+
def sort_extensions_execution(ext)
|
209
|
+
case ext
|
210
|
+
when :xml then 0
|
211
|
+
when :rxl then 1
|
212
|
+
when :presentation then 2
|
213
|
+
else
|
214
|
+
99
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def wrap_html(options, file_extension, outfilename)
|
219
|
+
if options[:wrapper] and /html$/.match file_extension
|
220
|
+
outfilename = outfilename.sub(/\.html$/, "")
|
221
|
+
FileUtils.mkdir_p outfilename
|
222
|
+
FileUtils.mv "#{outfilename}.html", outfilename
|
223
|
+
FileUtils.mv "#{outfilename}_images", outfilename, force: true
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# isodoc is Raw Metanorma XML
|
198
228
|
def process_extensions(extensions, file, isodoc, options)
|
199
|
-
|
229
|
+
f = change_output_dir options
|
230
|
+
xml_name = f.sub(/\.[^.]+$/, ".xml")
|
231
|
+
presentationxml_name = f.sub(/\.[^.]+$/, ".presentation.xml")
|
232
|
+
extensions.sort do |a, b|
|
233
|
+
sort_extensions_execution(a) <=> sort_extensions_execution(b)
|
234
|
+
end.each do |ext|
|
200
235
|
isodoc_options = @processor.extract_options(file)
|
201
236
|
isodoc_options[:datauriimage] = true if options[:datauriimage]
|
202
237
|
file_extension = @processor.output_formats[ext]
|
203
|
-
outfilename =
|
238
|
+
outfilename = f.sub(/\.[^.]+$/, ".#{file_extension}")
|
204
239
|
if ext == :rxl
|
205
240
|
options[:relaton] = outfilename
|
206
241
|
relaton_export(isodoc, options)
|
207
242
|
else
|
208
243
|
begin
|
209
|
-
|
210
|
-
|
244
|
+
@processor.use_presentation_xml(ext) ?
|
245
|
+
@processor.output(nil, presentationxml_name, outfilename, ext, isodoc_options) :
|
246
|
+
@processor.output(isodoc, xml_name, outfilename, ext, isodoc_options)
|
247
|
+
rescue StandardError => e
|
211
248
|
puts e.message
|
212
249
|
end
|
213
250
|
end
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
251
|
+
wrap_html(options, file_extension, outfilename)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
private
|
256
|
+
|
257
|
+
# @param options [Hash]
|
258
|
+
# @return [String]
|
259
|
+
def change_output_dir(options)
|
260
|
+
if options[:"output-dir"]
|
261
|
+
File.join options[:"output-dir"], File.basename(options[:filename])
|
262
|
+
else options[:filename]
|
220
263
|
end
|
221
264
|
end
|
222
265
|
end
|
data/lib/metanorma/document.rb
CHANGED
@@ -1,12 +1,82 @@
|
|
1
1
|
module Metanorma
|
2
2
|
class Document
|
3
|
+
# @return [Strin]
|
4
|
+
attr_reader :file
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
@
|
7
|
-
@
|
8
|
-
@output_formats
|
6
|
+
# @param bibitem [RelatonBib::BibliographicItem]
|
7
|
+
def initialize(bibitem, file)
|
8
|
+
@bibitem = bibitem
|
9
|
+
@file = file
|
9
10
|
end
|
10
11
|
|
12
|
+
class << self
|
13
|
+
# @param file [String] file path
|
14
|
+
# @return [Metanorma::Document]
|
15
|
+
def parse_file(file)
|
16
|
+
new bibitem(file), file
|
17
|
+
end
|
18
|
+
|
19
|
+
# #param xml [Nokogiri::XML::Document, Nokogiri::XML::Element]
|
20
|
+
# @return [Metanorma::Document]
|
21
|
+
def parse_xml(xml)
|
22
|
+
new from_xml(xml)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# #param xml [Nokogiri::XML::Document, Nokogiri::XML::Element]
|
28
|
+
# @return [RelatonBib::BibliographicItem,RelatonIso::IsoBibliographicItem]
|
29
|
+
def from_xml(xml)
|
30
|
+
Relaton::Cli.parse_xml xml.at("//xmlns:bibitem|//xmlns:bibdata")
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param file [String]
|
34
|
+
# @return [Symbol] file type
|
35
|
+
def format(file)
|
36
|
+
case file
|
37
|
+
when /\.xml$/ then :xml
|
38
|
+
when /.ya?ml$/ then :yaml
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param file [String]
|
43
|
+
# @return [RelatonBib::BibliographicItem,
|
44
|
+
# RelatonIso::IsoBibliographicItem]
|
45
|
+
def bibitem(file)
|
46
|
+
case format(file)
|
47
|
+
when :xml
|
48
|
+
from_xml Nokogiri::XML(File.read(file, encoding: "UTF-8"))
|
49
|
+
when :yaml
|
50
|
+
yaml = File.read(file, ecoding: "UTF-8")
|
51
|
+
Relaton::Cli::YAMLConvertor.convert_single_file(yaml)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param builder [Nokogiri::XML::Builder, nil]
|
57
|
+
# @return [Nokogiri::XML::Builder, String]
|
58
|
+
def to_xml(builder = nil)
|
59
|
+
if builder
|
60
|
+
render_xml builder
|
61
|
+
else
|
62
|
+
Nokogiri::XML::Builder.new do |b|
|
63
|
+
root = render_xml b
|
64
|
+
root["xmlns"] = "http://metanorma.org"
|
65
|
+
end.to_xml
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [String]
|
70
|
+
def type
|
71
|
+
@type ||= (@bibitem.docidentifier.first&.type ||
|
72
|
+
@bibitem.docidentifier.first&.id&.match(/^[^\s]+/)&.to_s)&.downcase ||
|
73
|
+
"standoc"
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def render_xml(builder)
|
79
|
+
builder.send(type + "-standard") { |b| @bibitem.to_xml b, bibdata: true }
|
80
|
+
end
|
11
81
|
end
|
12
82
|
end
|
@@ -5,7 +5,7 @@ module Metanorma
|
|
5
5
|
|
6
6
|
class Asciidoc < Base
|
7
7
|
|
8
|
-
def process(file, filename, type)
|
8
|
+
def process(file, filename, type, options = {})
|
9
9
|
require "asciidoctor"
|
10
10
|
::Asciidoctor.convert(
|
11
11
|
file,
|
@@ -13,7 +13,10 @@ module Metanorma
|
|
13
13
|
safe: :safe,
|
14
14
|
backend: type,
|
15
15
|
header_footer: true,
|
16
|
-
attributes: [
|
16
|
+
attributes: [
|
17
|
+
"nodoc", "stem", "xrefstyle=short", "docfile=#{filename}",
|
18
|
+
"output_dir=#{options[:"output-dir"]}"
|
19
|
+
],
|
17
20
|
)
|
18
21
|
end
|
19
22
|
|
@@ -7,7 +7,13 @@ module Metanorma
|
|
7
7
|
def convert(url_path, output_path, xsl_stylesheet)
|
8
8
|
return if url_path.nil? || output_path.nil? || xsl_stylesheet.nil?
|
9
9
|
|
10
|
-
Mn2pdf.convert(url_path, output_path, xsl_stylesheet)
|
10
|
+
Mn2pdf.convert(quote(url_path), quote(output_path), quote(xsl_stylesheet))
|
11
|
+
end
|
12
|
+
|
13
|
+
def quote(x)
|
14
|
+
return x if /^'.*'$/.match(x)
|
15
|
+
return x if /^".*"$/.match(x)
|
16
|
+
%("#{x}")
|
11
17
|
end
|
12
18
|
end
|
13
19
|
end
|
data/lib/metanorma/processor.rb
CHANGED
@@ -15,15 +15,28 @@ module Metanorma
|
|
15
15
|
def output_formats
|
16
16
|
{
|
17
17
|
xml: "xml",
|
18
|
+
presentation: "presentation.xml",
|
18
19
|
rxl: "rxl"
|
19
20
|
}
|
20
21
|
end
|
21
22
|
|
22
|
-
def input_to_isodoc(file, filename)
|
23
|
-
|
23
|
+
def input_to_isodoc(file, filename, options = {})
|
24
|
+
Metanorma::Input::Asciidoc.new.process(file, filename, @asciidoctor_backend, options)
|
25
|
+
end
|
26
|
+
|
27
|
+
# def input_to_isodoc(file, filename)
|
28
|
+
# raise "This is an abstract class!"
|
29
|
+
# end
|
30
|
+
|
31
|
+
def use_presentation_xml(ext)
|
32
|
+
case ext
|
33
|
+
when :html, :doc, :pdf then true
|
34
|
+
else
|
35
|
+
false
|
36
|
+
end
|
24
37
|
end
|
25
38
|
|
26
|
-
def output(isodoc_node, outname, format, options={})
|
39
|
+
def output(isodoc_node, inname, outname, format, options={})
|
27
40
|
File.open(outname, "w:UTF-8") { |f| f.write(isodoc_node) }
|
28
41
|
end
|
29
42
|
|
data/lib/metanorma/registry.rb
CHANGED
@@ -14,14 +14,23 @@ module Metanorma
|
|
14
14
|
|
15
15
|
def initialize
|
16
16
|
@processors = {}
|
17
|
+
@aliases = {csd: :cc, m3d: :m3aawg, mpfd: :mpfa, csand: :csa}
|
18
|
+
end
|
19
|
+
|
20
|
+
def alias(x)
|
21
|
+
@aliases[x]
|
17
22
|
end
|
18
23
|
|
19
24
|
def register processor
|
20
25
|
raise Error unless processor < ::Metanorma::Processor
|
21
26
|
p = processor.new
|
22
|
-
|
23
|
-
|
27
|
+
# p.short[-1] is the canonical name
|
28
|
+
short = Array(p.short)
|
29
|
+
@processors[short[-1]] = p
|
30
|
+
short.each do |s|
|
31
|
+
@aliases[s] = short[-1]
|
24
32
|
end
|
33
|
+
Array(p.short)
|
25
34
|
Util.log("[metanorma] processor \"#{Array(p.short)[0]}\" registered", :info)
|
26
35
|
end
|
27
36
|
|
data/lib/metanorma/version.rb
CHANGED
data/metanorma.gemspec
CHANGED
@@ -26,12 +26,14 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_runtime_dependency 'asciidoctor'
|
27
27
|
spec.add_runtime_dependency 'htmlentities'
|
28
28
|
spec.add_runtime_dependency 'nokogiri'
|
29
|
-
spec.add_runtime_dependency 'mn2pdf', "~> 1
|
29
|
+
spec.add_runtime_dependency 'mn2pdf', "~> 1"
|
30
|
+
spec.add_dependency "relaton-cli", "~> 1.2.0"
|
30
31
|
|
31
32
|
spec.add_development_dependency "rake", "~> 12.0"
|
32
33
|
spec.add_development_dependency "rspec", "~> 3.0"
|
33
34
|
spec.add_development_dependency "byebug", "~> 10.0"
|
34
35
|
spec.add_development_dependency "rspec-command", "~> 1.0"
|
35
36
|
spec.add_development_dependency "equivalent-xml", "~> 0.6"
|
36
|
-
spec.add_development_dependency "metanorma-iso", "~> 1.
|
37
|
+
spec.add_development_dependency "metanorma-iso", "~> 1.5"
|
38
|
+
spec.add_development_dependency "isodoc", "~> 1.2.1"
|
37
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metanorma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asciidoctor
|
@@ -58,14 +58,28 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '1
|
61
|
+
version: '1'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '1
|
68
|
+
version: '1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: relaton-cli
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.2.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.2.0
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rake
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,14 +156,28 @@ dependencies:
|
|
142
156
|
requirements:
|
143
157
|
- - "~>"
|
144
158
|
- !ruby/object:Gem::Version
|
145
|
-
version: '1.
|
159
|
+
version: '1.5'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '1.5'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: isodoc
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 1.2.1
|
146
174
|
type: :development
|
147
175
|
prerelease: false
|
148
176
|
version_requirements: !ruby/object:Gem::Requirement
|
149
177
|
requirements:
|
150
178
|
- - "~>"
|
151
179
|
- !ruby/object:Gem::Version
|
152
|
-
version:
|
180
|
+
version: 1.2.1
|
153
181
|
description: Library to process any Metanorma standard.
|
154
182
|
email:
|
155
183
|
- open.source@ribose.com
|
@@ -182,6 +210,9 @@ files:
|
|
182
210
|
- lib/metanorma.rb
|
183
211
|
- lib/metanorma/asciidoctor_extensions.rb
|
184
212
|
- lib/metanorma/asciidoctor_extensions/glob_include_processor.rb
|
213
|
+
- lib/metanorma/collection.rb
|
214
|
+
- lib/metanorma/collection_manifest.rb
|
215
|
+
- lib/metanorma/collection_renderer.rb
|
185
216
|
- lib/metanorma/compile.rb
|
186
217
|
- lib/metanorma/config.rb
|
187
218
|
- lib/metanorma/document.rb
|
@@ -202,7 +233,7 @@ homepage: https://github.com/metanorma/metanorma
|
|
202
233
|
licenses:
|
203
234
|
- BSD-2-Clause
|
204
235
|
metadata: {}
|
205
|
-
post_install_message:
|
236
|
+
post_install_message:
|
206
237
|
rdoc_options: []
|
207
238
|
require_paths:
|
208
239
|
- lib
|
@@ -217,9 +248,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
217
248
|
- !ruby/object:Gem::Version
|
218
249
|
version: '0'
|
219
250
|
requirements: []
|
220
|
-
|
221
|
-
|
222
|
-
signing_key:
|
251
|
+
rubygems_version: 3.0.3
|
252
|
+
signing_key:
|
223
253
|
specification_version: 4
|
224
254
|
summary: Metanorma is the standard of standards; the metanorma gem allows you to create
|
225
255
|
any standard document type supported by Metanorma.
|