From 6cf6e1647b97256ad7f6f20e5d32fd0a0fe042d1 Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@ruby-lang.org>
Date: Wed, 15 Sep 2021 17:26:14 +0900
Subject: [PATCH] Dump plain objects as `RDoc::Options`

So that the generated `.rdoc_options` file is loadable.

Reference:https://github.com/ruby/rdoc/commit/6cf6e164
---
 lib/rdoc/options.rb            | 39 ++++++++++++++++++---------------
 lib/rdoc/rdoc.rb               |  2 +-
 test/rdoc/test_rdoc_options.rb | 40 +++++++++++++++++++++++-----------
 test/rdoc/test_rdoc_rdoc.rb    | 11 +++++++++-
 4 files changed, 59 insertions(+), 33 deletions(-)

diff --git a/lib/rdoc/options.rb b/lib/rdoc/options.rb
index dadb694..a78116f 100644
--- a/lib/rdoc/options.rb
+++ b/lib/rdoc/options.rb
@@ -106,6 +106,7 @@ class RDoc::Options
     generator_options
     generators
     op_dir
+    page_dir
     option_parser
     pipe
     rdoc_include
@@ -434,6 +435,7 @@ class RDoc::Options
     @main_page      = map['main_page']      if map.has_key?('main_page')
     @markup         = map['markup']         if map.has_key?('markup')
     @op_dir         = map['op_dir']         if map.has_key?('op_dir')
+    @page_dir       = map['page_dir']       if map.has_key?('page_dir')
     @show_hash      = map['show_hash']      if map.has_key?('show_hash')
     @tab_width      = map['tab_width']      if map.has_key?('tab_width')
     @template_dir   = map['template_dir']   if map.has_key?('template_dir')
@@ -513,19 +515,22 @@ class RDoc::Options
   ##
   # For dumping YAML
 
-  def encode_with coder # :nodoc:
+  def to_yaml(*options) # :nodoc:
     encoding = @encoding ? @encoding.name : nil
 
-    coder.add 'encoding', encoding
-    coder.add 'static_path',  sanitize_path(@static_path)
-    coder.add 'rdoc_include', sanitize_path(@rdoc_include)
+    yaml = {}
+    yaml['encoding'] = encoding
+    yaml['static_path'] = sanitize_path(@static_path)
+    yaml['rdoc_include'] = sanitize_path(@rdoc_include)
+    yaml['page_dir'] = (sanitize_path([@page_dir]).first if @page_dir)
 
     ivars = instance_variables.map { |ivar| ivar.to_s[1..-1] }
     ivars -= SPECIAL
 
     ivars.sort.each do |ivar|
-      coder.add ivar, instance_variable_get("@#{ivar}")
+      yaml[ivar] = instance_variable_get("@#{ivar}")
     end
+    yaml.to_yaml
   end
 
   ##
@@ -548,6 +553,11 @@ class RDoc::Options
   # #template.
 
   def finish
+    if @write_options then
+      write_options
+      exit
+    end
+
     @op_dir ||= 'doc'
 
     @rdoc_include << "." if @rdoc_include.empty?
@@ -585,14 +595,14 @@ class RDoc::Options
   def finish_page_dir
     return unless @page_dir
 
-    @files << @page_dir.to_s
+    @files << @page_dir
 
-    page_dir = nil
+    page_dir = Pathname(@page_dir)
     begin
-      page_dir = @page_dir.expand_path.relative_path_from @root
+      page_dir = page_dir.expand_path.relative_path_from @root
     rescue ArgumentError
       # On Windows, sometimes crosses different drive letters.
-      page_dir = @page_dir.expand_path
+      page_dir = page_dir.expand_path
     end
 
     @page_dir = page_dir
@@ -847,7 +857,7 @@ Usage: #{opt.program_name} [options] [names...]
              "such files at your project root.",
              "NOTE: Do not use the same file name in",
              "the page dir and the root of your project") do |page_dir|
-        @page_dir = Pathname(page_dir)
+        @page_dir = page_dir
       end
 
       opt.separator nil
@@ -1159,13 +1169,6 @@ Usage: #{opt.program_name} [options] [names...]
 
     @files = argv.dup
 
-    finish
-
-    if @write_options then
-      write_options
-      exit
-    end
-
     self
   end
 
@@ -1278,7 +1281,7 @@ Usage: #{opt.program_name} [options] [names...]
     File.open '.rdoc_options', 'w' do |io|
       io.set_encoding Encoding::UTF_8
 
-      YAML.dump self, io
+      io.print to_yaml
     end
   end
 
diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb
index 6c69553..91eb861 100644
--- a/lib/rdoc/rdoc.rb
+++ b/lib/rdoc/rdoc.rb
@@ -469,11 +469,11 @@ The internal error was:
 
     if RDoc::Options === options then
       @options = options
-      @options.finish
     else
       @options = load_options
       @options.parse options
     end
+    @options.finish
 
     if @options.pipe then
       handle_pipe
diff --git a/test/rdoc/test_rdoc_options.rb b/test/rdoc/test_rdoc_options.rb
index c28f64c..5a34a97 100644
--- a/test/rdoc/test_rdoc_options.rb
+++ b/test/rdoc/test_rdoc_options.rb
@@ -55,11 +55,8 @@ class TestRDocOptions < RDoc::TestCase
     refute @options.dry_run
   end
 
-  def test_encode_with
-    coder = {}
-    class << coder; alias add []=; end
-
-    @options.encode_with coder
+  def test_to_yaml
+    coder = YAML.load(@options.to_yaml)
 
     encoding = 'UTF-8'
 
@@ -89,10 +86,9 @@ class TestRDocOptions < RDoc::TestCase
     assert_equal expected, coder
   end
 
-  def test_encode_with_trim_paths
+  def test_to_yaml_trim_paths
     subdir = nil
-    coder = {}
-    class << coder; alias add []=; end
+    coder = nil
 
     temp_dir do |dir|
       FileUtils.mkdir 'project'
@@ -113,7 +109,7 @@ class TestRDocOptions < RDoc::TestCase
           --include /
         ]
 
-        @options.encode_with coder
+        coder = YAML.load(@options.to_yaml)
       end
     end
 
@@ -145,7 +141,9 @@ class TestRDocOptions < RDoc::TestCase
 
     @options.encoding = Encoding::IBM437
 
-    options = YAML.safe_load(YAML.dump(@options), permitted_classes: [RDoc::Options, Symbol])
+    options = @options.to_yaml
+    options = YAML.safe_load(options, permitted_classes: [Symbol])
+    options = RDoc::Options.new(options)
 
     assert_equal Encoding::IBM437, options.encoding
   end
@@ -154,14 +152,15 @@ class TestRDocOptions < RDoc::TestCase
     RDoc.load_yaml
 
     yaml = <<-YAML
---- !ruby/object:RDoc::Options
+---
 static_path:
 - /etc
 rdoc_include:
 - /etc
     YAML
 
-    options = YAML.safe_load(yaml, permitted_classes: [RDoc::Options, Symbol])
+    options = YAML.safe_load(yaml, permitted_classes: [Symbol])
+    options = RDoc::Options.new(options)
 
     assert_empty options.rdoc_include
     assert_empty options.static_path
@@ -243,6 +242,7 @@ rdoc_include:
 
   def test_parse_default
     @options.parse []
+    @options.finish
 
     assert_equal RDoc::Generator::Darkfish,             @options.generator
     assert_equal 'darkfish',                            @options.template
@@ -502,6 +502,7 @@ rdoc_include:
 
     out, err = capture_output do
       @options.parse %W[--page-dir #{Dir.tmpdir}]
+      @options.finish
     end
 
     assert_empty out
@@ -530,6 +531,7 @@ rdoc_include:
 
       out, err = capture_output do
         @options.parse %W[--page-dir #{abs_page_dir} --root #{abs_root}]
+        @options.finish
       end
 
       assert_empty out
@@ -558,6 +560,8 @@ rdoc_include:
     assert_empty err
 
     assert_equal Pathname(Dir.tmpdir), @options.root
+
+    @options.finish
     assert_includes @options.rdoc_include, @options.root.to_s
   end
 
@@ -602,6 +606,7 @@ rdoc_include:
     assert_empty out
     assert_equal "could not find template NONEXISTENT\n", err
 
+    @options.finish
     assert_equal 'darkfish', @options.template
     assert_match %r%rdoc/generator/template/darkfish$%, @options.template_dir
   end
@@ -668,6 +673,7 @@ rdoc_include:
     Dir.chdir tmpdir do
       e = assert_raise SystemExit do
         @options.parse %w[--write-options]
+        @options.finish
       end
 
       assert_equal 0, e.status
@@ -764,7 +770,9 @@ rdoc_include:
 
       assert File.exist? '.rdoc_options'
 
-      assert_equal @options, YAML.safe_load(File.read('.rdoc_options'), permitted_classes: [RDoc::Options, Symbol])
+      options = File.read('.rdoc_options')
+      options = YAML.safe_load(options, permitted_classes: [Symbol])
+      assert_equal @options, RDoc::Options.new(options)
     end
   end
 
@@ -792,4 +800,10 @@ rdoc_include:
     @options.visibility = :all
     assert_equal :private, @options.visibility
   end
+
+  class DummyCoder < Hash
+    alias add :[]=
+    def tag=(tag)
+    end
+  end
 end
diff --git a/test/rdoc/test_rdoc_rdoc.rb b/test/rdoc/test_rdoc_rdoc.rb
index 7b84bb6..940934f 100644
--- a/test/rdoc/test_rdoc_rdoc.rb
+++ b/test/rdoc/test_rdoc_rdoc.rb
@@ -147,12 +147,20 @@ class TestRDocRDoc < RDoc::TestCase
   def test_load_options_partial_override
     temp_dir do
       File.open '.rdoc_options', 'w' do |io|
-        io.write "markup: Markdown"
+        io.puts "markup: Markdown"
+        io.puts "encoding: iso-8859-1"
+        io.puts "static_path: [static]"
+        io.puts "rdoc_include: [.]"
+        io.puts "page_dir: pages"
       end
 
       options = @rdoc.load_options
 
       assert_equal 'Markdown', options.markup
+      assert_equal Encoding::ISO_8859_1, options.encoding
+      assert_equal ["static"], options.static_path
+      assert_equal ["."], options.rdoc_include
+      assert_equal "pages", options.page_dir
     end
   end
 
@@ -312,6 +320,7 @@ class TestRDocRDoc < RDoc::TestCase
     top_level = nil
     temp_dir do |dir|
       @rdoc.options.parse %W[--root #{test_path}]
+      @rdoc.options.finish
 
       File.open 'include.txt', 'w' do |io|
         io.puts ':include: test.txt'
-- 
2.27.0

