Forum: Ruby MiniTest: a curious case of include (1.8 vs 1.9)

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
2e2d8c8ff86e18bf49f777f39028823e?d=identicon&s=25 Simon Chiang (bahuvrihi)
on 2009-01-29 16:16
(Received via mailing list)
I've been messing around with minitest and came across something very
strange.  Does anyone have an explanation for what is going on here?
I think it must indicate subtle differences in blocks between 1.8 and
1.9.

  require 'rubygems'
  require 'minitest/spec'

  #
  # Including a module in a spec does not make constants
  # available under ruby 1.8 but it does under ruby 1.9.
  #
  # This script requires the minitest gem to be installed:
  #
  #   % gem install minitest
  #

  module A
    module B
    end
  end

  # This passes on ruby 1.9, but not on 1.8.
  describe "MiniTest Includes" do
    include A

    it "should show inclusion works" do
      B.must_equal A::B
    end
  end

  # This passes on both.  What's more, if you uncomment this
  # spec, the assignment TRANSLATES to the "MiniTest Includes"
  # spec and that spec will pass!
  #
  # describe "MiniTest Assigns" do
  #   B = A::B
  #
  #   it "should show assignment works" do
  #     B.must_equal A::B
  #   end
  # end

  # Here is an example showing the assignment case works.
  module X
    module Y
    end
  end

  describe "MiniTest Assigns X::Y" do
    Y = X::Y

    it "should show constant assignment works" do
      Y.must_equal X::Y
    end
  end

  MiniTest::Unit.autorun
2e2d8c8ff86e18bf49f777f39028823e?d=identicon&s=25 Simon Chiang (bahuvrihi)
on 2009-01-29 17:08
(Received via mailing list)
As an additional note to this, assigning constants in a describe under
1.8 causes namespace pollution.

  require 'rubygems'
  require 'minitest/spec'

  module X
    module Y
    end
  end

  describe "Namespace Pollution" do
    Y = X::Y
  end

  puts Y  # => 'X::Y' on 1.8, error on 1.9
F53b05cdbdf561cfe141f69b421244f3?d=identicon&s=25 David A. Black (Guest)
on 2009-01-29 17:24
(Received via mailing list)
Hi --

On Fri, 30 Jan 2009, Simon Chiang wrote:

>
>  describe "Namespace Pollution" do
>    Y = X::Y
>  end
>
>  puts Y  # => 'X::Y' on 1.8, error on 1.9

It's not specific to minitest; it's a change in how constants are
resolved. I'm not sure of the exact formulation but what's happening
is that in a class_eval'd code block (which I think is what describe
does), 1.8 is looking for a constant scoped to the outer level, while
1.9 is looking for one that is scope to the class that's being
class_evaled.

You can see this also with a block for a new class:

module A
   module B
   end
end

Class.new do
   include A
   p B == A::B   # true in 1.9, error in 1.8 (unknown constant B)
end


David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2)

http://www.wishsight.com => Independent, social wishlist management!
2e2d8c8ff86e18bf49f777f39028823e?d=identicon&s=25 Simon Chiang (bahuvrihi)
on 2009-01-29 19:54
(Received via mailing list)
> It's not specific to minitest; it's a change in how constants are
> resolved. I'm not sure of the exact formulation but what's happening
> is that in a class_eval'd code block (which I think is what describe
> does), 1.8 is looking for a constant scoped to the outer level, while
> 1.9 is looking for one that is scope to the class that's being
> class_evaled.

Interesting.  I expected it would be something like this.  Kinda makes
specs hard to use under 1.8 IMO.  You're left with nesting describes
within a module, or using the full constant name.

  module A
    module B
    end

    describe "Nest in Module" do
      it "should show nesting works" do
        B.must_equal A::B
      end
    end
  end

  describe "Full Constant Name" do
    it "should show full names works" do
      A::B.must_equal A::B
    end
  end
F53b05cdbdf561cfe141f69b421244f3?d=identicon&s=25 David A. Black (Guest)
on 2009-01-29 21:40
(Received via mailing list)
Hi --

On Fri, 30 Jan 2009, Simon Chiang wrote:

> within a module, or using the full constant name.
>  end
>
>  describe "Full Constant Name" do
>    it "should show full names works" do
>      A::B.must_equal A::B
>    end
>  end

All it means is that you can't make an assertion in the spec that
conflicts with how the language is engineered, and that's always true
:-)


David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2)

http://www.wishsight.com => Independent, social wishlist management!
2e2d8c8ff86e18bf49f777f39028823e?d=identicon&s=25 Simon Chiang (bahuvrihi)
on 2009-01-30 18:54
(Received via mailing list)
> All it means is that you can't make an assertion in the spec that
> conflicts with how the language is engineered, and that's always true
> :-)

I guess there's something to that.  Here's a good workaround that
doesn't pollute and works on 1.8 and 1.9... evade the block by
foregoing describe.

  module A
    module B
    end
  end

  # This passes on both ruby 1.8 and 1.9 and doesn't pollute.
  class MiniTestIncludes < MiniTest::Spec
    include A

    it "should show inclusion works" do
      B.must_equal A::B
    end
  end
883ee4d990ef9e57a79b5b0ff3b66241?d=identicon&s=25 bwv549 (Guest)
on 2009-02-02 21:05
(Received via mailing list)
Here's a workaround that combines the include call with a const_get
call.  Can still use 'describe'.  Doesn't pollute namespace.  Works on
1.8 and 1.9.  Not too ugly:

  require 'minitest/spec'
  MiniTest::Unit.autorun

  # put this little method in some kind of spec_helper.rb file
  module Kernel
    def use(const, subconst)
      self.instance_eval( "include #{const}" )
      const.const_get(subconst)
    end
  end

  module A
    module B
    end
  end

  describe 'Includes' do
    B = use A, 'B'

    it 'shows inclusion working' do
      B.must_equal A::B
    end
  end
This topic is locked and can not be replied to.