.freeze block with Timecop 0.6.1 and Ruby 2.0.0 #83

Closed
michrome opened this Issue May 2, 2013 · 6 comments

Projects

None yet

4 participants

@michrome
michrome commented May 2, 2013

Hi—Are there any issues with Timecop 0.6.1 and Ruby 2.0.0?

This simple spec passes using sing Timecop 0.4.5 and Ruby 1.9.3 but fails with 0.6.1 and Ruby 2.0.0.

require 'timecop'
require 'spec_helper'

describe Class do
  it "freezes time" do
    Timecop.freeze Date.new(2012,7,1) do
      expect(Date.today).to eq(Date.new 2012,7,1)
    end
  end
end
$ rspec spec/models/time_cop_spec.rb 

Failures:

  1) Class freezes time
     Failure/Error: expect(Date.today).to eq(Date.new 2012,7,1)

       expected: Sun, 01 Jul 2012
            got: Thu, 02 May 2013

       (compared using ==)

       Diff:
       @@ -1,2 +1,2 @@
       -Sun, 01 Jul 2012
       +Thu, 02 May 2013
michrome commented May 2, 2013

The following passes. Has Date.today support been dropped in favour of Time.now.to_date?

require 'timecop'
require 'spec_helper'

describe Class do
  it "freezes time" do
    Timecop.freeze Date.new(2012,7,1) do
      expect(Time.now.to_date).to eq(Date.new 2012,7,1)
    end
  end
end
Contributor

Here's the short answer: Add require 'date' to the very top (before require 'timecop') and your spec will pass with Date.today on both versions and you won't have to worry about it. The difference is actually between versions of Bundler rather than versions of Ruby--if you update your Bundler on the Ruby 1.9.3 side you'll see the same problem.

Here's the longwinded explanation:

The immediate cause of the test failure is that Timecop won't patch the Date class if it doesn't exist and have the today method. See lib/time_extensions.rb where the patching of Date is guarded by if Object.const_defined?(:Date) && Date.respond_to?(:today). (The intent behind this is explained in the commit message of 2ea5028. I think a simpler way would be to just require 'date' from timecop itself, avoiding this unexpected behavior without re-introducing the problem that the guard was intended to fix. I'll create a pull request for that and see if @travisjeffery agrees.)

So that explains why it fails on 2.0.0. But that code hasn't changed between timecop 0.4.5 and 0.6.1. So how does your spec pass in 1.9.3?

Well I had a similar situation, and here's what it was for me: I was using Bundler and running the test under bundle exec. That, in turn, adds -rbundler/setup to RUBYOPT, causing bundler/setup to be loaded before the first line of code in my file. And in Bundler 1.2.4 (which was the version I had in my 1.9.3 installation), bundler/setup causes Date to be loaded, thus covering up the problem. But in Bundler 1.3.4, which is what I had in my Ruby 2.0.0 installation, it only half-loads it--the class exists, but doesn't have the today method. A short command line demonstration of this:

$ rbenv local 1.9.3-p327
$ bundle --version
Bundler version 1.2.4
$ ruby -rbundler/setup -e 'puts Object.const_defined?(:Date), Date.respond_to?(:today)'
true
true
$ rbenv local 2.0.0-p0
$ bundle --version
Bundler version 1.3.4
$ ruby -rbundler/setup -e 'puts Object.const_defined?(:Date), Date.respond_to?(:today)'
true
false

I confirmed that this explains the whole thing by updating my Bundler version in 1.9.3:

$ rbenv local 1.9.3-p327
$ gem update bundler
Updating installed gems
Updating bundler
Fetching: bundler-1.3.5.gem (100%)
Successfully installed bundler-1.3.5
Gems updated: bundler
Installing ri documentation for bundler-1.3.5...
Installing RDoc documentation for bundler-1.3.5...
$ ruby -rbundler/setup -e 'puts Object.const_defined?(:Date), Date.respond_to?(:today)'
true
false

and once I do that, the test fails on both Ruby versions.

@MicahChalmer thank you! Your explanation is very clear and concise.

Contributor
yaauie commented Jun 4, 2013

Does that mean this issue is resolved?

michrome commented Jun 4, 2013

@yaauie I think so!

@michrome michrome closed this Jun 4, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment