diff options
| author | Dan Allen <dan.j.allen@gmail.com> | 2021-12-31 23:50:22 -0700 |
|---|---|---|
| committer | Dan Allen <dan.j.allen@gmail.com> | 2022-01-01 04:34:50 -0700 |
| commit | de1ba697bdbc8da1a6598269f4b0093c83887f5b (patch) | |
| tree | 961fed2fe83687cbf336aff7744cde8f4e997543 | |
| parent | 56440ab73f6227634f3866f34d171095c26aa2d5 (diff) | |
handle return value of process method for block and block macro extension properly
* don't crash if value is an abstract block with context :compound that isn't of type Block (e.g., a list)
* ignore value if it matches parent argument
| -rw-r--r-- | CHANGELOG.adoc | 2 | ||||
| -rw-r--r-- | lib/asciidoctor/parser.rb | 6 | ||||
| -rw-r--r-- | test/extensions_test.rb | 124 |
3 files changed, 129 insertions, 3 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 35d457c9..5447a386 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -37,6 +37,8 @@ Compliance:: Bug Fixes:: + * Don't crash if process method for custom block returns an abstract block with context `:compound` that isn't of type `Block` (e.g., a list) + * Ignore return value of process method for custom block or block macro if value matches parent argument * Remove unnamespaced selectors in Pygments stylesheet * Normalize output from Pygments to use `linenos` class for inline line numbering and trim space after number; update default stylesheet accordingly * Change `AbstractBlock#sections?` to return false when called on block that isn't a Section or Document (PR #3591) *@mogztter* diff --git a/lib/asciidoctor/parser.rb b/lib/asciidoctor/parser.rb index ad9d34cc..ccfee715 100644 --- a/lib/asciidoctor/parser.rb +++ b/lib/asciidoctor/parser.rb @@ -660,7 +660,7 @@ class Parser if (default_attrs = ext_config[:default_attrs]) attributes.update(default_attrs) {|_, old_v| old_v } end - if (block = extension.process_method[parent, target, attributes]) + if (block = extension.process_method[parent, target, attributes]) && block != parent attributes.replace block.attributes break else @@ -1050,12 +1050,12 @@ class Parser if (extension = options[:extension]) # QUESTION do we want to delete the style? attributes.delete 'style' - return unless (block = extension.process_method[parent, block_reader || (Reader.new lines), attributes.merge]) + return unless (block = extension.process_method[parent, block_reader || (Reader.new lines), attributes.merge]) && block != parent attributes.replace block.attributes # FIXME if the content model is set to compound, but we only have simple in this context, then # forcefully set the content_model to simple to prevent parsing blocks from children # TODO document this behavior!! - if block.content_model == :compound && !(lines = block.lines).empty? + if block.content_model == :compound && Block === block && !(lines = block.lines).empty? content_model = :compound block_reader = Reader.new lines end diff --git a/test/extensions_test.rb b/test/extensions_test.rb index 5537925e..303f0abd 100644 --- a/test/extensions_test.rb +++ b/test/extensions_test.rb @@ -1572,6 +1572,75 @@ context 'Extensions' do end end + test 'should allow extension to replace custom block with a list' do + begin + Asciidoctor::Extensions.register do + block do + named :lst + on_context :paragraph + process do |parent, reader| + reader.read_lines.each_with_object create_list parent, :ulist do |line, list| + list << (create_list_item list, line) + end + end + end + end + input = <<~'EOS' + before + + [lst] + a + b + c + + after + EOS + doc = document_from_string input + assert_equal 3, doc.blocks.size + list = doc.blocks[1] + assert_equal :ulist, list.context + assert_equal 3, list.items.size + assert_equal 'a', list.items[0].text + assert_css 'li', doc.convert, 3 + ensure + Asciidoctor::Extensions.unregister_all + end + end + + test 'should allow extension to replace custom block with a section' do + begin + Asciidoctor::Extensions.register do + block do + named :sect + on_context :open + process do |parent, _, attrs| + create_section parent, attrs['title'], {} + end + end + end + input = <<~'EOS' + .Section Title + [sect] + -- + a + + b + -- + EOS + doc = document_from_string input + assert_equal 1, doc.blocks.size + sect = doc.blocks[0] + assert_equal :section, sect.context + assert_equal 'Section Title', sect.title + assert_equal 2, sect.blocks.size + assert_equal :paragraph, sect.blocks[0].context + assert_equal :paragraph, sect.blocks[1].context + assert_css 'p', doc.convert, 2 + ensure + Asciidoctor::Extensions.unregister_all + end + end + test 'can use parse_content to append blocks to current parent' do begin Asciidoctor::Extensions.register do @@ -1604,6 +1673,61 @@ context 'Extensions' do end end + test 'should ignore return value of custom block if value is parent' do + begin + Asciidoctor::Extensions.register do + block do + named :unwrap + on_context :open + process do |parent, reader| + parse_content parent, reader.read_lines + end + end + end + input = <<~'EOS' + [unwrap] + -- + a + + b + + c + -- + EOS + doc = document_from_string input + assert_equal 3, doc.blocks.size + doc.blocks.each do |block| + assert_equal :paragraph, block.context + end + assert_equal 'a', doc.blocks[0].source + assert_css 'p', doc.convert, 3 + ensure + Asciidoctor::Extensions.unregister_all + end + end + + test 'should ignore return value of custom block macro if value is parent' do + begin + Asciidoctor::Extensions.register do + block_macro :para do + process do |parent, target| + parse_content parent, target + end + end + end + input = <<~'EOS' + para::text[] + EOS + doc = document_from_string input + assert_equal 1, doc.blocks.size + assert_equal :paragraph, doc.blocks[0].context + assert_equal 'text', doc.blocks[0].source + assert_css 'p', doc.convert, 1 + ensure + Asciidoctor::Extensions.unregister_all + end + end + test 'parse_content should not share attributes between parsed blocks' do begin Asciidoctor::Extensions.register do |
