metanorma-standoc 1.10.3 → 1.10.5

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/lib/asciidoctor/standoc/base.rb +15 -5
  3. data/lib/asciidoctor/standoc/blocks.rb +37 -31
  4. data/lib/asciidoctor/standoc/cleanup.rb +12 -69
  5. data/lib/asciidoctor/standoc/cleanup_block.rb +6 -3
  6. data/lib/asciidoctor/standoc/cleanup_maths.rb +113 -21
  7. data/lib/asciidoctor/standoc/cleanup_reqt.rb +60 -14
  8. data/lib/asciidoctor/standoc/cleanup_section.rb +1 -0
  9. data/lib/asciidoctor/standoc/cleanup_section_names.rb +31 -14
  10. data/lib/asciidoctor/standoc/cleanup_text.rb +70 -0
  11. data/lib/asciidoctor/standoc/converter.rb +2 -0
  12. data/lib/asciidoctor/standoc/isodoc.rng +29 -9
  13. data/lib/asciidoctor/standoc/lists.rb +9 -6
  14. data/lib/asciidoctor/standoc/reqt.rb +39 -27
  15. data/lib/asciidoctor/standoc/reqt.rng +15 -4
  16. data/lib/asciidoctor/standoc/table.rb +22 -20
  17. data/lib/asciidoctor/standoc/validate_section.rb +2 -1
  18. data/lib/isodoc/base.standard.xsl +6003 -0
  19. data/lib/isodoc/pdf_convert.rb +20 -0
  20. data/lib/metanorma/standoc/processor.rb +5 -1
  21. data/lib/metanorma/standoc/version.rb +1 -1
  22. data/lib/metanorma-standoc.rb +1 -0
  23. data/metanorma-standoc.gemspec +1 -1
  24. data/spec/asciidoctor/base_spec.rb +6 -0
  25. data/spec/asciidoctor/blocks_spec.rb +43 -23
  26. data/spec/asciidoctor/cleanup_sections_spec.rb +67 -1
  27. data/spec/asciidoctor/cleanup_spec.rb +148 -21
  28. data/spec/asciidoctor/isobib_cache_spec.rb +8 -8
  29. data/spec/asciidoctor/macros_spec.rb +114 -1
  30. data/spec/asciidoctor/refs_dl_spec.rb +1 -1
  31. data/spec/asciidoctor/refs_spec.rb +218 -442
  32. data/spec/asciidoctor/section_spec.rb +1 -1
  33. data/spec/asciidoctor/validate_spec.rb +4 -0
  34. data/spec/examples/datamodel/address_class_profile.adoc +1 -0
  35. data/spec/examples/datamodel/address_component_profile.adoc +1 -0
  36. data/spec/examples/datamodel/blank_definition_profile.adoc +1 -0
  37. data/spec/examples/datamodel/common_models_diagram.adoc +2 -1
  38. data/spec/examples/datamodel/top_down_diagram.adoc +2 -1
  39. data/spec/fixtures/datamodel_description_sections_tree.xml +326 -0
  40. data/spec/fixtures/test.xmi +9250 -0
  41. data/spec/metanorma/processor_spec.rb +50 -50
  42. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +231 -143
  43. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec1.yml +152 -0
  44. data/spec/vcr_cassettes/isobib_get_123.yml +51 -35
  45. data/spec/vcr_cassettes/isobib_get_123_1.yml +103 -71
  46. data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +112 -80
  47. data/spec/vcr_cassettes/isobib_get_123_2001.yml +51 -35
  48. data/spec/vcr_cassettes/isobib_get_124.yml +51 -35
  49. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +14 -14
  50. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +49 -47
  51. metadata +10 -4
@@ -1,40 +1,42 @@
1
1
  module Asciidoctor
2
2
  module Standoc
3
3
  module Cleanup
4
- def requirement_cleanup(reqt)
5
- requirement_descriptions(reqt)
6
- requirement_inherit(reqt)
4
+ def requirement_cleanup(xmldoc)
5
+ requirement_metadata(xmldoc)
6
+ requirement_descriptions(xmldoc)
7
+ requirement_inherit(xmldoc)
7
8
  end
8
9
 
9
- def requirement_inherit(reqt)
10
- reqt.xpath("//requirement | //recommendation | //permission")
11
- .each do |r|
10
+ REQRECPER = "//requirement | //recommendation | //permission".freeze
11
+
12
+ def requirement_inherit(xmldoc)
13
+ xmldoc.xpath(REQRECPER).each do |r|
12
14
  ins = r.at("./classification") ||
13
15
  r.at("./description | ./measurementtarget | ./specification | "\
14
16
  "./verification | ./import | ./description | ./requirement | "\
15
- "./recommendation | ./permission")
17
+ "./recommendation | ./permission | ./component")
16
18
  r.xpath("./*//inherit").each { |i| ins.previous = i }
17
19
  end
18
20
  end
19
21
 
20
- def requirement_descriptions(reqt)
21
- reqt.xpath("//requirement | //recommendation | //permission")
22
- .each do |r|
22
+ def requirement_descriptions(xmldoc)
23
+ xmldoc.xpath(REQRECPER).each do |r|
23
24
  r.children.each do |e|
24
25
  unless e.element? && (reqt_subpart(e.name) ||
25
26
  %w(requirement recommendation permission).include?(e.name))
26
- t = Nokogiri::XML::Element.new("description", reqt)
27
+ next if e.text.strip.empty?
28
+ t = Nokogiri::XML::Element.new("description", r)
27
29
  e.before(t)
28
30
  t.children = e.remove
29
31
  end
30
32
  end
31
- requirement_cleanup1(r)
33
+ requirement_description_cleanup1(r)
32
34
  end
33
35
  end
34
36
 
35
- def requirement_cleanup1(reqt)
37
+ def requirement_description_cleanup1(reqt)
36
38
  while d = reqt.at("./description[following-sibling::*[1]"\
37
- "[self::description]]")
39
+ "[self::description]]")
38
40
  n = d.next.remove
39
41
  d << n.children
40
42
  end
@@ -42,6 +44,50 @@ module Asciidoctor
42
44
  r.replace("\n")
43
45
  end
44
46
  end
47
+
48
+ def requirement_metadata(xmldoc)
49
+ xmldoc.xpath(REQRECPER).each do |r|
50
+ dl = r&.at("./dl[@metadata = 'true']")&.remove or next
51
+ requirement_metadata1(r, dl)
52
+ end
53
+ end
54
+
55
+ def requirement_metadata1(reqt, dlist)
56
+ unless ins = reqt.at("./title")
57
+ reqt.children.first.previous = " "
58
+ ins = reqt.children.first
59
+ end
60
+ %w(label subject inherit).each do |a|
61
+ ins = reqt_dl_to_elems(ins, reqt, dlist, a)
62
+ end
63
+ reqt_dl_to_classif(ins, reqt, dlist)
64
+ end
65
+
66
+ def reqt_dl_to_elems(ins, reqt, dlist, name)
67
+ if a = reqt.at("./#{name}[last()]")
68
+ ins = a
69
+ end
70
+ dlist.xpath("./dt[text()='#{name}']").each do |e|
71
+ val = e.at("./following::dd/p") || e.at("./following::dd")
72
+ val.name = name
73
+ ins.next = val
74
+ ins = ins.next
75
+ end
76
+ ins
77
+ end
78
+
79
+ def reqt_dl_to_classif(ins, reqt, dlist)
80
+ if a = reqt.at("./classification[last()]")
81
+ ins = a
82
+ end
83
+ dlist.xpath("./dt[text()='classification']").each do |e|
84
+ val = e.at("./following::dd/p") || e.at("./following::dd")
85
+ req_classif_parse(val.text).each do |r|
86
+ ins.next = "<classification><tag>#{r[0]}</tag>"\
87
+ "<value>#{r[1]}</value></classification>"
88
+ end
89
+ end
90
+ end
45
91
  end
46
92
  end
47
93
  end
@@ -114,6 +114,7 @@ module Asciidoctor
114
114
  sections_order_cleanup(xml)
115
115
  sections_level_cleanup(xml)
116
116
  sections_names_cleanup(xml)
117
+ sections_variant_title_cleanup(xml)
117
118
  change_clauses(xml)
118
119
  end
119
120
 
@@ -37,39 +37,56 @@ module Asciidoctor
37
37
  end
38
38
 
39
39
  def section_names_refs_cleanup(xml)
40
- replace_title(xml, "//references[@normative = 'true']",
40
+ replace_title(xml, "//bibliography/references[@normative = 'true']",
41
41
  @i18n&.normref, true)
42
- replace_title(xml, "//references[@normative = 'false']",
42
+ replace_title(xml, "//bibliography/references[@normative = 'false']",
43
43
  @i18n&.bibliography, true)
44
44
  end
45
45
 
46
46
  NO_SYMABBR = "[.//definitions[not(@type)]]".freeze
47
47
  SYMABBR = "[.//definitions[@type = 'symbols']]"\
48
- "[.//definitions[@type = 'abbreviated_terms']]".freeze
48
+ "[.//definitions[@type = 'abbreviated_terms']]".freeze
49
49
  SYMnoABBR = "[.//definitions[@type = 'symbols']]"\
50
- "[not(.//definitions[@type = 'abbreviated_terms'])]".freeze
50
+ "[not(.//definitions[@type = 'abbreviated_terms'])]".freeze
51
51
  ABBRnoSYM = "[.//definitions[@type = 'abbreviated_terms']]"\
52
- "[not(.//definitions[@type = 'symbols'])]".freeze
52
+ "[not(.//definitions[@type = 'symbols'])]".freeze
53
53
 
54
- def section_names_terms_cleanup(x)
55
- replace_title(x, "//definitions[@type = 'symbols']", @i18n&.symbols)
56
- replace_title(x, "//definitions[@type = 'abbreviated_terms']",
54
+ def section_names_terms_cleanup(xml)
55
+ replace_title(xml, "//definitions[@type = 'symbols']", @i18n&.symbols)
56
+ replace_title(xml, "//definitions[@type = 'abbreviated_terms']",
57
57
  @i18n&.abbrev)
58
- replace_title(x, "//definitions[not(@type)]", @i18n&.symbolsabbrev)
59
- replace_title(x, "//terms#{SYMnoABBR} | //clause[.//terms]#{SYMnoABBR}",
58
+ replace_title(xml, "//definitions[not(@type)]", @i18n&.symbolsabbrev)
59
+ replace_title(xml, "//terms#{SYMnoABBR} | //clause[.//terms]#{SYMnoABBR}",
60
60
  @i18n&.termsdefsymbols, true)
61
- replace_title(x, "//terms#{ABBRnoSYM} | //clause[.//terms]#{ABBRnoSYM}",
61
+ replace_title(xml, "//terms#{ABBRnoSYM} | //clause[.//terms]#{ABBRnoSYM}",
62
62
  @i18n&.termsdefabbrev, true)
63
- replace_title(x, "//terms#{SYMABBR} | //clause[.//terms]#{SYMABBR}",
63
+ replace_title(xml, "//terms#{SYMABBR} | //clause[.//terms]#{SYMABBR}",
64
64
  @i18n&.termsdefsymbolsabbrev, true)
65
- replace_title(x, "//terms#{NO_SYMABBR} | //clause[.//terms]#{NO_SYMABBR}",
65
+ replace_title(xml, "//terms#{NO_SYMABBR} | //clause[.//terms]#{NO_SYMABBR}",
66
66
  @i18n&.termsdefsymbolsabbrev, true)
67
67
  replace_title(
68
- x,
68
+ xml,
69
69
  "//terms[not(.//definitions)] | //clause[.//terms][not(.//definitions)]",
70
70
  @i18n&.termsdef, true
71
71
  )
72
72
  end
73
+
74
+ SECTION_CONTAINERS = %w(foreword introduction acknowledgements abstract
75
+ clause clause references terms definitions annex
76
+ appendix).freeze
77
+
78
+ def sections_variant_title_cleanup(xml)
79
+ path = SECTION_CONTAINERS.map { |x| "./ancestor::#{x}" }.join(" | ")
80
+ xml.xpath("//p[@variant_title]").each do |p|
81
+ p.xpath("(#{path})[last()]").each do |sect|
82
+ p.name = "variant-title"
83
+ p.delete("id")
84
+ if ins = sect.at("./title") then ins.next = p
85
+ else sect.children.first.previous = p
86
+ end
87
+ end
88
+ end
89
+ end
73
90
  end
74
91
  end
75
92
  end
@@ -0,0 +1,70 @@
1
+ module Asciidoctor
2
+ module Standoc
3
+ module Cleanup
4
+ def textcleanup(result)
5
+ text = result.flatten.map { |l| l.sub(/\s*$/, "") } * "\n"
6
+ !@keepasciimath and text = asciimath2mathml(text)
7
+ text = text.gsub(/\s+<fn /, "<fn ")
8
+ text.gsub(%r{<passthrough\s+formats="metanorma">([^<]*)
9
+ </passthrough>}mx) { HTMLEntities.new.decode($1) }
10
+ end
11
+
12
+ IGNORE_DUMBQUOTES = "//pre | //pre//* | //tt | //tt//* | "\
13
+ "//sourcecode | //sourcecode//* | //bibdata//* | //stem | "\
14
+ "//stem//* | //figure[@class = 'pseudocode'] | "\
15
+ "//figure[@class = 'pseudocode']//*".freeze
16
+
17
+ def smartquotes_cleanup(xmldoc)
18
+ xmldoc.xpath("//date").each { |d| Metanorma::Utils::endash_date(d) }
19
+ if @smartquotes then smartquotes_cleanup1(xmldoc)
20
+ else dumbquote_cleanup(xmldoc)
21
+ end
22
+ end
23
+
24
+ def smartquotes_cleanup1(xmldoc)
25
+ uninterrupt_quotes_around_xml(xmldoc)
26
+ dumb2smart_quotes(xmldoc)
27
+ end
28
+
29
+ # "abc<tag/>", def => "abc",<tag/> def
30
+ def uninterrupt_quotes_around_xml(xmldoc)
31
+ xmldoc.xpath("//*[following::text()[1]"\
32
+ "[starts-with(., '\"') or starts-with(., \"'\")]]")
33
+ .each do |x|
34
+ next if !x.ancestors("pre, tt, sourcecode, stem, figure").empty?
35
+ uninterrupt_quotes_around_xml1(x)
36
+ end
37
+ end
38
+
39
+ def uninterrupt_quotes_around_xml1(elem)
40
+ prev = elem.at(".//preceding::text()[1]") or return
41
+ /\S$/.match?(prev.text) or return
42
+ foll = elem.at(".//following::text()[1]")
43
+ m = /^(["'][[:punct:]]*)(\s|$)/.match(HTMLEntities.new.decode(foll&.text)) or return
44
+ foll.content = foll.text.sub(/^(["'][[:punct:]]*)/, "")
45
+ prev.content = "#{prev.text}#{m[1]}"
46
+ end
47
+
48
+ def dumb2smart_quotes(xmldoc)
49
+ (xmldoc.xpath("//*[child::text()]") - xmldoc.xpath(IGNORE_DUMBQUOTES))
50
+ .each do |x|
51
+ x.children.each do |n|
52
+ next unless n.text?
53
+
54
+ /[-'"(<>]|\.\.|\dx/.match(n) or next
55
+
56
+ n.replace(Metanorma::Utils::smartformat(n.text))
57
+ end
58
+ end
59
+ end
60
+
61
+ def dumbquote_cleanup(xmldoc)
62
+ xmldoc.traverse do |n|
63
+ next unless n.text?
64
+
65
+ n.replace(n.text.gsub(/(?<=\p{Alnum})\u2019(?=\p{Alpha})/, "'")) # .
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -27,6 +27,7 @@ module Asciidoctor
27
27
  preprocessor Metanorma::Plugin::Datastruct::Yaml2TextPreprocessor
28
28
  preprocessor Metanorma::Plugin::Lutaml::LutamlPreprocessor
29
29
  preprocessor Metanorma::Plugin::Lutaml::LutamlUmlAttributesTablePreprocessor
30
+ preprocessor Metanorma::Plugin::Lutaml::LutamlUmlDatamodelDescriptionPreprocessor
30
31
  inline_macro Asciidoctor::Standoc::AltTermInlineMacro
31
32
  inline_macro Asciidoctor::Standoc::DeprecatedTermInlineMacro
32
33
  inline_macro Asciidoctor::Standoc::DomainTermInlineMacro
@@ -48,6 +49,7 @@ module Asciidoctor
48
49
  inline_macro Asciidoctor::Standoc::FormSelectMacro
49
50
  inline_macro Asciidoctor::Standoc::FormOptionMacro
50
51
  inline_macro Asciidoctor::Standoc::ToCInlineMacro
52
+ inline_macro Metanorma::Plugin::Lutaml::LutamlFigureInlineMacro
51
53
  block_macro Metanorma::Plugin::Lutaml::LutamlDiagramBlockMacro
52
54
  block Asciidoctor::Standoc::ToDoAdmonitionBlock
53
55
  treeprocessor Asciidoctor::Standoc::ToDoInlineAdmonitionBlock
@@ -32,6 +32,18 @@
32
32
  <ref name="DocumentType"/>
33
33
  </element>
34
34
  </define>
35
+ <define name="section-title">
36
+ <element name="title">
37
+ <zeroOrMore>
38
+ <ref name="TextElement"/>
39
+ </zeroOrMore>
40
+ </element>
41
+ <zeroOrMore>
42
+ <element name="variant-title">
43
+ <ref name="TypedTitleString"/>
44
+ </element>
45
+ </zeroOrMore>
46
+ </define>
35
47
  <define name="hyperlink">
36
48
  <element name="link">
37
49
  <attribute name="target">
@@ -158,15 +170,17 @@
158
170
  <data type="boolean"/>
159
171
  </attribute>
160
172
  </optional>
161
- <attribute name="type">
162
- <choice>
163
- <value>roman</value>
164
- <value>alphabet</value>
165
- <value>arabic</value>
166
- <value>roman_upper</value>
167
- <value>alphabet_upper</value>
168
- </choice>
169
- </attribute>
173
+ <optional>
174
+ <attribute name="type">
175
+ <choice>
176
+ <value>roman</value>
177
+ <value>alphabet</value>
178
+ <value>arabic</value>
179
+ <value>roman_upper</value>
180
+ <value>alphabet_upper</value>
181
+ </choice>
182
+ </attribute>
183
+ </optional>
170
184
  <oneOrMore>
171
185
  <ref name="li"/>
172
186
  </oneOrMore>
@@ -1011,8 +1025,14 @@
1011
1025
  <ref name="imagemap"/>
1012
1026
  <ref name="svgmap"/>
1013
1027
  <ref name="inputform"/>
1028
+ <ref name="toc"/>
1014
1029
  </choice>
1015
1030
  </define>
1031
+ <define name="toc">
1032
+ <element name="toc">
1033
+ <ref name="ul"/>
1034
+ </element>
1035
+ </define>
1016
1036
  <define name="inputform">
1017
1037
  <element name="form">
1018
1038
  <attribute name="id">
@@ -31,7 +31,7 @@ module Asciidoctor
31
31
  c = node.attr?("checked")
32
32
  attr_code(
33
33
  uncheckedcheckbox: node.attr?("checkbox") ? !c : nil,
34
- checkedcheckbox: node.attr?("checkbox") ? c : nil
34
+ checkedcheckbox: node.attr?("checkbox") ? c : nil,
35
35
  )
36
36
  end
37
37
 
@@ -52,12 +52,14 @@ module Asciidoctor
52
52
  return "roman" if style == "lowerroman"
53
53
  return "roman_upper" if style == "upperroman"
54
54
  return "alphabet_upper" if style == "upperalpha"
55
+
55
56
  style
56
57
  end
57
58
 
58
59
  def ol_attrs(node)
59
- attr_code(keep_attrs(node).merge(id: Metanorma::Utils::anchor_or_uuid(node),
60
- type: olist_style(node.style)))
60
+ attr_code(keep_attrs(node)
61
+ .merge(id: Metanorma::Utils::anchor_or_uuid(node),
62
+ type: olist_style(node.style)))
61
63
  end
62
64
 
63
65
  def olist(node)
@@ -89,9 +91,10 @@ module Asciidoctor
89
91
  end
90
92
 
91
93
  def dl_attrs(node)
92
- attr_code(keep_attrs(node).
93
- merge(id: Metanorma::Utils::anchor_or_uuid(node),
94
- key: node.option?("key") ? "true" : nil))
94
+ attr_code(keep_attrs(node)
95
+ .merge(id: Metanorma::Utils::anchor_or_uuid(node),
96
+ metadata: node.option?("metadata") ? "true" : nil,
97
+ key: node.option?("key") ? "true" : nil))
95
98
  end
96
99
 
97
100
  def dlist(node)
@@ -6,20 +6,23 @@ require "base64"
6
6
  module Asciidoctor
7
7
  module Standoc
8
8
  module Blocks
9
- def reqt_subpart(x)
9
+ def reqt_subpart(name)
10
10
  %w(specification measurement-target verification import label
11
- subject inherit classification title).include? x
11
+ component subject inherit classification title).include? name
12
12
  end
13
13
 
14
- def reqt_subpart_attrs(node)
15
- attr_code(keep_attrs(node).merge(exclude: node.option?("exclude"),
16
- type: node.attr("type")))
14
+ def reqt_subpart_attrs(node, name)
15
+ klass = node.attr("class") || "component"
16
+ attr_code(keep_attrs(node)
17
+ .merge(exclude: node.option?("exclude"),
18
+ type: node.attr("type"),
19
+ class: name == "component" ? klass : nil))
17
20
  end
18
21
 
19
22
  def requirement_subpart(node)
20
23
  name = node.role || node.attr("style")
21
24
  noko do |xml|
22
- xml.send name, **reqt_subpart_attrs(node) do |o|
25
+ xml.send name, **reqt_subpart_attrs(node, name) do |o|
23
26
  o << node.content
24
27
  end
25
28
  end
@@ -30,14 +33,15 @@ module Asciidoctor
30
33
  HTMLEntities.new.decode(classif).split(/;\s*/).each do |c|
31
34
  c1 = c.split(/:\s*/)
32
35
  next unless c1.size == 2
33
- c1[1].split(/,\s*/).each { |v| ret << [ c1[0], v ] }
36
+
37
+ c1[1].split(/,\s*/).each { |v| ret << [c1[0], v] }
34
38
  end
35
39
  ret
36
40
  end
37
41
 
38
- def requirement_classification(classif, ex)
42
+ def requirement_classification(classif, out)
39
43
  req_classif_parse(classif).each do |r|
40
- ex.classification do |c|
44
+ out.classification do |c|
41
45
  c.tag { |t| t << r[0] }
42
46
  c.value { |v| v << r[1] }
43
47
  end
@@ -46,29 +50,37 @@ module Asciidoctor
46
50
 
47
51
  def reqt_attrs(node)
48
52
  attr_code(keep_attrs(node).merge(id_unnum_attrs(node)).merge(
49
- id: Metanorma::Utils::anchor_or_uuid(node),
50
- unnumbered: node.option?("unnumbered") ? "true" : nil,
51
- number: node.attr("number"),
52
- subsequence: node.attr("subsequence"),
53
- obligation: node.attr("obligation"),
54
- filename: node.attr("filename"),
55
- type: node.attr("type"),
56
- model: node.attr("model"),
57
- ))
53
+ id: Metanorma::Utils::anchor_or_uuid(node),
54
+ unnumbered: node.option?("unnumbered") ? "true" : nil,
55
+ number: node.attr("number"),
56
+ subsequence: node.attr("subsequence"),
57
+ obligation: node.attr("obligation"),
58
+ filename: node.attr("filename"),
59
+ type: node.attr("type"),
60
+ model: node.attr("model"),
61
+ ))
62
+ end
63
+
64
+ def requirement_elems(node, out)
65
+ node.title and out.title { |t| t << node.title }
66
+ a = node.attr("label") and out.label do |l|
67
+ l << a
68
+ end
69
+ a = node.attr("subject") and csv_split(a)&.each do |subj|
70
+ out.subject { |s| s << subj }
71
+ end
72
+ a = HTMLEntities.new.decode(node.attr("inherit")) and
73
+ csv_split(a)&.each do |i|
74
+ out.inherit { |inh| inh << i }
75
+ end
76
+ classif = node.attr("classification") and
77
+ requirement_classification(classif, out)
58
78
  end
59
79
 
60
80
  def requirement(node, obligation)
61
- classif = node.attr("classification")
62
81
  noko do |xml|
63
82
  xml.send obligation, **reqt_attrs(node) do |ex|
64
- node.title and ex.title { |t| t << node.title }
65
- node.attr("label") and ex.label { |l| l << node.attr("label") }
66
- node.attr("subject") and ex.subject { |s| s << node.attr("subject") }
67
- i = HTMLEntities.new.decode(node.attr("inherit"))
68
- i&.split(/;\s*/)&.each do |i|
69
- ex.inherit { |inh| inh << i }
70
- end
71
- requirement_classification(classif, ex) if classif
83
+ requirement_elems(node, ex)
72
84
  wrap_in_para(node, ex)
73
85
  end
74
86
  end.join("\n")