Last active
January 4, 2016 20:49
-
-
Save gabriel-dehan/8677098 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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