Making a Module Inherit from Another Module in Ruby

Making a module inherit from another module in Ruby

In fact you can define a module inside of another module, and then include it within the outer one.

so ross$ cat >> mods.rb
module ApplicationHelper
module Helper
def time
Time.now.year
end
end
include Helper
end

class Test
include ApplicationHelper
def run
p time
end
self
end.new.run
so ross$ ruby mods.rb
2012

How Can I Inherit a Ruby Module to Create Another Module?

You can just include module WithReviews in module Reviewable.

module WithReviews
def getReviews;end
end
module Reviewable
include WithReviews
def createReview;end
end

Making a module pre-include another (module inheritance) ruby

The answer is present in a duplicate question, though I didn't see it at first:

module XMLBacked
include FileBacked
# other XMLBacked methods here
end

This causes FileBacked to be injected into the lookup chain before XMLBacked whenever XMLBacked it is included.

inheritance from multiple modules?

To help you understand that, ruby provides you with Module#ancestors:

Object.ancestors # => [Object, Kernel, BasicObject]

This is the order, in which an instance method of Object will be searched for. So lets test your examples.


First, two modules included:

module M; end
module N; end
class C
include M
include N
end

C.ancestors # => [C, N, M, Object, Kernel, BasicObject]

So the methods will first be searched for in C. If a method with the given name is not found, it is searched for first in N and then in M. In other words - the reverse order of which you included the modules.


Second, module, including a module, included in a class:

module X; end
module Y
include X
end
class K
include Y
end

K.ancestors # => [K, Y, X, Object, Kernel, BasicObject]

So we can see that the same rule applies for including in modules. Just as in the previous example a method will first be searched for in C and only then in the modules included in C, here a method will first will be searched for in a module, and only then in the included modules in that module.


The reason for that, other than consistency, is that classes are actually modules in Ruby:

Class.superclass # => Module

There are a lot of rules. For example including the same module twice in the hierarchy, singleton classes, #prepend, #method_missing and so on. But you can deduce all of it knowing how to use #ancestors.

Inheriting from class Module

Module is indeed a Ruby class. An instance of the class Module is a Ruby module. To illustrate, these two ways of defining a module are equivalent:

module MyModule
# ...
end

# is equivalent to

MyModule = Module.new do
# ...
end

If an instance of Module is a Ruby module, that means that an instance of any subclass of Module is also a Ruby module, including Shrine::Attachment. This makes sense, because we know that we can include only modules, so an instance of Shrine::Attachment has to be a module.

Because of Shrine's plugin system design, this:

class Attachment < Module
@shrine_class = ::Shrine
end

isn't the whole implementation of Shrine::Attachment; the actual implementation is defined in the Shrine::Plugins::Base::AttachmentMethods module, which gets included into Shrine::Attachment.

If we look at the implementation of Shrine::Attachment.new, we can see that it dynamically defines methods on itself based on the given attribute name. For example, Shrine::Attachment.new(:image) will generate a module with the following methods defined: #image_attacher, #image=, #image, and #image_url. These methods will then get added to the model that includes that Shrine::Attachment instance.


Why didn't I just have a method that creates a new module via Module.new (like Refile does), instead of creating a whole subclass of Module? Well, two main reasons:

First, this gives better introspection, because instead of seeing #<Module:0x007f8183d27ab0> in your model's ancestors list, you now see an actual Shrine::Attachment instance that points to its definition. You could still manually override #to_s and #inspect, but this is better.

Second, since Shrine::Attachment is now a class, other Shrine plugins can extend it with more behaviour. So remote_url plugin adds the #<attachment>_remote_url accessor, data_uri plugin adds the #<attachment>_data_uri accessor etc.

Can a ruby class method inherit from another class?

class Users::PasswordsController < Devise::PasswordsController
...
end

In the above code, Users is the module and PasswordsController is the class inside Users module. Similarly Devise is the module and PasswordsController is the class inside Devise module.

so when you run

Users::PasswordsController.class
#=> Class
Users.class
#=>Module


Related Topics



Leave a reply



Submit