Alex Rivera | Logout

Is it possible to give a sub-module the same name as a top-level class?

Asked 2011-06-06T15:41:13.167
27

Background:

Here's the problem, distilled down to a minimal example:

# bar.rb
class Bar
end

# foo/bar.rb
module Foo::Bar
end

# foo.rb
class Foo
  include Foo::Bar
end

# runner.rb
require 'bar'
require 'foo'
➔ ruby runner.rb
./foo.rb:2: warning: toplevel constant Bar referenced by Foo::Bar
./foo.rb:2:in `include': wrong argument type Class (expected Module) (TypeError)
    from ./foo.rb:2
    from runner.rb:2:in `require'
    from runner.rb:2
Edit
Report

1 Answer

2

Here is a more minimal example to demonstrate this behavior:

class Bar; end
class Foo
  include Foo::Bar
end

Output:

warning: toplevel constant Bar referenced by Foo::Bar
TypeError: wrong argument type Class (expected Module)

And here is even more minimal:

Bar = 0
class Foo; end
Foo::Bar

Output:

warning: toplevel constant Bar referenced by Foo::Bar

The explanation is simple, there is no bug: there is no Bar in Foo, and Foo::Bar is not yet defined. For Foo::Bar to be defined, Foo has to be defined first. The following code works fine:

class Bar; end
class Foo
  module ::Foo::Bar; end
  include Foo::Bar
end

However, there is something that is unexpected to me. The following two blocks behave differently:

Bar = 0
class Foo; end
Foo::Bar

produces a warning:

warning: toplevel constant Bar referenced by Foo::Bar

but

Bar = 0
module Foo; end
Foo::Bar

produces an error:

uninitialized constant Foo::Bar (NameError)
answered 2013-03-30T09:29:25.247

Your Answer