Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
657 views
in Technique[技术] by (71.8m points)

ruby modules and classes same name in structure

I have a folder structure like the following in one of my projects:

  • lib
    • bar.rb
    • bar
      • other_bar.rb
      • another_bar.rb
      • next_bar.rb
      • ...

bar.rb

require File.expand_path(File.dirname(__FILE__) + "/bar/other_bar.rb")

class Bar
  puts "running BarBase"
end

bar/other_bar.rb

module Bar
  class OtherBar
    puts "running module Bar with class OtherBar"
  end
end

If I now run ruby bar.rb I get this:

running module Bar with class OtherBar
bar.rb:3:in `': Bar is not a class (TypeError)

I'd like to have a similar structure to a rails model inheritance structure. How can I fix this? So far as I know ruby does not support this out of the box. Is there a workaround for such a situation?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Bar can't be a module and a class, they are different things.

Change bar.rb to module Bar or change other_bar.rb to class Bar.

Whichever it is, it has to be consistent. You can't change one to the other. The question is which should it be? If Bar is a container for other classes and only has a few global singleton methods? Then it's a module. But if it can be instantiated, then it's a class.

And yes, you can nest classes. This is totally acceptable:

class Bar
  class OtherBar
    puts "running module Bar with class OtherBar"
  end
end

Bar::OtherBar.new # yay!

Modules and Classes can be nested inside either other in any way you see fit.


Edit with some commented examples to help clear this all up:

module Foo

  # Foo::A
  class A
    # simple namespaced class
  end

  # Foo::B, inherits from Foo::A
  class B < A
    # inherting from a class in the same namespace
  end

  # modify Foo::B
  class B
    # When modifying an existing class you don't need to define the superclass
    # again. It will raise an error if you reopen a class and define a different
    # superclass. But leaving it off is fine.
  end

  # nested module Foo::Inner
  module Inner

    # Foo::Inner::C 
    class C
      # simple more deeply namespaced class
    end

    # Foo::Inner::D, inherits from Foo::A
    class D < A
      # inherits from a class in a parent namespace

      # works because ruby looks upward in the nesting chain to find missing constants.
    end

    # Foo::Inner::Foo
    class Foo
      # simple nested class with the same name as something in a parent namespace

      # This is a totally different Foo, because it's in a different namespace
    end

    # Foo::Inner::E, inherits from Foo::Inner::Foo
    class E < Foo
      # class inhereting from another class in the same namespace

      # Foo::Inner::Foo is "closer" than the global Foo, so that gets found as the superclass
    end

    # Foo::Inner::F, which mixes in the gloabl module Foo
    class F
      # the :: constant prefix says to start looking in the global namespace
      # so here we include the top level module Foo, and not the "closer" in namespace Foo::Inner::Foo
      include ::Foo

      # This is an error. This attempts to include the class Foo::Inner::Foo since thats the closest by namespace
      # thing that matches the constant Foo. (you can't include classes, only modules)
      # You need the :: prefix to grab the global Foo module
      include Foo
    end

  end
end

# Z decalred in the global namespace, which inherits from the deeply nested class Foo::Inner::C
class Z < Foo::Inner::C
  # Any class anywhere can inherit from any other class in any namespace.
  # Just drill in!
end

# the following 2 declarations at this point would be identical

# This defines a class deep with in a namespace
class Foo::Inner::Foo::Bar < Foo::A
end

# same as above, but reopens each namespace
module Foo
  module Inner
    class Foo
      class Bar < ::Foo::A
      end
    end
  end
end

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...