metanorma-standoc 1.4.4 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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