metanorma 2.1.4 → 2.1.6
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 +4 -1
- data/lib/metanorma/collection/collection.rb +9 -3
- data/lib/metanorma/collection/config/manifest.rb +4 -1
- data/lib/metanorma/collection/filelookup/filelookup.rb +13 -4
- data/lib/metanorma/collection/filelookup/filelookup_sectionsplit.rb +1 -1
- data/lib/metanorma/collection/manifest/manifest.rb +1 -6
- data/lib/metanorma/collection/renderer/fileprocess.rb +26 -10
- data/lib/metanorma/collection/renderer/navigation.rb +1 -1
- data/lib/metanorma/collection/renderer/renderer.rb +11 -0
- data/lib/metanorma/compile/compile.rb +248 -92
- data/lib/metanorma/compile/compile_options.rb +87 -82
- data/lib/metanorma/compile/extract.rb +76 -56
- data/lib/metanorma/compile/flavor.rb +57 -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/validator.rb +28 -0
- data/lib/metanorma/compile/writeable.rb +12 -0
- data/lib/metanorma/version.rb +1 -1
- data/metanorma.gemspec +1 -1
- metadata +8 -3
- data/lib/metanorma/compile/compile_validate.rb +0 -68
@@ -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 | .//annotation | .//xmlns:callout | "\
|
40
|
+
".//xmlns: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,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Metanorma
|
4
|
+
class Compile
|
5
|
+
module Flavor
|
6
|
+
# Load the flavor gem for the given standard type
|
7
|
+
# @param stdtype [Symbol] the standard type
|
8
|
+
# @return [void]
|
9
|
+
def load_flavor(stdtype)
|
10
|
+
stdtype = stdtype.to_sym
|
11
|
+
flavor = stdtype2flavor(stdtype)
|
12
|
+
@registry.supported_backends.include? stdtype or
|
13
|
+
Util.log("[metanorma] Info: Loading `#{flavor}` gem "\
|
14
|
+
"for standard type `#{stdtype}`.", :info)
|
15
|
+
require_flavor(flavor)
|
16
|
+
@registry.supported_backends.include? stdtype or
|
17
|
+
Util.log("[metanorma] Error: The `#{flavor}` gem does not "\
|
18
|
+
"support the standard type #{stdtype}. Exiting.", :fatal)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Convert the standard type to the flavor gem name
|
22
|
+
# @param stdtype [Symbol] the standard type
|
23
|
+
# @return [String] the flavor gem name
|
24
|
+
def stdtype2flavor(stdtype)
|
25
|
+
flavor = STDTYPE2FLAVOR[stdtype] || stdtype
|
26
|
+
"metanorma-#{flavor}"
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
STDTYPE2FLAVOR = {}.freeze
|
32
|
+
|
33
|
+
def require_flavor(flavor)
|
34
|
+
require flavor
|
35
|
+
Util.log("[metanorma] Info: gem `#{flavor}` loaded.", :info)
|
36
|
+
rescue LoadError => e
|
37
|
+
error_log = "#{Date.today}-error.log"
|
38
|
+
File.write(error_log, e)
|
39
|
+
|
40
|
+
msg = <<~MSG
|
41
|
+
Error: #{e.message}
|
42
|
+
Metanorma has encountered an exception.
|
43
|
+
|
44
|
+
If this problem persists, please report this issue at the following link:
|
45
|
+
|
46
|
+
* https://github.com/metanorma/metanorma/issues/new
|
47
|
+
|
48
|
+
Please attach the #{error_log} file.
|
49
|
+
Your valuable feedback is very much appreciated!
|
50
|
+
|
51
|
+
- The Metanorma team
|
52
|
+
MSG
|
53
|
+
Util.log(msg, :fatal)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
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
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Metanorma
|
4
|
+
class Compile
|
5
|
+
module Validator
|
6
|
+
def validate_options!(options)
|
7
|
+
validate_type!(options)
|
8
|
+
validate_format!(options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate_type!(options)
|
12
|
+
unless options[:type]
|
13
|
+
Util.log("[metanorma] Error: Please specify a standard type: "\
|
14
|
+
"#{@registry.supported_backends}.", :fatal)
|
15
|
+
end
|
16
|
+
stdtype = options[:type].to_sym
|
17
|
+
load_flavor(stdtype)
|
18
|
+
end
|
19
|
+
|
20
|
+
def validate_format!(options)
|
21
|
+
unless options[:format] == :asciidoc
|
22
|
+
Util.log("[metanorma] Error: Only source file format currently "\
|
23
|
+
"supported is 'asciidoc'.", :fatal)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/metanorma/version.rb
CHANGED
data/metanorma.gemspec
CHANGED
@@ -45,7 +45,7 @@ Gem::Specification.new do |spec|
|
|
45
45
|
spec.add_development_dependency "rspec", "~> 3.0"
|
46
46
|
spec.add_development_dependency "rspec-command", "~> 1.0"
|
47
47
|
spec.add_development_dependency "rubocop", "~> 1"
|
48
|
-
spec.add_development_dependency "rubocop-performance"
|
48
|
+
spec.add_development_dependency "rubocop-performance"
|
49
49
|
spec.add_development_dependency "sassc-embedded", "~> 1"
|
50
50
|
spec.add_development_dependency "simplecov", "~> 0.15"
|
51
51
|
spec.add_development_dependency "xml-c14n"
|
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: 2.1.
|
4
|
+
version: 2.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-03-
|
11
|
+
date: 2025-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asciidoctor
|
@@ -340,8 +340,13 @@ files:
|
|
340
340
|
- lib/metanorma/collection/xrefprocess/xrefprocess.rb
|
341
341
|
- lib/metanorma/compile/compile.rb
|
342
342
|
- lib/metanorma/compile/compile_options.rb
|
343
|
-
- lib/metanorma/compile/compile_validate.rb
|
344
343
|
- lib/metanorma/compile/extract.rb
|
344
|
+
- lib/metanorma/compile/flavor.rb
|
345
|
+
- lib/metanorma/compile/output_filename.rb
|
346
|
+
- lib/metanorma/compile/output_filename_config.rb
|
347
|
+
- lib/metanorma/compile/relaton_drop.rb
|
348
|
+
- lib/metanorma/compile/validator.rb
|
349
|
+
- lib/metanorma/compile/writeable.rb
|
345
350
|
- lib/metanorma/config/config.rb
|
346
351
|
- lib/metanorma/input.rb
|
347
352
|
- lib/metanorma/input/asciidoc.rb
|
@@ -1,68 +0,0 @@
|
|
1
|
-
module Metanorma
|
2
|
-
class Compile
|
3
|
-
def validate_options(options)
|
4
|
-
validate_type(options)
|
5
|
-
validate_format(options)
|
6
|
-
end
|
7
|
-
|
8
|
-
def validate_type(options)
|
9
|
-
unless options[:type]
|
10
|
-
Util.log("[metanorma] Error: Please specify a standard type: "\
|
11
|
-
"#{@registry.supported_backends}.", :fatal)
|
12
|
-
end
|
13
|
-
stdtype = options[:type].to_sym
|
14
|
-
load_flavor(stdtype)
|
15
|
-
end
|
16
|
-
|
17
|
-
def validate_format(options)
|
18
|
-
unless options[:format] == :asciidoc
|
19
|
-
Util.log("[metanorma] Error: Only source file format currently "\
|
20
|
-
"supported is 'asciidoc'.", :fatal)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def load_flavor(stdtype)
|
25
|
-
stdtype = stdtype.to_sym
|
26
|
-
flavor = stdtype2flavor(stdtype)
|
27
|
-
@registry.supported_backends.include? stdtype or
|
28
|
-
Util.log("[metanorma] Info: Loading `#{flavor}` gem "\
|
29
|
-
"for standard type `#{stdtype}`.", :info)
|
30
|
-
require_flavor(flavor)
|
31
|
-
@registry.supported_backends.include? stdtype or
|
32
|
-
Util.log("[metanorma] Error: The `#{flavor}` gem does not "\
|
33
|
-
"support the standard type #{stdtype}. Exiting.", :fatal)
|
34
|
-
end
|
35
|
-
|
36
|
-
def stdtype2flavor(stdtype)
|
37
|
-
flavor = STDTYPE2FLAVOR[stdtype] || stdtype
|
38
|
-
"metanorma-#{flavor}"
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
STDTYPE2FLAVOR = {}.freeze
|
44
|
-
|
45
|
-
def require_flavor(flavor)
|
46
|
-
require flavor
|
47
|
-
Util.log("[metanorma] Info: gem `#{flavor}` loaded.", :info)
|
48
|
-
rescue LoadError => e
|
49
|
-
error_log = "#{Date.today}-error.log"
|
50
|
-
File.write(error_log, e)
|
51
|
-
|
52
|
-
msg = <<~MSG
|
53
|
-
Error: #{e.message}
|
54
|
-
Metanorma has encountered an exception.
|
55
|
-
|
56
|
-
If this problem persists, please report this issue at the following link:
|
57
|
-
|
58
|
-
* https://github.com/metanorma/metanorma/issues/new
|
59
|
-
|
60
|
-
Please attach the #{error_log} file.
|
61
|
-
Your valuable feedback is very much appreciated!
|
62
|
-
|
63
|
-
- The Metanorma team
|
64
|
-
MSG
|
65
|
-
Util.log(msg, :fatal)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|