10

In Ruby I want to have a class include a series of modules and have these individual modules execute a block or method (or just find some way to edit an instance variable) when initializing that class.

I know I can do this by creating a method in the module and then calling it in the class' initialize method, but I want some way to do this by simply including the module and calling one method to execute any code the modules add to initialize, that way I can have a large amount of things included in a class without worrying about adding a line of code in the initialize method for every single module included.

I've checked out aliasing, super, and related things but haven't gotten anything...

If it helps to understand what I'm hoping to accomplish here's some pseudocode:

module Mod1  
    call_this_block_on_initialize { @a.push 4 }  
end  
  
module Mod2  
    call_this_block_on_initialize { @a.push 5 }  
end  
  
class Test  
    attr_accessor :a  
    include Mod1  
    include Mod2  
  
    def initialize  
      @a = [1, 2, 3]  
      call_those_blocks_set_by_mods  
    end  
end  

t = Test.new
t.a # returns [1, 2, 3, 4, 5]

This may be a bit wordy but I think the title sums up what I'm trying to do. Thanks for any help!

1 Answer 1

11

There are a few ways you can do this. This example will redefine the initialize method and add whatever extra code you want:

module MyModule
  def self.included(base) # built-in Ruby hook for modules
    base.class_eval do    
      original_method = instance_method(:initialize)
      define_method(:initialize) do |*args, &block|
        original_method.bind(self).call(*args, &block)
        @a.push 4 # (your module code here)
      end
    end
  end
end

class Test  
  attr_accessor :a  

  def initialize  
    @a = [1, 2, 3]    
  end  

  # It must be included after the `initialize` 
  # definition or the module won't find the method:
  include MyModule
end  

However: I think what you really want is subclassing. If you have a lot of classes with similar behavior, as it seems you do, ask yourself if there is a natural abstract parent class. Can you explain what you did with super and why it didn't work?

Sign up to request clarification or add additional context in comments.

2 Comments

You're right, I looked into how super works and I'm able to execute code for any number of modules added no matter what combination or which modules. Basically made a chain of supers for the modules:
This is so money, thank you. I used this to separate out ability.rb files for a Rails CanCan authorization pattern: stackoverflow.com/a/25723811/293280

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.