Two different results for Module.nesting

Discussion in 'Ruby' started by Brian Marick, Apr 12, 2004.

  1. Brian Marick

    Brian Marick Guest

    Consider this:

    module M1
    module M2
    class C
    puts Module.nesting.inspect
    end
    end
    end

    It produces [M1::M2::C, M1::M2, M1], which I expected.

    Now try this:

    M1::M2::C.class_eval("Module.nesting")

    It produces [M1::M2::C], which I did not expect. Why the difference?
    Thanks.

    VERSION: 1.8.1 and 1.6.8

    -----
    Brian Marick
    Consulting, training, and contracting
    Mostly on agile methods with a testing slant
    www.testing.com, www.testing.com/cgi-bin/blog
     
    Brian Marick, Apr 12, 2004
    #1
    1. Advertising

  2. On Tue, 13 Apr 2004 07:15:58 +0900, Brian Marick wrote:
    > Consider this:

    [snip]
    > It produces [M1::M2::C], which I did not expect. Why the difference?


    Quoted form RI
    "Returns the list of +Modules+ nested at the point of call."

    The 'puts' occurs at 3 levels of nesting.
    There is no modules surrounding 'p'..

    Does that help ?

    server> ruby -v
    ruby 1.9.0 (2004-04-06) [i386-freebsd5.1]
    server> ruby a.rb
    [M1::M2::C, M1::M2, M1]
    [M1::M2::C]
    server> expand -t2 a.rb
    module M1
    module M2
    class C
    puts Module.nesting.inspect
    end
    end
    end
    p M1::M2::C.class_eval("Module.nesting")
    server>


    --
    Simon Strandgaard
     
    Simon Strandgaard, Apr 12, 2004
    #2
    1. Advertising

  3. Brian Marick wrote:

    > Consider this:
    >
    > module M1
    > module M2
    > class C
    > puts Module.nesting.inspect
    > end
    > end
    > end
    >
    > It produces [M1::M2::C, M1::M2, M1], which I expected.
    >
    > Now try this:
    >
    > M1::M2::C.class_eval("Module.nesting")
    >
    > It produces [M1::M2::C], which I did not expect. Why the difference?
    > Thanks.


    It's returning the proper nesting. But as you haven't opened each of
    the Modules individually to reach the C const, Module::nesting isn't
    returning them each individual.

    Let's illustrate:

    module M1::M2
    class C
    puts Module.nesting.inspect
    end
    end
    #=> [M1::M2::C, M1::M2]

    _why
     
    why the lucky stiff, Apr 13, 2004
    #3
  4. Brian Marick

    Chad Fowler Guest

    On 12/4/2004, at 9:26 PM, why the lucky stiff wrote:

    > Brian Marick wrote:
    >
    >> Consider this:
    >>
    >> module M1
    >> module M2
    >> class C
    >> puts Module.nesting.inspect
    >> end
    >> end
    >> end
    >>
    >> It produces [M1::M2::C, M1::M2, M1], which I expected.
    >>
    >> Now try this:
    >>
    >> M1::M2::C.class_eval("Module.nesting")
    >>
    >> It produces [M1::M2::C], which I did not expect. Why the difference?
    >> Thanks.

    >
    > It's returning the proper nesting. But as you haven't opened each of
    > the Modules individually to reach the C const, Module::nesting isn't
    > returning them each individual.
    >
    > Let's illustrate:
    >
    > module M1::M2
    > class C
    > puts Module.nesting.inspect
    > end
    > end
    > #=> [M1::M2::C, M1::M2]
    >
    >


    This strikes me as being a bit unintuitive, though I don't ever really
    need it so I'm not too bothered. :)

    It appears that this behavior is a remnant of the way Ruby is parsed
    (or, more correctly, how it's eval(.c)uated). Brian, were you using
    this for your automock thing?

    I'm interested to hear what other uses people have found for this
    method.

    Chad
     
    Chad Fowler, Apr 13, 2004
    #4
  5. Brian Marick

    Brian Marick Guest

    On Apr 12, 2004, at 9:32 PM, Chad Fowler wrote:

    >
    > On 12/4/2004, at 9:26 PM, why the lucky stiff wrote:
    >
    >> Brian Marick wrote:
    >>
    >>> Consider this:
    >>>
    >>> module M1
    >>> module M2
    >>> class C
    >>> puts Module.nesting.inspect
    >>> end
    >>> end
    >>> end
    >>>
    >>> It produces [M1::M2::C, M1::M2, M1], which I expected.
    >>>
    >>> Now try this:
    >>>
    >>> M1::M2::C.class_eval("Module.nesting")
    >>>
    >>> It produces [M1::M2::C], which I did not expect. Why the difference?
    >>> Thanks.

    >>
    >> It's returning the proper nesting. But as you haven't opened each of
    >> the Modules individually to reach the C const, Module::nesting isn't
    >> returning them each individual.
    >>
    >> Let's illustrate:
    >>
    >> module M1::M2
    >> class C
    >> puts Module.nesting.inspect
    >> end
    >> end
    >> #=> [M1::M2::C, M1::M2]
    >>
    >>

    >
    > This strikes me as being a bit unintuitive, though I don't ever really
    > need it so I'm not too bothered. :)


    It seems unintuitive to me as well. I thought it would tell me about
    the runtime module-nesting structure of the program, not about the
    syntax by which I'm talking about that structure.


    > It appears that this behavior is a remnant of the way Ruby is parsed
    > (or, more correctly, how it's eval(.c)uated). Brian, were you using
    > this for your automock thing?


    I came across it while fiddling around with automock.
    <http://www.testing.com/cgi-bin/blog/2004/04/12#automock>
    But I didn't have to use it.

    -----
    Brian Marick
    Consulting, training, and contracting
    Mostly on agile methods with a testing slant
    www.testing.com, www.testing.com/cgi-bin/blog
     
    Brian Marick, Apr 13, 2004
    #5
  6. Brian Marick wrote:
    >
    > On Apr 12, 2004, at 9:32 PM, Chad Fowler wrote:
    >
    >>
    >> On 12/4/2004, at 9:26 PM, why the lucky stiff wrote:
    >>
    >>> Brian Marick wrote:
    >>>
    >>>> Consider this:
    >>>>
    >>>> module M1
    >>>> module M2
    >>>> class C
    >>>> puts Module.nesting.inspect
    >>>> end
    >>>> end
    >>>> end
    >>>>
    >>>> It produces [M1::M2::C, M1::M2, M1], which I expected.
    >>>>
    >>>> Now try this:
    >>>>
    >>>> M1::M2::C.class_eval("Module.nesting")
    >>>>
    >>>> It produces [M1::M2::C], which I did not expect. Why the difference?
    >>>> Thanks.
    >>>
    >>>
    >>> It's returning the proper nesting. But as you haven't opened each of
    >>> the Modules individually to reach the C const, Module::nesting isn't
    >>> returning them each individual.
    >>>
    >>> Let's illustrate:
    >>>
    >>> module M1::M2
    >>> class C
    >>> puts Module.nesting.inspect
    >>> end
    >>> end
    >>> #=> [M1::M2::C, M1::M2]
    >>>
    >>>

    >>
    >> This strikes me as being a bit unintuitive, though I don't ever really
    >> need it so I'm not too bothered. :)

    >
    >
    > It seems unintuitive to me as well. I thought it would tell me about the
    > runtime module-nesting structure of the program, not about the syntax by
    > which I'm talking about that structure.


    I guess the value returned by #nesting has to be lexically determined
    because ruby classes can be reopened. The following prints two different
    nestings:

    module M1
    module M2
    class C
    puts Module.nesting.inspect
    end
    end
    end

    module M3
    module M4
    class C
    puts Module.nesting.inspect
    end
    end
    end

    So there really is no "runtime" nesting structure. The nesting only
    exists while the interpreter is evaluating code inside it.
     
    Joel VanderWerf, Apr 13, 2004
    #6
  7. Brian Marick

    Christoph Guest

    Joel VanderWerf wrote:
    ---
    > I guess the value returned by #nesting has to be lexically determined
    > because ruby classes can be reopened. The following prints two different
    > nestings:
    >
    > module M1
    > module M2
    > class C
    > puts Module.nesting.inspect
    > end
    > end
    > end
    >
    > module M3
    > module M4
    > class C
    > puts Module.nesting.inspect
    > end
    > end
    > end
    >
    > So there really is no "runtime" nesting structure. The nesting only
    > exists while the interpreter is evaluating code inside it.


    Here is another scriptlet demonstrating your point

    ---
    module T
    end

    module Outer
    module Inner
    C = ::T
    module C
    $c = binding
    end
    end
    end


    class A
    B = ::T
    module B
    $b = binding
    end
    end


    p eval("Module.nesting",$c)
    p eval("Module.nesting",$b)

    ---
    [T, Outer::Inner, Outer]
    [T, A]


    /Christoph
     
    Christoph, Apr 13, 2004
    #7
  8. Thanks for the very clear demonstration Christoph!

    This issue of lexical code nesting vs 'intuitive' class/module nesting
    isn't widely documented, but goes further than affecting just
    Module.nesting. Its tentacles tickle the corner cases for class
    variable and constant lookup, particularly when 'class X::Y' style
    declarations are used.


    Example for class variables:
    http://www.rubygarden.org/ruby?ClassVariables


    Example for constants:

    E:\>type nesting.rb
    class A
    X = 1
    class B
    $b = self
    puts "class A; class B"
    puts X
    end
    end

    class A::B
    puts "Same class as previously? #{self == $b}"
    puts "class A::B"
    puts X
    end

    E:\>ruby -v nesting.rb
    ruby 1.8.1 (2004-01-27) [i386-mswin32]
    class A; class B
    1
    Same class as previously? true
    class A::B
    nesting.rb:13: uninitialized constant A::B::X (NameError)


    -- George
     
    George Marrows, Apr 14, 2004
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Qiangning Hong
    Replies:
    12
    Views:
    708
    Grant Edwards
    Jul 12, 2006
  2. Kerry, Richard
    Replies:
    2
    Views:
    406
    Piet van Oostrum
    Jul 13, 2006
  3. =?Utf-8?B?Ymlj?=
    Replies:
    1
    Views:
    364
    Alexey Smirnov
    May 5, 2007
  4. gga
    Replies:
    3
    Views:
    159
    William Morgan
    Feb 19, 2005
  5. Trans
    Replies:
    10
    Views:
    305
    Sean O'Halpin
    Sep 16, 2005
Loading...

Share This Page