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.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +67 -5
- data/CONTRIBUTING.adoc +171 -0
- data/LICENSE.adoc +1 -1
- data/README.adoc +62 -30
- data/bin/asciidoctor +3 -3
- data/bin/asciidoctor-safe +8 -5
- data/lib/asciidoctor.rb +10 -21
- data/lib/asciidoctor/abstract_block.rb +29 -11
- data/lib/asciidoctor/abstract_node.rb +11 -6
- data/lib/asciidoctor/callouts.rb +6 -10
- data/lib/asciidoctor/cli/options.rb +2 -2
- data/lib/asciidoctor/converter.rb +1 -1
- data/lib/asciidoctor/converter/docbook5.rb +46 -23
- data/lib/asciidoctor/converter/factory.rb +3 -3
- data/lib/asciidoctor/converter/html5.rb +27 -24
- data/lib/asciidoctor/converter/manpage.rb +72 -61
- data/lib/asciidoctor/converter/template.rb +5 -9
- data/lib/asciidoctor/document.rb +18 -18
- data/lib/asciidoctor/extensions.rb +5 -5
- data/lib/asciidoctor/helpers.rb +2 -2
- data/lib/asciidoctor/inline.rb +2 -2
- data/lib/asciidoctor/parser.rb +59 -59
- data/lib/asciidoctor/path_resolver.rb +23 -15
- data/lib/asciidoctor/reader.rb +34 -29
- data/lib/asciidoctor/section.rb +6 -8
- data/lib/asciidoctor/substitutors.rb +2 -2
- data/lib/asciidoctor/table.rb +46 -23
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +11 -11
- data/man/asciidoctor.adoc +2 -2
- data/test/attributes_test.rb +21 -37
- data/test/blocks_test.rb +41 -14
- data/test/converter_test.rb +4 -4
- data/test/document_test.rb +61 -8
- data/test/extensions_test.rb +2 -2
- data/test/invoker_test.rb +3 -3
- data/test/links_test.rb +13 -3
- data/test/lists_test.rb +114 -114
- data/test/manpage_test.rb +203 -0
- data/test/paragraphs_test.rb +3 -3
- data/test/parser_test.rb +4 -4
- data/test/preamble_test.rb +1 -1
- data/test/reader_test.rb +149 -109
- data/test/sections_test.rb +137 -27
- data/test/substitutions_test.rb +24 -16
- data/test/tables_test.rb +183 -31
- data/test/test_helper.rb +10 -22
- metadata +9 -6
- data/compat/asciidoc.conf +0 -395
- data/compat/font-awesome-3-compat.css +0 -397
data/lib/asciidoctor/document.rb
CHANGED
@@ -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
|
-
|
188
|
-
|
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
|
695
|
-
def <<
|
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
|
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
|
data/lib/asciidoctor/helpers.rb
CHANGED
@@ -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
|
data/lib/asciidoctor/inline.rb
CHANGED
@@ -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
|
data/lib/asciidoctor/parser.rb
CHANGED
@@ -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
|
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
|
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
|
-
#
|
108
|
-
|
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
|
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
|
119
|
-
document.set_attribute
|
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
|
-
|
125
|
-
|
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
|
132
|
+
parse_header_metadata reader, document
|
128
133
|
end
|
129
134
|
|
130
|
-
|
131
|
-
|
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 ' '
|
1943
|
-
|
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'].
|
2280
|
-
|
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'] ||=
|
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
|
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
|
-
|
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
|