summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Allen <dan.j.allen@gmail.com>2018-10-12 23:47:21 -0600
committerGitHub <noreply@github.com>2018-10-12 23:47:21 -0600
commit9d5f400ecefb82d8ace3ffe098ca2ebd33aabc06 (patch)
treed0dde568abef124fd46991d6b6329b4b61c8b0be
parent88a8b16f937f1c5d5da1a12e196b21cf6461ad0e (diff)
resolves #2067 allow filter block passed to AbstractBlock#find_by to skip subtrees (PR #2902)
- interpret :skip return value of filter block to mean skip node and its descendants - interpret :skip_children return value of filter block to mean accept node, but skip its descendants
-rw-r--r--CHANGELOG.adoc1
-rw-r--r--lib/asciidoctor/abstract_block.rb26
-rw-r--r--test/api_test.rb50
3 files changed, 72 insertions, 5 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index 44fd3184..01d26075 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -31,6 +31,7 @@ Enhancements::
* add more conventional styles to quote block when it has the excerpt role (#2092)
* colspecs can be separated by semi-colon instead of comma (#2798)
* change AbstractBlock#find_by to respond to StopIteration exception; stop traversal after matching ID (#2900)
+ * change AbstractBlock#find_by to honor return values :skip and :skip_children from filter block to skip node and its descendants or just its descendants, respectively (#2067)
Fixes::
diff --git a/lib/asciidoctor/abstract_block.rb b/lib/asciidoctor/abstract_block.rb
index c3423ac7..2c47814c 100644
--- a/lib/asciidoctor/abstract_block.rb
+++ b/lib/asciidoctor/abstract_block.rb
@@ -136,10 +136,16 @@ class AbstractBlock < AbstractNode
@next_section_index > 0
end
- # Public: Query for all descendant block-level nodes in the document tree
- # that match the specified selector (context, style, id, and/or role). If a
- # Ruby block is given, it's used as an additional filter. If no selector or
- # Ruby block is supplied, all block-level nodes in the tree are returned.
+ # Public: Walk the document tree and find all block-level nodes that match
+ # the specified selector (context, style, id, role, and/or custom filter).
+ #
+ # If a Ruby block is given, it's treated as an supplemental filter. If the
+ # filter returns true, the node is accepted and traversal continues. If the
+ # filter returns false, the node is rejected, but traversal continues. If the
+ # filter returns :skip, the node and all its descendants are rejected. If the
+ # filter returns :skip_children, the node is accepted, but its descendants
+ # are rejected. If no selector or filter block is supplied, all block-level
+ # nodes in the tree are returned.
#
# Examples
#
@@ -174,7 +180,17 @@ class AbstractBlock < AbstractNode
result.replace block_given? ? ((yield self) ? [self] : []) : [self]
raise ::StopIteration
elsif block_given?
- result << self if (yield self)
+ if (verdict = yield self)
+ case verdict
+ when :skip_children
+ result << self
+ return result
+ when :skip
+ return result
+ else
+ result << self
+ end
+ end
else
result << self
end
diff --git a/test/api_test.rb b/test/api_test.rb
index c411a8fd..4daa3b20 100644
--- a/test/api_test.rb
+++ b/test/api_test.rb
@@ -576,6 +576,56 @@ content
assert_equal 'Section', result[0].title
end
+ test 'find_by should skip node and its children if block returns :skip' do
+ input = <<-EOS
+paragraph 1
+
+====
+paragraph 2
+
+term::
++
+paragraph 3
+====
+
+paragraph 4
+ EOS
+ doc = Asciidoctor.load input
+ result = doc.find_by do |candidate|
+ ctx = candidate.context
+ if ctx == :example
+ :skip
+ elsif ctx == :paragraph
+ true
+ end
+ end
+ refute_nil result
+ assert_equal 2, result.size
+ assert_equal :paragraph, result[0].context
+ assert_equal :paragraph, result[1].context
+ end
+
+ test 'find_by should accept node but skip its children if block returns :skip_children' do
+ input = <<-EOS
+====
+paragraph 2
+
+term::
++
+paragraph 3
+====
+ EOS
+ doc = Asciidoctor.load input
+ result = doc.find_by do |candidate|
+ if candidate.context == :example
+ :skip_children
+ end
+ end
+ refute_nil result
+ assert_equal 1, result.size
+ assert_equal :example, result[0].context
+ end
+
test 'find_by should stop looking for blocks when StopIteration is raised' do
input = <<-EOS
paragraph 1