Modules in ruby using metaprogramming, activesupport concern

Modules in ruby using metaprogramming, activesupport concern

We have two files and the content is the next:
image_utils.rb

def preview(image)

end

def transfer(image, destination)
end

run.rb

require ‘./image_utils’
preview “something”

The problem with the before example is that in the future we can mix differents methods for that problema we can use the namespace, using module the before example will looks like:
image_utils.rb

module Mymodule
  def self.preview image
     puts image
  end

  def self.transferi image, destination

  end
end

run.rb

require './image_utils'

Mymodule.preview "un mensaje"

In ruby we can use only one superclass for inheritance for example

class Car < SuperCar
end

The diference is that we can use severals modules for example

module Share
   def somemethod
   end
end
module Favorite
end

class Oneclass
  include Share
   include Favorite
end

class ClassTwo
   include Share
   include Favorite
end

if we use include module the module will be included like instance methods:

If we use the extend Module the module is included like a class methods, in other words we can invoke using direcly our class for example

OneClass.somemethod

Namespacing
Create a module named GameUtils and place the lend_to_friend method inside the module. Changelend_to_friend to a class method by prefixing it with self..
You won’t need to require this module since it’ll be inside the same file (already required), but you will have to namespace your method call.

module GameUtils
  def self.lend_to_friend(game, friend_email)
    puts "#{game} y #{friend_email}"
  end
end

GameUtils::lend_to_friend("contra super 7", "gregg@codeschool.com")
#or
#GameUtils.lend_to_friend("contra super 7", "gregg@codeschool.com")

Mixin
Re-open the Game class and include the GameUtils module so its methods are exposed as instance methods. Make sure to do this before it is called.

class Game
  include GameUtils
end
game = Game.new("contra")
game.lend_to_friend("Gregg")

Extend
Good job! Now expose the methods from the GameUtils module as class methods of the Game class.

class Game
 extend GameUtils
end

Game.find_all_from_user("Gregg")

Object Extend
Extend the single game object with the Playable module, so we can call the play method on it.

class Game
end
game = Game.new("Contra")
game.extend(Playable)
game.play

Hook Methods
Define a new self.included method hook for the LibraryUtils module which will extend the ClassMethods on the passed in class. Also, since we’ll now be extending ClassMethods when LibraryUtils is included, remove duplicate code in the AtariLibrary class.


module LibraryUtils
  def self.included(base)
    base.extend(ClassMethods)
  end

  def add_game(game)
  end

  def remove_game(game)
  end

  module ClassMethods
   def search_by_game_name(name)
   end
  end
end

class AtariLibrary
  include LibraryUtils
end

ActiveSupport::Concern
Now refactor the following code to use ActiveSupport::Concern’s ability to expose class methods from a module.


module LibraryUtils

 extend ActiveSupport::Concern
 include do
 search_by_game_name
 end

 def add_game(game)
 end

 def remove_game(game)
 end

 module ClassMethods
  def search_by_game_name(name)
  end
 end
end

ActiveSupport::Concern – Part II
Call the included method from inside the LibraryUtils module and pass in a block that calls the load_game_list class method.

module LibraryUtils

 extend ActiveSupport::Concern
 included do
 load_game_list
 end

 def add_game(game)
 end

 def remove_game(game)
 end

module ClassMethods
  def search_by_game_name(name)
  end

  def load_game_list
  end
end
end

ActiveSupport::Concern
Make sure the AtariLibrary class includes only the LibraryUtils module and let ActiveSupport::Concern take care of loading its dependencies. Then, refactor the self.included method on LibraryUtils to use the included method.


module LibraryLoader

 extend ActiveSupport::Concern

 module ClassMethods
  def load_game_list
  end
 end
end

module LibraryUtils
  extend ActiveSupport::Concern
  include LibraryLoader
  included do
    load_game_list
  end
end

class AtariLibrary
  include LibraryUtils
end

Other example using model validations with a module

module ModelHelpers
module Card::Validator
extend ActiveSupport::Concern

included do
validates :cvn_number, format: { with: /^[0-9]{3,4}$/,
message: 'Please enter a valid card security code.'}

validates :card_first_name, presence: { message: 'Please enter a valid first name.' }

validates :agreed_terms, acceptance: { accept: true,
message: 'Please agree to the Terms and Conditions.'}

validates :account, uniqueness: { message: 'the card is already registered' }

validates :card_number, length: {minimum: 16, maximum: 19,
message:  'Debit Card number is not valid...'}

end
end
end

And in our model:


class Card < ActiveRecord::Base
include ModelHelpers::Card::Validator
end

And that’s it

1 Comment
  • Jason
    Posted at 12:23h, 19 July

    Looks like you lifted this directly from CodeSchool.

Post A Comment