Change namespace scope / nesting problem

Hello everybody. I am having problem with nested modules and includes
not changing namespaces.
I am trying to be DRY by moving out some common methods into a module,
but when I do that, my nesting changes and the class names are not
resolved properly.

For example if I have modules Foo and Foo2, and each of those modules
have 2 classes Bar and Helper. I also have Module Mixin:A which has
methods for class Bar for each module. If a method in Mixin::A tries to
access Helper, I get error Mixin::a::Helper is undefined. It is
resolving to Mixin::A namespace instead of Foo or Foo2. Here is the
sample code that demonstrates my problem.

Thanks.

module Mixins; end

module Mixins::A
def self.included(base)
base.class_eval do
def test_it
Helper
end
end
end
end

module Foo
class Helper
end

class Bar
include Mixins::A
end
end

module Foo2
class Helper
end

class Bar
include Mixins::A
end
end

Foo::Bar.new.test_it #=> should return Foo::Helper
Foo2::Bar.new.test_it #=> Should return Foo2::Helper

Hi,

I think in the current version of Ruby, constants are always looked up
lexically (this is different from past versions). So you may not be able
to reference the constant in the context of “base”.

Anyway, I generally find it a bad idea to rely on obscure lookup paths.
Even it did work, it would be difficult to track where the constant
actually comes from. I’d rather restructure the classes and modules.

On Wed, May 9, 2012 at 5:35 PM, Jan E. [email protected] wrote:

I think in the current version of Ruby, constants are always looked up
lexically (this is different from past versions). So you may not be able
to reference the constant in the context of “base”.

I don’t think I would call this behavior “lexical lookup”:

irb(main):001:0> class A; class Helper; def x; “in A” end end end
=> nil
irb(main):002:0> class B; class Helper; def x; “in B” end end end
=> nil
irb(main):003:0> [A,B].map {|cl| cl::Helper.new.x}
=> [“in A”, “in B”]
irb(main):004:0> RUBY_VERSION
=> “1.9.3”

Anyway, I generally find it a bad idea to rely on obscure lookup paths.
Even it did work, it would be difficult to track where the constant
actually comes from. I’d rather restructure the classes and modules.

Right. It’s a bad idea to require Mixins::A to know something about
the environment of the class passed to #included. One way out would
be to nest Helper in the class in the same way I demonstrated above.

But then, the class_eval is superfluous because the method could be
simply defined in Mixin::A to achieve the same effect of defining a
method for all instances:

module Mixins::A
def test_it
# Helper here does not make sense, unless it’s
self.class::Helper
end
end

Iuri, why do you think you need to construct the code you showed?
There’s probably another - better - way. For example, you could add
an instance method helper which returns the class, e.g.

module Mixins
module A
def test_it
helper
end
end
end

module Foo
class Helper
end

class Bar
include ::Mixins::A
def helper; Helper; end
end

end

Kind regards

robert