Adding Enumerable mixin at the class-level in Ruby

ruby, ruby-on-rails

Solution

You can use `include` from within `class << self`:

class Foo

  class << self
    include Enumerable
  end

  def self.each
    yield 1
    yield 2
    yield 3
  end
end

Foo.map { |x| x * 2 } # => [2, 4, 6]

This pattern is used in Ruby's `Prime` class. Writing `include` to include a module looks cleaner to me, but you can probably use `extend` as well (see Uri Agassi's answer).

There would be a difference if the included module relied on the `included` callback (`Enumerable` doesn't):

module M
  def self.included(other)
    puts "included in #{other}"
  end
end

class Foo
  class << self
    include M
  end
end
#=> "included in #<Class:Foo>"

class Bar
  extend M
end
#=> nothing

As noted by Зелёный you could define `each` right within the block: (and without using `self`)

class Foo
  class << self
    include Enumerable

    def each
      # ...
    end
  end
end

Problem

I'm using postgres schemas in my Rails app so there's no clear way to query across all companies (for our own analytics). I'd like to implement each method that iterates over all the companies and switches the postgres schema appropriately. I'd like to be able to call: ``` Company.each do |company| # do something in the context of each company end ``` but I'd also like to get some of the other Enumerable methods like `collect` in this example of getting all managers across all companies: ``` Company.collect do |company| Users.managers end ``` Currently I have this which works well ``` class Company < ActiveRecord::Base # ... def self.each(&block) Company.all.each do |company| if Schemas.include? company.subdomain # this changes to that company's schema so all queries are scoped Apartment::Database.switch company.subdomain yield company if block_given? end end end ``` but how do I get the Enumerable mixin at the class-level not the instance level. i.e., when `include Enumerable` is in the class, Enumerable methods get called like ``` company = Company.new # which might iterate over the contents (users?) in a company company.collect {|u| u} ``` but I want to call ``` # iterate over all companies and collect the managers Company.collect {|c| User.managers} ``` and have it use ``` Company.each ``` I feel like the answer is obvious but my meta-programming foo is weak this morning.

Original source