asciidoctor 1.5.3 → 1.5.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of asciidoctor might be problematic. Click here for more details.

Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +67 -5
  3. data/CONTRIBUTING.adoc +171 -0
  4. data/LICENSE.adoc +1 -1
  5. data/README.adoc +62 -30
  6. data/bin/asciidoctor +3 -3
  7. data/bin/asciidoctor-safe +8 -5
  8. data/lib/asciidoctor.rb +10 -21
  9. data/lib/asciidoctor/abstract_block.rb +29 -11
  10. data/lib/asciidoctor/abstract_node.rb +11 -6
  11. data/lib/asciidoctor/callouts.rb +6 -10
  12. data/lib/asciidoctor/cli/options.rb +2 -2
  13. data/lib/asciidoctor/converter.rb +1 -1
  14. data/lib/asciidoctor/converter/docbook5.rb +46 -23
  15. data/lib/asciidoctor/converter/factory.rb +3 -3
  16. data/lib/asciidoctor/converter/html5.rb +27 -24
  17. data/lib/asciidoctor/converter/manpage.rb +72 -61
  18. data/lib/asciidoctor/converter/template.rb +5 -9
  19. data/lib/asciidoctor/document.rb +18 -18
  20. data/lib/asciidoctor/extensions.rb +5 -5
  21. data/lib/asciidoctor/helpers.rb +2 -2
  22. data/lib/asciidoctor/inline.rb +2 -2
  23. data/lib/asciidoctor/parser.rb +59 -59
  24. data/lib/asciidoctor/path_resolver.rb +23 -15
  25. data/lib/asciidoctor/reader.rb +34 -29
  26. data/lib/asciidoctor/section.rb +6 -8
  27. data/lib/asciidoctor/substitutors.rb +2 -2
  28. data/lib/asciidoctor/table.rb +46 -23
  29. data/lib/asciidoctor/version.rb +1 -1
  30. data/man/asciidoctor.1 +11 -11
  31. data/man/asciidoctor.adoc +2 -2
  32. data/test/attributes_test.rb +21 -37
  33. data/test/blocks_test.rb +41 -14
  34. data/test/converter_test.rb +4 -4
  35. data/test/document_test.rb +61 -8
  36. data/test/extensions_test.rb +2 -2
  37. data/test/invoker_test.rb +3 -3
  38. data/test/links_test.rb +13 -3
  39. data/test/lists_test.rb +114 -114
  40. data/test/manpage_test.rb +203 -0
  41. data/test/paragraphs_test.rb +3 -3
  42. data/test/parser_test.rb +4 -4
  43. data/test/preamble_test.rb +1 -1
  44. data/test/reader_test.rb +149 -109
  45. data/test/sections_test.rb +137 -27
  46. data/test/substitutions_test.rb +24 -16
  47. data/test/tables_test.rb +183 -31
  48. data/test/test_helper.rb +10 -22
  49. metadata +9 -6
  50. data/compat/asciidoc.conf +0 -395
  51. data/compat/font-awesome-3-compat.css +0 -397
@@ -96,7 +96,7 @@ module Asciidoctor
96
96
  # begin
97
97
  # resolver.system_path('images', '/etc', '/path/to/docs')
98
98
  # rescue SecurityError => e
99
- # puts e.message
99
+ # puts e.message
100
100
  # end
101
101
  # => Start path /etc is outside of jail: /path/to/docs'
102
102
  #
@@ -145,6 +145,9 @@ class PathResolver
145
145
  # Windows roots can begin with drive letter
146
146
  elsif @file_separator == BACKSLASH && WindowsRootRx =~ path
147
147
  true
148
+ # Absolute paths in the browser start with file:///
149
+ elsif ::RUBY_ENGINE_OPAL && ::JAVASCRIPT_PLATFORM == 'browser' && (path.start_with? 'file:///')
150
+ true
148
151
  else
149
152
  false
150
153
  end
@@ -167,7 +170,7 @@ class PathResolver
167
170
  def is_web_root? path
168
171
  path.start_with? SLASH
169
172
  end
170
-
173
+
171
174
  # Public: Normalize path by converting any backslashes to forward slashes
172
175
  #
173
176
  # path - the String path to normalize
@@ -198,7 +201,7 @@ class PathResolver
198
201
  path_segments, path_root, _ = partition_path path
199
202
  join_path path_segments, path_root
200
203
  end
201
-
204
+
202
205
  # Public: Partition the path into path segments and remove any empty segments
203
206
  # or segments that are self references (.). The path is converted to a posix
204
207
  # path before being partitioned.
@@ -211,7 +214,7 @@ class PathResolver
211
214
  # path root (e.g., '/', './', 'c:/') if the path is absolute and the posix
212
215
  # version of the path.
213
216
  #--
214
- # QUESTION is it worth it to normalize slashes? it doubles the time elapsed
217
+ # QUESTION is it worth it to normalize slashes? it doubles the time elapsed
215
218
  def partition_path path, web_path = false
216
219
  if (result = web_path ? @_partition_path_web[path] : @_partition_path_sys[path])
217
220
  return result
@@ -238,7 +241,7 @@ class PathResolver
238
241
  # ex. /sample/path
239
242
  elsif posix_path.start_with? SLASH
240
243
  SLASH
241
- # ex. c:/sample/path
244
+ # ex. c:/sample/path (or file:///sample/path in browser environment)
242
245
  else
243
246
  posix_path[0..(posix_path.index SLASH)]
244
247
  end
@@ -255,6 +258,11 @@ class PathResolver
255
258
  # shift twice for a UNC path
256
259
  if root == DOUBLE_SLASH
257
260
  path_segments = path_segments[2..-1]
261
+ # shift twice for a file:/// path and adjust root
262
+ # NOTE technically file:/// paths work without this adjustment
263
+ #elsif ::RUBY_ENGINE_OPAL && ::JAVASCRIPT_PLATFORM == 'browser' && root == 'file:/'
264
+ # root = 'file://'
265
+ # path_segments = path_segments[2..-1]
258
266
  # shift once for any other root
259
267
  elsif root
260
268
  path_segments.shift
@@ -265,7 +273,7 @@ class PathResolver
265
273
  #posix_path = posix_path.chomp '/'
266
274
  (web_path ? @_partition_path_web : @_partition_path_sys)[path] = [path_segments, root, posix_path]
267
275
  end
268
-
276
+
269
277
  # Public: Join the segments using the posix file separator (since Ruby knows
270
278
  # how to work with paths specified this way, regardless of OS). Use the root,
271
279
  # if specified, to construct an absolute path. Otherwise join the segments as
@@ -283,7 +291,7 @@ class PathResolver
283
291
  segments * SLASH
284
292
  end
285
293
  end
286
-
294
+
287
295
  # Public: Resolve a system path from the target and start paths. If a jail
288
296
  # path is specified, enforce that the resolved directory is contained within
289
297
  # the jail path. If a jail path is not provided, the resolved path may be
@@ -313,7 +321,7 @@ class PathResolver
313
321
  if target.nil_or_empty?
314
322
  target_segments = []
315
323
  else
316
- target_segments, target_root, _ = partition_path target
324
+ target_segments, target_root, _ = partition_path target
317
325
  end
318
326
 
319
327
  if target_segments.empty?
@@ -327,7 +335,7 @@ class PathResolver
327
335
  return system_path start, jail, jail, opts
328
336
  end
329
337
  end
330
-
338
+
331
339
  if target_root && target_root != DOT_SLASH
332
340
  resolved_target = join_path target_segments, target_root
333
341
  # if target is absolute and a sub-directory of jail, or
@@ -336,7 +344,7 @@ class PathResolver
336
344
  return resolved_target
337
345
  end
338
346
  end
339
-
347
+
340
348
  if start.nil_or_empty?
341
349
  start = jail ? jail : @working_dir
342
350
  elsif is_root? start
@@ -344,7 +352,7 @@ class PathResolver
344
352
  else
345
353
  start = system_path start, jail, jail, opts
346
354
  end
347
-
355
+
348
356
  # both jail and start have been posixfied at this point
349
357
  if jail == start
350
358
  jail_segments, jail_root, _ = partition_path jail
@@ -354,9 +362,9 @@ class PathResolver
354
362
  raise ::SecurityError, %(#{opts[:target_name] || 'Start path'} #{start} is outside of jail: #{jail} (disallowed in safe mode))
355
363
  end
356
364
 
357
- start_segments, start_root, _ = partition_path start
365
+ start_segments, start_root, _ = partition_path start
358
366
  jail_segments, jail_root, _ = partition_path jail
359
-
367
+
360
368
  # Already checked for this condition
361
369
  #if start_root != jail_root
362
370
  # raise ::SecurityError, %(Jail root #{jail_root} does not match root of #{opts[:target_name] || 'start path'}: #{start_root})
@@ -365,7 +373,7 @@ class PathResolver
365
373
  start_segments, start_root, _ = partition_path start
366
374
  jail_root = start_root
367
375
  end
368
-
376
+
369
377
  resolved_segments = start_segments.dup
370
378
  warned = false
371
379
  target_segments.each do |segment|
@@ -386,7 +394,7 @@ class PathResolver
386
394
  resolved_segments.push segment
387
395
  end
388
396
  end
389
-
397
+
390
398
  join_path resolved_segments, jail_root
391
399
  end
392
400
 
@@ -7,7 +7,7 @@ class Reader
7
7
  attr_accessor :dir
8
8
  attr_accessor :path
9
9
  attr_accessor :lineno
10
-
10
+
11
11
  def initialize file, dir = nil, path = nil, lineno = nil
12
12
  @file = file
13
13
  @dir = dir
@@ -147,7 +147,7 @@ class Reader
147
147
  # returns the first element of the internal @lines Array. (default: false)
148
148
  #
149
149
  # Returns the next line of the source data as a String if there are lines remaining.
150
- # Returns nil if there is no more data.
150
+ # Returns nothing if there is no more data.
151
151
  def peek_line direct = false
152
152
  if direct || @look_ahead > 0
153
153
  @unescape_next_line ? @lines[0][1..-1] : @lines[0]
@@ -205,7 +205,7 @@ class Reader
205
205
  # returns the first element of the internal @lines Array. (default: false)
206
206
  #
207
207
  # Returns the String of the next line of the source data if data is present.
208
- # Returns nil if there is no more data.
208
+ # Returns nothing if there is no more data.
209
209
  def read_line direct = false
210
210
  if direct || @look_ahead > 0 || has_more_lines?
211
211
  shift
@@ -245,7 +245,7 @@ class Reader
245
245
  # direct - A Boolean flag to bypasses the check for more lines and immediately
246
246
  # returns the first element of the internal @lines Array. (default: true)
247
247
  #
248
- # returns a Boolean indicating whether there was a line to discard.
248
+ # Returns a Boolean indicating whether there was a line to discard.
249
249
  def advance direct = true
250
250
  !!read_line(direct)
251
251
  end
@@ -255,7 +255,9 @@ class Reader
255
255
  # Since this line was (assumed to be) previously retrieved through the
256
256
  # reader, it is marked as seen.
257
257
  #
258
- # returns nil
258
+ # line_to_restore - the line to restore onto the stack
259
+ #
260
+ # Returns nothing.
259
261
  def unshift_line line_to_restore
260
262
  unshift line_to_restore
261
263
  nil
@@ -267,7 +269,7 @@ class Reader
267
269
  # Since these lines were (assumed to be) previously retrieved through the
268
270
  # reader, they are marked as seen.
269
271
  #
270
- # Returns nil
272
+ # Returns nothing.
271
273
  def unshift_lines lines_to_restore
272
274
  # QUESTION is it faster to use unshift(*lines_to_restore)?
273
275
  lines_to_restore.reverse_each {|line| unshift line }
@@ -275,20 +277,22 @@ class Reader
275
277
  end
276
278
  alias :restore_lines :unshift_lines
277
279
 
278
- # Public: Replace the current line with the specified line.
280
+ # Public: Replace the next line with the specified line.
279
281
  #
280
282
  # Calls Reader#advance to consume the current line, then calls
281
283
  # Reader#unshift to push the replacement onto the top of the
282
284
  # line stack.
283
285
  #
284
- # replacement - The String line to put in place of the line at the cursor.
286
+ # replacement - The String line to put in place of the next line (i.e., the line at the cursor).
285
287
  #
286
288
  # Returns nothing.
287
- def replace_line replacement
289
+ def replace_next_line replacement
288
290
  advance
289
291
  unshift replacement
290
292
  nil
291
293
  end
294
+ # deprecated
295
+ alias :replace_line :replace_next_line
292
296
 
293
297
  # Public: Strip off leading blank lines in the Array of lines.
294
298
  #
@@ -441,7 +445,7 @@ class Reader
441
445
  skip_comments = options[:skip_line_comments]
442
446
  line_read = false
443
447
  line_restored = false
444
-
448
+
445
449
  complete = false
446
450
  while !complete && (line = read_line)
447
451
  complete = while true
@@ -462,7 +466,7 @@ class Reader
462
466
  line_read = true
463
467
  end
464
468
  if options[:preserve_last_line]
465
- restore_line line
469
+ unshift line
466
470
  line_restored = true
467
471
  end
468
472
  else
@@ -656,7 +660,7 @@ class PreprocessorReader < Reader
656
660
  #
657
661
  # Returns the next line of the source data as a String if there are lines remaining
658
662
  # in the current include context or a parent include context.
659
- # Returns nil if there are no more lines remaining and the include stack is empty.
663
+ # Returns nothing if there are no more lines remaining and the include stack is empty.
660
664
  def peek_line direct = false
661
665
  if (line = super)
662
666
  line
@@ -687,7 +691,7 @@ class PreprocessorReader < Reader
687
691
  # Used for a single-line conditional block in the case of the ifdef or
688
692
  # ifndef directives, and for the conditional expression for the ifeval directive.
689
693
  #
690
- # returns a Boolean indicating whether the cursor should be advanced
694
+ # Returns a Boolean indicating whether the cursor should be advanced
691
695
  def preprocess_conditional_inclusion directive, target, delimiter, text
692
696
  # must have a target before brackets if ifdef or ifndef
693
697
  # must not have text between brackets if endif
@@ -773,8 +777,9 @@ class PreprocessorReader < Reader
773
777
  unless @skipping || skip
774
778
  # FIXME slight hack to skip past conditional line
775
779
  # but keep our synthetic line marked as processed
780
+ # QUESTION can we use read_line true and unshift twice instead?
776
781
  conditional_line = peek_line true
777
- replace_line text.rstrip
782
+ replace_next_line text.rstrip
778
783
  unshift conditional_line
779
784
  return true
780
785
  end
@@ -803,16 +808,14 @@ class PreprocessorReader < Reader
803
808
  # target - The name of the source document to include as specified in the
804
809
  # target slot of the include::[] macro
805
810
  #
806
- # returns a Boolean indicating whether the line under the cursor has changed.
811
+ # Returns a Boolean indicating whether the line under the cursor has changed.
807
812
  def preprocess_include raw_target, raw_attributes
808
813
  if (target = @document.sub_attributes raw_target, :attribute_missing => 'drop-line').empty?
814
+ advance
809
815
  if @document.attributes.fetch('attribute-missing', Compliance.attribute_missing) == 'skip'
810
- replace_line %(Unresolved directive in #{@path} - include::#{raw_target}[#{raw_attributes}])
811
- true
812
- else
813
- advance
814
- true
816
+ unshift %(Unresolved directive in #{@path} - include::#{raw_target}[#{raw_attributes}])
815
817
  end
818
+ true
816
819
  # assume that if an include processor is given, the developer wants
817
820
  # to handle when and how to process the include
818
821
  elsif include_processors? &&
@@ -825,7 +828,7 @@ class PreprocessorReader < Reader
825
828
  # however, be friendly and at least make it a link to the source document
826
829
  elsif @document.safe >= SafeMode::SECURE
827
830
  # FIXME we don't want to use a link macro if we are in a verbatim context
828
- replace_line %(link:#{target}[])
831
+ replace_next_line %(link:#{target}[])
829
832
  true
830
833
  elsif (abs_maxdepth = @maxdepth[:abs]) > 0 && @include_stack.size >= abs_maxdepth
831
834
  warn %(asciidoctor: ERROR: #{line_info}: maximum include depth of #{@maxdepth[:rel]} exceeded)
@@ -843,7 +846,7 @@ class PreprocessorReader < Reader
843
846
  end
844
847
  elsif Helpers.uriish? target
845
848
  unless @document.attributes.has_key? 'allow-uri-read'
846
- replace_line %(link:#{target}[])
849
+ replace_next_line %(link:#{target}[])
847
850
  return true
848
851
  end
849
852
 
@@ -863,7 +866,7 @@ class PreprocessorReader < Reader
863
866
  include_file = @document.normalize_system_path(target, @dir, nil, :target_name => 'include file')
864
867
  unless ::File.file? include_file
865
868
  warn %(asciidoctor: WARNING: #{line_info}: include file not found: #{include_file})
866
- replace_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
869
+ replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
867
870
  return true
868
871
  end
869
872
  #path = @document.relative_path include_file
@@ -923,7 +926,7 @@ class PreprocessorReader < Reader
923
926
  end
924
927
  rescue
925
928
  warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file})
926
- replace_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
929
+ replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
927
930
  return true
928
931
  end
929
932
  advance
@@ -966,7 +969,7 @@ class PreprocessorReader < Reader
966
969
  end
967
970
  rescue
968
971
  warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file})
969
- replace_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
972
+ replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
970
973
  return true
971
974
  end
972
975
  unless (missing_tags = tags.to_a - tags_found.to_a).empty?
@@ -978,11 +981,13 @@ class PreprocessorReader < Reader
978
981
  end
979
982
  else
980
983
  begin
984
+ # NOTE read content first so that we only advance cursor if IO operation succeeds
985
+ include_content = open(include_file, 'r') {|f| f.read }
981
986
  advance
982
- push_include open(include_file, 'r') {|f| f.read }, include_file, path, 1, attributes
987
+ push_include include_content, include_file, path, 1, attributes
983
988
  rescue
984
989
  warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file})
985
- replace_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
990
+ replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
986
991
  return true
987
992
  end
988
993
  end
@@ -1005,7 +1010,7 @@ class PreprocessorReader < Reader
1005
1010
  # data = IO.read file
1006
1011
  # reader.push_include data, file, path
1007
1012
  #
1008
- # Returns nothing
1013
+ # Returns nothing.
1009
1014
  def push_include data, file = nil, path = nil, lineno = 1, attributes = {}
1010
1015
  @include_stack << [@lines, @file, @dir, @path, @lineno, @maxdepth, @process_lines]
1011
1016
  if file
@@ -1075,7 +1080,7 @@ class PreprocessorReader < Reader
1075
1080
  end
1076
1081
 
1077
1082
  def include_depth
1078
- @include_stack.size
1083
+ @include_stack.size
1079
1084
  end
1080
1085
 
1081
1086
  def exceeded_max_depth?
@@ -95,9 +95,9 @@ class Section < AbstractBlock
95
95
  gen_id = base_id
96
96
  cnt = Compliance.unique_id_start_index
97
97
  while @document.references[:ids].has_key? gen_id
98
- gen_id = "#{base_id}#{sep}#{cnt}"
98
+ gen_id = %(#{base_id}#{sep}#{cnt})
99
99
  cnt += 1
100
- end
100
+ end
101
101
  gen_id
102
102
  else
103
103
  nil
@@ -150,9 +150,9 @@ class Section < AbstractBlock
150
150
  def sectnum(delimiter = '.', append = nil)
151
151
  append ||= (append == false ? '' : delimiter)
152
152
  if @level && @level > 1 && @parent && @parent.context == :section
153
- "#{@parent.sectnum(delimiter)}#{@number}#{append}"
153
+ %(#{@parent.sectnum(delimiter)}#{@number}#{append})
154
154
  else
155
- "#{@number}#{append}"
155
+ %(#{@number}#{append})
156
156
  end
157
157
  end
158
158
 
@@ -162,12 +162,10 @@ class Section < AbstractBlock
162
162
  #
163
163
  # block - The child Block to append to this parent Block
164
164
  #
165
- # Returns nothing.
165
+ # Returns The parent Block
166
166
  def << block
167
+ assign_index block if block.context == :section
167
168
  super
168
- if block.context == :section
169
- assign_index block
170
- end
171
169
  end
172
170
 
173
171
  def to_s
@@ -1303,12 +1303,12 @@ module Substitutors
1303
1303
  current.push c
1304
1304
  end
1305
1305
  end
1306
-
1306
+
1307
1307
  values << current.join.strip
1308
1308
  else
1309
1309
  values = str.split(',').map {|it| it.strip }
1310
1310
  end
1311
-
1311
+
1312
1312
  values
1313
1313
  end
1314
1314
 
@@ -42,7 +42,7 @@ class Table < AbstractBlock
42
42
  'v' => :verse,
43
43
  'a' => :asciidoc
44
44
  }
45
-
45
+
46
46
  # Public: A Hash mapping alignment abbreviations to alignments (horizontal
47
47
  # and vertial) that can be applies to a table column or cell
48
48
  ALIGNMENTS = {
@@ -99,21 +99,45 @@ class Table < AbstractBlock
99
99
  # Internal: Creates the Column objects from the column spec
100
100
  #
101
101
  # returns nothing
102
- def create_columns(col_specs)
103
- total_width = 0
102
+ def create_columns col_specs
104
103
  cols = []
104
+ width_base = 0
105
105
  col_specs.each do |col_spec|
106
- total_width += col_spec['width']
107
- cols << Column.new(self, cols.size, col_spec)
106
+ width_base += col_spec['width']
107
+ cols << (Column.new self, cols.size, col_spec)
108
108
  end
109
-
110
- unless cols.empty?
109
+ unless (@columns = cols).empty?
111
110
  @attributes['colcount'] = cols.size
112
- even_width = (100.0 / cols.size).floor
113
- cols.each {|c| c.assign_width(total_width, even_width) }
111
+ assign_col_widths(width_base == 0 ? nil : width_base)
112
+ end
113
+ nil
114
+ end
115
+
116
+ # Internal: Assign column widths to columns
117
+ #
118
+ # This method rounds the percentage width values to 4 decimal places and
119
+ # donates the balance to the final column.
120
+ #
121
+ # This method assumes there's at least one column in the columns array.
122
+ #
123
+ # width_base - the total of the relative column values used for calculating percentage widths (default: nil)
124
+ #
125
+ # returns nothing
126
+ def assign_col_widths width_base = nil
127
+ pf = 10.0 ** 4 # precision factor (multipler / divisor) for managing precision of calculated result
128
+ total_width = col_pcwidth = 0
129
+
130
+ if width_base
131
+ @columns.each {|col| total_width += (col_pcwidth = col.assign_width nil, width_base, pf) }
132
+ else
133
+ col_pcwidth = ((100 * pf / @columns.size).to_i) / pf
134
+ col_pcwidth = col_pcwidth.to_i if col_pcwidth.to_i == col_pcwidth
135
+ @columns.each {|col| total_width += col.assign_width col_pcwidth }
114
136
  end
115
137
 
116
- @columns = cols
138
+ # donate balance, if any, to final column
139
+ @columns[-1].assign_width(((100 - total_width + col_pcwidth) * pf).round / pf) unless total_width == 100
140
+
117
141
  nil
118
142
  end
119
143
 
@@ -139,7 +163,7 @@ class Table < AbstractBlock
139
163
  if num_body_rows > 0 && attributes.key?('footer-option')
140
164
  @rows.foot = [@rows.body.pop]
141
165
  end
142
-
166
+
143
167
  nil
144
168
  end
145
169
  end
@@ -167,19 +191,18 @@ class Table::Column < AbstractNode
167
191
  #
168
192
  # This method assigns the colpcwidth and colabswidth attributes.
169
193
  #
170
- # returns nothing
171
- def assign_width(total_width, even_width)
172
- if total_width > 0
173
- width = ((@attributes['width'].to_f / total_width) * 100).floor
174
- else
175
- width = even_width
194
+ # returns the resolved colpcwidth value
195
+ def assign_width col_pcwidth, width_base = nil, pf = 10000.0
196
+ if width_base
197
+ col_pcwidth = ((@attributes['width'].to_f / width_base) * 100 * pf).to_i / pf
198
+ col_pcwidth = col_pcwidth.to_i if col_pcwidth.to_i == col_pcwidth
176
199
  end
177
- @attributes['colpcwidth'] = width
200
+ @attributes['colpcwidth'] = col_pcwidth
178
201
  if parent.attributes.key? 'tableabswidth'
179
- @attributes['colabswidth'] = ((width.to_f / 100) * parent.attributes['tableabswidth']).round
202
+ # FIXME calculate more accurately (only used in DocBook output)
203
+ @attributes['colabswidth'] = ((col_pcwidth / 100.0) * parent.attributes['tableabswidth']).round
180
204
  end
181
-
182
- nil
205
+ col_pcwidth
183
206
  end
184
207
  end
185
208
 
@@ -348,7 +371,7 @@ class Table::ParserContext
348
371
 
349
372
  # Public: Determines whether the buffer has unclosed quotes. Used for CSV data.
350
373
  #
351
- # returns true if the buffer has unclosed quotes, false if it doesn't or it
374
+ # returns true if the buffer has unclosed quotes, false if it doesn't or it
352
375
  # isn't quoted data
353
376
  def buffer_has_unclosed_quotes?(append = nil)
354
377
  record = %(#{@buffer}#{append}).strip
@@ -455,7 +478,7 @@ class Table::ParserContext
455
478
  # unquote
456
479
  cell_text = cell_text[1...-1].strip
457
480
  end
458
-
481
+
459
482
  # collapses escaped quotes
460
483
  cell_text = cell_text.tr_s('"', '"')
461
484
  end