asciidoctor-iso 0.0.1 → 0.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -0
  3. data/.gitignore +1 -0
  4. data/.hound.yml +3 -0
  5. data/.rubocop.ribose.yml +65 -0
  6. data/.rubocop.tb.yml +640 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.lock +162 -0
  9. data/Makefile +39 -0
  10. data/README.adoc +396 -59
  11. data/Rakefile +6 -0
  12. data/asciidoctor-iso.gemspec +11 -3
  13. data/lib/asciidoctor/iso/base.rb +122 -51
  14. data/lib/asciidoctor/iso/blocks.rb +119 -108
  15. data/lib/asciidoctor/iso/cleanup.rb +214 -0
  16. data/lib/asciidoctor/iso/cleanup_block.rb +157 -0
  17. data/lib/asciidoctor/iso/converter.rb +5 -3
  18. data/lib/asciidoctor/iso/front.rb +37 -28
  19. data/lib/asciidoctor/iso/html/header.html +184 -0
  20. data/lib/asciidoctor/iso/html/html_iso_intro.html +73 -0
  21. data/lib/asciidoctor/iso/html/html_iso_titlepage.html +31 -0
  22. data/lib/asciidoctor/iso/html/htmlstyle.css +67 -0
  23. data/lib/asciidoctor/iso/html/isodoc.css +679 -0
  24. data/lib/asciidoctor/iso/html/word_iso_intro.html +72 -0
  25. data/lib/asciidoctor/iso/html/word_iso_titlepage.html +58 -0
  26. data/lib/asciidoctor/iso/inline_anchor.rb +20 -26
  27. data/lib/asciidoctor/iso/isostandard.rnc +177 -0
  28. data/lib/asciidoctor/iso/isostandard.rng +1478 -0
  29. data/lib/asciidoctor/iso/isostandard_diff.rnc +295 -0
  30. data/lib/asciidoctor/iso/lists.rb +152 -109
  31. data/lib/asciidoctor/iso/section.rb +164 -0
  32. data/lib/asciidoctor/iso/table.rb +30 -27
  33. data/lib/asciidoctor/iso/utils.rb +61 -183
  34. data/lib/asciidoctor/iso/validate.make.sh +8 -0
  35. data/lib/asciidoctor/iso/validate.rb +195 -24
  36. data/lib/asciidoctor/iso/validate_style.rb +175 -0
  37. data/lib/asciidoctor/iso/version.rb +1 -1
  38. data/spec/examples/rice.adoc +45 -24
  39. data/spec/examples/rice.doc +17708 -0
  40. data/spec/examples/rice.html +1574 -1662
  41. data/spec/examples/rice.preview.html +1811 -0
  42. data/spec/examples/rice.sh +4 -0
  43. data/spec/examples/rice.xml +888 -62
  44. data/spec/examples/rice_images/rice_image1.png +0 -0
  45. data/spec/examples/rice_images/rice_image2.png +0 -0
  46. data/spec/examples/rice_images/rice_image3_1.png +0 -0
  47. data/spec/examples/rice_images/rice_image3_2.png +0 -0
  48. data/spec/examples/rice_images/rice_image3_3.png +0 -0
  49. metadata +135 -12
  50. data/grammar1.gif +0 -0
  51. data/grammar2.gif +0 -0
  52. data/grammar3.gif +0 -0
  53. data/grammar4.gif +0 -0
  54. data/lib/asciidoctor/iso/validate.rnc +0 -444
  55. data/lib/asciidoctor/iso/validate.rng +0 -1001
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -10,7 +10,8 @@ Gem::Specification.new do |spec|
10
10
  spec.authors = ["Ribose Inc."]
11
11
  spec.email = ["open.source@ribose.com"]
12
12
 
13
- spec.summary = "asciidoctor-iso lets you write ISO standards in AsciiDoc."
13
+ spec.summary = "asciidoctor-iso lets you write ISO standards "\
14
+ "in AsciiDoc."
14
15
  spec.description = <<~DESCRIPTION
15
16
  asciidoctor-iso lets you write ISO standards in AsciiDoc syntax.
16
17
 
@@ -24,12 +25,19 @@ Gem::Specification.new do |spec|
24
25
  spec.require_paths = ["lib"]
25
26
  spec.files = `git ls-files`.split("\n")
26
27
  spec.test_files = `git ls-files -- {spec}/*`.split("\n")
27
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
28
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
28
29
 
29
30
  spec.add_dependency "asciidoctor", "~> 1.5.6"
31
+ spec.add_dependency "asciimath"
30
32
  spec.add_dependency "htmlentities", "~> 4.3.4"
31
- spec.add_dependency "nokogiri", "~> 1.8.1"
33
+ spec.add_dependency "image_size"
34
+ spec.add_dependency "mime-types"
35
+ spec.add_dependency "nokogiri", "= 1.8.1"
36
+ spec.add_dependency "ruby-jing"
37
+ spec.add_dependency "ruby-xslt"
32
38
  spec.add_dependency "thread_safe"
39
+ spec.add_dependency "uuidtools"
40
+ spec.add_dependency "html2doc"
33
41
 
34
42
  spec.add_development_dependency "bundler", "~> 1.15"
35
43
  spec.add_development_dependency "byebug", "~> 9.1"
@@ -5,86 +5,150 @@ require "json"
5
5
  require "pathname"
6
6
  require "open-uri"
7
7
  require "pp"
8
+ require "isodoc"
8
9
 
9
10
  module Asciidoctor
10
11
  module ISO
11
12
  module Base
13
+
12
14
  def content(node)
13
15
  node.content
14
16
  end
15
17
 
16
18
  def skip(node, name = nil)
17
- warn %(asciidoctor: WARNING (#{current_location(node)}): \
18
- converter missing for #{name || node.node_name} node in ISO backend)
19
+ name = name || node.node_name
20
+ w = "converter missing for #{name} node in ISO backend"
21
+ warning(node, w, nil)
19
22
  nil
20
23
  end
21
24
 
25
+ def html_doc_path(file)
26
+ File.join(File.dirname(__FILE__), File.join("html", file))
27
+ end
28
+
29
+ def doc_converter
30
+ IsoDoc::Convert.new(
31
+ htmlstylesheet: html_doc_path("htmlstyle.css"),
32
+ wordstylesheet: nil,
33
+ standardstylesheet: html_doc_path("isodoc.css"),
34
+ header: html_doc_path("header.html"),
35
+ htmlcoverpage: html_doc_path("html_iso_titlepage.html"),
36
+ wordcoverpage: html_doc_path("word_iso_titlepage.html"),
37
+ htmlintropage: html_doc_path("html_iso_intro.html"),
38
+ wordintropage: html_doc_path("word_iso_intro.html"),
39
+ )
40
+ end
41
+
42
+ def init
43
+ @fn_number = 0
44
+ @draft = false
45
+ @refids = Set.new
46
+ @anchors = {}
47
+ end
48
+
22
49
  def document(node)
23
- result = ["<?xml version='1.0' encoding='UTF-8'?>\n<iso-standard#{document_ns_attributes node}>"]
24
- $draft = node.attributes.has_key?("draft")
50
+ init
51
+ ret1 = makexml(node)
52
+ validate(ret1)
53
+ ret = ret1.to_xml(indent: 2)
54
+ filename = node.attr("docfile").gsub(/\.adoc/, ".xml").
55
+ gsub(%r{^.*/}, '')
56
+ File.open("#{filename}", "w") { |f| f.write(ret) }
57
+ doc_converter.convert filename
58
+ ret
59
+ end
60
+
61
+ def makexml(node)
62
+ result = ["<?xml version='1.0' encoding='UTF-8'?>\n<iso-standard>"]
63
+ @draft = node.attributes.has_key?("draft")
25
64
  result << noko { |ixml| front node, ixml }
26
65
  result << noko { |ixml| middle node, ixml }
27
66
  result << "</iso-standard>"
28
- ret = result.flatten * "\n"
29
- ret1 = cleanup(Nokogiri::XML(ret))
30
- Validate::validate(ret1)
31
- ret1.to_xml(indent: 2)
67
+ result = textcleanup(result.flatten * "\n")
68
+ ret1 = cleanup(Nokogiri::XML(result))
69
+ ret1.root.add_namespace(nil, "http://riboseinc.com/isoxml")
70
+ ret1
71
+ end
72
+
73
+ def is_draft
74
+ @draft
32
75
  end
33
76
 
34
77
  def front(node, xml)
35
- xml.front do |xml_front|
36
- title node, xml_front
37
- metadata node, xml_front
38
- end
78
+ title node, xml
79
+ metadata node, xml
39
80
  end
40
81
 
41
82
  def middle(node, xml)
42
- xml.middle do |xml_middle|
43
- xml_middle << node.content if node.blocks?
83
+ xml.sections do |s|
84
+ s << node.content if node.blocks?
44
85
  end
45
86
  end
46
87
 
47
- def termsource(node)
48
- result = []
49
- result << noko do |xml|
50
- xml.termref do |xml_t|
51
- matched = /^(?<xref><xref[^>]+>)
52
- (,\s(?<section>.[^, ]+))?
53
- (,\s(?<text>.*))?$/x.match node.content
54
- if matched.nil?
55
- warn %(asciidoctor: WARNING (#{current_location(node)}): term reference not in expected format: #{node.content})
56
- else
57
- seen_xref = Nokogiri::XML.fragment(matched[:xref])
58
- attr = {
59
- target: seen_xref.children[0]["target"],
60
- format: seen_xref.children[0]["format"],
61
- }
62
- xml_t.xref seen_xref.children[0].content, **attr_code(attr)
63
- xml_t.isosection matched[:section] if matched[:section]
64
- xml_t.modification { |m| m << matched[:text] } if matched[:text]
65
- end
88
+ def add_term_source(xml_t, seen_xref, m)
89
+ attr = { bibitemid: seen_xref.children[0]["target"],
90
+ format: seen_xref.children[0]["format"] }
91
+ xml_t.origin seen_xref.children[0].content, **attr_code(attr)
92
+ xml_t.isosection m[:section].gsub(/ /, "") if m[:section]
93
+ if m[:text]
94
+ xml_t.modification do |mod|
95
+ mod.p { |p| p << m[:text] }
66
96
  end
67
97
  end
68
- result
98
+ end
99
+
100
+ TERM_REFERENCE_RE_STR = <<~REGEXP
101
+ ^(?<xref><xref[^>]+>)
102
+ (,\s(?<section>[^, ]+))?
103
+ (,\s(?<text>.*))?
104
+ $
105
+ REGEXP
106
+ TERM_REFERENCE_RE =
107
+ Regexp.new(TERM_REFERENCE_RE_STR.gsub(/\s/, "").gsub(/_/, "\\s"),
108
+ Regexp::IGNORECASE)
109
+
110
+
111
+ def extract_termsource_refs(text)
112
+ matched = TERM_REFERENCE_RE.match text
113
+ if matched.nil?
114
+ warning(node, "term reference not in expected format", text)
115
+ end
116
+ matched
117
+ end
118
+
119
+ def termsource(node)
120
+ matched = extract_termsource_refs(node.content) or return
121
+ noko do |xml|
122
+ attrs = { status: matched[:text] ? "identical" : "modified" }
123
+ xml.termsource **attrs do |xml_t|
124
+ seen_xref = Nokogiri::XML.fragment(matched[:xref])
125
+ add_term_source(xml_t, seen_xref, matched)
126
+ style(node, matched[:text])
127
+ end
128
+ end.join("\n")
69
129
  end
70
130
 
71
131
  def paragraph(node)
72
132
  return termsource(node) if node.role == "source"
73
- result = []
74
- result << noko do |xml|
75
- xml.p do |xml_t|
133
+ attrs = { align: node.attr("align"),
134
+ id: Utils::anchor_or_uuid(node) }
135
+ noko do |xml|
136
+ xml.p **attr_code(attrs) do |xml_t|
76
137
  xml_t << node.content
138
+ style(node, Utils::flatten_rawtext(node).join(" "))
77
139
  end
78
- end
79
- result
140
+ end.join("\n")
80
141
  end
81
142
 
82
143
  def inline_footnote(node)
83
144
  noko do |xml|
84
- xml.fn do |xml_t|
85
- xml_t << node.text
145
+ @fn_number += 1
146
+ xml.fn **{reference: @fn_number} do |fn|
147
+ # TODO multi-paragraph footnotes
148
+ fn.p { |p| p << node.text }
149
+ footnote_style(node, node.text)
86
150
  end
87
- end.join
151
+ end.join("\n")
88
152
  end
89
153
 
90
154
  def open(node)
@@ -106,14 +170,21 @@ module Asciidoctor
106
170
  noko do |xml|
107
171
  xml << node.text
108
172
  xml.br
109
- end.join
173
+ end.join("\n")
110
174
  end
111
175
 
112
176
  def page_break(node)
113
177
  noko do |xml|
114
178
  xml << node.text
115
179
  xml.pagebreak
116
- end.join
180
+ end.join("\n")
181
+ end
182
+
183
+ def thematic_break(node)
184
+ noko do |xml|
185
+ xml << node.text
186
+ xml.hr
187
+ end.join("\n")
117
188
  end
118
189
 
119
190
  def inline_quoted(node)
@@ -126,14 +197,14 @@ module Asciidoctor
126
197
  when :single then xml << "'#{node.text}'"
127
198
  when :superscript then xml.sup node.text
128
199
  when :subscript then xml.sub node.text
129
- when :asciimath then xml.stem node.text
200
+ when :asciimath then xml.stem node.text, **{ type: "AsciiMath" }
130
201
  else
131
- if node.role == "alt"
132
- xml.admitted_term { |a| a << node.text }
133
- elsif node.role == "deprecated"
134
- xml.deprecated_term { |a| a << node.text }
135
- elsif node.role == "domain"
136
- xml.termdomain { |a| a << node.text }
202
+ case node.role
203
+ when "alt" then xml.admitted { |a| a << node.text }
204
+ when "deprecated" then xml.deprecates { |a| a << node.text }
205
+ when "domain" then xml.domain { |a| a << node.text }
206
+ when "strike" then xml.strike node.text
207
+ when "smallcap" then xml.smallcap node.text
137
208
  else
138
209
  xml << node.text
139
210
  end
@@ -4,165 +4,172 @@ require "uri"
4
4
  module Asciidoctor
5
5
  module ISO
6
6
  module Blocks
7
+ def id_attr(node = nil)
8
+ { id: Utils::anchor_or_uuid(node) }
9
+ end
10
+
7
11
  def stem(node)
8
- stem_attributes = {
9
- anchor: node.id,
10
- }
11
12
  # NOTE: html escaping is performed by Nokogiri
12
13
  stem_content = node.lines.join("\n")
13
14
 
14
15
  noko do |xml|
15
- xml.formula **attr_code(stem_attributes) do |s|
16
- s.stem stem_content
16
+ xml.formula **id_attr(node) do |s|
17
+ s.stem stem_content, **{ type: "AsciiMath" }
18
+ style(node, stem_content)
17
19
  end
18
20
  end
19
21
  end
20
22
 
23
+ def sidebar_attrs(node)
24
+ date = node.attr("date") || DateTime.now.iso8601.gsub(/\+.*$/, "")
25
+ date += "T0000" unless /T/.match? date
26
+ {
27
+ reviewer: node.attr("reviewer") || node.attr("source") || "(Unknown)",
28
+ id: Utils::anchor_or_uuid(node),
29
+ date: date.gsub(/[:-]/, ""),
30
+ }
31
+ end
32
+
21
33
  def sidebar(node)
22
- if $draft
23
- note_attributes = {
24
- color: node.attr("color") ? node.attr("color") : "red",
25
- }
26
- content = flatten_rawtext(node.content).join("\n")
27
- noko do |xml|
28
- xml.review_note content, **attr_code(note_attributes)
34
+ return unless is_draft
35
+ content = Utils::flatten_rawtext(node.content).join("\n")
36
+ noko do |xml|
37
+ xml.review **attr_code(sidebar_attrs(node)) do |r|
38
+ r << content
29
39
  end
30
40
  end
31
41
  end
32
42
 
33
- def termnote(node)
34
- note_attributes = { anchor: node.id }
35
-
36
- warn <<~WARNING_MESSAGE if node.blocks?
37
- asciidoctor: WARNING (#{current_location(node)}): \
38
- comment can not contain blocks of text in XML RFC:\n #{node.content}
39
- WARNING_MESSAGE
43
+ def termnote(n)
44
+ noko do |xml|
45
+ xml.termnote **id_attr(n) do |ex|
46
+ if n.blocks? then ex << n.content
47
+ else
48
+ ex.p {|p| p << n.content }
49
+ end
50
+ style(n, Utils::flatten_rawtext(n.content).join("\n"))
51
+ end
52
+ end.join("\n")
53
+ end
40
54
 
55
+ def note(n)
41
56
  noko do |xml|
42
- xml.termnote **attr_code(note_attributes) do |xml_cref|
43
- xml_cref << node.content
57
+ xml.note **id_attr(n) do |c|
58
+ if n.blocks? then c << n.content
59
+ else
60
+ c.p { |p| p << n.content }
61
+ end
62
+ text = Utils::flatten_rawtext(n.content).join("\n")
63
+ note_style(n, text)
44
64
  end
45
- end.join
65
+ end.join("\n")
66
+ end
67
+
68
+ def admonition_attrs(node)
69
+ name = node.attr("name")
70
+ type = node.attr("type") and
71
+ ["danger", "safety precautions"].each do |t|
72
+ name = t if type.casecmp(t).zero?
73
+ end
74
+ { id: Utils::anchor_or_uuid(node), type: name }
46
75
  end
47
76
 
48
77
  def admonition(node)
49
- return termnote(node) if $term_def
78
+ return termnote(node) if in_terms
79
+ return note(node) if node.attr("name") == "note"
50
80
  noko do |xml|
51
- xml.note **attr_code(anchor: node.id) do |xml_cref|
52
- if node.blocks?
53
- xml_cref << node.content
81
+ xml.admonition **admonition_attrs(node) do |a|
82
+ if node.blocks? then a << node.content
54
83
  else
55
- xml_cref.p { |p| p << node.content }
84
+ a.p { |p| p << node.content }
56
85
  end
57
86
  end
58
- end.join
87
+ end.join("\n")
59
88
  end
60
89
 
61
90
  def term_example(node)
62
91
  noko do |xml|
63
- xml.termexample **attr_code(anchor: node.id) do |ex|
64
- ex << node.content
92
+ xml.termexample **id_attr(node) do |ex|
93
+ c = node.content
94
+ if node.blocks? then ex << c
95
+ else
96
+ ex.p {|p| p << c }
97
+ end
98
+ text = Utils::flatten_rawtext(c).join("\n")
99
+ termexample_style(node, text)
65
100
  end
66
- end.join
101
+ end.join("\n")
67
102
  end
68
103
 
69
104
  def example(node)
70
- return term_example(node) if $term_def
105
+ return term_example(node) if in_terms
71
106
  noko do |xml|
72
- xml.example **attr_code(anchor: node.id) do |ex|
73
- ex << node.content
107
+ xml.example **id_attr(node) do |ex|
108
+ content = node.content
109
+ ex << content
110
+ text = Utils::flatten_rawtext(content).join("\n")
111
+ termexample_style(node, text)
74
112
  end
75
- end.join
113
+ end.join("\n")
76
114
  end
77
115
 
78
116
  def preamble(node)
79
- result = []
80
- result << noko do |xml|
81
- xml.foreword do |xml_abstract|
82
- xml_abstract << node.content
117
+ noko do |xml|
118
+ xml.content do |xml_abstract|
119
+ xml_abstract.title { |t| t << "Foreword" }
120
+ content = node.content
121
+ xml_abstract << content
122
+ text = Utils::flatten_rawtext(content).join("\n")
123
+ foreword_style(node, text)
83
124
  end
84
- end
85
- result
125
+ end.join("\n")
86
126
  end
87
127
 
88
- def section(node)
89
- attr = { anchor: node.id.empty? ? nil : node.id }
128
+ def image_attributes(node)
129
+ uri = node.image_uri node.attr("target")
130
+ types = MIME::Types.type_for(uri)
131
+ { src: uri,
132
+ id: Utils::anchor_or_uuid,
133
+ imagetype: types.first.sub_type.upcase,
134
+ height: node.attr("height"),
135
+ width: node.attr("width") }
136
+ end
137
+
138
+ def image(node)
90
139
  noko do |xml|
91
- case node.title.downcase
92
- when "introduction"
93
- xml.introduction **attr_code(attr) do |xml_section|
94
- xml_section << node.content
95
- end
96
- when "patent notice"
97
- xml.patent_notice **attr_code(attr) do |xml_section|
98
- xml_section << node.content
99
- end
100
- when "scope"
101
- xml.scope **attr_code(attr) do |xml_section|
102
- xml_section << node.content
103
- end
104
- when "normative references"
105
- $norm_ref = true
106
- xml.norm_ref **attr_code(attr) do |xml_section|
107
- xml_section << node.content
108
- end
109
- $norm_ref = false
110
- when "terms and definitions"
111
- $term_def = true
112
- xml.terms_defs **attr_code(attr) do |xml_section|
113
- xml_section << node.content
114
- end
115
- $term_def = false
116
- when "bibliography"
117
- $biblio = true
118
- xml.bibliography **attr_code(attr) do |xml_section|
119
- xml_section << node.content
120
- end
121
- $biblio = true
122
- else
123
- if $term_def
124
- xml.termdef **attr_code(attr) do |xml_section|
125
- xml_section.term { |name| name << node.title }
126
- xml_section << node.content
127
- end
128
- elsif node.attr("style") == "appendix"
129
- xml.annex **attr_code(attr) do |xml_section|
130
- xml_section.name { |name| name << node.title }
131
- xml_section << node.content
132
- end
133
- else
134
- xml.clause **attr_code(attr) do |xml_section|
135
- unless node.title.nil?
136
- xml_section.name { |name| name << node.title }
137
- end
138
- xml_section << node.content
139
- end
140
- end
140
+ xml.figure **id_attr(node) do |f|
141
+ f.name { |name| name << node.title } unless node.title.nil?
142
+ f.image **attr_code(image_attributes(node))
141
143
  end
142
- end.join
144
+ end
143
145
  end
144
146
 
145
- def image(node)
146
- uri = node.image_uri node.attr("target")
147
- artwork_attributes = {
148
- anchor: node.id,
149
- src: uri,
147
+ def quote_attrs(node)
148
+ {
149
+ id: Utils::anchor_or_uuid(node),
150
+ align: node.attr("align"),
150
151
  }
152
+ end
151
153
 
152
- noko do |xml|
153
- xml.figure **attr_code(artwork_attributes) do |f|
154
- f.name { |name| name << node.title } unless node.title.nil?
154
+ def quote_attribution(node, out)
155
+ if node.attr("attribution")
156
+ out.fullname do |f|
157
+ f.surname { |s| s << node.attr("attribution") }
158
+ # TODO: will break up into name components
155
159
  end
156
160
  end
161
+ if node.attr("citetitle")
162
+ # TODO: eref
163
+ end
157
164
  end
158
165
 
159
166
  def quote(node)
160
167
  noko do |xml|
161
- xml.quote **attr_code(anchor: node.id) do |xml_blockquote|
162
- if node.blocks?
163
- xml_blockquote << node.content
168
+ xml.quote **attr_code(quote_attrs(node)) do |q|
169
+ quote_attribution(node, out)
170
+ if node.blocks? then q << node.content
164
171
  else
165
- xml_blockquote.p { |p| p << node.content }
172
+ q.p { |p| p << node.content }
166
173
  end
167
174
  end
168
175
  end
@@ -173,10 +180,14 @@ module Asciidoctor
173
180
  noko do |xml|
174
181
  if node.parent.context != :example
175
182
  xml.figure do |xml_figure|
176
- xml_figure.sourcecode { |s| s << node.content }
183
+ xml_figure.sourcecode **id_attr(node) do |s|
184
+ s << node.content
185
+ end
177
186
  end
178
187
  else
179
- xml.sourcecode { |s| s << node.content }
188
+ xml.sourcecode **id_attr(node) do |s|
189
+ s << node.content
190
+ end
180
191
  end
181
192
  end
182
193
  end