asciidoctor-iso 0.0.1 → 0.6.0

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