Ruby Modules and Classes Same Name in Structure

ruby modules and classes same name in structure

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

Having a module and class with the same name

I'd do:

::Stat.by_user_id("ID")

What is the relationship between a ruby class and module with the same name?


What is the relationship between a ruby class and module with the same name?

A class and a module can't have the same fully qualified name in ruby. It's possible to have a class Foo::Bar and a module Baz::Bar, in which case there is no relation between the class and the module. However it is not possible to both have class Foo::Bar and a module Foo::Bar at the same time.

(I'm not sure what this has to do with the rest of your question though)

Is my inclusion line in Foo necessary, or does Rails autoinclude those modules?

Rails will not automatically include your modules. However that does not mean it's necessary to include yourself, you could just access it qualified. I.e. use Exceptions::MySpecialException instead of just MySpecialException inside the Foo class.

Why does MySpecialException exist in the top level Foo namespace and point to Foo::Exceptions::MySpecialException?

Because you included Foo::Exceptions into Foo. Because of that all instance methods of Foo::Exceptions are also instance methods of Foo and all constants of Foo::Exceptions are also constants of Foo - including MySpecialException.

What does it mean that those two classes are == but not ===?

== means that it's the same class. That it's not === means that the class is not an instance of itself (since x === y is the same as y.is_a?(x) if x is a class).

Difference between a class and a module

The first answer is good and gives some structural answers, but another approach is to think about what you're doing. Modules are about providing methods that you can use across multiple classes - think about them as "libraries" (as you would see in a Rails app). Classes are about objects; modules are about functions.

For example, authentication and authorization systems are good examples of modules. Authentication systems work across multiple app-level classes (users are authenticated, sessions manage authentication, lots of other classes will act differently based on the auth state), so authentication systems act as shared APIs.

You might also use a module when you have shared methods across multiple apps (again, the library model is good here).

How to use the same class name over multiple modules?

Use the FQN (fully-qualified name) ::ApplicationService to refer to your top-level class.

module Processing
module Callback
class ApplicationService < ::ApplicationService; end
end
end

Rails: Same name for a library module and a group of controllers?

I think the problem lies with the load path. I think the require should be:

require "#{Rails.root}/lib/admin/pagerduty.rb"

Another solution, albeit a little heavy handed, is to load all of the lib subdirectories in the LOAD_PATH, eg:

In application.rb for config.autoload_path:

config.autoload_paths += Dir["#{config.root}/lib/**/"]

How to distinguish classes with the same name defined in different Gems?

In your specific example, the include Origami is unnecessary, I don't know why they added that example to their README.

require 'pdf/reader'
require 'origami'

PDF::Reader.new(dir) # (first gem)
Origami::PDF.read dir # (second gem)

Sometimes it may be possible to do something like:

require 'pdf/reader'

PDFReader = PDF::Reader

require 'origami'
include Origami

PDFReader.new(dir)
PDF.read(dir)

When to use nested classes and classes nested in modules?

Other OOP languages have inner classes which cannot be instantiated without being bound to an upper level class. For instance, in Java,

class Car {
class Wheel { }
}

only methods in the Car class can create Wheels.

Ruby doesn’t have that behaviour.

In Ruby,

class Car
class Wheel
end
end

differs from

class Car
end

class Wheel
end

only in the name of the class Wheel vs. Car::Wheel. This difference in name can make explicit to programmers that the Car::Wheel class can only represent a car wheel, as opposed to a general wheel. Nesting class definitions in Ruby is a matter of preference, but it serves a purpose in the sense that it more strongly enforces a contract between the two classes and in doing so conveys more information about them and their uses.

But to the Ruby interpreter, it’s only a difference in name.

As for your second observation, classes nested inside of modules are generally used to namespace the classes. For instance:

module ActiveRecord
class Base
end
end

differs from

module ActionMailer
class Base
end
end

Although this is not the only use of classes nested inside of modules, it is generally the most common.



Related Topics



Leave a reply



Submit