所以它与撬无关。我可以用完全不加载 pry 的 ruby 代码在 ruby 2.2.2 中重现您的报告。
那么为什么 Date.parse 愿意解析“23 条狗”并想出一些东西呢?我不知道。我会说这是 Date 解析中的一些特质,甚至是错误;它试图解析各种事物,但这会导致一些奇怪的边缘情况。
要对已知固定格式的日期进行更可预测的解析,请改用Date#strptime。要对不可预测格式的自然语言日期进行更复杂的解析,请使用 chronic gem。
就个人而言,我从不直接使用Date.parse,因为它有点不可预测,而是使用这两种方法之一。 (或特定的格式解析方法,如Date.iso8601)。
我试图查看Date.parse 的 MRI 代码,因为我很好奇我是否能弄清楚它在做什么。但很快就迷失在我无法理解或遵循的 C 代码中,不得不放弃。
有趣的是,这也可以在 JRuby 1.7.10 中重现(我还没有安装 jruby 9x)。 “23只狗”解析为同样的东西,“3只狗”提出。嗯,也许 JRuby Java 代码比 MRI 的 C 代码更容易理解。但是我没有时间尝试通过/调试 JRuby 中的 Date#parse 正在做的事情。它的核心也许开始于here,尽管我可能没有找到当前版本实现的正确位置。您可以看到它尝试按顺序根据多种不同格式解析日期,当它根据某种格式成功解析时停止。我们可以猜测该列表中有一些奇怪的格式以某种方式成功解析“23 只狗”而不是“3 条狗”。这很可能不是复活节彩蛋,也不是故意的;这只是尝试通过尝试猜测日期的格式并按顺序尝试各种格式来解析日期的奇怪副作用,而不是非常复杂的算法。
更新好的,至少在我正在查看的 jruby 代码中(可能不是当前的实现,而是一些实现)
最终,在尝试其他可能失败的解析后,它会尝试Date._parse_ddd -- 两个输入。
Date._parse_ddd("23 dogs", e) 返回 true,并用 mday 组件填充 Date::Parse::Bag,但 Date._parse_ddd("3 dogs", e) 返回 false 并且不填充 Bag。所以其他一切都从这里开始。
如果我们看一下Date._parse_ddd 的实现……就会发现一些怪异的正则表达式和奇怪的逻辑。可能从 MRI 复制以与 MRI 一致,或以其他方式与 MRI 行为一致。
我不想进一步调试。如果你愿意,你可以。如您所见,JRuby 实现实际上是用 ruby 编写的,甚至不是用 Java 编写的。
您或我或其他人可以尝试进一步调试(甚至可能在 JRuby 标准库实现上使用交互式调试器)以找出 确切发生了什么。但我相信答案基本上是“这是 Date.parse 的一个奇怪的副作用,并不真正知道它的输入格式,但只是尝试了一堆东西,使用不是很复杂的算法,有时会发生奇怪的事情”
更多更新:请注意,Date.parse("03 dogs") 会解析而不是提升。所以它决定的两个数字是可解析的,一个则不能。但当然Date.parse("3 May") 工作正常。并不是Date.parse 需要两位数的日期,只是它尝试了一大堆不同的解析方式,并且会正确捕捉到实际的好日期,但可能会通过一种认为的方式捕捉到不好的日期这似乎足够好,但在这种情况下是错误的。
更多想法所以它不是故意这样解析的。这是旨在捕捉其他日期的启发式规则的副产品。由于代码没有注释,我们不能准确地说出哪些部分要捕获的日期类型。这是一堆拼凑在一起的东西,试图以各种格式(包括国际格式)捕捉日期。
您可以查看测试以了解它要捕获的各种日期。或者您可以尝试通过代码来准确了解哪些行会导致您看到的行为。代码令人困惑——对我们大多数人来说,尤其是 MRI 中的 C 代码。 JRuby 中的纯 ruby 代码对于我们 ruby 爱好者来说当然更具可读性。由于浏览代码既混乱又耗时,而且几乎没有什么好处(谁在乎?),你可能不会让其他人为你做这件事。