Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is Ruby module.included?

I'm trying to better my understanding of meta-programming in Ruby and am confused as to what Module.included is? My current understanding is that this is a callback invoked by Ruby whenever the module is included into another module or class. Other than that, what types of (meta-)programming constructs are these used in? Any examples?

like image 791
yesyouken Avatar asked Jun 13 '26 05:06

yesyouken


1 Answers

Module#included allows modules to inject both class and instance methods, and execute associated code, from a single include.

The documentation for ActiveSupport::Concern illustrates a typical use. It's injecting class methods into the calling class, and executing code. In this case, adding a scope.

module M
  def self.included(base)
    base.extend ClassMethods
    base.class_eval do
      scope :disabled, -> { where(disabled: true) }
    end
  end

  module ClassMethods
    ...
  end
end

And here's the ActiveSupport::Concern version which does the same thing, but adds declarative syntax sugar.

require 'active_support/concern'

module M
  extend ActiveSupport::Concern

  included do
    scope :disabled, -> { where(disabled: true) }
  end

  class_methods do
    ...
  end
end

With included a class simply includes the module. It allows the module to be one neat package: instance methods, class methods, and setup code.

class Thing
  # Class and instance methods are injected, and the new scope is added.
  include M
end

Without included a module can only inject instance methods. Class methods would have to be added separately, as well as executing any setup code.

module M
  def some_instance_method
    ...
  end

  module ClassMethods
    def setup
      scope :disabled, -> { where(disabled: true) }
    end
  end
end
class Thing
  # Inject the instance methods
  include M

  # Inject the class methods
  extend M::ClassMethods

  # Run any setup code.
  setup
end

Other examples might be registering a class, for example as an available plugin.

module Plugin
  def self.included(base)
    base.extend ClassMethods
    base.class_eval do
      register_as_plugin(base)
    end
  end

  module ClassMethods
    def register_as_plugin(klass)
      ...
    end
  end
end

class Thing
  include Plugin
end

Or adding necessary accessors.

module HasLogger
  def self.included(base)
    base.class_eval do
      attr_writer :logger
    end
  end

  def logger
    @logger ||= Rails.logger
  end
end

class Thing
  include HasLogger
end
like image 188
Schwern Avatar answered Jun 16 '26 07:06

Schwern



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!