I have a folder structure like the following in one of my projects:
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?
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).
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 .
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.
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.
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
Just use class Bar
instead of module Bar
. In Ruby, classes can be reopened and added to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With