【问题标题】:How does using String#between? with DateTime objects work in Rails?如何使用 String#between?使用 DateTime 对象在 Rails 中工作?
【发布时间】:2020-09-28 15:04:20
【问题描述】:

使用 Ruby 2.3.2Rails 5.0.0.1

在 Ruby 控制台中

2.3.2 :001 > date_time_str = "2015-01-08 08:17:15 UTC"
 => "2015-01-08 08:17:15 UTC" 
2.3.2 :002 > date_time_range_start = "2015-01-08 08:16:15 UTC"
 => "2015-01-08 08:16:15 UTC" 
2.3.2 :003 > date_time_range_end = "2015-01-08 08:20:15 UTC"
 => "2015-01-08 08:20:15 UTC" 

2.3.2 :008 > require 'date'
 => true 

2.3.2 :009 > date_time_str.between?(DateTime.parse(date_time_range_start), DateTime.parse(date_time_range_end))

ArgumentError: comparison of String with DateTime failed
    from (irb):9:in `between?'
    from (irb):9
    from /home/jignesh/.rvm/rubies/ruby-2.3.2/bin/irb:11:in `<main>'

当我试图将String 实例与DateTime 实例进行比较时,我预计会出现上述行为。但是,当我在 rails 控制台中尝试相同的操作时,它会返回预期结果,如下所示。

在 Rails 控制台中

Loading development environment (Rails 5.0.0.1)
2.3.2 :001 > date_time_str = "2015-01-08 08:17:15 UTC"
 => "2015-01-08 08:17:15 UTC" 
2.3.2 :002 > date_time_range_start = "2015-01-08 08:16:15 UTC"
 => "2015-01-08 08:16:15 UTC" 
2.3.2 :003 > date_time_range_end = "2015-01-08 08:20:15 UTC"
 => "2015-01-08 08:20:15 UTC" 
2.3.2 :004 > date_time_str.between?(DateTime.parse(date_time_range_start), DateTime.parse(date_time_range_end))
 => true 
2.3.2 :005 > date_time_str_2 = "2015-01-08 08:21:15 UTC"
 => "2015-01-08 08:21:15 UTC" 
2.3.2 :006 > date_time_str_2.between?(DateTime.parse(date_time_range_end), DateTime.parse(r_e))
 => false 

谁能帮我理解 Rails 在内部做了什么来完成上述工作?

【问题讨论】:

    标签: ruby string datetime ruby-on-rails-5


    【解决方案1】:

    String#&lt;=&gt; in ruby​​ 尝试将自己与另一个对象进行比较。如果另一个对象是不可比较的(不是字符串),那么具体的字符串实现 (c-source here) 会将另一个对象与接收字符串进行比较。

    换句话说,"str" &lt;=&gt; obj 等价于

    if obj.is_a?(String)
      # compare bytes
    elsif obj.respond_to?(:to_str)
      obj = obj.to_str
      # compare bytes
    else
      # a few safety checks
      -1 * (obj <=> "str")
    end
    

    现在我们将"str" &lt;=&gt; obj 归结为obj &lt;=&gt; "str"。到目前为止,这只是 Ruby,没有 Rails。由于Datetime#&lt;=&gt; 对字符串没有特殊处理,所以它返回 nil,故事到此结束。

    在 Rails 中,他们重新定义了 Datetime#&lt;=&gt; 并定义了 String#to_datetime

    【讨论】:

    • 感谢@Siim 提供参考。我想知道String.to_datetime 是如何被自动调用的? between?Comparable 模块提供的方法,我在字符串上调用该方法。用技术术语来说,receiver,在Comparable 术语中,在我的例子中是一个String 实例,它与another object 进行比较,DateTime 实例......
    • 如果我在DateTime 实例上调用between?,那么可以理解,它重新定义的&lt;=&gt; 被调用,并在内部调用to_datetimeString 实例上进行比较.如我的帖子所示,Ruby 甚至不允许与不同类型进行比较,而 Rails 允许。我检查了 String 类的 Rails 增强行为,但在那些文件中找不到它重新定义 &lt;=&gt; 运算符的行为。
    • 编辑了答案,解释了String#&lt;=&gt; 最终如何调用DateTime#&lt;=&gt;。这有帮助吗?
    • 这绝对结束了我的好奇心。非常感谢您的热心帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-02
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-24
    相关资源
    最近更新 更多