metanorma-standoc 1.4.4 → 1.6.0

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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/macos.yml +4 -9
  3. data/.github/workflows/ubuntu.yml +1 -5
  4. data/.github/workflows/windows.yml +2 -12
  5. data/.rubocop.yml +1 -1
  6. data/lib/asciidoctor/standoc/base.rb +11 -5
  7. data/lib/asciidoctor/standoc/base_structured_text_preprocessor.rb +123 -0
  8. data/lib/asciidoctor/standoc/basicdoc.rng +23 -0
  9. data/lib/asciidoctor/standoc/cleanup.rb +32 -12
  10. data/lib/asciidoctor/standoc/cleanup_amend.rb +54 -0
  11. data/lib/asciidoctor/standoc/cleanup_block.rb +0 -2
  12. data/lib/asciidoctor/standoc/cleanup_boilerplate.rb +11 -24
  13. data/lib/asciidoctor/standoc/cleanup_footnotes.rb +0 -3
  14. data/lib/asciidoctor/standoc/cleanup_inline.rb +62 -1
  15. data/lib/asciidoctor/standoc/cleanup_ref.rb +10 -7
  16. data/lib/asciidoctor/standoc/cleanup_section.rb +91 -8
  17. data/lib/asciidoctor/standoc/cleanup_terms.rb +12 -2
  18. data/lib/asciidoctor/standoc/converter.rb +3 -3
  19. data/lib/asciidoctor/standoc/front.rb +0 -12
  20. data/lib/asciidoctor/standoc/front_contributor.rb +51 -10
  21. data/lib/asciidoctor/standoc/inline.rb +21 -31
  22. data/lib/asciidoctor/standoc/isodoc.rng +137 -21
  23. data/lib/asciidoctor/standoc/json2_text_preprocessor.rb +44 -0
  24. data/lib/asciidoctor/standoc/log.rb +10 -1
  25. data/lib/asciidoctor/standoc/macros.rb +45 -33
  26. data/lib/asciidoctor/standoc/ref.rb +45 -45
  27. data/lib/asciidoctor/standoc/section.rb +39 -30
  28. data/lib/asciidoctor/standoc/table.rb +3 -2
  29. data/lib/asciidoctor/standoc/utils.rb +18 -1
  30. data/lib/asciidoctor/standoc/validate.rb +30 -18
  31. data/lib/asciidoctor/standoc/validate_section.rb +1 -1
  32. data/lib/asciidoctor/standoc/views/datamodel/model_representation.adoc.erb +10 -10
  33. data/lib/asciidoctor/standoc/yaml2_text_preprocessor.rb +46 -0
  34. data/lib/liquid/custom_blocks/key_iterator.rb +21 -0
  35. data/lib/liquid/custom_filters/values.rb +7 -0
  36. data/lib/metanorma/standoc.rb +0 -5
  37. data/lib/metanorma/standoc/version.rb +20 -1
  38. data/metanorma-standoc.gemspec +4 -5
  39. data/spec/asciidoctor-standoc/base_spec.rb +140 -7
  40. data/spec/asciidoctor-standoc/blocks_spec.rb +275 -149
  41. data/spec/asciidoctor-standoc/cleanup_spec.rb +1372 -56
  42. data/spec/asciidoctor-standoc/inline_spec.rb +133 -6
  43. data/spec/asciidoctor-standoc/isobib_cache_spec.rb +9 -7
  44. data/spec/asciidoctor-standoc/macros_json2text_spec.rb +10 -0
  45. data/spec/asciidoctor-standoc/macros_spec.rb +43 -23
  46. data/spec/asciidoctor-standoc/macros_yaml2text_spec.rb +5 -560
  47. data/spec/asciidoctor-standoc/refs_dl_spec.rb +9 -7
  48. data/spec/asciidoctor-standoc/refs_spec.rb +43 -34
  49. data/spec/asciidoctor-standoc/section_spec.rb +42 -39
  50. data/spec/asciidoctor-standoc/table_spec.rb +119 -113
  51. data/spec/asciidoctor-standoc/validate_spec.rb +45 -1
  52. data/spec/assets/i18n.yaml +17 -2
  53. data/spec/examples/codes_table.html +1365 -1365
  54. data/spec/fixtures/macros_datamodel/address_class_profile.xml +46 -46
  55. data/spec/fixtures/macros_datamodel/address_component_profile.xml +21 -21
  56. data/spec/fixtures/macros_datamodel/blank_definition_profile.xml +21 -21
  57. data/spec/metanorma/processor_spec.rb +1 -2
  58. data/spec/spec_helper.rb +110 -109
  59. data/spec/support/shared_examples/structured_data_2_text_preprocessor.rb +629 -0
  60. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +71 -71
  61. data/spec/vcr_cassettes/isobib_get_123.yml +16 -16
  62. data/spec/vcr_cassettes/isobib_get_123_1.yml +36 -36
  63. data/spec/vcr_cassettes/isobib_get_123_2001.yml +16 -16
  64. data/spec/vcr_cassettes/isobib_get_124.yml +17 -17
  65. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +8 -8
  66. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +39 -37
  67. metadata +29 -14
  68. data/lib/asciidoctor-yaml/i18n-en.yaml +0 -20
  69. data/lib/asciidoctor-yaml/i18n-fr.yaml +0 -13
  70. data/lib/asciidoctor-yaml/i18n-zh-Hans.yaml +0 -15
  71. data/lib/asciidoctor/standoc/i18n.rb +0 -39
  72. data/lib/asciidoctor/standoc/macros_yaml2text.rb +0 -165
  73. data/lib/metanorma/standoc/latexml_requirement.rb +0 -62
  74. data/lib/metanorma/standoc/requirement.rb +0 -13
@@ -1,10 +1,7 @@
1
1
  require "date"
2
- require "nokogiri"
3
2
  require "htmlentities"
4
3
  require "json"
5
- require "pathname"
6
4
  require "open-uri"
7
- require "pp"
8
5
 
9
6
  module Asciidoctor
10
7
  module Standoc
@@ -50,6 +50,10 @@ module Asciidoctor
50
50
 
51
51
  def extract_localities(x)
52
52
  text = x&.children&.first&.remove&.text
53
+ extract_localities1(x, text)
54
+ end
55
+
56
+ def extract_localities1(x, text)
53
57
  b = x.add_child("<localityStack/>").first if LOCALITY_RE.match text
54
58
  while (m = LOCALITY_RE.match text)
55
59
  ref = m[:ref] ? "<referenceFrom>#{tq m[:ref]}</referenceFrom>" : ""
@@ -117,7 +121,8 @@ module Asciidoctor
117
121
  def concept_termbase_cleanup(x)
118
122
  text = x&.children&.first&.remove&.text
119
123
  termbase, key = x["key"].split(/:/, 2)
120
- x.add_child(%(<termref base="#{termbase}" target="#{key}">#{text}</termref>))
124
+ x.add_child(%(<termref base="#{termbase}" target="#{key}">) +
125
+ "#{text}</termref>")
121
126
  end
122
127
 
123
128
  def concept_xref_cleanup(x)
@@ -129,6 +134,62 @@ module Asciidoctor
129
134
  x.children = "<eref>#{x.children.to_xml}</eref>"
130
135
  extract_localities(x.first_element_child)
131
136
  end
137
+
138
+ NAMECHAR = "\u0000-\u0022\u0024\u002c\u002f\u003a-\u0040\\u005b-\u005e"\
139
+ "\u0060\u007b-\u00b6\u00b8-\u00bf\u00d7\u00f7\u037e\u2000-\u200b"\
140
+ "\u200e-\u203e\u2041-\u206f\u2190-\u2bff\u2ff0-\u3000".freeze
141
+ #"\ud800-\uf8ff\ufdd0-\ufdef\ufffe-\uffff".freeze
142
+ NAMESTARTCHAR = "\\u002d\u002e\u0030-\u0039\u00b7\u0300-\u036f"\
143
+ "\u203f-\u2040".freeze
144
+
145
+ def to_ncname(s)
146
+ start = s[0]
147
+ ret1 = %r([#{NAMECHAR}#]).match(start) ? "_" :
148
+ (%r([#{NAMESTARTCHAR}#]).match(start) ? "_#{start}" : start)
149
+ ret2 = s[1..-1] || ""
150
+ ret = (ret1 || "") + ret2.gsub(%r([#{NAMECHAR}#]), "_")
151
+ ret
152
+ end
153
+
154
+ def to_xreftarget(s)
155
+ return to_ncname(s) unless /^[^#]+#.+$/.match(s)
156
+ /^(?<pref>[^#]+)#(?<suff>.+)$/ =~ s
157
+ pref = pref.gsub(%r([#{NAMECHAR}]), "_")
158
+ suff = suff.gsub(%r([#{NAMECHAR}]), "_")
159
+ "#{pref}##{suff}"
160
+ end
161
+
162
+ IDREF = "//*/@id | //review/@from | //review/@to | "\
163
+ "//callout/@target | //citation/@bibitemid | //eref/@bibitemid".freeze
164
+
165
+ def anchor_cleanup(x)
166
+ anchor_cleanup1(x)
167
+ xreftarget_cleanup(x)
168
+ end
169
+
170
+ def anchor_cleanup1(x)
171
+ x.xpath(IDREF).each do |s|
172
+ if (ret = to_ncname(s.value)) != (orig = s.value)
173
+ s.value = ret
174
+ output = s.parent.dup
175
+ output.children.remove
176
+ @log.add("Anchors", s.parent, "normalised identifier in #{output} "\
177
+ "from #{orig}")
178
+ end
179
+ end
180
+ end
181
+
182
+ def xreftarget_cleanup(x)
183
+ x.xpath("//xref/@target").each do |s|
184
+ if (ret = to_xreftarget(s.value)) != (orig = s.value)
185
+ s.value = ret
186
+ output = s.parent.dup
187
+ output.children.remove
188
+ @log.add("Anchors", s.parent, "normalised identifier in #{output} "\
189
+ "from #{orig}")
190
+ end
191
+ end
192
+ end
132
193
  end
133
194
  end
134
195
  end
@@ -49,9 +49,8 @@ module Asciidoctor
49
49
  # consecutively, but that standards codes are preserved as is:
50
50
  # only numeric references are renumbered
51
51
  def biblio_renumber(xmldoc)
52
- r = xmldoc.at("//references[@normative = 'false'] | "\
53
- "//clause[.//references[@normative = 'false']] | "\
54
- "//annex[.//references[@normative = 'false']]") or return
52
+ r = xmldoc.at("//references | //clause[.//references] | "\
53
+ "//annex[.//references]") or return
55
54
  r.xpath(".//bibitem[not(ancestor::bibitem)]").each_with_index do |b, i|
56
55
  next unless docid = b.at("./docidentifier[@type = 'metanorma']")
57
56
  next unless /^\[\d+\]$/.match(docid.text)
@@ -133,14 +132,16 @@ module Asciidoctor
133
132
  end
134
133
 
135
134
  def validate_ref_dl(bib, c)
136
- unless bib["id"]
135
+ id = bib["id"]
136
+ id ||= c["id"] unless /^_/.match(c["id"]) # do not accept implicit id
137
+ unless id
137
138
  @log.add("Anchors", c, "The following reference is missing "\
138
139
  "an anchor:\n" + c.to_xml)
139
140
  return
140
141
  end
141
- bib["title"] or @log.add("Bibliography", c, "Reference #{bib['id']} "\
142
+ bib["title"] or @log.add("Bibliography", c, "Reference #{id} "\
142
143
  "is missing a title")
143
- bib["docid"] or @log.add("Bibliography", c, "Reference #{bib['id']} "\
144
+ bib["docid"] or @log.add("Bibliography", c, "Reference #{id} "\
144
145
  "is missing a document identifier (docid)")
145
146
  end
146
147
 
@@ -201,7 +202,9 @@ module Asciidoctor
201
202
  end
202
203
  if !nested and c.at("./title")
203
204
  title = c.at("./title").remove.children.to_xml
204
- bib["title"] = bib["title"] ? Array(bib["title"]) : []
205
+ bib["title"] = [bib["title"]] if bib["title"].is_a? Hash
206
+ bib["title"] = [bib["title"]] if bib["title"].is_a? String
207
+ bib["title"] = [] unless bib["title"]
205
208
  bib["title"] << title if !title.empty?
206
209
  end
207
210
  bib
@@ -1,8 +1,6 @@
1
1
  require "date"
2
- require "nokogiri"
3
2
  require "htmlentities"
4
3
  require "json"
5
- require "pathname"
6
4
  require "open-uri"
7
5
  require "mathml2asciimath"
8
6
 
@@ -39,6 +37,7 @@ module Asciidoctor
39
37
  dupabstract.traverse { |n| n.remove_attribute("id") }
40
38
  dupabstract.remove_attribute("language")
41
39
  dupabstract.remove_attribute("script")
40
+ dupabstract&.at("./title")&.remove
42
41
  bibabstract.next = dupabstract
43
42
  end
44
43
  end
@@ -105,6 +104,8 @@ module Asciidoctor
105
104
  def sections_cleanup(x)
106
105
  sections_order_cleanup(x)
107
106
  sections_level_cleanup(x)
107
+ sections_names_cleanup(x)
108
+ change_clauses(x)
108
109
  end
109
110
 
110
111
  def obligations_cleanup(x)
@@ -118,15 +119,15 @@ module Asciidoctor
118
119
  (s = x.at("//introduction")) && s["obligation"] = "informative"
119
120
  (s = x.at("//acknowledgements")) && s["obligation"] = "informative"
120
121
  x.xpath("//references").each { |r| r["obligation"] = "informative" }
121
- x.xpath("//preface//clause").each { |r| r["obligation"] = "informative" }
122
+ x.xpath("//preface//clause").each do |r|
123
+ r["obligation"] = "informative"
124
+ end
122
125
  end
123
126
 
124
127
  def obligations_cleanup_norm(x)
125
- (s = x.at("//clause[title = 'Scope']")) && s["obligation"] = "normative"
126
- (s = x.at("//clause[title = 'Symbols and Abbreviated Terms']")) &&
127
- s["obligation"] = "normative"
128
+ (s = x.at("//clause[@type = 'scope']")) && s["obligation"] = "normative"
128
129
  x.xpath("//terms").each { |r| r["obligation"] = "normative" }
129
- x.xpath("//symbols-abbrevs").each { |r| r["obligation"] = "normative" }
130
+ x.xpath("//definitions").each { |r| r["obligation"] = "normative" }
130
131
  end
131
132
 
132
133
  def obligations_cleanup_inherit(x)
@@ -139,16 +140,98 @@ module Asciidoctor
139
140
  end
140
141
 
141
142
  def clausebefore_cleanup(xmldoc)
143
+ preface_clausebefore_cleanup(xmldoc)
144
+ sections_clausebefore_cleanup(xmldoc)
145
+ end
146
+
147
+ def preface_clausebefore_cleanup(xmldoc)
148
+ return unless xmldoc.at("//preface")
149
+ unless ins = xmldoc.at("//preface").children.first
150
+ xmldoc.at("//preface") << " "
151
+ ins = xmldoc.at("//preface").children.first
152
+ end
153
+ xmldoc.xpath("//preface//*[@beforeclauses = 'true']").each do |x|
154
+ x.delete("beforeclauses")
155
+ ins.previous = x.remove
156
+ end
157
+ end
158
+
159
+ def sections_clausebefore_cleanup(xmldoc)
142
160
  return unless xmldoc.at("//sections")
143
161
  unless ins = xmldoc.at("//sections").children.first
144
162
  xmldoc.at("//sections") << " "
145
163
  ins = xmldoc.at("//sections").children.first
146
164
  end
147
- xmldoc.xpath("//*[@beforeclauses = 'true']").each do |x|
165
+ xmldoc.xpath("//sections//*[@beforeclauses = 'true']").each do |x|
148
166
  x.delete("beforeclauses")
149
167
  ins.previous = x.remove
150
168
  end
151
169
  end
170
+
171
+ def get_or_make_title(node)
172
+ unless node.at("./title")
173
+ if node.children.empty?
174
+ node << "<title/>"
175
+ else
176
+ node.children.first.previous = "<title/>"
177
+ end
178
+ end
179
+ node.at("./title")
180
+ end
181
+
182
+ def replace_title(doc, xpath, text, first = false)
183
+ return unless text
184
+ doc.xpath(xpath).each_with_index do |node, i|
185
+ next if first && !i.zero?
186
+ title = get_or_make_title(node)
187
+ fn = title.xpath("./fn")
188
+ fn.each { |n| n.remove }
189
+ title.content = text
190
+ fn.each { |n| title << n }
191
+ end
192
+ end
193
+
194
+ def sections_names_cleanup(x)
195
+ replace_title(x, "//clause[@type = 'scope']", @i18n&.scope)
196
+ replace_title(x, "//preface//abstract", @i18n&.abstract)
197
+ replace_title(x, "//foreword", @i18n&.foreword)
198
+ replace_title(x, "//introduction", @i18n&.introduction)
199
+ replace_title(x, "//acknowledgements", @i18n&.acknowledgements)
200
+ section_names_refs_cleanup(x)
201
+ section_names_terms_cleanup(x)
202
+ end
203
+
204
+ def section_names_refs_cleanup(x)
205
+ replace_title(x, "//references[@normative = 'true']",
206
+ @i18n&.normref, true)
207
+ replace_title(x, "//references[@normative = 'false']",
208
+ @i18n&.bibliography, true)
209
+ end
210
+
211
+ NO_SYMABBR = "[.//definitions[not(@type)]]"
212
+ SYMABBR = "[.//definitions[@type = 'symbols']"\
213
+ "[@type = 'abbreviated_terms']]".freeze
214
+ SYMnoABBR = "[.//definitions[@type = 'symbols']"\
215
+ "[not(@type = 'abbreviated_terms')]]".freeze
216
+ ABBRnoSYM = "[.//definitions[not(@type = 'symbols')]"\
217
+ "[@type = 'abbreviated_terms']]".freeze
218
+
219
+ def section_names_terms_cleanup(x)
220
+ replace_title(x, "//definitions[@type = 'symbols']", @i18n&.symbols)
221
+ replace_title(x, "//definitions[@type = 'abbreviated_terms']", @i18n&.abbrev)
222
+ replace_title(x, "//definitions[not(@type)]", @i18n&.symbolsabbrev)
223
+ replace_title(x, "//terms#{SYMnoABBR} | //clause[.//terms]#{SYMnoABBR}",
224
+ @i18n&.termsdefsymbols, true)
225
+ replace_title(x, "//terms#{ABBRnoSYM} | //clause[.//terms]#{ABBRnoSYM}",
226
+ @i18n&.termsdefabbrev, true)
227
+ replace_title(x, "//terms#{SYMABBR} | //clause[.//terms]#{SYMABBR}",
228
+ @i18n&.termsdefsymbolsabbrev, true)
229
+ replace_title(x, "//terms#{NO_SYMABBR} | //clause[.//terms]#{NO_SYMABBR}",
230
+ @i18n&.termsdefsymbolsabbrev, true)
231
+ replace_title(
232
+ x, "//terms[not(.//definitions)] | //clause[.//terms][not(.//definitions)]",
233
+ @i18n&.termsdef, true)
234
+ end
152
235
  end
153
236
  end
154
237
  end
@@ -76,6 +76,15 @@ module Asciidoctor
76
76
  end
77
77
  end
78
78
 
79
+ def termnote_example_cleanup(xmldoc)
80
+ xmldoc.xpath("//termnote[not(ancestor::term)]").each do |x|
81
+ x.name = "note"
82
+ end
83
+ xmldoc.xpath("//termexample[not(ancestor::term)]").each do |x|
84
+ x.name = "note"
85
+ end
86
+ end
87
+
79
88
  def termdef_cleanup(xmldoc)
80
89
  termdef_from_termbase(xmldoc)
81
90
  termdef_unnest_cleanup(xmldoc)
@@ -83,6 +92,7 @@ module Asciidoctor
83
92
  termdomain_cleanup(xmldoc)
84
93
  termdefinition_cleanup(xmldoc)
85
94
  termdomain1_cleanup(xmldoc)
95
+ termnote_example_cleanup(xmldoc)
86
96
  termdef_boilerplate_cleanup(xmldoc)
87
97
  termdef_subclause_cleanup(xmldoc)
88
98
  term_children_cleanup(xmldoc)
@@ -100,8 +110,8 @@ module Asciidoctor
100
110
  end
101
111
  ret = Nokogiri::XML(key.to_xml)
102
112
  HTMLEntities.new.decode(ret.text).
103
- gsub(/[\[\]\{\}<>\(\)]/, "").strip.
104
- gsub(/[[:punct]]|[_^]/, ":\\0").gsub(/`/, "").
113
+ gsub(/[\[\]\{\}<>\(\)]/, "").gsub(/\s/m, "").
114
+ gsub(/[[:punct:]]|[_^]/, ":\\0").gsub(/`/, "").
105
115
  gsub(/[0-9]+/, "þ\\0")
106
116
  end
107
117
 
@@ -11,7 +11,6 @@ require "asciidoctor/standoc/table"
11
11
  require "asciidoctor/standoc/validate"
12
12
  require "asciidoctor/standoc/utils"
13
13
  require "asciidoctor/standoc/cleanup"
14
- require "asciidoctor/standoc/i18n"
15
14
  require "asciidoctor/standoc/reqt"
16
15
  require_relative "./macros.rb"
17
16
  require_relative "./log.rb"
@@ -25,12 +24,14 @@ module Asciidoctor
25
24
  preprocessor Asciidoctor::Standoc::Datamodel::AttributesTablePreprocessor
26
25
  preprocessor Asciidoctor::Standoc::Datamodel::DiagramPreprocessor
27
26
  preprocessor Asciidoctor::Standoc::Yaml2TextPreprocessor
27
+ preprocessor Asciidoctor::Standoc::Json2TextPreprocessor
28
28
  inline_macro Asciidoctor::Standoc::AltTermInlineMacro
29
29
  inline_macro Asciidoctor::Standoc::DeprecatedTermInlineMacro
30
30
  inline_macro Asciidoctor::Standoc::DomainTermInlineMacro
31
31
  inline_macro Asciidoctor::Standoc::InheritInlineMacro
32
32
  inline_macro Asciidoctor::Standoc::HTML5RubyMacro
33
33
  inline_macro Asciidoctor::Standoc::ConceptInlineMacro
34
+ inline_macro Asciidoctor::Standoc::AutonumberInlineMacro
34
35
  block Asciidoctor::Standoc::ToDoAdmonitionBlock
35
36
  treeprocessor Asciidoctor::Standoc::ToDoInlineAdmonitionBlock
36
37
  block Asciidoctor::Standoc::PlantUMLBlockMacro
@@ -48,7 +49,6 @@ module Asciidoctor
48
49
  include ::Asciidoctor::Standoc::Section
49
50
  include ::Asciidoctor::Standoc::Table
50
51
  include ::Asciidoctor::Standoc::Utils
51
- include ::Asciidoctor::Standoc::I18n
52
52
  include ::Asciidoctor::Standoc::Cleanup
53
53
  include ::Asciidoctor::Standoc::Validate
54
54
 
@@ -67,7 +67,7 @@ module Asciidoctor
67
67
  attr_accessor :_file
68
68
  end
69
69
 
70
- def self.inherited( k )
70
+ def self.inherited(k)
71
71
  k._file = caller_locations.first.absolute_path
72
72
  end
73
73
 
@@ -25,18 +25,6 @@ module Asciidoctor
25
25
  end
26
26
  end
27
27
 
28
- def metadata_copyright(node, xml)
29
- publishers = node.attr("publisher") || " "
30
- publishers.split(/,[ ]?/).each do |p|
31
- xml.copyright do |c|
32
- c.from (node.attr("copyright-year") || Date.today.year)
33
- p.match(/[A-Za-z]/).nil? or c.owner do |owner|
34
- owner.organization { |o| organization(o, p) }
35
- end
36
- end
37
- end
38
- end
39
-
40
28
  def metadata_status(node, xml)
41
29
  xml.status do |s|
42
30
  s.stage ( node.attr("status") || node.attr("docstage") || "published" )
@@ -3,6 +3,7 @@ require "nokogiri"
3
3
  require "htmlentities"
4
4
  require "pathname"
5
5
  require "open-uri"
6
+ require "csv"
6
7
 
7
8
  module Asciidoctor
8
9
  module Standoc
@@ -21,11 +22,22 @@ module Asciidoctor
21
22
  end
22
23
 
23
24
  def organization(org, orgname)
25
+ abbrevs = org_abbrev
26
+ n = abbrevs.invert[orgname] and orgname = n
24
27
  org.name orgname
28
+ a = org_abbrev[orgname] and org.abbreviation a
29
+ end
30
+
31
+ # , " => ," : CSV definition does not deal with space followed by quote
32
+ # at start of field
33
+ def csv_split(s, delim = ",")
34
+ CSV.parse_line(s&.gsub(/, "(?!")/, ',"'),
35
+ liberal_parsing: true,
36
+ col_sep: delim)&.compact&.map { |x| x.strip }
25
37
  end
26
38
 
27
39
  def metadata_author(node, xml)
28
- (node.attr("publisher") || "").split(/,[ ]?/).each do |p|
40
+ csv_split(node.attr("publisher") || default_publisher || "")&.each do |p|
29
41
  xml.contributor do |c|
30
42
  c.role **{ type: "author" }
31
43
  c.organization { |a| organization(a, p) }
@@ -44,18 +56,26 @@ module Asciidoctor
44
56
  end
45
57
  end
46
58
 
59
+ def personal_role(node, c, suffix)
60
+ c.role **{ type: node.attr("role#{suffix}")&.downcase || "author" }
61
+ end
62
+
63
+ def personal_contact(node, suffix, p)
64
+ node.attr("phone#{suffix}") and p.phone node.attr("phone#{suffix}")
65
+ node.attr("fax#{suffix}") and
66
+ p.phone node.attr("fax#{suffix}"), **{type: "fax"}
67
+ node.attr("email#{suffix}") and p.email node.attr("email#{suffix}")
68
+ node.attr("contributor-uri#{suffix}") and
69
+ p.uri node.attr("contributor-uri#{suffix}")
70
+ end
71
+
47
72
  def personal_author1(node, xml, suffix)
48
73
  xml.contributor do |c|
49
- c.role **{ type: node.attr("role#{suffix}")&.downcase || "author" }
74
+ personal_role(node, c, suffix)
50
75
  c.person do |p|
51
76
  person_name(node, xml, suffix, p)
52
77
  person_affiliation(node, xml, suffix, p)
53
- node.attr("phone#{suffix}") and p.phone node.attr("phone#{suffix}")
54
- node.attr("fax#{suffix}") and
55
- p.phone node.attr("fax#{suffix}"), **{type: "fax"}
56
- node.attr("email#{suffix}") and p.email node.attr("email#{suffix}")
57
- node.attr("contributor-uri#{suffix}") and
58
- p.uri node.attr("contributor-uri#{suffix}")
78
+ personal_contact(node, suffix, p)
59
79
  end
60
80
  end
61
81
  end
@@ -85,15 +105,36 @@ module Asciidoctor
85
105
  end
86
106
  end
87
107
 
108
+ def default_publisher
109
+ nil
110
+ end
111
+
112
+ def org_abbrev
113
+ { }
114
+ end
115
+
88
116
  def metadata_publisher(node, xml)
89
- publishers = node.attr("publisher") || return
90
- publishers.split(/,[ ]?/).each do |p|
117
+ publishers = node.attr("publisher") || default_publisher || return
118
+ csv_split(publishers)&.each do |p|
91
119
  xml.contributor do |c|
92
120
  c.role **{ type: "publisher" }
93
121
  c.organization { |a| organization(a, p) }
94
122
  end
95
123
  end
96
124
  end
125
+
126
+ def metadata_copyright(node, xml)
127
+ publishers = node.attr("copyright-holder") || node.attr("publisher") ||
128
+ default_publisher || "-"
129
+ csv_split(publishers)&.each do |p|
130
+ xml.copyright do |c|
131
+ c.from (node.attr("copyright-year") || Date.today.year)
132
+ p.match(/[A-Za-z]/).nil? or c.owner do |owner|
133
+ owner.organization { |o| organization(o, p) }
134
+ end
135
+ end
136
+ end
137
+ end
97
138
  end
98
139
  end
99
140
  end