metanorma 2.1.4 → 2.5.4
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/.rubocop.yml +23 -2
- data/Gemfile +14 -0
- data/README.adoc +1 -1
- data/lib/metanorma/collection/artifact_store.rb +142 -0
- data/lib/metanorma/collection/collection.rb +140 -131
- data/lib/metanorma/collection/config/bibdata.rb +1 -1
- data/lib/metanorma/collection/config/config.rb +50 -20
- data/lib/metanorma/collection/config/converters.rb +89 -31
- data/lib/metanorma/collection/config/doc_container.rb +28 -0
- data/lib/metanorma/collection/config/manifest.rb +30 -6
- data/lib/metanorma/collection/config/namespaces.rb +12 -0
- data/lib/metanorma/collection/document/document.rb +54 -15
- data/lib/metanorma/collection/filelookup/filelookup.rb +170 -74
- data/lib/metanorma/collection/filelookup/filelookup_sectionsplit.rb +62 -27
- data/lib/metanorma/collection/filelookup/utils.rb +52 -0
- data/lib/metanorma/collection/helpers.rb +82 -0
- data/lib/metanorma/collection/log.rb +24 -0
- data/lib/metanorma/collection/manifest/manifest.rb +27 -14
- data/lib/metanorma/collection/multilingual/multilingual.rb +1 -1
- data/lib/metanorma/collection/renderer/filelocation.rb +166 -0
- data/lib/metanorma/collection/renderer/fileparse.rb +60 -55
- data/lib/metanorma/collection/renderer/fileprocess.rb +184 -40
- data/lib/metanorma/collection/renderer/navigation.rb +20 -6
- data/lib/metanorma/collection/renderer/render_word.rb +8 -4
- data/lib/metanorma/collection/renderer/renderer.rb +202 -19
- data/lib/metanorma/collection/renderer/svg.rb +60 -5
- data/lib/metanorma/collection/renderer/utils.rb +76 -42
- data/lib/metanorma/collection/sectionsplit/collection.rb +14 -4
- data/lib/metanorma/collection/sectionsplit/sectionsplit.rb +141 -61
- data/lib/metanorma/collection/util/disambig_files.rb +4 -5
- data/lib/metanorma/collection/util/util.rb +147 -23
- data/lib/metanorma/collection/xrefprocess/xrefprocess.rb +7 -7
- data/lib/metanorma/compile/assets/icc-boilerplate.adoc +41 -0
- data/lib/metanorma/compile/compile.rb +180 -165
- data/lib/metanorma/compile/compile_options.rb +155 -83
- data/lib/metanorma/compile/extract.rb +76 -56
- data/lib/metanorma/compile/flavor.rb +19 -0
- data/lib/metanorma/compile/output_filename.rb +75 -0
- data/lib/metanorma/compile/output_filename_config.rb +27 -0
- data/lib/metanorma/compile/relaton_drop.rb +56 -0
- data/lib/metanorma/compile/render.rb +196 -0
- data/lib/metanorma/compile/validator.rb +26 -0
- data/lib/metanorma/compile/writeable.rb +12 -0
- data/lib/metanorma/util/fontist_helper.rb +35 -19
- data/lib/metanorma/version.rb +1 -1
- data/lib/metanorma.rb +1 -7
- data/metanorma.gemspec +11 -20
- data/plans/collection-rendering-architecture-review.md +516 -0
- metadata +42 -122
- data/.hound.yml +0 -5
- data/lib/metanorma/asciidoctor_extensions/glob_include_processor.rb +0 -22
- data/lib/metanorma/asciidoctor_extensions.rb +0 -1
- data/lib/metanorma/compile/compile_validate.rb +0 -68
- data/lib/metanorma/config/config.rb +0 -23
- data/lib/metanorma/input/asciidoc.rb +0 -88
- data/lib/metanorma/input/base.rb +0 -9
- data/lib/metanorma/input.rb +0 -7
- data/lib/metanorma/processor/processor.rb +0 -54
- data/lib/metanorma/processor.rb +0 -6
- data/lib/metanorma/registry/registry.rb +0 -63
- data/lib/metanorma/util/util.rb +0 -45
|
@@ -2,104 +2,176 @@ require "csv"
|
|
|
2
2
|
|
|
3
3
|
module Metanorma
|
|
4
4
|
class Compile
|
|
5
|
-
|
|
6
|
-
options
|
|
7
|
-
|
|
5
|
+
module CompileOptions
|
|
6
|
+
def require_libraries(options)
|
|
7
|
+
options&.dig(:require)&.each { |r| require r }
|
|
8
|
+
end
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
def extract_xml_options(file)
|
|
11
|
+
xml = Nokogiri::XML(file, &:huge)
|
|
12
|
+
if xml.root
|
|
13
|
+
@registry.root_tags.each do |k, v|
|
|
14
|
+
return { type: k } if v == xml.root.name
|
|
15
|
+
end
|
|
14
16
|
end
|
|
17
|
+
{}
|
|
15
18
|
end
|
|
16
|
-
{}
|
|
17
|
-
end
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
options[:format] ||= :asciidoc
|
|
31
|
-
options[:filename] = filename
|
|
32
|
-
options[:fontlicenseagreement] ||= "no-install-fonts"
|
|
33
|
-
options[:novalid] = o[:novalid] if o[:novalid]
|
|
34
|
-
options
|
|
35
|
-
end
|
|
20
|
+
def extract_options(filename, options)
|
|
21
|
+
o = options_in_file(filename)
|
|
22
|
+
extract_flavor_options(options, o)
|
|
23
|
+
extract_dir_options(options, o, filename)
|
|
24
|
+
extract_extension_options(options, o)
|
|
25
|
+
options[:format] ||= :asciidoc
|
|
26
|
+
options[:filename] = filename
|
|
27
|
+
options[:fontlicenseagreement] ||= "no-install-fonts"
|
|
28
|
+
options[:novalid] = o[:novalid] if o[:novalid]
|
|
29
|
+
options
|
|
30
|
+
end
|
|
36
31
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
32
|
+
def extract_extension_options(opt, doc_opt)
|
|
33
|
+
opt[:extension_keys] == [:all] and opt[:extension_keys] = []
|
|
34
|
+
ext = opt[:extension_keys] || []
|
|
35
|
+
doc_opt[:extensions] == "all" and doc_opt[:extensions] = ""
|
|
36
|
+
ext1 = (doc_opt[:extensions] || "").split(/, */).map(&:to_sym)
|
|
37
|
+
!ext1.empty? && ext.empty? and opt[:extension_keys] = ext1
|
|
38
|
+
opt[:extension_keys]&.empty? and opt[:extension_keys] = nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def options_in_file(filename)
|
|
42
|
+
content = read_file(filename)
|
|
43
|
+
Metanorma::Input::Asciidoc.new.extract_metanorma_options(content)
|
|
44
|
+
.merge(extract_xml_options(content))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def extract_flavor_options(options, options_in_file)
|
|
48
|
+
options[:type] ||= options_in_file[:type]
|
|
49
|
+
options[:type] = options[:type]&.to_sym
|
|
50
|
+
options[:supplied_type] = options[:type]
|
|
51
|
+
t = @registry.alias(options[:type]) and options[:type] = t
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def extract_dir_options(options, options_in_file, filename)
|
|
55
|
+
filename.is_a?(Tempfile) and return
|
|
56
|
+
dir = filename.sub(%r(/[^/]+$), "/")
|
|
57
|
+
options_in_file[:relaton] and
|
|
58
|
+
options[:relaton] ||= File.join(dir,
|
|
59
|
+
options_in_file[:relaton])
|
|
60
|
+
options_in_file[:sourcecode] and
|
|
61
|
+
options[:sourcecode] ||= File.join(dir,
|
|
62
|
+
options_in_file[:sourcecode])
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Document-model transformer specs contributed by the active taste
|
|
66
|
+
# (+options[:supplied_type]+), or +{}+. Lets a taste (e.g. OIML) make its
|
|
67
|
+
# own output format selectable and choose its presentation/semantic leg,
|
|
68
|
+
# via the taste-aware metanorma-core Processor (metanorma-core#12).
|
|
69
|
+
def taste_transformers(options)
|
|
70
|
+
taste = options[:supplied_type]
|
|
71
|
+
return {} unless taste && defined?(Metanorma::TasteRegister) &&
|
|
72
|
+
Metanorma::TasteRegister.respond_to?(:document_transformers_for)
|
|
73
|
+
|
|
74
|
+
Metanorma::TasteRegister.document_transformers_for(taste) || {}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# The processor's output formats merged with the suffixes of any
|
|
78
|
+
# taste-contributed document-model formats, so those formats pass
|
|
79
|
+
# extension validation and get an output suffix.
|
|
80
|
+
def effective_output_formats(options)
|
|
81
|
+
@processor.output_formats.merge(
|
|
82
|
+
taste_transformers(options)
|
|
83
|
+
.transform_values { |spec| spec[:suffix] }.compact,
|
|
84
|
+
)
|
|
85
|
+
end
|
|
46
86
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
87
|
+
# Whether +ext+ is generated from presentation XML, honouring both the
|
|
88
|
+
# processor's own answer and a taste transformer's +:presentation+ flag.
|
|
89
|
+
def uses_presentation_xml?(ext, options)
|
|
90
|
+
@processor.use_presentation_xml(ext) ||
|
|
91
|
+
(taste_transformers(options)[ext] || {})[:presentation] == true
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def get_extensions(options)
|
|
95
|
+
ext = extract_extensions(options)
|
|
96
|
+
!ext.include?(:presentation) && ext.any? do |e|
|
|
97
|
+
uses_presentation_xml?(e, options)
|
|
98
|
+
end and ext << :presentation
|
|
99
|
+
!ext.include?(:rxl) && options[:site_generate] and
|
|
100
|
+
ext << :rxl
|
|
101
|
+
ext
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def extract_extensions(options)
|
|
105
|
+
formats = effective_output_formats(options)
|
|
106
|
+
options[:extension_keys] ||=
|
|
107
|
+
formats.reduce([]) { |memo, (k, _)| memo << k }
|
|
108
|
+
options[:extension_keys].reduce([]) do |memo, e|
|
|
109
|
+
if formats[e] then memo << e
|
|
110
|
+
else
|
|
111
|
+
unsupported_format_error(e)
|
|
112
|
+
memo
|
|
113
|
+
end
|
|
55
114
|
end
|
|
56
115
|
end
|
|
57
|
-
end
|
|
58
116
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
117
|
+
def font_install(opt)
|
|
118
|
+
@fontist_installed or
|
|
119
|
+
Util::FontistHelper.install_fonts(@processor, opt)
|
|
120
|
+
@fontist_installed = true
|
|
121
|
+
end
|
|
64
122
|
|
|
65
|
-
|
|
123
|
+
private
|
|
66
124
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
125
|
+
def unsupported_format_error(ext)
|
|
126
|
+
message = "[metanorma] Error: #{ext} format is not supported " \
|
|
127
|
+
"for this standard."
|
|
128
|
+
@errors << message
|
|
129
|
+
Util.log(message, :error)
|
|
130
|
+
end
|
|
73
131
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
end
|
|
132
|
+
def get_isodoc_options(file, options, ext)
|
|
133
|
+
ret = @processor.extract_options(file)
|
|
134
|
+
get_isodoc_fileparams(options, ret)
|
|
135
|
+
copy_isodoc_options_attrs(options, ret)
|
|
136
|
+
font_manifest_mn2pdf(options, ret, ext)
|
|
137
|
+
ret[:output_formats]&.select! do |k, _|
|
|
138
|
+
options[:extension_keys].include?(k)
|
|
139
|
+
end
|
|
140
|
+
ret[:log] = @log
|
|
141
|
+
ret
|
|
142
|
+
end
|
|
86
143
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
144
|
+
def get_isodoc_fileparams(options, ret)
|
|
145
|
+
%i(i18nyaml relatonrenderconfig).each do |k|
|
|
146
|
+
dir = File.dirname(options[:filename])
|
|
147
|
+
ret[k] or next
|
|
148
|
+
(Pathname.new ret[k]).absolute? or
|
|
149
|
+
ret[k] = File.join(dir, ret[k])
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def copy_isodoc_options_attrs(options, ret)
|
|
154
|
+
ret[:datauriimage] = true if options[:datauriimage]
|
|
155
|
+
ret[:sourcefilename] = options[:filename]
|
|
156
|
+
# Carry the active taste through to Processor#output, so its taste-aware
|
|
157
|
+
# document_transformers resolve there (metanorma-core#12).
|
|
158
|
+
ret[:supplied_type] = options[:supplied_type]
|
|
159
|
+
%i(bare sectionsplit sectionsplit_filename install_fonts baseassetpath
|
|
160
|
+
aligncrosselements tocfigures toctables tocrecommendations tocexamples
|
|
161
|
+
strict fonts)
|
|
162
|
+
.each { |x| ret[x] ||= options[x] }
|
|
163
|
+
end
|
|
94
164
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
165
|
+
def font_manifest_mn2pdf(options, ret, ext)
|
|
166
|
+
custom_fonts = Util::FontistHelper
|
|
167
|
+
.has_custom_fonts?(@processor, options, ret)
|
|
98
168
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
169
|
+
ext == :pdf && custom_fonts and
|
|
170
|
+
ret[:mn2pdf] = {
|
|
171
|
+
font_manifest: Util::FontistHelper
|
|
172
|
+
.location_manifest(@processor, ret),
|
|
173
|
+
}
|
|
174
|
+
end
|
|
103
175
|
end
|
|
104
176
|
end
|
|
105
177
|
end
|
|
@@ -1,68 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "writeable"
|
|
4
|
+
|
|
1
5
|
module Metanorma
|
|
2
6
|
class Compile
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
module Extract
|
|
8
|
+
# @param isodoc [String] the XML document
|
|
9
|
+
# @param dirname [String, nil] the directory to extract to
|
|
10
|
+
# @param extract_types [Array<Symbol>, nil] the types to extract
|
|
11
|
+
# @return [void]
|
|
12
|
+
def self.extract(isodoc, dirname, extract_types)
|
|
13
|
+
dirname or return
|
|
14
|
+
extract_types.nil? || extract_types.empty? and
|
|
15
|
+
extract_types = %i[sourcecode image requirement]
|
|
16
|
+
FileUtils.rm_rf dirname
|
|
17
|
+
FileUtils.mkdir_p dirname
|
|
18
|
+
xml = Nokogiri::XML(isodoc, &:huge)
|
|
19
|
+
extract_types.each do |type|
|
|
20
|
+
case type
|
|
21
|
+
when :sourcecode
|
|
22
|
+
export_sourcecode(xml, dirname)
|
|
23
|
+
when :image
|
|
24
|
+
export_image(xml, dirname)
|
|
25
|
+
when :requirement
|
|
26
|
+
export_requirement(xml, dirname)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
9
30
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
".//xmlns:annotation").each(&:remove)
|
|
13
|
-
xml.xpath(".//br | .//xmlns:br").each { |x| x.replace("\n") }
|
|
14
|
-
a = xml.at("./body | ./xmlns:body") and xml = a
|
|
15
|
-
HTMLEntities.new.decode(xml.children.to_xml)
|
|
16
|
-
end
|
|
31
|
+
class << self
|
|
32
|
+
include Writeable
|
|
17
33
|
|
|
18
|
-
|
|
19
|
-
dirname or return
|
|
20
|
-
extract_types.nil? || extract_types.empty? and
|
|
21
|
-
extract_types = %i[sourcecode image requirement]
|
|
22
|
-
FileUtils.rm_rf dirname
|
|
23
|
-
FileUtils.mkdir_p dirname
|
|
24
|
-
xml = Nokogiri::XML(isodoc, &:huge)
|
|
25
|
-
sourcecode_export(xml, dirname) if extract_types.include? :sourcecode
|
|
26
|
-
image_export(xml, dirname) if extract_types.include? :image
|
|
27
|
-
extract_types.include?(:requirement) and
|
|
28
|
-
requirement_export(xml, dirname)
|
|
29
|
-
end
|
|
34
|
+
private
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
# @param xml [Nokogiri::XML::Document] the XML document
|
|
37
|
+
# @return [String] the cleaned sourcecode
|
|
38
|
+
def clean_sourcecode(xml)
|
|
39
|
+
xml.xpath(".//callout | .//callout-annotation | .//xmlns:callout | "\
|
|
40
|
+
".//xmlns:callout-annotation").each(&:remove)
|
|
41
|
+
xml.xpath(".//br | .//xmlns:br").each { |x| x.replace("\n") }
|
|
42
|
+
a = xml.at("./body | ./xmlns:body") and xml = a
|
|
43
|
+
HTMLEntities.new.decode(xml.children.to_xml)
|
|
44
|
+
end
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
def export_sourcecode(xml, dirname)
|
|
47
|
+
xml.at("//sourcecode | //xmlns:sourcecode") or return
|
|
48
|
+
FileUtils.mkdir_p "#{dirname}/sourcecode"
|
|
49
|
+
xml.xpath("//sourcecode | //xmlns:sourcecode").each_with_index do |s, i|
|
|
50
|
+
filename = s["filename"] || sprintf("sourcecode-%04d.txt", i)
|
|
51
|
+
export_output("#{dirname}/sourcecode/#{filename}",
|
|
52
|
+
clean_sourcecode(s.dup))
|
|
53
|
+
end
|
|
54
|
+
end
|
|
46
55
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
def export_image(xml, dirname)
|
|
57
|
+
xml.at("//image | //xmlns:image") or return
|
|
58
|
+
FileUtils.mkdir_p "#{dirname}/image"
|
|
59
|
+
xml.xpath("//image | //xmlns:image").each_with_index do |s, i|
|
|
60
|
+
next unless /^data:image/.match? s["src"]
|
|
61
|
+
|
|
62
|
+
%r{^data:image/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ s["src"]
|
|
63
|
+
fn = s["filename"] || sprintf("image-%<num>04d.%<name>s",
|
|
64
|
+
num: i, name: imgtype)
|
|
65
|
+
export_output(
|
|
66
|
+
"#{dirname}/image/#{fn}",
|
|
67
|
+
Base64.strict_decode64(imgdata),
|
|
68
|
+
binary: true,
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
54
72
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
73
|
+
REQUIREMENT_XPATH =
|
|
74
|
+
"//requirement | //xmlns:requirement | //recommendation | "\
|
|
75
|
+
"//xmlns:recommendation | //permission | //xmlns:permission"
|
|
58
76
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
77
|
+
def export_requirement(xml, dirname)
|
|
78
|
+
xml.at(REQUIREMENT_XPATH) or return
|
|
79
|
+
FileUtils.mkdir_p "#{dirname}/requirement"
|
|
80
|
+
xml.xpath(REQUIREMENT_XPATH).each_with_index do |s, i|
|
|
81
|
+
fn = s["filename"] ||
|
|
82
|
+
sprintf("%<name>s-%<num>04d.xml", name: s.name, num: i)
|
|
83
|
+
export_output("#{dirname}/requirement/#{fn}", s)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
66
86
|
end
|
|
67
87
|
end
|
|
68
88
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Metanorma
|
|
4
|
+
class Compile
|
|
5
|
+
module Flavor
|
|
6
|
+
def load_flavor(stdtype)
|
|
7
|
+
Metanorma::Core::FlavorLoader.load_flavor(stdtype)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def taste2flavor(stdtype)
|
|
11
|
+
Metanorma::Core::FlavorLoader.taste2flavor(stdtype)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def stdtype2flavor_gem(stdtype)
|
|
15
|
+
Metanorma::Core::FlavorLoader.stdtype2flavor_gem(stdtype)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Metanorma
|
|
4
|
+
class Compile
|
|
5
|
+
class OutputFilename
|
|
6
|
+
# Returns an instance of OutputFilename from the source filename
|
|
7
|
+
# @param source_filename [String] the source filename
|
|
8
|
+
# @param output_dir [String, nil] the output directory
|
|
9
|
+
# @param processor [Metanorma::Processor, nil] the processor
|
|
10
|
+
# @return [OutputFilename] the instance of OutputFilename
|
|
11
|
+
def self.from_filename(source_filename, output_dir = nil, processor = nil)
|
|
12
|
+
new(strip_ext(source_filename), output_dir, processor)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def strip_ext(filename)
|
|
19
|
+
filename.sub(/\.[^.]*$/, "")
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @param noext_filename [String] the path (absolute/relative) of the source file, without extension (e.g., "/a/b/c/test")
|
|
24
|
+
# @param output_dir [String, nil] the output directory
|
|
25
|
+
# @param processor [Metanorma::Processor, nil] the processor
|
|
26
|
+
# @return [OutputFilename] the instance of OutputFilename
|
|
27
|
+
def initialize(noext_filename, output_dir = nil, processor = nil)
|
|
28
|
+
@noext_filename = noext_filename
|
|
29
|
+
@output_dir = output_dir
|
|
30
|
+
@processor = processor
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns the full file path name with the semantic XML extension
|
|
34
|
+
# @return [String] the full file path name with the semantic XML extension
|
|
35
|
+
def semantic_xml
|
|
36
|
+
with_extension("xml")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Returns the full file path name with the presentation XML extension
|
|
40
|
+
# @return [String] the full file path name with the presentation XML extension
|
|
41
|
+
def presentation_xml
|
|
42
|
+
with_extension("presentation.xml")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Returns the full file path name with the given format extension
|
|
46
|
+
# @param format [Symbol] the format
|
|
47
|
+
# @return [String, nil] the full file path name with the format extension
|
|
48
|
+
def for_format(format)
|
|
49
|
+
ext = @processor&.output_formats&.[](format)
|
|
50
|
+
ext ? with_extension(ext) : nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns the full file path name with the given extension
|
|
54
|
+
# @param ext [String] the extension
|
|
55
|
+
# @return [String] the full file path name with the extension
|
|
56
|
+
def with_extension(ext)
|
|
57
|
+
file = change_output_dir
|
|
58
|
+
"#{file}.#{ext}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def change_output_dir
|
|
64
|
+
File.expand_path(if !@output_dir.nil?
|
|
65
|
+
File.join(
|
|
66
|
+
@output_dir,
|
|
67
|
+
File.basename(@noext_filename),
|
|
68
|
+
)
|
|
69
|
+
else
|
|
70
|
+
@noext_filename
|
|
71
|
+
end)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Metanorma
|
|
4
|
+
class Compile
|
|
5
|
+
class OutputFilenameConfig
|
|
6
|
+
DEFAULT_TEMPLATE =
|
|
7
|
+
"{{ document.docidentifier | downcase" \
|
|
8
|
+
" | replace: '/' , '-'" \
|
|
9
|
+
" | replace: ' ' , '-' }}"
|
|
10
|
+
|
|
11
|
+
attr_reader :template
|
|
12
|
+
|
|
13
|
+
def initialize(template)
|
|
14
|
+
@template = if template.nil? || template.empty?
|
|
15
|
+
DEFAULT_TEMPLATE
|
|
16
|
+
else
|
|
17
|
+
template
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def generate_filename(relaton_data)
|
|
22
|
+
template = Liquid::Template.parse(@template)
|
|
23
|
+
template.render("document" => relaton_data)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "liquid"
|
|
4
|
+
|
|
5
|
+
module Metanorma
|
|
6
|
+
class Compile
|
|
7
|
+
class RelatonDrop < Liquid::Drop
|
|
8
|
+
def initialize(relaton_data)
|
|
9
|
+
@relaton = relaton_data
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def docidentifier
|
|
13
|
+
at("./docidentifier")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def title
|
|
17
|
+
at("./title")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def date
|
|
21
|
+
at("./date/on")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def publisher
|
|
25
|
+
at("./contributor[role/@type = 'publisher']/organization/name")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def language
|
|
29
|
+
at("./language")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def script
|
|
33
|
+
at("./script")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def version
|
|
37
|
+
at("./version")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def slugify
|
|
41
|
+
docidentifier&.downcase
|
|
42
|
+
&.gsub(/[^a-z0-9]+/, "-")
|
|
43
|
+
&.gsub(/-+/, "-")
|
|
44
|
+
&.gsub(/^-|-$/, "")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def at(xpath)
|
|
50
|
+
@relaton.at(xpath)&.text
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|