Repository: asciidoctor/asciidoctor (Ruby)

Issue:
Unset attributes don't inherit to AsciiDoc table cell
Attributes which are unset in the main document do not remain unset inside an AsciiDoc table cell.

Example:

```
:example-caption!:

|===
a|
.Title
====
example in table
====
|===
```

The caption on the example should not include the label and number (e.g., Example 1), but it does.


Discussion:
The relationship between the main document and the AsciiDoc table cell is no well defined. But I think it's reasonable to assume that default attributes that have been unset in the main document remain unset in the AsciiDoc table cell document.

We'll need to have a separate, larger conversation about what the inheritance and override rules really should be.



Patch:
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index 1281fc7899..0172971fb1 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -18,6 +18,7 @@ For a detailed view of what has changed, refer to the {uri-repo}/commits/master[
 Bug Fixes::
 
   * Do not allow AsciiDoc table cell to set document attribute that was unset from the API (except compat-mode and toc) (#4017)
+  * Ensure default document attributes unset in parent document remain unset in AsciiDoc table cell (nested) document (#2586)
   * Ensure mtime of input file honors TZ environment variable on JRuby for Windows (affects value of docdatetime attribute) (#3550)
   * Honor caption attribute on blocks that support captioned title even if corresponding *-caption document attribute is not set (#4023)
 
diff --git a/lib/asciidoctor/document.rb b/lib/asciidoctor/document.rb
index f857df7b7d..76a3af91e7 100644
--- a/lib/asciidoctor/document.rb
+++ b/lib/asciidoctor/document.rb
@@ -264,7 +264,7 @@ def initialize data = nil, options = {}
       parent_doctype = attr_overrides.delete 'doctype'
       # QUESTION if toc is hard unset in parent document, should it be hard unset in nested document?
       attr_overrides.delete 'toc'
-      attr_overrides.delete 'toc-placement'
+      @attributes['toc-placement'] = (attr_overrides.delete 'toc-placement') || 'auto'
       attr_overrides.delete 'toc-position'
       @safe = parent_doc.safe
       @attributes['compat-mode'] = '' if (@compat_mode = parent_doc.compat_mode)
@@ -339,11 +339,13 @@ def initialize data = nil, options = {}
     (@options = options).freeze
 
     attrs = @attributes
-    attrs['attribute-undefined'] = Compliance.attribute_undefined
-    attrs['attribute-missing'] = Compliance.attribute_missing
-    attrs.update DEFAULT_ATTRIBUTES
-    # TODO if lang attribute is set, @safe mode < SafeMode::SERVER, and !parent_doc,
-    # load attributes from data/locale/attributes-<lang>.adoc
+    unless parent_doc
+      attrs['attribute-undefined'] = Compliance.attribute_undefined
+      attrs['attribute-missing'] = Compliance.attribute_missing
+      attrs.update DEFAULT_ATTRIBUTES
+      # TODO if lang attribute is set, @safe mode < SafeMode::SERVER, and !parent_doc,
+      # load attributes from data/locale/attributes-<lang>.adoc
+    end
 
     if standalone
       # sync embedded attribute with :standalone option value


Test patch:
diff --git a/test/tables_test.rb b/test/tables_test.rb
index a6ba9d6ddb..0f15359fee 100644
--- a/test/tables_test.rb
+++ b/test/tables_test.rb
@@ -1421,6 +1421,78 @@
       assert_xpath '//td[@class="icon"]/*[@class="title"][text()="Note"]', result, 1
     end
 
+    test 'should keep attribute unset in AsciiDoc table cell if unset in parent document' do
+      input = <<~'EOS'
+      :!sectids:
+      :!table-caption:
+
+      == Outer Heading
+
+      .Outer Table
+      |===
+      a|
+
+      == Inner Heading
+
+      .Inner Table
+      !===
+      ! table cell
+      !===
+      |===
+      EOS
+
+      result = convert_string_to_embedded input
+      assert_xpath 'h2[id]', result, 0
+      assert_xpath '//caption[text()="Outer Table"]', result, 1
+      assert_xpath '//caption[text()="Inner Table"]', result, 1
+    end
+
+    test 'should allow attribute unset in parent document to be set in AsciiDoc table cell' do
+      input = <<~'EOS'
+      :!sectids:
+
+      == No ID
+
+      |===
+      a|
+
+      == No ID
+
+      :sectids:
+
+      == Has ID
+      |===
+      EOS
+
+      result = convert_string_to_embedded input
+      headings = xmlnodes_at_css 'h2', result
+      assert_equal 3, headings.size
+      assert_nil headings[0].attr :id
+      assert_nil headings[1].attr :id
+      assert_equal '_has_id', (headings[2].attr :id)
+    end
+
+    test 'should not allow locked attribute unset in parent document to be set in AsciiDoc table cell' do
+      input = <<~'EOS'
+      == No ID
+
+      |===
+      a|
+
+      == No ID
+
+      :sectids:
+
+      == Has ID
+      |===
+      EOS
+
+      result = convert_string_to_embedded input, attributes: { 'sectids' => nil }
+      headings = xmlnodes_at_css 'h2', result
+      assert_equal 3, headings.size
+      headings.each {|heading| assert_nil (heading.attr :id) }
+    end
+
     test 'AsciiDoc content' do
       input = <<~'EOS'
       [cols="1e,1,5a"]