Repository: ruby/psych (Ruby)

Issue:
Breaking change in 5.2.0
I've run into the following behavior after upgrading to psych v5.2.0:

#### With 5.1.2

```ruby
irb(main):001> require 'yaml'
=> true
irb(main):002> Gem.loaded_specs['psych'].version
=> Gem::Version.new("5.1.2")
irb(main):003> '2020-01-01'.to_yaml
=> "--- '2020-01-01'\n"
```

Observe how the string is quoted in the Yaml file

#### With 5.2.0

```ruby
irb(main):001> require 'yaml'
=> true
irb(main):002> Gem.loaded_specs['psych'].version
=> Gem::Version.new("5.2.0")
irb(main):003> '2020-01-01'.to_yaml
=> "--- 2020-01-01\n"
```

Now the string is unquoted, which makes it invalid to be parsed back with `YAML.safe_load`.

I believe this behavior originates from [this commit](https://github.com/ruby/psych/commit/06db36fa3a849f229e2cbc7b495d142ff58a1f89), also because I noticed that manually requiring `'date'` before calling `.to_yaml` still yields the expected result of `v5.1.2`:

```ruby
irb(main):001> require 'yaml'
=> true
irb(main):002> Gem.loaded_specs['psych'].version
=> Gem::Version.new("5.2.0")
irb(main):003> require 'date'
=> true
irb(main):004> '2020-01-01'.to_yaml
=> "--- '2020-01-01'\n"
```

I think the following error probably hints as to where the problem originates from:
```irb
irb(main):001> require 'yaml'; Psych::ClassLoader.new.date
/Users/thierry/.asdf/installs/ruby/3.3.5/lib/ruby/gems/3.3.0/gems/psych-5.2.0/lib/psych/class_loader.rb:58:in `path2class': undefined class/module Date (ArgumentError)

        path2class(name)
                   ^^^^
	from /Users/thierry/.asdf/installs/ruby/3.3.5/lib/ruby/gems/3.3.0/gems/psych-5.2.0/lib/psych/class_loader.rb:58:in `resolve'
	from /Users/thierry/.asdf/installs/ruby/3.3.5/lib/ruby/gems/3.3.0/gems/psych-5.2.0/lib/psych/class_loader.rb:50:in `find'
	from /Users/thierry/.asdf/installs/ruby/3.3.5/lib/ruby/gems/3.3.0/gems/psych-5.2.0/lib/psych/class_loader.rb:30:in `load'
	from /Users/thierry/.asdf/installs/ruby/3.3.5/lib/ruby/gems/3.3.0/gems/psych-5.2.0/lib/psych/class_loader.rb:42:in `date'
	from (irb):1:in `<main>'
```
and that actually, `autoload :Date, date` probably rather belongs in `Psych::ClassLoader` than `Psych::ScalarScanner`. I'll try writing a regression and submit a PR if I succeed


Discussion:
@byroot did you see this issue and the [related PR](https://github.com/ruby/psych/pull/695) by any chance as you authored the commit I suspect to be responsible? 
No, I'm the maintainer, but I'll have a look.
I can repro the same issue before my change.
> I can repro the same issue before my change.

Nevermind, my LOAD PATH was incorrect, it's indeed a regression.



Patch:
diff --git a/lib/psych.rb b/lib/psych.rb
index d227b1f2..05a3f9c9 100644
--- a/lib/psych.rb
+++ b/lib/psych.rb
@@ -1,4 +1,6 @@
 # frozen_string_literal: true
+require 'date'
+
 require_relative 'psych/versions'
 case RUBY_ENGINE
 when 'jruby'
diff --git a/lib/psych/scalar_scanner.rb b/lib/psych/scalar_scanner.rb
index de214423..8cf868f8 100644
--- a/lib/psych/scalar_scanner.rb
+++ b/lib/psych/scalar_scanner.rb
@@ -4,8 +4,6 @@ module Psych
   ###
   # Scan scalars for built in types
   class ScalarScanner
-    autoload :Date, "date"
-
     # Taken from http://yaml.org/type/timestamp.html
     TIME = /^-?\d{4}-\d{1,2}-\d{1,2}(?:[Tt]|\s+)\d{1,2}:\d\d:\d\d(?:\.\d*)?(?:\s*(?:Z|[-+]\d{1,2}:?(?:\d\d)?))?$/
 
diff --git a/lib/psych/visitors/to_ruby.rb b/lib/psych/visitors/to_ruby.rb
index 9e4da5ef..f0b4a94e 100644
--- a/lib/psych/visitors/to_ruby.rb
+++ b/lib/psych/visitors/to_ruby.rb
@@ -79,7 +79,6 @@ def deserialize o
           class_loader.big_decimal._load o.value
         when "!ruby/object:DateTime"
           class_loader.date_time
-          require 'date' unless defined? DateTime
           t = @ss.parse_time(o.value)
           DateTime.civil(*t.to_a[0, 6].reverse, Rational(t.utc_offset, 86400)) +
             (t.subsec/86400)
diff --git a/psych.gemspec b/psych.gemspec
index a3fc53a8..a32f79bc 100644
--- a/psych.gemspec
+++ b/psych.gemspec
@@ -75,6 +75,8 @@ DESCRIPTION
     s.add_dependency 'stringio'
   end
 
+  s.add_dependency 'date'
+
   s.metadata['msys2_mingw_dependencies'] = 'libyaml'
   s.metadata['changelog_uri'] = s.homepage + '/releases'
 end


Test patch:
diff --git a/test/psych/helper.rb b/test/psych/helper.rb
index 4e82887c..639f6055 100644
--- a/test/psych/helper.rb
+++ b/test/psych/helper.rb
@@ -2,7 +2,6 @@
 require 'test/unit'
 require 'stringio'
 require 'tempfile'
-require 'date'
 
 require 'psych'
 
diff --git a/test/psych/test_date_time.rb b/test/psych/test_date_time.rb
index 3379bd24..4565b8e7 100644
--- a/test/psych/test_date_time.rb
+++ b/test/psych/test_date_time.rb
@@ -1,6 +1,5 @@
 # frozen_string_literal: true
 require_relative 'helper'
-require 'date'
 
 module Psych
   class TestDateTime < TestCase
diff --git a/test/psych/test_scalar_scanner.rb b/test/psych/test_scalar_scanner.rb
index 8907d125..2637a74d 100644
--- a/test/psych/test_scalar_scanner.rb
+++ b/test/psych/test_scalar_scanner.rb
@@ -1,6 +1,5 @@
 # frozen_string_literal: true
 require_relative 'helper'
-require 'date'
 
 module Psych
   class TestScalarScanner < TestCase
diff --git a/test/psych/test_string.rb b/test/psych/test_string.rb
index 84ae5cbb..cfd235a5 100644
--- a/test/psych/test_string.rb
+++ b/test/psych/test_string.rb
@@ -50,6 +50,16 @@ def test_doublequotes_when_there_is_a_single
       assert_equal str, Psych.load(yaml)
     end
 
+    def test_single_quote_when_matching_date
+      pend "Failing on JRuby" if RUBY_PLATFORM =~ /java/
+
+      lib = File.expand_path("../../../lib", __FILE__)
+      assert_separately(["-I", lib, "-r", "psych"], __FILE__, __LINE__ + 1, <<~'RUBY')
+        yml = Psych.dump('2024-11-19')
+        assert_equal '2024-11-19', Psych.load(yml)
+      RUBY
+    end
+
     def test_plain_when_shorten_than_line_width_and_no_final_line_break
       str = "Lorem ipsum"
       yaml = Psych.dump str, line_width: 12