Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 628
Matthias Avatar asked Nov 07 '12 00:11

Matthias


People also ask

Is module and class are same?

What is the difference between a class and a module? Modules are collections of methods and constants. They cannot generate instances. Classes may generate instances (objects), and have per-instance state (instance variables).

Are modules classes Ruby?

In Ruby, modules are somewhat similar to classes: they are things that hold methods, just like classes do. However, modules can not be instantiated. I.e., it is not possible to create objects from a module. And modules, unlike classes, therefore do not have a method new .

Can modules include other modules Ruby?

Actually, Ruby facilitates the use of composition by using the mixin facility. Indeed, a module can be included in another module or class by using the include , prepend and extend keywords.

What is a Ruby namespace?

Namespace in Ruby allows multiple structures to be written using hierarchical manner. Thus, one can reuse the names within the single main namespace. The namespace in Ruby is defined by prefixing the keyword module in front of the namespace name. The name of namespaces and classes always start from a capital letter.


2 Answers

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 
like image 175
Alex Wayne Avatar answered Oct 03 '22 21:10

Alex Wayne


Just use class Bar instead of module Bar. In Ruby, classes can be reopened and added to.

like image 36
mpartel Avatar answered Oct 03 '22 19:10

mpartel