Whenever you define a new module you call the method module:
module A
...
end
I've looked for it in https://ruby-doc.org/core-2.7.2/ but I didn't find it. Where is it?
The module keyword is exactly that: a keyword, not a method. Since this is part of Ruby's language syntax it is not documented along with defined classes and their methods, but in its syntax documentation at
https://ruby-doc.org/core-2.7.2/doc/syntax/modules_and_classes_rdoc.html#label-Modules
Module is Both a Keyword and an Object
While module is certainly a defined Ruby keyword, the underlying implementation is more complex. Pragmatically, a Module is a class-like Object that serves as the parent class of Class. It provides namespacing, and offers some additional features for mixin and module/class composition.
AFAICT, the syntax for creating a Module definition (rather than instantiating it) is handled by the RACC grammar, so if you’re looking for implementation details you may want to explore RACC, Ripper, and other interpreter elements to determine how the keyword actually implements the module definition.
Related
I think both are used for namespace.
Modules are generally mixed into classes, right? So, what would be the purpose of defining a module inside a class?
Generally speaking modules have two uses:
Namespacing modules. When you nest stuff here and the module is intended only for specifying paths.
Functional modules. When the module has actual functionality that is intended to be called directly on the module or the module is intended to be included/extended.
Classes should be used for functionality only, even though Ruby doesn't enforce it.
Trying to do something but the above (like use module for both namespacing and functionality (1) or use a class for namespacing (2)) will generally confuse you.
(1) Some will disagree pointing to the rails' module with instance methods that also holds another module, called ClassMethods. I think it would have been cleaner if there was a module with two modules - ClassMethods and InstanceMethods instead.
(2) Some will disagree. A probably valid case is if you try to emulate private classes from other languages (where the private class will be nested inside your public class).
I have a logger method that I would like to make accessible to all classes within a module. Is there a way of doing that without just putting the method in a module and including it in every single class? I'd also prefer not to have to call the method with the module (e.g. Module.logger)
From what I can tell, the class does not inherit at all from the module it is in, so I can't figure out anyway of doing this, but I thought I'd ask to be sure.
Ruby doesn't have nested classes. The classes aren't in the module. There is no relationship whatsoever between the classes and the module.
The constants which reference the classes are namespaced inside the module, but that has nothing to do with the relationship between the classes and the module.
So, no, what you want is not possible, for the simple reason that there is no relationship between the classes and the module that could be exploited to somehow make the method available. You will have to go for good old (mixin) inheritance.
Lately I bumped into this very interesting post: http://opensoul.org/blog/archives/2011/02/07/concerning-activesupportconcern/ which walks through (and explains) the ActiveSupport::Concern source code.
A few questions arose, but the most important was this:
Obviously there's a method called append_features which (by the docs at least) says: "Ruby’s default implementation of this method will add constants, methods, and variables of this module to the base module".
I always thought that module works the same as classes in the sense of the method lookup chain - the only difference is that you can't instantiate objects from it, and that it's not defined as a 'superclass' of this class (since a module is not actually a class). meaning that when a class includes a module, the module is simply being added as a direct parent in the class's inheritance hierarchy, and as a result, methods which are missing in the including class, will be looked for at the module.
But if that's the case, then what does it mean that append_features actually "adds methods to the base module", which means that you can actually prevent this behaviour, by overriding this method (which ActiveSupport::Concern actually does).
Can someone create some order in my head?
Basically, the append_features is - or should be considered - a deeply internal ruby method.
The Module.include method is defined (in the "eval.c" file with the name of rb_mod_include) as a loop, which just calls mod.append_features (and then mod.included) for every Module argument passed to it.
The default append_features implementation (rb_mod_append_features in "eval.c" file), calls the rb_include_module, and this is the method which does the real job.
(Actually the really real job is done by the include_modules_at few lines below)
It means that you are perfectly right saying that you can prevent or break this basic ruby functionality by overriding the append_features (at least if you don't call the super).
The ActiveSupport::Concern actually calls the super, just in some cases it postpones the actual call until the "concerned" module is included by some "non-concerned" one.
It's usually better to override the included method instead of append_features. The included is defined as just "return nil", thus the probability of breaking anything is smaller. And that is what the documentation of the included method advices.
I'm pretty familiar with when to use subclasses and modules, but more recently I've been seeing nested classes like this:
class Foo
class Bar
# do some useful things
end
end
As well as classes nested in modules like so:
module Baz
class Quux
# more code
end
end
Either documentation and articles are sparse or I'm not educated on the subject enough to grope for the right search terms, but I can't seem to locate much information on the topic.
Could somebody provide examples or links to posts on why/when those techniques would be used?
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.
In Ruby, defining a nested class is similar to defining a class in a module. It doesn't actually force an association between the classes, it just makes a namespace for the constants. (Class and Module names are constants.)
The accepted answer wasn't correct about anything. In the example below I create an instance of the lexically enclosed class without an instance of the enclosing class ever existing.
class A; class B; end; end
A::B.new
The advantages are the same as those for modules: encapsulation, grouping code used in only one place, and placing code closer to where it is used. A large project might have one outer module that occurs over and over in each source file and contains a lot of class definitions. When the various frameworks and library codes all do this, then they contribute only one name each to the top level, reducing the chance of conflicts. Prosaic, to be sure, but that's why they are used.
Using a class instead of a module to define the outer namespace might make sense in a one-file program or script, or if you already use the top level class for something, or if you are actually going to add code to link the classes together in true inner-class style. Ruby doesn't have inner classes but nothing stops you from creating about the same behavior in code. Referencing the outer objects from the inner ones will still require dotting in from the instance of the outer object but nesting the classes will suggest that this is what you might be doing. A carefully modularized program might always create the enclosing classes first, and they might reasonably be decomposed with nested or inner classes. You can't call new on a module.
You can use the general pattern even for scripts, where the namespace isn't terribly needed, just for fun and practice...
#!/usr/bin/env ruby
class A
class Realwork_A
...
end
class Realwork_B
...
end
def run
...
end
self
end.new.run
You probably want to use this to group your classes into a module. Sort of a namespace thing.
for example the Twitter gem uses namespaces to achieve this:
Twitter::Client.new
Twitter::Search.new
So both Client and Search classes live under the Twitter module.
If you want to check the sources, the code for both classes can be found here and here.
Hope this helps!
There is yet another difference between nested classes and nested modules in Ruby prior to 2.5 that other answers failed to cover that I feel must be mentioned here. It is the lookup process.
In short: due to top level constant lookup in Ruby prior to 2.5, Ruby may end up looking for your nested class in the wrong place (in Object in particular) if you use nested classes.
In Ruby prior to 2.5:
Nested class structure:
Suppose you have a class X, with nested class Y, or X::Y. And then you have a top level class named also Y. If X::Y is not loaded, then following happens when you call X::Y:
Having not found Y in X, Ruby will try to look it up in ancestors of X. Since X is a class and not a module, it has ancestors, among which are [Object, Kernel, BasicObject]. So, it tries to look for Y in Object, where it finds it successfully.Yet it is the top level Y and not X::Y.
You will get this warning:
warning: toplevel constant Y referenced by X::Y
Nested module structure:
Suppose in the previous example X is a module and not a class.A module only has itself as ancestor: X.ancestors would produce [X].
In this case, Ruby won't be able to look for Y in one of ancestors of X and will throw a NameError. Rails (or any other framework with autoloading) will try to load X::Y after that.
See this article for more information: https://blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications/
In Ruby 2.5:
Top level constant lookup removed.You may use nested classes without fear of encountering this bug.
In the addition to previous answers: Module in Ruby is a class
$ irb
> module Some end
=> nil
> Some.class
=> Module
> Module.superclass
=> Object
When you import a module into a class, is it similar in nature to OOP composition?
No, it's more like multiple inheritance, but not completely the same. Modules can be used to mix-in functionality, so you don't have to rewrite the same code for multiple classes. Composition is where objects hold references to other objects.
I may be getting my design pattern terminology mixed up, but have you looked at def_delegator and def_delegators from Ruby's standard library forwardable?