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] ... end
Pretty clear, isn’t it? No additional lines of code, all the options are passed in module include line.
module PModule def self.(options) Module.new do define_singleton_method(:included) do |base| base.class_eval do # we have access to options hash here end end end end end
Let’s examine the code.
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