asciidoctor 1.5.8 → 2.0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (197) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +11 -0
  3. data/CHANGELOG.adoc +628 -45
  4. data/LICENSE +2 -1
  5. data/README-de.adoc +28 -38
  6. data/README-fr.adoc +30 -43
  7. data/README-jp.adoc +255 -201
  8. data/README-zh_CN.adoc +40 -44
  9. data/README.adoc +170 -143
  10. data/asciidoctor.gemspec +22 -34
  11. data/bin/asciidoctor +5 -4
  12. data/data/locale/attributes-ar.adoc +4 -3
  13. data/data/locale/attributes-be.adoc +23 -0
  14. data/data/locale/attributes-bg.adoc +4 -3
  15. data/data/locale/attributes-ca.adoc +6 -5
  16. data/data/locale/attributes-cs.adoc +4 -3
  17. data/data/locale/attributes-da.adoc +6 -5
  18. data/data/locale/attributes-de.adoc +6 -5
  19. data/data/locale/attributes-en.adoc +4 -4
  20. data/data/locale/attributes-es.adoc +6 -5
  21. data/data/locale/attributes-fa.adoc +4 -3
  22. data/data/locale/attributes-fi.adoc +4 -3
  23. data/data/locale/attributes-fr.adoc +8 -7
  24. data/data/locale/attributes-hu.adoc +4 -3
  25. data/data/locale/attributes-id.adoc +4 -3
  26. data/data/locale/attributes-it.adoc +6 -5
  27. data/data/locale/attributes-ja.adoc +4 -3
  28. data/data/locale/{attributes-kr.adoc → attributes-ko.adoc} +4 -3
  29. data/data/locale/attributes-nb.adoc +4 -3
  30. data/data/locale/attributes-nl.adoc +6 -5
  31. data/data/locale/attributes-nn.adoc +4 -3
  32. data/data/locale/attributes-pl.adoc +8 -7
  33. data/data/locale/attributes-pt.adoc +6 -5
  34. data/data/locale/attributes-pt_BR.adoc +6 -5
  35. data/data/locale/attributes-ro.adoc +4 -3
  36. data/data/locale/attributes-ru.adoc +6 -5
  37. data/data/locale/attributes-sr.adoc +4 -4
  38. data/data/locale/attributes-sr_Latn.adoc +4 -4
  39. data/data/locale/attributes-sv.adoc +4 -4
  40. data/data/locale/attributes-th.adoc +23 -0
  41. data/data/locale/attributes-tr.adoc +4 -3
  42. data/data/locale/attributes-uk.adoc +6 -5
  43. data/data/locale/attributes-vi.adoc +23 -0
  44. data/data/locale/attributes-zh_CN.adoc +4 -3
  45. data/data/locale/attributes-zh_TW.adoc +4 -3
  46. data/data/reference/syntax.adoc +296 -0
  47. data/data/stylesheets/asciidoctor-default.css +120 -114
  48. data/data/stylesheets/coderay-asciidoctor.css +15 -17
  49. data/lib/asciidoctor/abstract_block.rb +146 -140
  50. data/lib/asciidoctor/abstract_node.rb +152 -170
  51. data/lib/asciidoctor/attribute_list.rb +77 -89
  52. data/lib/asciidoctor/block.rb +29 -28
  53. data/lib/asciidoctor/callouts.rb +4 -2
  54. data/lib/asciidoctor/cli/invoker.rb +20 -24
  55. data/lib/asciidoctor/cli/options.rb +107 -96
  56. data/lib/asciidoctor/cli.rb +3 -2
  57. data/lib/asciidoctor/convert.rb +199 -0
  58. data/lib/asciidoctor/converter/composite.rb +40 -48
  59. data/lib/asciidoctor/converter/docbook5.rb +627 -644
  60. data/lib/asciidoctor/converter/html5.rb +1053 -951
  61. data/lib/asciidoctor/converter/manpage.rb +581 -532
  62. data/lib/asciidoctor/converter/template.rb +232 -271
  63. data/lib/asciidoctor/converter.rb +370 -185
  64. data/lib/asciidoctor/core_ext/float/truncate.rb +20 -0
  65. data/lib/asciidoctor/core_ext/hash/merge.rb +8 -0
  66. data/lib/asciidoctor/core_ext/match_data/names.rb +7 -0
  67. data/lib/asciidoctor/core_ext/nil_or_empty.rb +1 -0
  68. data/lib/asciidoctor/core_ext/regexp/is_match.rb +4 -2
  69. data/lib/asciidoctor/core_ext.rb +8 -17
  70. data/lib/asciidoctor/document.rb +503 -461
  71. data/lib/asciidoctor/extensions.rb +127 -174
  72. data/lib/asciidoctor/helpers.rb +184 -107
  73. data/lib/asciidoctor/inline.rb +9 -12
  74. data/lib/asciidoctor/list.rb +11 -29
  75. data/lib/asciidoctor/load.rb +119 -0
  76. data/lib/asciidoctor/logging.rb +22 -17
  77. data/lib/asciidoctor/parser.rb +673 -719
  78. data/lib/asciidoctor/path_resolver.rb +48 -33
  79. data/lib/asciidoctor/reader.rb +383 -338
  80. data/lib/asciidoctor/rouge_ext.rb +39 -0
  81. data/lib/asciidoctor/rx.rb +723 -0
  82. data/lib/asciidoctor/section.rb +17 -16
  83. data/lib/asciidoctor/stylesheets.rb +19 -37
  84. data/lib/asciidoctor/substitutors.rb +926 -1022
  85. data/lib/asciidoctor/syntax_highlighter/coderay.rb +88 -0
  86. data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +34 -0
  87. data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
  88. data/lib/asciidoctor/syntax_highlighter/prettify.rb +30 -0
  89. data/lib/asciidoctor/syntax_highlighter/pygments.rb +157 -0
  90. data/lib/asciidoctor/syntax_highlighter/rouge.rb +143 -0
  91. data/lib/asciidoctor/syntax_highlighter.rb +253 -0
  92. data/lib/asciidoctor/table.rb +152 -114
  93. data/lib/asciidoctor/timings.rb +7 -5
  94. data/lib/asciidoctor/version.rb +2 -1
  95. data/lib/asciidoctor/writer.rb +30 -0
  96. data/lib/asciidoctor.rb +266 -1340
  97. data/man/asciidoctor.1 +49 -47
  98. data/man/asciidoctor.adoc +54 -45
  99. metadata +50 -245
  100. data/CONTRIBUTING.adoc +0 -185
  101. data/Gemfile +0 -60
  102. data/Rakefile +0 -129
  103. data/bin/asciidoctor-safe +0 -15
  104. data/features/open_block.feature +0 -92
  105. data/features/pass_block.feature +0 -66
  106. data/features/step_definitions.rb +0 -49
  107. data/features/text_formatting.feature +0 -57
  108. data/features/xref.feature +0 -1039
  109. data/lib/asciidoctor/converter/base.rb +0 -59
  110. data/lib/asciidoctor/converter/docbook45.rb +0 -93
  111. data/lib/asciidoctor/converter/factory.rb +0 -226
  112. data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +0 -6
  113. data/lib/asciidoctor/core_ext/1.8.7/concurrent/hash.rb +0 -5
  114. data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +0 -4
  115. data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +0 -6
  116. data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +0 -5
  117. data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +0 -6
  118. data/lib/asciidoctor/core_ext/1.8.7/string/limit_bytesize.rb +0 -29
  119. data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +0 -6
  120. data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +0 -6
  121. data/lib/asciidoctor/core_ext/string/limit_bytesize.rb +0 -10
  122. data/test/api_test.rb +0 -1240
  123. data/test/attribute_list_test.rb +0 -242
  124. data/test/attributes_test.rb +0 -1623
  125. data/test/blocks_test.rb +0 -3870
  126. data/test/converter_test.rb +0 -470
  127. data/test/document_test.rb +0 -1853
  128. data/test/extensions_test.rb +0 -1560
  129. data/test/fixtures/asciidoc_index.txt +0 -521
  130. data/test/fixtures/basic-docinfo-footer.html +0 -6
  131. data/test/fixtures/basic-docinfo-footer.xml +0 -8
  132. data/test/fixtures/basic-docinfo.html +0 -1
  133. data/test/fixtures/basic-docinfo.xml +0 -4
  134. data/test/fixtures/basic.asciidoc +0 -5
  135. data/test/fixtures/chapter-a.adoc +0 -3
  136. data/test/fixtures/child-include.adoc +0 -5
  137. data/test/fixtures/circle.svg +0 -9
  138. data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +0 -6
  139. data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +0 -6
  140. data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +0 -3
  141. data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +0 -5
  142. data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +0 -1
  143. data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +0 -6
  144. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +0 -3
  145. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +0 -5
  146. data/test/fixtures/custom-docinfodir/basic-docinfo.html +0 -1
  147. data/test/fixtures/custom-docinfodir/docinfo.html +0 -1
  148. data/test/fixtures/docinfo-footer.html +0 -1
  149. data/test/fixtures/docinfo-footer.xml +0 -9
  150. data/test/fixtures/docinfo.html +0 -1
  151. data/test/fixtures/docinfo.xml +0 -3
  152. data/test/fixtures/doctime-localtime.adoc +0 -2
  153. data/test/fixtures/dot.gif +0 -0
  154. data/test/fixtures/encoding.asciidoc +0 -13
  155. data/test/fixtures/file-with-missing-include.adoc +0 -1
  156. data/test/fixtures/grandchild-include.adoc +0 -3
  157. data/test/fixtures/hello-asciidoctor.pdf +0 -69
  158. data/test/fixtures/include-file.asciidoc +0 -24
  159. data/test/fixtures/include-file.jsx +0 -8
  160. data/test/fixtures/include-file.ml +0 -3
  161. data/test/fixtures/include-file.xml +0 -5
  162. data/test/fixtures/lists.adoc +0 -96
  163. data/test/fixtures/master.adoc +0 -5
  164. data/test/fixtures/mismatched-end-tag.adoc +0 -7
  165. data/test/fixtures/other-chapters.adoc +0 -11
  166. data/test/fixtures/outer-include.adoc +0 -5
  167. data/test/fixtures/parent-include-restricted.adoc +0 -5
  168. data/test/fixtures/parent-include.adoc +0 -5
  169. data/test/fixtures/sample.asciidoc +0 -30
  170. data/test/fixtures/section-a.adoc +0 -4
  171. data/test/fixtures/stylesheets/custom.css +0 -3
  172. data/test/fixtures/subdir/index.adoc +0 -3
  173. data/test/fixtures/subdir/inner-include.adoc +0 -3
  174. data/test/fixtures/subdir/middle-include.adoc +0 -5
  175. data/test/fixtures/subs-docinfo.html +0 -2
  176. data/test/fixtures/subs.adoc +0 -6
  177. data/test/fixtures/tagged-class-enclosed.rb +0 -25
  178. data/test/fixtures/tagged-class.rb +0 -23
  179. data/test/fixtures/tip.gif +0 -0
  180. data/test/fixtures/unclosed-tag.adoc +0 -3
  181. data/test/fixtures/unexpected-end-tag.adoc +0 -4
  182. data/test/invoker_test.rb +0 -745
  183. data/test/links_test.rb +0 -855
  184. data/test/lists_test.rb +0 -5151
  185. data/test/logger_test.rb +0 -211
  186. data/test/manpage_test.rb +0 -660
  187. data/test/options_test.rb +0 -262
  188. data/test/paragraphs_test.rb +0 -562
  189. data/test/parser_test.rb +0 -742
  190. data/test/paths_test.rb +0 -395
  191. data/test/preamble_test.rb +0 -173
  192. data/test/reader_test.rb +0 -2161
  193. data/test/sections_test.rb +0 -3575
  194. data/test/substitutions_test.rb +0 -2066
  195. data/test/tables_test.rb +0 -2036
  196. data/test/test_helper.rb +0 -447
  197. data/test/text_test.rb +0 -309
@@ -1,10 +1,10 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
  module Asciidoctor
3
3
  # Public: Methods and constants for managing AsciiDoc table content in a document.
4
4
  # It supports all three of AsciiDoc's table formats: psv, dsv and csv.
5
5
  class Table < AbstractBlock
6
- # multipler / divisor for tuning precision of calculated result
7
- DEFAULT_PRECISION_FACTOR = 10000.0
6
+ # precision of column widths
7
+ DEFAULT_PRECISION = 4
8
8
 
9
9
  # Public: A data object that encapsulates the collection of rows (head, foot, body) for a table
10
10
  class Rows
@@ -18,7 +18,7 @@ class Table < AbstractBlock
18
18
 
19
19
  alias [] send
20
20
 
21
- # Public: Returns the rows grouped by section.
21
+ # Public: Retrieve the rows grouped by section as a nested Array.
22
22
  #
23
23
  # Creates a 2-dimensional array of two element entries. The first element
24
24
  # is the section name as a symbol. The second element is the Array of rows
@@ -28,6 +28,16 @@ class Table < AbstractBlock
28
28
  def by_section
29
29
  [[:head, @head], [:body, @body], [:foot, @foot]]
30
30
  end
31
+
32
+ # Public: Retrieve the rows as a Hash.
33
+ #
34
+ # The keys are the names of the section groups and the values are the Array of rows in that section.
35
+ # The keys are in document order (head, foot, body).
36
+ #
37
+ # Returns a Hash of rows grouped by section.
38
+ def to_h
39
+ { head: @head, body: @body, foot: @foot }
40
+ end
31
41
  end
32
42
 
33
43
  # Public: Get/Set the columns for this table
@@ -48,7 +58,7 @@ class Table < AbstractBlock
48
58
  @rows = Rows.new
49
59
  @columns = []
50
60
 
51
- @has_header_option = attributes.key? 'header-option'
61
+ @has_header_option = false
52
62
 
53
63
  # smells like we need a utility method here
54
64
  # to resolve an integer width from potential bogus input
@@ -61,19 +71,17 @@ class Table < AbstractBlock
61
71
  end
62
72
  @attributes['tablepcwidth'] = pcwidth_intval
63
73
 
64
- if @document.attributes.key? 'pagewidth'
65
- # FIXME calculate more accurately (only used in DocBook output)
66
- @attributes['tableabswidth'] ||=
67
- ((@attributes['tablepcwidth'].to_f / 100) * @document.attributes['pagewidth']).round
74
+ if @document.attributes['pagewidth']
75
+ @attributes['tableabswidth'] = (abswidth_val = (((pcwidth_intval / 100.0) * @document.attributes['pagewidth'].to_f).truncate DEFAULT_PRECISION)) == abswidth_val.to_i ? abswidth_val.to_i : abswidth_val
68
76
  end
69
77
 
70
- attributes['orientation'] = 'landscape' if attributes.key? 'rotate-option'
78
+ @attributes['orientation'] = 'landscape' if attributes['rotate-option']
71
79
  end
72
80
 
73
- # Internal: Returns whether the current row being processed is
74
- # the header row
81
+ # Internal: Returns the current state of the header option (true or :implicit) if
82
+ # the row being processed is (or is assumed to be) the header row, otherwise nil
75
83
  def header_row?
76
- @has_header_option && @rows.body.empty?
84
+ (val = @has_header_option) && @rows.body.empty? ? val : nil
77
85
  end
78
86
 
79
87
  # Internal: Creates the Column objects from the column spec
@@ -111,7 +119,7 @@ class Table < AbstractBlock
111
119
  #
112
120
  # returns nothing
113
121
  def assign_column_widths width_base = nil, autowidth_cols = nil
114
- pf = DEFAULT_PRECISION_FACTOR
122
+ precision = DEFAULT_PRECISION
115
123
  total_width = col_pcwidth = 0
116
124
 
117
125
  if width_base
@@ -120,32 +128,22 @@ class Table < AbstractBlock
120
128
  autowidth = 0
121
129
  logger.warn %(total column width must not exceed 100% when using autowidth columns; got #{width_base}%)
122
130
  else
123
- autowidth = ((100.0 - width_base) / autowidth_cols.size * pf).to_i / pf
131
+ autowidth = ((100.0 - width_base) / autowidth_cols.size).truncate precision
124
132
  autowidth = autowidth.to_i if autowidth.to_i == autowidth
125
133
  width_base = 100
126
134
  end
127
135
  autowidth_attrs = { 'width' => autowidth, 'autowidth-option' => '' }
128
136
  autowidth_cols.each {|col| col.update_attributes autowidth_attrs }
129
137
  end
130
- @columns.each {|col| total_width += (col_pcwidth = col.assign_width nil, width_base, pf) }
138
+ @columns.each {|col| total_width += (col_pcwidth = col.assign_width nil, width_base, precision) }
131
139
  else
132
- col_pcwidth = ((100 * pf / @columns.size).to_i) / pf
133
- # or...
134
- #col_pcwidth = (100.0 / @columns.size).truncate 4
140
+ col_pcwidth = (100.0 / @columns.size).truncate precision
135
141
  col_pcwidth = col_pcwidth.to_i if col_pcwidth.to_i == col_pcwidth
136
- @columns.each {|col| total_width += col.assign_width col_pcwidth }
142
+ @columns.each {|col| total_width += col.assign_width col_pcwidth, nil, precision }
137
143
  end
138
144
 
139
145
  # donate balance, if any, to final column (using half up rounding)
140
- unless total_width == 100
141
- @columns[-1].assign_width(((100 - total_width + col_pcwidth) * pf).round / pf)
142
- # or (manual half up rounding)...
143
- #numerator = (raw_numerator = (100 - total_width + col_pcwidth) * pf).to_i
144
- #numerator += 1 if raw_numerator >= numerator + 0.5
145
- #@columns[-1].assign_width numerator / pf
146
- # or...
147
- #@columns[-1].assign_width((100 - total_width + col_pcwidth).round 4)
148
- end
146
+ @columns[-1].assign_width(((100 - total_width + col_pcwidth).round precision), nil, precision) unless total_width == 100
149
147
 
150
148
  nil
151
149
  end
@@ -156,22 +154,19 @@ class Table < AbstractBlock
156
154
  # returns nothing
157
155
  def partition_header_footer(attrs)
158
156
  # set rowcount before splitting up body rows
159
- @attributes['rowcount'] = @rows.body.size
160
-
161
- num_body_rows = @rows.body.size
162
- if num_body_rows > 0 && @has_header_option
163
- head = @rows.body.shift
164
- num_body_rows -= 1
165
- # styles aren't applied to header row
166
- head.each {|c| c.style = nil }
167
- # QUESTION why does AsciiDoc use an array for head? is it
168
- # possible to have more than one based on the syntax?
169
- @rows.head = [head]
157
+ num_body_rows = @attributes['rowcount'] = (body = @rows.body).size
158
+
159
+ if num_body_rows > 0
160
+ if @has_header_option
161
+ @rows.head = [body.shift.map {|cell| cell.reinitialize true }]
162
+ num_body_rows -= 1
163
+ elsif @has_header_option.nil?
164
+ @has_header_option = false
165
+ body.unshift(body.shift.map {|cell| cell.reinitialize false })
166
+ end
170
167
  end
171
168
 
172
- if num_body_rows > 0 && attrs.key?('footer-option')
173
- @rows.foot = [@rows.body.pop]
174
- end
169
+ @rows.foot = [body.pop] if num_body_rows > 0 && attrs['footer-option']
175
170
 
176
171
  nil
177
172
  end
@@ -180,11 +175,11 @@ end
180
175
  # Public: Methods to manage the columns of an AsciiDoc table. In particular, it
181
176
  # keeps track of the column specs
182
177
  class Table::Column < AbstractNode
183
- # Public: Get/Set the Symbol style for this column.
178
+ # Public: Get/Set the style Symbol for this column.
184
179
  attr_accessor :style
185
180
 
186
181
  def initialize table, index, attributes = {}
187
- super table, :column
182
+ super table, :table_column
188
183
  @style = attributes['style']
189
184
  attributes['colnumber'] = index + 1
190
185
  attributes['width'] ||= 1
@@ -201,32 +196,29 @@ class Table::Column < AbstractNode
201
196
  # This method assigns the colpcwidth and colabswidth attributes.
202
197
  #
203
198
  # returns the resolved colpcwidth value
204
- def assign_width col_pcwidth, width_base = nil, pf = 10000.0
199
+ def assign_width col_pcwidth, width_base, precision
205
200
  if width_base
206
- col_pcwidth = ((@attributes['width'].to_f / width_base) * 100 * pf).to_i / pf
207
- # or...
208
- #col_pcwidth = (@attributes['width'].to_f * 100.0 / width_base).truncate 4
201
+ col_pcwidth = (@attributes['width'].to_f * 100.0 / width_base).truncate precision
209
202
  col_pcwidth = col_pcwidth.to_i if col_pcwidth.to_i == col_pcwidth
210
203
  end
211
- @attributes['colpcwidth'] = col_pcwidth
212
- if parent.attributes.key? 'tableabswidth'
213
- # FIXME calculate more accurately (only used in DocBook output)
214
- @attributes['colabswidth'] = ((col_pcwidth / 100.0) * parent.attributes['tableabswidth']).round
204
+ if parent.attributes['tableabswidth']
205
+ @attributes['colabswidth'] = (col_abswidth = ((col_pcwidth / 100.0) * parent.attributes['tableabswidth']).truncate precision) == col_abswidth.to_i ? col_abswidth.to_i : col_abswidth
215
206
  end
216
- col_pcwidth
207
+ @attributes['colpcwidth'] = col_pcwidth
217
208
  end
218
- end
219
209
 
220
- # Public: Methods for managing the a cell in an AsciiDoc table.
221
- class Table::Cell < AbstractNode
222
- # Public: Gets/Sets the location in the AsciiDoc source where this cell begins
223
- attr_reader :source_location
210
+ def block?
211
+ false
212
+ end
224
213
 
225
- # Public: Get/Set the Symbol style for this cell (default: nil)
226
- attr_accessor :style
214
+ def inline?
215
+ false
216
+ end
217
+ end
227
218
 
228
- # Public: Substitutions to be applied to content in this cell
229
- attr_accessor :subs
219
+ # Public: Methods for managing the a cell in an AsciiDoc table.
220
+ class Table::Cell < AbstractBlock
221
+ DOUBLE_LF = LF * 2
230
222
 
231
223
  # Public: An Integer of the number of columns this cell will span (default: nil)
232
224
  attr_accessor :colspan
@@ -237,14 +229,23 @@ class Table::Cell < AbstractNode
237
229
  # Public: An alias to the parent block (which is always a Column)
238
230
  alias column parent
239
231
 
240
- # Public: The internal Asciidoctor::Document for a cell that has the asciidoc style
232
+ # Public: Returns the nested Document in an AsciiDoc table cell (only set when style is :asciidoc)
241
233
  attr_reader :inner_document
242
234
 
243
235
  def initialize column, cell_text, attributes = {}, opts = {}
244
- super column, :cell
236
+ super column, :table_cell
237
+ @cursor = @reinitialize_args = nil
245
238
  @source_location = opts[:cursor].dup if @document.sourcemap
239
+ # NOTE: column is always set when parsing; may not be set when building table from the API
246
240
  if column
247
- cell_style = column.attributes['style'] unless (in_header_row = column.table.header_row?)
241
+ if (in_header_row = column.table.header_row?)
242
+ if in_header_row == :implicit && (cell_style = column.style || (attributes && attributes['style']))
243
+ @reinitialize_args = [column, cell_text, attributes && attributes.merge, opts] if cell_style == :asciidoc || cell_style == :literal
244
+ cell_style = nil
245
+ end
246
+ else
247
+ cell_style = column.style
248
+ end
248
249
  # REVIEW feels hacky to inherit all attributes from column
249
250
  update_attributes column.attributes
250
251
  end
@@ -258,7 +259,8 @@ class Table::Cell < AbstractNode
258
259
  cell_style = attributes['style'] || cell_style unless in_header_row
259
260
  update_attributes attributes
260
261
  end
261
- if cell_style == :asciidoc
262
+ case cell_style
263
+ when :asciidoc
262
264
  asciidoc = true
263
265
  inner_document_cursor = opts[:cursor]
264
266
  if (cell_text = cell_text.rstrip).start_with? LF
@@ -269,7 +271,8 @@ class Table::Cell < AbstractNode
269
271
  else
270
272
  cell_text = cell_text.lstrip
271
273
  end
272
- elsif (literal = cell_style == :literal) || cell_style == :verse
274
+ when :literal
275
+ literal = true
273
276
  cell_text = cell_text.rstrip
274
277
  # QUESTION should we use same logic as :asciidoc cell? strip leading space if text doesn't start with newline?
275
278
  cell_text = cell_text.slice 1, cell_text.length while cell_text.start_with? LF
@@ -303,21 +306,46 @@ class Table::Cell < AbstractNode
303
306
  inner_document_lines.unshift(*preprocessed_lines) unless preprocessed_lines.empty?
304
307
  end
305
308
  end unless inner_document_lines.empty?
306
- @inner_document = Document.new(inner_document_lines, :header_footer => false, :parent => @document, :cursor => inner_document_cursor)
309
+ @inner_document = Document.new inner_document_lines, standalone: false, parent: @document, cursor: inner_document_cursor
307
310
  @document.attributes['doctitle'] = parent_doctitle unless parent_doctitle.nil?
308
311
  @subs = nil
309
312
  elsif literal
313
+ @content_model = :verbatim
310
314
  @subs = BASIC_SUBS
311
315
  else
312
- if normal_psv && (cell_text.start_with? '[[') && LeadingInlineAnchorRx =~ cell_text
313
- Parser.catalog_inline_anchor $1, $2, self, opts[:cursor], @document
316
+ if normal_psv
317
+ if in_header_row
318
+ @cursor = opts[:cursor] # used in deferred catalog_inline_anchor call
319
+ else
320
+ catalog_inline_anchor cell_text, opts[:cursor]
321
+ end
314
322
  end
323
+ @content_model = :simple
315
324
  @subs = NORMAL_SUBS
316
325
  end
317
326
  @text = cell_text
318
327
  @style = cell_style
319
328
  end
320
329
 
330
+ def reinitialize has_header
331
+ if has_header
332
+ @reinitialize_args = nil
333
+ elsif @reinitialize_args
334
+ return Table::Cell.new(*@reinitialize_args)
335
+ else
336
+ @style = @attributes['style']
337
+ end
338
+ catalog_inline_anchor if @cursor
339
+ self
340
+ end
341
+
342
+ def catalog_inline_anchor cell_text = @text, cursor = nil
343
+ cursor, @cursor = @cursor, nil unless cursor
344
+ if (cell_text.start_with? '[[') && LeadingInlineAnchorRx =~ cell_text
345
+ Parser.catalog_inline_anchor $1, $2, self, cursor, @document
346
+ end
347
+ end
348
+
321
349
  # Public: Get the String text of this cell with substitutions applied.
322
350
  #
323
351
  # Used for cells in the head row as well as text-only (non-AsciiDoc) cells in
@@ -330,30 +358,40 @@ class Table::Cell < AbstractNode
330
358
  apply_subs @text, @subs
331
359
  end
332
360
 
333
- # Public: Set the String text.
361
+ # Public: Set the String text for this cell.
334
362
  #
335
363
  # This method shouldn't be used for cells that have the AsciiDoc style.
336
- #
337
- # Returns the new String text assigned to this Cell
338
- def text= val
339
- @text = val
340
- end
364
+ attr_writer :text
341
365
 
342
366
  # Public: Handles the body data (tbody, tfoot), applying styles and partitioning into paragraphs
343
367
  #
344
- # This method should not be used for cells in the head row or that have the literal or verse style.
368
+ # This method should not be used for cells in the head row or that have the literal style.
345
369
  #
346
370
  # Returns the converted String for this Cell
347
371
  def content
348
- if @style == :asciidoc
372
+ if (cell_style = @style) == :asciidoc
349
373
  @inner_document.convert
350
- else
351
- text.split(BlankLineRx).map do |p|
352
- !@style || @style == :header ? p : Inline.new(parent, :quoted, p, :type => @style).convert
374
+ elsif @text.include? DOUBLE_LF
375
+ (text.split BlankLineRx).map do |para|
376
+ cell_style && cell_style != :header ? (Inline.new parent, :quoted, para, type: cell_style).convert : para
353
377
  end
378
+ elsif (subbed_text = text).empty?
379
+ []
380
+ elsif cell_style && cell_style != :header
381
+ [(Inline.new parent, :quoted, subbed_text, type: cell_style).convert]
382
+ else
383
+ [subbed_text]
354
384
  end
355
385
  end
356
386
 
387
+ def lines
388
+ @text.split LF
389
+ end
390
+
391
+ def source
392
+ @text
393
+ end
394
+
357
395
  # Public: Get the source file where this block started
358
396
  def file
359
397
  @source_location && @source_location.file
@@ -365,7 +403,7 @@ class Table::Cell < AbstractNode
365
403
  end
366
404
 
367
405
  def to_s
368
- "#{super.to_s} - [text: #@text, colspan: #{@colspan || 1}, rowspan: #{@rowspan || 1}, attributes: #@attributes]"
406
+ %(#{super} - [text: #{@text}, colspan: #{@colspan || 1}, rowspan: #{@rowspan || 1}, attributes: #{@attributes}])
369
407
  end
370
408
  end
371
409
 
@@ -373,7 +411,7 @@ end
373
411
  # class are primarily responsible for tracking the buffer of a cell as the parser
374
412
  # moves through the lines of the table using tail recursion. When a cell boundary
375
413
  # is located, the previous cell is closed, an instance of Table::Cell is
376
- # instantiated, the row is closed if the cell satisifies the column count and,
414
+ # instantiated, the row is closed if the cell satisfies the column count and,
377
415
  # finally, a new buffer is allocated to track the next cell.
378
416
  class Table::ParserContext
379
417
  include Logging
@@ -388,8 +426,8 @@ class Table::ParserContext
388
426
  'psv' => ['|', /\|/],
389
427
  'csv' => [',', /,/],
390
428
  'dsv' => [':', /:/],
391
- 'tsv' => [%(\t), /\t/],
392
- '!sv' => ['!', /!/]
429
+ 'tsv' => [?\t, /\t/],
430
+ '!sv' => ['!', /!/],
393
431
  }
394
432
 
395
433
  # Public: The Table currently being parsed
@@ -427,7 +465,7 @@ class Table::ParserContext
427
465
  xsv = '!sv'
428
466
  end
429
467
  else
430
- logger.error message_with_context %(illegal table format: #{xsv}), :source_location => reader.cursor_at_prev_line
468
+ logger.error message_with_context %(illegal table format: #{xsv}), source_location: reader.cursor_at_prev_line
431
469
  @format, xsv = 'psv', (table.document.nested? ? '!sv' : 'psv')
432
470
  end
433
471
  else
@@ -436,15 +474,15 @@ class Table::ParserContext
436
474
 
437
475
  if attributes.key? 'separator'
438
476
  if (sep = attributes['separator']).nil_or_empty?
439
- @delimiter, @delimiter_re = DELIMITERS[xsv]
477
+ @delimiter, @delimiter_rx = DELIMITERS[xsv]
440
478
  # QUESTION should we support any other escape codes or multiple tabs?
441
479
  elsif sep == '\t'
442
- @delimiter, @delimiter_re = DELIMITERS['tsv']
480
+ @delimiter, @delimiter_rx = DELIMITERS['tsv']
443
481
  else
444
- @delimiter, @delimiter_re = sep, /#{::Regexp.escape sep}/
482
+ @delimiter, @delimiter_rx = sep, /#{::Regexp.escape sep}/
445
483
  end
446
484
  else
447
- @delimiter, @delimiter_re = DELIMITERS[xsv]
485
+ @delimiter, @delimiter_rx = DELIMITERS[xsv]
448
486
  end
449
487
 
450
488
  @colcount = table.columns.empty? ? -1 : table.columns.size
@@ -470,7 +508,7 @@ class Table::ParserContext
470
508
  #
471
509
  # returns Regexp MatchData if the line contains the delimiter, false otherwise
472
510
  def match_delimiter(line)
473
- @delimiter_re.match(line)
511
+ @delimiter_rx.match(line)
474
512
  end
475
513
 
476
514
  # Public: Skip past the matched delimiter because it's inside quoted text.
@@ -493,12 +531,13 @@ class Table::ParserContext
493
531
  #
494
532
  # returns true if the buffer has unclosed quotes, false if it doesn't or it
495
533
  # isn't quoted data
496
- def buffer_has_unclosed_quotes? append = nil
497
- if (record = append ? (@buffer + append).strip : @buffer.strip) == '"'
534
+ def buffer_has_unclosed_quotes? append = nil, q = '"'
535
+ if (record = append ? (@buffer + append).strip : @buffer.strip) == q
498
536
  true
499
- elsif record.start_with? '"'
500
- if ((trailing_quote = record.end_with? '"') && (record.end_with? '""')) || (record.start_with? '""')
501
- ((record = record.gsub '""', '').start_with? '"') && !(record.end_with? '"')
537
+ elsif record.start_with? q
538
+ qq = q + q
539
+ if ((trailing_quote = record.end_with? q) && (record.end_with? qq)) || (record.start_with? qq)
540
+ ((record = record.gsub qq, '').start_with? q) && !(record.end_with? q)
502
541
  else
503
542
  !trailing_quote
504
543
  end
@@ -582,7 +621,7 @@ class Table::ParserContext
582
621
  if (cellspec = take_cellspec)
583
622
  repeat = cellspec.delete('repeatcol') || 1
584
623
  else
585
- logger.error message_with_context 'table missing leading separator; recovering automatically', :source_location => Reader::Cursor.new(*@start_cursor_data)
624
+ logger.error message_with_context 'table missing leading separator; recovering automatically', source_location: Reader::Cursor.new(*@start_cursor_data)
586
625
  cellspec = {}
587
626
  repeat = 1
588
627
  end
@@ -591,20 +630,20 @@ class Table::ParserContext
591
630
  @buffer = ''
592
631
  cellspec = nil
593
632
  repeat = 1
594
- if @format == 'csv' && !cell_text.empty? && cell_text.include?('"')
633
+ if @format == 'csv' && !cell_text.empty? && (cell_text.include? (q = '"'))
595
634
  # this may not be perfect logic, but it hits the 99%
596
- if cell_text.start_with?('"') && cell_text.end_with?('"')
635
+ if (cell_text.start_with? q) && (cell_text.end_with? q)
597
636
  # unquote
598
637
  if (cell_text = cell_text.slice(1, cell_text.length - 2))
599
638
  # trim whitespace and collapse escaped quotes
600
- cell_text = cell_text.strip.squeeze('"')
639
+ cell_text = cell_text.strip.squeeze q
601
640
  else
602
- logger.error message_with_context 'unclosed quote in CSV data; setting cell to empty', :source_location => @reader.cursor_at_prev_line
641
+ logger.error message_with_context 'unclosed quote in CSV data; setting cell to empty', source_location: @reader.cursor_at_prev_line
603
642
  cell_text = ''
604
643
  end
605
644
  else
606
645
  # collapse escaped quotes
607
- cell_text = cell_text.squeeze('"')
646
+ cell_text = cell_text.squeeze q
608
647
  end
609
648
  end
610
649
  end
@@ -622,12 +661,12 @@ class Table::ParserContext
622
661
  else
623
662
  # QUESTION is this right for cells that span columns?
624
663
  unless (column = @table.columns[@current_row.size])
625
- logger.error message_with_context 'dropping cell because it exceeds specified number of columns', :source_location => @reader.cursor_before_mark
626
- return
664
+ logger.error message_with_context 'dropping cell because it exceeds specified number of columns', source_location: @reader.cursor_before_mark
665
+ return nil
627
666
  end
628
667
  end
629
668
 
630
- cell = Table::Cell.new(column, cell_text, cellspec, :cursor => @reader.cursor_before_mark)
669
+ cell = Table::Cell.new(column, cell_text, cellspec, cursor: @reader.cursor_before_mark)
631
670
  @reader.mark
632
671
  unless !cell.rowspan || cell.rowspan == 1
633
672
  activate_rowspan(cell.rowspan, (cell.colspan || 1))
@@ -642,7 +681,9 @@ class Table::ParserContext
642
681
  nil
643
682
  end
644
683
 
645
- # Public: Close the row by adding it to the Table and resetting the row
684
+ private
685
+
686
+ # Internal: Close the row by adding it to the Table and resetting the row
646
687
  # Array and counter variables.
647
688
  #
648
689
  # returns nothing
@@ -658,24 +699,21 @@ class Table::ParserContext
658
699
  nil
659
700
  end
660
701
 
661
- # Public: Activate a rowspan. The rowspan Array is consulted when
702
+ # Internal: Activate a rowspan. The rowspan Array is consulted when
662
703
  # determining the effective number of cells in the current row.
663
704
  #
664
705
  # returns nothing
665
706
  def activate_rowspan(rowspan, colspan)
666
- 1.upto(rowspan - 1).each {|i|
667
- # longhand assignment used for Opal compatibility
668
- @active_rowspans[i] = (@active_rowspans[i] || 0) + colspan
669
- }
707
+ 1.upto(rowspan - 1) {|i| @active_rowspans[i] = (@active_rowspans[i] || 0) + colspan }
670
708
  nil
671
709
  end
672
710
 
673
- # Public: Check whether we've met the number of effective columns for the current row.
711
+ # Internal: Check whether we've met the number of effective columns for the current row.
674
712
  def end_of_row?
675
713
  @colcount == -1 || effective_column_visits == @colcount
676
714
  end
677
715
 
678
- # Public: Calculate the effective column visits, which consists of the number of
716
+ # Internal: Calculate the effective column visits, which consists of the number of
679
717
  # cells plus any active rowspans.
680
718
  def effective_column_visits
681
719
  @column_visits + @active_rowspans[0]
@@ -1,4 +1,4 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
  module Asciidoctor
3
3
  class Timings
4
4
  def initialize
@@ -49,12 +49,14 @@ module Asciidoctor
49
49
 
50
50
  def print_report to = $stdout, subject = nil
51
51
  to.puts %(Input file: #{subject}) if subject
52
- to.puts %( Time to read and parse source: #{'%05.5f' % read_parse.to_f})
53
- to.puts %( Time to convert document: #{'%05.5f' % convert.to_f})
54
- to.puts %( Total time (read, parse and convert): #{'%05.5f' % read_parse_convert.to_f})
52
+ to.puts %( Time to read and parse source: #{sprintf '%05.5f', read_parse.to_f})
53
+ to.puts %( Time to convert document: #{sprintf '%05.5f', convert.to_f})
54
+ to.puts %( Total time (read, parse and convert): #{sprintf '%05.5f', read_parse_convert.to_f})
55
55
  end
56
56
 
57
- if (::Process.const_defined? :CLOCK_MONOTONIC) && (::Process.respond_to? :clock_gettime)
57
+ private
58
+
59
+ if (::Process.const_defined? :CLOCK_MONOTONIC, false) && (defined? ::Process.clock_gettime) == 'method'
58
60
  CLOCK_ID = ::Process::CLOCK_MONOTONIC
59
61
  def now
60
62
  ::Process.clock_gettime CLOCK_ID
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Asciidoctor
2
- VERSION = '1.5.8'
3
+ VERSION = '2.0.17'
3
4
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ module Asciidoctor
3
+ # A module that can be used to mix the {#write} method into a {Converter} implementation to allow the converter to
4
+ # control how the output is written to disk.
5
+ module Writer
6
+ # Public: Writes the output to the specified target file name or stream.
7
+ #
8
+ # output - The output String to write
9
+ # target - The String file name or stream object to which the output should be written.
10
+ #
11
+ # Returns nothing
12
+ def write output, target
13
+ if target.respond_to? :write
14
+ # ensure there's a trailing newline to be nice to terminals
15
+ target.write output.chomp + LF
16
+ else
17
+ # QUESTION shouldn't we ensure a trailing newline here too?
18
+ ::File.write target, output, mode: FILE_WRITE_MODE
19
+ end
20
+ nil
21
+ end
22
+ end
23
+
24
+ module VoidWriter
25
+ include Writer
26
+
27
+ # Public: Does not write output
28
+ def write output, target; end
29
+ end
30
+ end