Skip to content

Instantly share code, notes, and snippets.

@gabriel-dehan
Last active January 4, 2016 20:49
Show Gist options
  • Select an option

  • Save gabriel-dehan/8677098 to your computer and use it in GitHub Desktop.

Select an option

Save gabriel-dehan/8677098 to your computer and use it in GitHub Desktop.
# I - Modules as namespaces
# II - Module extension
# III - Module inclusion
# IV - Module are the answer to the lack of multiple inheritance in Ruby
# -----------------------------------------------------------------
# | Modules as namespaces |
# -----------------------------------------------------------------
# Modules can be used to encapsulate other classes
module ActiveRecord
class Migration
# Do stuff
end
class Base
# Do stuff
end
end
# This is a well known example. It's used to regroup similar classes
# You can call one of this class by using ModuleName::ClassName
ActiveRecord::Migration.new
# Or the example we are used to :
class MyModel < ActiveRecord::Base
end
# You can also encapsulate modules in modules
module Rails
module ActiveRecord
class Migration
# Do stuff
end
class Base
# Do stuff
end
end
end
# Here it would work but you would need to do
class MyModel < Rails::ActiveRecord::Base
end
# End that would be tedious
# -----------------------------------------------------------------
# | Module extension |
# -----------------------------------------------------------------
# One can use module to extend a class. When a class extends a module it will give it all it's class methods
class Alcohol
end
module Liquid
def evaporate
puts "All the liquid is gone."
end
end
# We all agree that the class Alcohol does not have any evaporate method, right ?
# Now if we do :
class Alcohol
extend Liquid
end
# We can do :
Alcohol.evaporate # => All the liquid is gone
# It's exactly as if you would have written
class Alcohol
def self.evaporate
puts "All the liquid is gone."
end
end
# -----------------------------------------------------------------
# | Module inclusion |
# -----------------------------------------------------------------
# You can use a module to be included in a class. When a class includes a module it will give it all it's instance methods
module Alcohol
def drink
puts "You are now drunk"
end
end
class Beer
include Alcohol
end
my_beer = Beer.new
my_beer.drink # => You are now drunk
# You can also include and extend multiple modules :
module Liquid
def evaporate
puts "All the liquid is gone."
end
end
class Beer
extend Liquid
include Alcohol
end
Beer.evaporate # => All the liquid is gone
Beer.new.drink # => You are now drunk
# It's worth mentionning that you can actually use your modules multiple times :
class Vodka
extend Liquid
include Alcohol
end
class Rhum
extend Liquid
include Alcohol
end
class Beer
extend Liquid
include Alcohol
end
# Handy isn't it ?
# -----------------------------------------------------------------
# | Modules as multiple inheritance |
# -----------------------------------------------------------------
# It's important to note that modules' inclusions are considered the same as multiple inheritance
# We have those classes :
class Liquid
def self.evaporate
puts "All the liquid is gone."
end
end
module Alcohol
def drink
puts "You are now drunk"
end
end
# Let's look at this :
class Beer < Liquid
end
# When you do this, the Beer class and instances will inherit from all of Liquid's class and instance methods
--------------
| |
| Liquid |
| |
--------------
|
|
| Gives all classes and instance methods to
|
|
\ /
--------------
| |
| Beer |
| |
--------------
# Now you want to have the drink method for you future Beer objects, so you do this :
class Beer < Liquid
include Alcohol
end
# And it's actually pretty much the same as if you did this :
class Beer < Alcohol < Liquid
end
# But you can't in Ruby.
# When you do
class Beer < Liquid
include Alcohol
end
# The previous diagram becomes this :
--------------
| |
| Liquid |
| |
--------------
|
|
| Gives all classes and instance methods to
|
|
\ /
--------------
| |
| Alcohol |
| |
--------------
|
|
| Gives all instance methods to
|
|
\ /
--------------
| |
| Beer |
| |
--------------
# Get it ?
# Same goes with multiple modules inclusions
module Brewable
def brew
end
end
class Beer < Liquid
include Alcohol
include Brewable
end
# Gives this :
--------------
| |
| Liquid |
| |
--------------
|
|
| Gives all classes and instance methods to
|
|
\ /
--------------
| |
| Alcohol |
| |
--------------
|
|
| Gives all instance methods to
|
|
\ /
--------------
| |
| Brewable |
| |
--------------
|
|
| Gives all instance methods to
|
|
\ /
--------------
| |
| Beer |
| |
--------------
# Thus you have to be careful with this :
class Liquid
def drink
puts "You drank this liquid !"
end
end
class Beer < Liquid
def drink
puts "It tingles !"
end
end
Beer.new.drink # => It tingles !
# The same goes for modules :
class Liquid
def drink
puts "You drank this liquid !"
end
end
class Beer < Liquid
end
Beer.new.drink # => You drank this liquid !
module Alcohol
def drink
"You are now drunk !"
end
end
class Beer < Liquid
include Alcohol
end
Beer.new.drink # => You are now drunk
# The latest's module inclusion will always overwrite methods with the same name to avoid conflict
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment