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
@@ -107,7 +107,7 @@ class Document < AbstractBlock
107
107
  # Public: Get the Boolean AsciiDoc compatibility mode
108
108
  #
109
109
  # enabling this attribute activates the following syntax changes:
110
- #
110
+ #
111
111
  # * single quotes as constrained emphasis formatting marks
112
112
  # * single backticks parsed as inline literal, formatted as monospace
113
113
  # * single plus parsed as constrained, monospaced inline formatting
@@ -181,11 +181,13 @@ class Document < AbstractBlock
181
181
  end
182
182
  accum
183
183
  end
184
+ @callouts = parent_doc.callouts
184
185
  # QUESTION should we support setting attribute in parent document from nested document?
185
186
  # NOTE we must dup or else all the assignments to the overrides clobbers the real attributes
186
187
  attr_overrides = parent_doc.attributes.dup
187
- attr_overrides.delete 'doctype'
188
- attr_overrides.delete 'compat-mode'
188
+ ['doctype', 'compat-mode', 'toc', 'toc-placement', 'toc-position'].each do |key|
189
+ attr_overrides.delete key
190
+ end
189
191
  @attribute_overrides = attr_overrides
190
192
  @safe = parent_doc.safe
191
193
  @compat_mode = parent_doc.compat_mode
@@ -203,6 +205,7 @@ class Document < AbstractBlock
203
205
  :indexterms => [],
204
206
  :includes => ::Set.new,
205
207
  }
208
+ @callouts = Callouts.new
206
209
  # copy attributes map and normalize keys
207
210
  # attribute overrides are attributes that can only be set from the commandline
208
211
  # a direct assignment effectively makes the attribute a constant
@@ -243,7 +246,6 @@ class Document < AbstractBlock
243
246
  @parsed = false
244
247
  @header = nil
245
248
  @counters = {}
246
- @callouts = Callouts.new
247
249
  @attributes_modified = ::Set.new
248
250
  @options = options
249
251
  @docinfo_processor_extensions = {}
@@ -351,10 +353,10 @@ class Document < AbstractBlock
351
353
  attr_overrides['icons'] ||= nil
352
354
  end
353
355
  end
354
-
356
+
355
357
  attr_overrides.delete_if do |key, val|
356
358
  verdict = false
357
- # a nil value undefines the attribute
359
+ # a nil value undefines the attribute
358
360
  if val.nil?
359
361
  attrs.delete(key)
360
362
  else
@@ -443,7 +445,7 @@ class Document < AbstractBlock
443
445
  # Public: Parse the AsciiDoc source stored in the {Reader} into an abstract syntax tree.
444
446
  #
445
447
  # If the data parameter is not nil, create a new {PreprocessorReader} and assigned it to the reader
446
- # property of this object. Otherwise, continue with the reader that was created in {#initialize}.
448
+ # property of this object. Otherwise, continue with the reader that was created in {#initialize}.
447
449
  # Pass the reader to {Parser.parse} to parse the source data into an abstract syntax tree.
448
450
  #
449
451
  # If parsing has already been performed, this method returns without performing any processing.
@@ -532,7 +534,7 @@ class Document < AbstractBlock
532
534
  if intval.to_s != current.to_s
533
535
  (current[0].ord + 1).chr
534
536
  else
535
- intval + 1
537
+ intval + 1
536
538
  end
537
539
  end
538
540
  end
@@ -638,7 +640,7 @@ class Document < AbstractBlock
638
640
  else
639
641
  return
640
642
  end
641
-
643
+
642
644
  if (separator = opts[:partition])
643
645
  Title.new val, opts.merge({ :separator => (separator == true ? @attributes['title-separator'] : separator) })
644
646
  elsif opts[:sanitize] && val.include?('<')
@@ -691,12 +693,10 @@ class Document < AbstractBlock
691
693
  #
692
694
  # block - The child Block to append to this parent Block
693
695
  #
694
- # Returns nothing.
695
- def <<(block)
696
+ # Returns The parent Block
697
+ def << block
698
+ assign_index block if block.context == :section
696
699
  super
697
- if block.context == :section
698
- assign_index block
699
- end
700
700
  end
701
701
 
702
702
  # Internal: called after the header has been parsed and before the content
@@ -710,7 +710,7 @@ class Document < AbstractBlock
710
710
  unrooted_attributes['invalid-header'] = true unless header_valid
711
711
  unrooted_attributes
712
712
  end
713
-
713
+
714
714
  # Internal: Branch the attributes so that the original state can be restored
715
715
  # at a future time.
716
716
  def save_attributes
@@ -781,7 +781,7 @@ class Document < AbstractBlock
781
781
  @header_attributes = attrs.dup
782
782
 
783
783
  # unfreeze "flexible" attributes
784
- unless nested?
784
+ unless @parent_document
785
785
  FLEXIBLE_ATTRIBUTES.each do |name|
786
786
  # turning a flexible attribute off should be permanent
787
787
  # (we may need more config if that's not always the case)
@@ -794,7 +794,7 @@ class Document < AbstractBlock
794
794
 
795
795
  # Internal: Restore the attributes to the previously saved state (attributes in header)
796
796
  def restore_attributes
797
- @callouts.rewind
797
+ @callouts.rewind unless @parent_document
798
798
  # QUESTION shouldn't this be a dup in case we convert again?
799
799
  @attributes = @header_attributes
800
800
  end
@@ -1092,7 +1092,7 @@ class Document < AbstractBlock
1092
1092
 
1093
1093
  start = ::Time.now.to_f if monitor
1094
1094
  r.write output, target
1095
- monitor[:write] = ::Time.now.to_f - start if monitor
1095
+ monitor[:write] = ::Time.now.to_f - start if monitor
1096
1096
 
1097
1097
  output
1098
1098
  end
@@ -36,7 +36,7 @@ module Extensions
36
36
  class Processor
37
37
  class << self
38
38
  # Public: Get the static configuration for this processor class.
39
- #
39
+ #
40
40
  # Returns a configuration [Hash]
41
41
  def config
42
42
  @config ||= {}
@@ -848,7 +848,7 @@ module Extensions
848
848
  # is not passed as an argument, it gets read from the name property of the
849
849
  # BlockProcessor instance. If a name still cannot be determined, an error
850
850
  # is raised.
851
- #
851
+ #
852
852
  # Examples
853
853
  #
854
854
  # # as a BlockProcessor subclass
@@ -871,7 +871,7 @@ module Extensions
871
871
  #
872
872
  # # as a method block
873
873
  # block do
874
- # named :shout
874
+ # named :shout
875
875
  # process |parent, reader, attrs|
876
876
  # ...
877
877
  # end
@@ -937,7 +937,7 @@ module Extensions
937
937
  # registered to handle. If a block macro name is not passed as an argument,
938
938
  # it gets read from the name property of the BlockMacroProcessor instance.
939
939
  # If a name still cannot be determined, an error is raised.
940
- #
940
+ #
941
941
  # Examples
942
942
  #
943
943
  # # as a BlockMacroProcessor subclass
@@ -1026,7 +1026,7 @@ module Extensions
1026
1026
  # registered to handle. If a block macro name is not passed as an argument,
1027
1027
  # it gets read from the name property of the InlineMacroProcessor instance.
1028
1028
  # If a name still cannot be determined, an error is raised.
1029
- #
1029
+ #
1030
1030
  # Examples
1031
1031
  #
1032
1032
  # # as an InlineMacroProcessor subclass
@@ -63,7 +63,7 @@ module Helpers
63
63
  # returns a String Array of normalized lines
64
64
  def self.normalize_lines_array data
65
65
  return [] if data.empty?
66
-
66
+
67
67
  # NOTE if data encoding is UTF-*, we only need 0..1
68
68
  leading_bytes = (first_line = data[0])[0..2].bytes.to_a
69
69
  if COERCE_ENCODING
@@ -99,7 +99,7 @@ module Helpers
99
99
  # data - a String of lines to normalize
100
100
  #
101
101
  # returns a String Array of normalized lines
102
- def self.normalize_lines_from_string data
102
+ def self.normalize_lines_from_string data
103
103
  return [] if data.nil_or_empty?
104
104
 
105
105
  if COERCE_ENCODING
@@ -15,7 +15,7 @@ class Inline < AbstractNode
15
15
  super(parent, context)
16
16
  @node_name = %(inline_#{context})
17
17
 
18
- @text = text
18
+ @text = text
19
19
 
20
20
  @id = opts[:id]
21
21
  @type = opts[:type]
@@ -37,7 +37,7 @@ class Inline < AbstractNode
37
37
  def convert
38
38
  converter.convert self
39
39
  end
40
-
40
+
41
41
  # Alias render to convert to maintain backwards compatibility
42
42
  alias :render :convert
43
43
  end
@@ -85,13 +85,13 @@ class Parser
85
85
  #
86
86
  # returns the Hash of orphan block attributes captured above the header
87
87
  def self.parse_document_header(reader, document)
88
- # capture any lines of block-level metadata and plow away any comment lines
89
- # that precede first block
88
+ # capture lines of block-level metadata and plow away comment lines that precede first block
90
89
  block_attributes = parse_block_metadata_lines(reader, document)
91
90
 
92
91
  # special case, block title is not allowed above document title,
93
92
  # carry attributes over to the document body
94
- if block_attributes.has_key?('title')
93
+ if (has_doctitle_line = is_next_line_document_title?(reader, block_attributes)) &&
94
+ block_attributes.has_key?('title')
95
95
  return document.finalize_header block_attributes, false
96
96
  end
97
97
 
@@ -99,48 +99,49 @@ class Parser
99
99
  # definitely an area for spec refinement
100
100
  assigned_doctitle = nil
101
101
  unless (val = document.attributes['doctitle']).nil_or_empty?
102
- document.title = val
103
- assigned_doctitle = val
102
+ document.title = assigned_doctitle = val
104
103
  end
105
104
 
106
105
  section_title = nil
107
- # check if the first line is the document title
108
- # if so, add a header to the document and parse the header metadata
109
- if is_next_line_document_title?(reader, block_attributes)
106
+ # if the first line is the document title, add a header to the document and parse the header metadata
107
+ if has_doctitle_line
110
108
  source_location = reader.cursor if document.sourcemap
111
- document.id, _, doctitle, _, single_line = parse_section_title(reader, document)
109
+ document.id, _, doctitle, _, single_line = parse_section_title reader, document
112
110
  unless assigned_doctitle
113
- document.title = doctitle
114
- assigned_doctitle = doctitle
111
+ document.title = assigned_doctitle = doctitle
115
112
  end
116
113
  # default to compat-mode if document uses atx-style doctitle
117
114
  document.set_attribute 'compat-mode', '' unless single_line
118
- if (separator = block_attributes.delete('separator'))
119
- document.set_attribute('title-separator', separator)
115
+ if (separator = block_attributes.delete 'separator')
116
+ document.set_attribute 'title-separator', separator
120
117
  end
121
118
  document.header.source_location = source_location if source_location
122
119
  document.attributes['doctitle'] = section_title = doctitle
123
120
  # QUESTION: should the id assignment on Document be encapsulated in the Document class?
124
- unless document.id
125
- document.id = block_attributes.delete('id')
121
+ if document.id
122
+ block_attributes.delete 1
123
+ block_attributes.delete 'id'
124
+ else
125
+ if (style = block_attributes.delete 1)
126
+ style_attrs = { 1 => style }
127
+ parse_style_attribute style_attrs, reader
128
+ block_attributes['id'] = style_attrs['id'] if style_attrs.key? 'id'
129
+ end
130
+ document.id = block_attributes.delete 'id'
126
131
  end
127
- parse_header_metadata(reader, document)
132
+ parse_header_metadata reader, document
128
133
  end
129
134
 
130
- if !(val = document.attributes['doctitle']).nil_or_empty? &&
131
- val != section_title
132
- document.title = val
133
- assigned_doctitle = val
135
+ unless (val = document.attributes['doctitle']).nil_or_empty? || val == section_title
136
+ document.title = assigned_doctitle = val
134
137
  end
135
138
 
136
139
  # restore doctitle attribute to original assignment
137
- if assigned_doctitle
138
- document.attributes['doctitle'] = assigned_doctitle
139
- end
140
+ document.attributes['doctitle'] = assigned_doctitle if assigned_doctitle
140
141
 
141
142
  # parse title and consume name section of manpage document
142
143
  parse_manpage_header(reader, document) if document.doctype == 'manpage'
143
-
144
+
144
145
  # NOTE block_attributes are the block-level attributes (not document attributes) that
145
146
  # precede the first line of content (document title, first section or first block)
146
147
  document.finalize_header block_attributes
@@ -168,7 +169,7 @@ class Parser
168
169
  name_section_buffer = reader.read_lines_until(:break_on_blank_lines => true).join(' ').tr_s(' ', ' ')
169
170
  if (m = ManpageNamePurposeRx.match(name_section_buffer))
170
171
  document.attributes['manname'] = document.sub_attributes m[1]
171
- document.attributes['manpurpose'] = m[2]
172
+ document.attributes['manpurpose'] = m[2]
172
173
  # TODO parse multiple man names
173
174
 
174
175
  if document.backend == 'manpage'
@@ -339,7 +340,7 @@ class Parser
339
340
  elsif first_block.content_model != :compound
340
341
  intro = Block.new section, :open, :content_model => :compound
341
342
  intro.style = 'partintro'
342
- section.blocks.shift
343
+ section.blocks.shift
343
344
  if first_block.style == 'partintro'
344
345
  first_block.context = :paragraph
345
346
  first_block.style = nil
@@ -406,7 +407,7 @@ class Parser
406
407
  #
407
408
  # reader - The Reader from which to retrieve the next block
408
409
  # parent - The Document, Section or Block to which the next block belongs
409
- #
410
+ #
410
411
  # Returns a Section or Block object holding the parsed content of the processed lines
411
412
  #--
412
413
  # QUESTION should next_block have an option for whether it should keep looking until
@@ -425,7 +426,7 @@ class Parser
425
426
  options.delete(:text)
426
427
  text_only = false
427
428
  end
428
-
429
+
429
430
  parse_metadata = options.fetch(:parse_metadata, true)
430
431
  #parse_sections = options.fetch(:parse_sections, false)
431
432
 
@@ -834,7 +835,7 @@ class Parser
834
835
 
835
836
  when :literal
836
837
  block = build_block(block_context, :verbatim, terminator, parent, reader, attributes)
837
-
838
+
838
839
  when :pass
839
840
  block = build_block(block_context, :raw, terminator, parent, reader, attributes)
840
841
 
@@ -1078,7 +1079,7 @@ class Parser
1078
1079
  adjust_indentation! lines, indent, (attributes['tabsize'] || parent.document.attributes['tabsize'])
1079
1080
  elsif (tab_size = (attributes['tabsize'] || parent.document.attributes['tabsize']).to_i) > 0
1080
1081
  adjust_indentation! lines, nil, tab_size
1081
- end
1082
+ end
1082
1083
  end
1083
1084
 
1084
1085
  if (extension = options[:extension])
@@ -1325,7 +1326,7 @@ class Parser
1325
1326
  if list_item_reader.has_more_lines?
1326
1327
  comment_lines = list_item_reader.skip_line_comments
1327
1328
  subsequent_line = list_item_reader.peek_line
1328
- list_item_reader.unshift_lines comment_lines unless comment_lines.empty?
1329
+ list_item_reader.unshift_lines comment_lines unless comment_lines.empty?
1329
1330
 
1330
1331
  if !subsequent_line.nil?
1331
1332
  continuation_connects_first_block = subsequent_line.empty?
@@ -1374,7 +1375,7 @@ class Parser
1374
1375
  #
1375
1376
  # reader - The Reader from which to retrieve the lines.
1376
1377
  # list_type - The Symbol context of the list (:ulist, :olist, :colist or :dlist)
1377
- # sibling_trait - A Regexp that matches a sibling of this list item or String list marker
1378
+ # sibling_trait - A Regexp that matches a sibling of this list item or String list marker
1378
1379
  # of the items in this list (default: nil)
1379
1380
  # has_text - Whether the list item has text defined inline (always true except for labeled lists)
1380
1381
  #
@@ -1384,7 +1385,7 @@ class Parser
1384
1385
 
1385
1386
  # three states for continuation: :inactive, :active & :frozen
1386
1387
  # :frozen signifies we've detected sequential continuation lines &
1387
- # continuation is not permitted until reset
1388
+ # continuation is not permitted until reset
1388
1389
  continuation = :inactive
1389
1390
 
1390
1391
  # if we are within a nested list, we don't throw away the list
@@ -1444,7 +1445,7 @@ class Parser
1444
1445
  break
1445
1446
  else
1446
1447
  if continuation == :active && !this_line.empty?
1447
- # literal paragraphs have special considerations (and this is one of
1448
+ # literal paragraphs have special considerations (and this is one of
1448
1449
  # two entry points into one)
1449
1450
  # if we don't process it as a whole, then a line in it that looks like a
1450
1451
  # list item will throw off the exit from it
@@ -1477,7 +1478,7 @@ class Parser
1477
1478
  # advance to the next line of content
1478
1479
  if this_line.empty?
1479
1480
  reader.skip_blank_lines
1480
- this_line = reader.read_line
1481
+ this_line = reader.read_line
1481
1482
  # if we hit eof or a sibling, stop reading
1482
1483
  break if this_line.nil? || is_sibling_list_item?(this_line, list_type, sibling_trait)
1483
1484
  end
@@ -1834,7 +1835,7 @@ class Parser
1834
1835
  rev_metadata = {}
1835
1836
 
1836
1837
  if reader.has_more_lines? && !reader.next_line_empty?
1837
- rev_line = reader.read_line
1838
+ rev_line = reader.read_line
1838
1839
  if (match = RevisionInfoLineRx.match(rev_line))
1839
1840
  rev_metadata['revnumber'] = match[1].rstrip if match[1]
1840
1841
  unless (component = match[2].strip) == ''
@@ -1939,8 +1940,11 @@ class Parser
1939
1940
 
1940
1941
  segments = nil
1941
1942
  if names_only
1942
- # splitting on ' ' with limit will collapse repeating spaces
1943
- segments = author_entry.split(' ', 3)
1943
+ # splitting on ' ' collapses repeating spaces uniformly
1944
+ # `split ' ', 3` causes odd behavior in Opal; see https://github.com/asciidoctor/asciidoctor.js/issues/159
1945
+ if (segments = author_entry.split ' ').size > 3
1946
+ segments = segments[0..1].push(segments[2..-1].join ' ')
1947
+ end
1944
1948
  elsif (match = AuthorInfoLineRx.match(author_entry))
1945
1949
  segments = match.to_a
1946
1950
  segments.shift
@@ -2187,7 +2191,7 @@ class Parser
2187
2191
  # Parser.resolve_ordered_list_marker(marker, 1, true)
2188
2192
  # # => 'A.'
2189
2193
  #
2190
- # Returns the String of the first marker in this number series
2194
+ # Returns the String of the first marker in this number series
2191
2195
  def self.resolve_ordered_list_marker(marker, ordinal = 0, validate = false, reader = nil)
2192
2196
  number_style = ORDERED_LIST_STYLES.detect {|s| OrderedListMarkerRxMap[s] =~ marker }
2193
2197
  expected = actual = nil
@@ -2238,7 +2242,7 @@ class Parser
2238
2242
  #
2239
2243
  # line - The String line to check
2240
2244
  # list_type - The context of the list (:olist, :ulist, :colist, :dlist)
2241
- # sibling_trait - The String marker for the list or the Regexp to match a sibling
2245
+ # sibling_trait - The String marker for the list or the Regexp to match a sibling
2242
2246
  #
2243
2247
  # Returns a Boolean indicating whether this line is a sibling list item given
2244
2248
  # the criteria provided
@@ -2276,11 +2280,11 @@ class Parser
2276
2280
  table.assign_caption attributes.delete('caption')
2277
2281
  end
2278
2282
 
2279
- if attributes['cols'].nil_or_empty?
2280
- explicit_col_specs = false
2281
- else
2282
- table.create_columns(parse_col_specs(attributes['cols']))
2283
+ if (attributes.key? 'cols') && !(col_specs = parse_col_specs attributes['cols']).empty?
2284
+ table.create_columns col_specs
2283
2285
  explicit_col_specs = true
2286
+ else
2287
+ explicit_col_specs = false
2284
2288
  end
2285
2289
 
2286
2290
  skipped = table_reader.skip_blank_lines
@@ -2376,12 +2380,8 @@ class Parser
2376
2380
  end
2377
2381
  end
2378
2382
 
2379
- table.attributes['colcount'] ||= parser_ctx.col_count
2380
-
2381
- if !explicit_col_specs
2382
- # TODO further encapsulate this logic (into table perhaps?)
2383
- even_width = (100.0 / parser_ctx.col_count).floor
2384
- table.columns.each {|c| c.assign_width(0, even_width) }
2383
+ unless (table.attributes['colcount'] ||= table.columns.size) == 0 || explicit_col_specs
2384
+ table.assign_col_widths
2385
2385
  end
2386
2386
 
2387
2387
  table.partition_header_footer attributes
@@ -2393,17 +2393,17 @@ class Parser
2393
2393
  #
2394
2394
  # The column specs dictate the number of columns, relative
2395
2395
  # width of columns, default alignments for cells in each
2396
- # column, and/or default styles or filters applied to the cells in
2396
+ # column, and/or default styles or filters applied to the cells in
2397
2397
  # the column.
2398
2398
  #
2399
2399
  # Every column spec is guaranteed to have a width
2400
2400
  #
2401
2401
  # returns a Hash of attributes that specify how to format
2402
2402
  # and layout the cells in the table.
2403
- def self.parse_col_specs(records)
2403
+ def self.parse_col_specs records
2404
+ records = records.tr ' ', '' if records.include? ' '
2404
2405
  # check for deprecated syntax: single number, equal column spread
2405
- # REVIEW could use records == records.to_i.to_s instead of regexp
2406
- if DigitsRx =~ records
2406
+ if records == records.to_i.to_s
2407
2407
  return ::Array.new(records.to_i) { { 'width' => 1 } }
2408
2408
  end
2409
2409
 
@@ -2455,7 +2455,7 @@ class Parser
2455
2455
  # The default spec when pos == :end is {} since we already know we're at a
2456
2456
  # delimiter. When pos == :start, we *may* be at a delimiter, nil indicates
2457
2457
  # we're not.
2458
- #
2458
+ #
2459
2459
  # returns the Hash of attributes that indicate how to layout
2460
2460
  # and style this cell in the table.
2461
2461
  def self.parse_cell_spec(line, pos = :start, delimiter = nil)
@@ -2496,7 +2496,7 @@ class Parser
2496
2496
  spec['repeatcol'] = colspec unless colspec == 1
2497
2497
  end
2498
2498
  end
2499
-
2499
+
2500
2500
  if m[3]
2501
2501
  colspec, rowspec = m[3].split '.'
2502
2502
  if !colspec.nil_or_empty? && Table::ALIGNMENTS[:h].has_key?(colspec)
@@ -2584,7 +2584,7 @@ class Parser
2584
2584
  collector.push c
2585
2585
  end
2586
2586
  end
2587
-
2587
+
2588
2588
  # small optimization if no shorthand is found
2589
2589
  if type == :style
2590
2590
  parsed_style = attributes['style'] = raw_style
@@ -2610,7 +2610,7 @@ class Parser
2610
2610
  attributes[%(#{option}-option)] = ''
2611
2611
  end
2612
2612
  if (existing_opts = attributes['options'])
2613
- attributes['options'] = (options + existing_opts.split(',')) * ','
2613
+ attributes['options'] = (options + existing_opts.split(',')) * ','
2614
2614
  else
2615
2615
  attributes['options'] = options * ','
2616
2616
  end
@@ -2755,7 +2755,7 @@ class Parser
2755
2755
  value = value.downcase
2756
2756
  digits = { 'i' => 1, 'v' => 5, 'x' => 10 }
2757
2757
  result = 0
2758
-
2758
+
2759
2759
  (0..value.length - 1).each {|i|
2760
2760
  digit = digits[value[i..i]]
2761
2761
  if i + 1 < value.length && digits[value[i+1..i+1]] > digit