Passing options to included modules

Posted in engineering

One of the tasks I’ve faced recently was to allow configuring a module, included into multiple classes, by passing options (simple key => value hash) to it. The traditional approach would be using class or instance variables/accessors or so, but this time I decided to try something different.

Here is the final result:

class ClassA
  include PModule[option1: :value1, option2: :value2]

Pretty clear, isn’t it? No additional lines of code, all the options are passed in module include line.

The implementation

module PModule
  def self.[](options) do
      define_singleton_method(:included) do |base|
        base.class_eval do
          # we have access to options hash here

Let’s examine the code.

In PModule we define only self.[] method which takes one argument options and returns another anonymous module. That’s enough, no any other code should be added there. The anonymous module will be included into the target class and there we dynamically define included method which will extend the target with the code in block. In the block passed to base.class_eval we can define anything we need and we have access to options argument there.

Using this approach we can configure what will be included into the target class but we should keep in mind that options won’t be accessible in methods defined in the anonymous module. So any methods that require access to options argument should be defined dynamically by using define_method.