Why would we put a module inside a class in Ruby?
We could use it when writing ape-like code like this:
class DrugDealer
module Drug
def happy?; true; end
end
def approach(victim)
victim.extend Drug
end
end
o = Object.new
DrugDealer.new.approach(o)
o.happy? # => true
Another example that would be more practical in the real world is to have mixins that are only applied by subclasses.
This is useful when some facets of a thing apply to some subclasses and other facets apply to other subclasses, without there being enough order in the way these aspects apply to make way for a clear class hierarchy (tree). Think multiple inheritance! A simplified example:
class Person
def handshake
:sloppy
end
def mind_contents
:spam
end
module Proper
def handshake
:firm
end
end
module Clever
def mind_contents
:theories
end
end
end
class Professor < Person
include Proper
include Clever
# ...
end
And so on. Kind of nice, when used sensibly. Even super calls and constructors (I didn't define any here though) flow through all the mixins and classes the way I want them to.
Ruby: Use module method inside a class method
By including the module, you make module_method
is an instance method on TestClass
, meaning you need to invoke it on an instance of the class, not the class itself.
If you want to make it a method on the class itself, you need to extend TestModule
, not include
it.
module TestModule
def module_method
"module"
end
end
class TestClass
extend TestModule # extend, not include
def self.testSelfMethod
str = module_method
puts str
end
TestClass.testSelfMethod # "method"
end
How does include module works inside vs outside the class
From the other answer:
Outside of any class definition
include Foo
will addFoo
to the ancestors ofObject
. [...] all ofFoo
's instance methods are now available everywhere.
By including a module at the top level, you are effectively saying:
Object.include(Human)
# or
class Object
include Human
end
What you are missing is that modules and classes are objects, too.
The methods an object responds to come from its ancestors, e.g.:
1.0.class.ancestors
#=> [Float, Numeric, Comparable, Object, Kernel, BasicObject]
'abc'.class.ancestors
#=> [String, Comparable, Object, Kernel, BasicObject]
or, for your module:
Human.class.ancestors
#=> [Module, Object, Kernel, BasicObject]
When you include Human
at the top level, it adds that module to every object's ancestors:
include Human
1.0.class.ancestors
#=> [Float, Numeric, Comparable, Object, Human, Kernel, BasicObject]
# ^^^^^
'abc'.class.ancestors
#=> [String, Comparable, Object, Human, Kernel, BasicObject]
# ^^^^^
Human.class.ancestors
#=> [Module, Object, Human, Kernel, BasicObject]
# ^^^^^
Some examples:
1.0.living #=> true
'abc'.living #=> true
Float.living #=> true
Human.living #=> true
Why can't ruby classes inside modules have the same scope as regular classes?
I have a module with a class inside,
No, you don't. You have a module definition with a class definition inside, but that does not make the class a nested class. Ruby does not have nested classes.
Ruby is not Beta, Scala, or Newspeak, there are no nested classes in Ruby.
Nesting a module or class definition inside another module or class definition does not create nesting relationship between the two classes / modules. It only makes the constant which references the class / module part of the outer class' / module's namespace.
In other words, there is no difference between
module Foo
class Bar
end
end
and
class Quux
end
module Foo
Bar = Quux
end
Only the constant is nested, but not the object that is referenced by the constant.
but I find that the class inside can't reach any of the methods in the enclosing module without specifying the module path.
That is precisely because there is no "enclosing module". There is a lexically enclosing module definition but that does not create any form of relationship whatsoever between the Foo
class and the MyMod
module.
Another way to look at it is that the module_function doesn't seem to carry into the class.
I honestly don't understand what you mean by that, what it means for a method to "carry into a class", but Module#module_function
is not magic. It does exactly what the documentation says it does: it takes an instance method of the module, copies it as an instance method of the singleton class of the module, and makes the original instance method private
.
You can read its specification in the Ruby/Spec, it is fairly simple. Also, the Rubinius source code, both the basic version for booting the Rubinius kernel and the full version are fairly readable.
In the end, Module#module_function
really does not do much more than
class Module
def module_function(*meths)
meths.each do |meth|
define_singleton_method(meth, &instance_method(meth).bind(self))
private meth
end
self
end
end
If you run this, you get an error on the "But I can't..." line of:
undefined local variable or method `meaning'
The reason is simple: neither the class Foo
nor any of its superclasses has any method of that name, so of course you get an exception.
But if you remove the MyMod bits around the whole file, it has no problem accessing the outer method.
There is no "outer method". Ruby does not have Beta-like nested classes. That is really the fundamental cause of your misunderstanding. You expect Ruby to behave like Beta, but it just doesn't. Ruby takes inspiration from any languages, most notably (in rough order of importance) Smalltalk, Lisp, Perl, and Clu, but Beta is not among them.
This here works for a completely different reason:
def meaning
42
end
class Foo
def initialize
meaning
end
end
Methods that are defined at the top-level are implicitly defined as private instance methods of Object
. This is because the default definee at the top-level is ::Object
. Since Foo
inherits from Object
, method lookup will eventually find the meaning
method defined in Object
.
Is there an easy way to make these accessible without having to give the full path?
Inheritance. For example, Module#append_features
, which is called by Module#include
, makes the module the superclass of the including class, and thus all instance methods of the module become part of the method lookup ancestry chain.
An aside: if there is no nesting, then what does Module::nesting
do? Well, yeah, that is an unfortunately named method. The term "nested class" or "nested module" has a well-defined meaning in OO going all the way back to Beta. But this method is about a completely different kind of nesting:
It refers to the lexical nesting of module definitions, and not to nesting of modules themselves.
For example, these module definitions all define the exact same module, but the definition text has different nesting:
module Foo
module Bar
module Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz, Foo::Bar, Foo]
end
end
end
end
module Foo
module Bar
module Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar, Foo]
end
end
end
module Foo
module Bar::Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz, Foo]
end
end
end
module Foo::Bar
module Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz, Foo::Bar]
end
end
end
module Foo
module Bar::Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo]
end
end
module Foo::Bar::Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz]
end
end
module Foo::Bar
module Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar]
end
end
module Foo::Bar::Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux]
end
Again, this is purely lexical nesting of the module definition. The module itself is not nested; the module itself is the same in all of these cases. This nesting only affects constant lookup.
Constants are looked up first lexically outwards in enclosing module definitions, then upwards the inheritance chain.
There is another instance where things can be nested: blocks create nested lexical scopes, whereas all other lexical scopes (script, module / class definition, and method definition) don't nest. In other words, blocks and only blocks have access to the local variables (and self
) of their enclosing lexical scopes.
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 Wheel
s.
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.
ruby, why using a module inside a module?
Re: Question 1
The namespacing provides organization. Devise is made up of a few parts that integrate into your application eg. Models, Controllers, Authentication logic, etc...
The reason one would use the same namespacing can be
- to keep that same organizational structure.
- to add/edit the original modules and/or classes. Ruby allows one to reopen a class or module and override or add additional logic. So one doesn't have to extend/include a class/module to patch in there own code.
However, you do want to take care when reopening a class/module you don't own.
Re: Question 2
Modules are very similar to Class (Class actually is a child of Module, which then goes up the chain to Object then BasicObject), with the exception they can't be Instantiated. But, they can have methods, variables and all that jazz and act as a singular object. So modules can naturally include and extend other modules to gain the logic to use within the module that is doing the including or extending.
Ruby Class Docs,
Ruby Module Docs
Declaring a class within a module
what is the advantage of doing it this way?
It serves as namespace so classes with the same name do not clash (so it has nothing to do with mixins). It's standard.
Why are we appending self to class, is that not already implied?
That's just one of the ways of defining class-methods (the other being def self.method_name
).
Include a module on instances instead of a class
When you call self.class.send(:include, MM::NN)
, that's making a irreversible change to the class (the blueprint for all instances).
If you want a module to only be included for an instance, you have to use the singleton class (What exactly is the singleton class in ruby?):
module TestModule
def test_method; "ok"; end
end
class A
def initialize(add_module)
singleton_class.include(TestModule) if add_module
end
end
A.new(true).test_method # module method called
A.new(false).test_method # NoMethodError
Note that I changed display
to test_method
, because display
is a built in Kernel method so it won't raise NoMethodError even if you don't include the module on the instance.
Note, Ozer's answer is the same thing but using a different syntax.
-- edit in response to comment --
Adding methods on the singleton class takes priority over those added to the regular class, and if you include multiple modules onto the singleton class, the last on will take priority:
module A; def fn; 1; end; end
module B; def fn; 2; end; end
module C; def fn; 3; end; end
class D
include A
def initialize(add_b, add_c)
singleton_class.include(B) if add_b
singleton_class.include(C) if add_c
end
end
puts D.new(false, false).fn # => 1
puts D.new(true, true).fn # => 3
Ruby - How to include classes in a Module
Im not sure what the issue is. I understand that it says uninitialized but Im not sure why. It seems it is looking for a constant instead of reading the class?
It is not clear to me what you mean by "reading the class". Yes, Ruby is looking for a constant. Variable names that begin with a capital letter are constants, ergo, HtmlBody
is a constant, HeadingTags
is a constant, and HtmlBody::HeadingTags
is the constant HeadingTags
located in a class or module that is referenced by the constant HtmlBody
.
How are you supposed to include classes located in separated files inside a module?
You namespace a class inside a module by defining the class inside the module. If you are sure that the module already exists, you can define the class like this:
class HtmlBody::HeadingTags
# …
end
However, if HtmlBody
is not defined (or is not a class or module), this will fail.
module HtmlBody
class HeadingTags
# …
end
end
This will guarantee that module HtmlBody
will be created if it doesn't exist (and simply re-opened if it already exists).
There is also a slight difference in constant lookup rules between the two, which is however not relevant to your question (but be aware of it).
The is something that Im missing in Ruby and the require/require_relative probably.
Indeed, your question stems from a fundamental misunderstanding of what Kerne#load
/ Kernel#require
/ Kernel#require_relative
does.
Here is the very complicated, detailed, in-depth explanation of all the incredibly convoluted stuff that those three methods do. Brace yourself! Are you ready? Here we go:
They run the file.
Wait … that's it? Yes, that's it! That's all there is to it. They run the file.
So, what happens when you run a file that looks like this:
class HeadingTags
# …
end
It defines a class named HeadingTags
in the top-level namespace, right?
Okay, so what happens when we now do this:
require_relative './html_body/HeadingTags'
Well, we said that require_relative
simply runs the file. And we said that running that file defines a class named HeadingTags
in the top-level namespace. Therefore, this will obviously define a class named HeadingTags
in the top-level namespace.
Now, looking at your code: what happens, when we do this:
module HtmlBody
require_relative './html_body/HeadingTags'
end
Again, we said that require_relative
simply runs the file. Nothing more. Nothing less. Just run the file. And what did we say running that file does? It defines a class named HeadingTags
in the top-level namespace.
So, what will calling require_relative
from within the module definition of HtmlBody
do? It will define a class named HeadingTags
in the top-level namespace. Because require_relative
simply runs the file, and thus the result will be exactly the same as running the file, and the result of running file is that it defines the class in the top-level namespace.
So, how do you actually achieve what you are trying to do? Well, if you want to define a class inside a module, you have to … define the class inside the module!
lib/html_body.rb
require_relative 'html_body/heading_tags'
require_relative 'html_body/anchor_tags'
require_relative 'html_body/img_tags'
module HtmlBody; end
lib/html_body/heading_tags.rb
module HtmlBody
class HeadingTags
# …
end
end
lib/html_body/anchor_tags.rb
module HtmlBody
class AnchorTags
# …
end
end
lib/html_body/img_tags.rb
module HtmlBody
class ImgTags
# …
end
end
main.rb
require_relative 'lib/html_body'
HtmlBody::HeadingTags.new
Related Topics
Regex to Extract Boundary and Content Type Out of Mail Headers
Use Some Middleware Only for Specific Rack Website
Rails Cors Issue with Ajax API Endpoint Request
Rails Console Is Adding Nil Instead of Values
Bug in Implemented Tagging System
Activerecord::Recordnotfound in Articlescontroller#Show Couldn't Find Article Without an Id
Ruby - Permutation Between Elements of an Array
Rails Contact Form Not Working
How to Access Ruby Method Inside Module and Inside a Class from Another .Rb File
How to Set Text Area Properties Inside Controller Page Using Ror
Rally Ruby Toolkit: How to Get Url of Portfolio Item's State
How to Get Exit Status with Ruby's Net::Ssh Library
How to Add 'Each' Method to Ruby Object (Or Should I Extend Array)
Differencebetween Gsub and Sub Methods for Ruby Strings
Boot Up Rails App, Make Request to App from Outside Local Network