Module.nesting -> Kernel#nesting

I'm trying to write a little method called Module#modspace, which will
return the module/class a module/class is defined in. I.e.

  Module X
    Module Y
      Module Z
      end
    end
  end

  X::Y::Z.modspace #=> X::Y

So I thought, Module.nesting would help do the trick. But I discovered
the Module.nesting returns the nesting according where it is called in
the code, nothing more. It is like __LINE__ or __FILE__ in this
respect. So it seems to me that it would be more appropriate to define
#nesting in Kernel, not as a class method of Module.

BTW, any help writing Module#modspace appreciated.

T.

---- Original message from Trans on 8/16/2005 2:36 PM:

I'm trying to write a little method called Module#modspace, which will
return the module/class a module/class is defined in. I.e.

Module X
   Module Y
     Module Z
     end
   end
end

X::Y::Z.modspace #=> X::Y

So I thought, Module.nesting would help do the trick. But I discovered
the Module.nesting returns the nesting according where it is called in
the code, nothing more. It is like __LINE__ or __FILE__ in this
respect. So it seems to me that it would be more appropriate to define
#nesting in Kernel, not as a class method of Module.

This is mostlikely not the best way to do it, but here is a way to get at the information.

class Module
    def lineage
        eval self.ancestors.to_s.sub( /::[^:]$/, "" )
    end
    def modspace
        lineage
    end
end

module X
    module Y
        module Z
        end
    end
end

a = X::Y::Z

p a.modspace
p a.modspace.class

Dale Martenson wrote:

class Module
   def lineage
       eval self.ancestors.to_s.sub( /::[^:]$/, "" )

You can use name.sub(...) instead of self.ancestors.to_s.sub(...), but
it's not much better.

···

--
      vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Nice use of #eval. That's what I was missing. ( I usually try to avoid
#eval, but in this case it makes it much easier).

Thanks,
T.

P.S. Anyone on why #nesting isn't in Kernel?

---- Original message from Joel VanderWerf on 8/16/2005 5:04 PM:

Dale Martenson wrote:

class Module
  def lineage
      eval self.ancestors.to_s.sub( /::[^:]$/, "" )
   
You can use name.sub(...) instead of self.ancestors.to_s.sub(...), but
it's not much better.

Actually, it is a lot better since you avoid cases where there are additional includes. Module#ancestors
returns an array which causes problems with my original suggestion.

Example:

module X
    include Math
    module Y
        include Comparable
        module Z
            include Enumerable
        end
    end
end

Thanks, Joel for your suggestion. For some reason, Module#name just didn't come to mind.

Trans schrieb:

P.S. Anyone on why #nesting isn't in Kernel?

Maybe because the only thing you can nest are modules, and the result is a list of modules? IMO, it has nothing to do with general objects.

Regards,
Pit

Pit Capitain wrote:

Trans schrieb:
> P.S. Anyone on why #nesting isn't in Kernel?

Maybe because the only thing you can nest are modules, and the result is
a list of modules? IMO, it has nothing to do with general objects.

Actually that's my point. What you say is the common general thought,
it's exactly what I had thought, but it's isn't true. #nesting actually
has nothing to do with it's reciever 'class Module'. And has more do
with the object, namely, the nesting from _that place in the object_,
well, at least as much as __LINE__ and __FILE__ do. By analogy, we
don't use 'File.__LINE__'. Do you see what I'm getting at?

Kernel is not so much a mixin of Object, as it is a omni-accessible
toolchest for the Ruby coder.

T.

This does the same job without using eval:

class Module
  def lineage
    name.split(/::/)[0..-2].inject(self) do |mod, modname|
      mod.const_get(modname)
    end
  end
  def modspace
    lineage
  end
end

module X
  include Math
  module Y
    include Comparable
    module Z
      include Enumerable
    end
  end
end

x = X
y = X::Y
z = X::Y::Z

p x.modspace
p x.modspace.class

p y.modspace
p y.modspace.class

p z.modspace
p z.modspace.class

__END__
---------- Ruby ----------
X
Module
X
Module
X::Y
Module

Output completed (0 sec consumed) - Normal Termination

Not that I think eval is evil. I find it very handy.

I'm not sure what it means for X's modspace (aka 'lineage') to be X but that's
how the original worked. Perhaps it should be Module?
You can get this behaviour by changing inject(self) to inject(Module).

I'm curious - what would you do with this?

Regards

Sean

Trans schrieb:

Pit Capitain wrote:

Trans schrieb:

P.S. Anyone on why #nesting isn't in Kernel?

Maybe because the only thing you can nest are modules, and the result is
a list of modules? IMO, it has nothing to do with general objects.

Actually that's my point. What you say is the common general thought,
it's exactly what I had thought, but it's isn't true. #nesting actually
has nothing to do with it's reciever 'class Module'.

Seems I can't express my thoughts very well. I know that Module.nesting isn't an instance method of Module and that you can't ask an instance of Module for its nesting.

What I wanted to say is that the value of Module.nesting depends only on the nesting of module definitions. It only matters in which (lexical) module context it is called. It has nothing to do with other objects. If you'd remove the class Module from Ruby, a nesting method wouldn't make sense anymore.

And has more do
with the object, namely, the nesting from _that place in the object_,
well, at least as much as __LINE__ and __FILE__ do. By analogy, we
don't use 'File.__LINE__'. Do you see what I'm getting at?

Yes, but you could remove the class File from Ruby and it would still make sense to get the name of the current source file. The current source file is a property of the compile time environment and has nothing to do with any Ruby language constructs. From this point of view it wouldn't make sense to associate __FILE__ with the Ruby class File.

Kernel is not so much a mixin of Object, as it is a omni-accessible
toolchest for the Ruby coder.

But __FILE__ is a token recognized by the parser. It is neither a constant nor a method of any module, including Kernel.

As always just my 2 cents.

Regards,
Pit

But __FILE__ is a token recognized by the parser. It is neither a
constant nor a method of any module, including Kernel.

True. But if you were to try to define it yourself it woul be a Kernel
module.

Anyway, I've come back to this old thread b/c I realize now, why
exactly this would be more approriate as a Kernel method and not a
Module method: the definition requires a "Binding.of_caller" in order
to work --ie. if one were to try to do it in ruby themselves. So
underthehood it must be doing the same. Since Binding.of_caller is
considered "not good" (do I understand correctly that matz has
declined this functionality for Ruby?) then this method goes against
that grain.

How did I realize this? I was trying to write an Ruby interpolate
method as a String module function. And for the same reason it was not
possible --I had to put it in Kernel.

T.

Trans wrote:

> But __FILE__ is a token recognized by the parser. It is neither a
> constant nor a method of any module, including Kernel.

True. But if you were to try to define it yourself it woul be a Kernel
module.

Anyway, I've come back to this old thread b/c I realize now, why
exactly this would be more approriate as a Kernel method and not a
Module method: the definition requires a "Binding.of_caller" in order
to work --ie. if one were to try to do it in ruby themselves. So
underthehood it must be doing the same. Since Binding.of_caller is
considered "not good" (do I understand correctly that matz has
declined this functionality for Ruby?) then this method goes against
that grain.

How did I realize this? I was trying to write an Ruby interpolate
method as a String module function. And for the same reason it was not
possible --I had to put it in Kernel.

Well, I'll correct myself. Techincally, you still need
Binding.of_caller using Kernel. It's just that Kernel's modus operandi
is functionality unversally present, so it seems like the right place.

T.