Hello,

On 8 May 2012 20:41, boris_stitnicky (Boris Stitnicky)
<boris / iis.sinica.edu.tw> wrote:
> In this place, I'd also like to provide user feedback about my (unwarranted, but real)
> surprise involving a weakly related issue:
>
> module A; def initialize; puts "hello"; end; end # there was a missing end
> class B; include A end
> A = Module.new
> B.new
>> "hello"
>
> And there I was surprised. I did get constant redefine warning, but I ignored it,
> as I was writing tests and I wanted to blank out A mixin. I clung on the class
> name A, but to include statement, capital 'A' was just as irrelevant as if it
> was small 'a' (Another proof that there are actually no constants in Ruby :)

As you say, the constants are not constant in a usual sense, they are
global identifiers that should not be reassigned.

You can think of `module Name` as `Name = defined?(Name) ? Name :
Module.new` and the change of scope (same for `class Name`). That is,
if Name is already defined, just use it, otherwise create the module.

What happens here is you create a module A with a method initialize.
You then include it in B, which means adding the module instance in
the ancestors:
> B.ancestors
=> [B, A, Object, Kernel, BasicObject]

Then you actually redefine A to an empty module.

Unfortunately, if you do again
> B.ancestors
=> [B, A, Object, Kernel, BasicObject]

You still see A in the ancestors (this might be worth to be reported
as a separate issue),
although that module you see is still the old one, which name was not updated:
> B.ancestors[1].private_instance_methods
=> [:initialize]
> A.private_instance_methods
=> []

This is maybe not the most intuitive behavior, but it is consistent.
An object is not bound to a variable or a constant, and the references
are direct. The only "magic" that happens is when you assign for the
first time a class/module to a constant, it takes the name of that
constant.

In any case, avoid redefining constants as much as possible, and don't
make assumptions on constant resolution when the module is included.
If you want to ensure to re-open a class, just use
ClassName.class_exec { ... }.