84

Say there are three classes: A, B & C. I want each class to have a class method, say self.foo, that has exactly the same code for A, B & C.

Is it possible to define self.foo in a module and include this module in A, B & C? I tried to do so and got an error message saying that foo is not recognized.

1
  • 2
    Ruby doesn't really have a concept of static methods. In ruby, all methods have a receiver object. It just may be a method that happens to have a class of Class or Module. Commented Jan 15, 2011 at 21:56

5 Answers 5

131

Yep

module Foo
  def self.included(base)
    base.extend(ClassMethods)
  end
  module ClassMethods
    def some_method
      # stuff
    end
  end
end

One possible note I should add - if the module is going to be ALL class methods - better off just using extend ModuleName in the Model and defining the methods directly in the module instead - rather than having a ClassMethods module inside the Module, a la

 module ModuleName
   def foo
     # stuff
   end
 end
Sign up to request clarification or add additional context in comments.

Comments

55
module Common
  def foo
    puts 'foo'
  end
end

class A
  extend Common
end

class B
  extend Common
end

class C
  extend Common
end

A.foo

Or, you can extend the classes afterwards:

class A
end

class B
end

class C
end

[A, B, C].each do |klass|
  klass.extend Common
end

4 Comments

Isn't foo an instance method of A, B, and C, in this case ?
As Andrew already pointed out, Ruby's methods are always instance methods. But in this case, instances are classes. So, foo is class instance method. You call it with class as a receiver: A.foo. From within A's instance methods, you can also use self.class.foo.
@MladenJablanović well, instance is usually used to refer to the objects that a class generates, not to the class object itself. I propose calling them class methods instead of class instance methods to avoid confusion.
It's perhaps worth a mention that class A; extend Common; end is equivalent to class A; singleton_class.include Common; end.
39

This is basic ruby mixin functionality that makes ruby so special. While extend turns module methods into class methods, include turns module methods into instance methods in the including/extending class or module.

module SomeClassMethods
  def a_class_method
    'I´m a class method'
  end
end

module SomeInstanceMethods
  def an_instance_method
   'I´m an instance method!'
  end
end

class SomeClass
  include SomeInstanceMethods
  extend SomeClassMethods
end

instance = SomeClass.new
instance.an_instance_method => 'I´m an instance method!'

SomeClass.a_class_method => 'I´m a class method'

1 Comment

Thanks for showcasing the difference between include and extend.
31

Rails 3 introduced a module named ActiveSupport::Concern which has the goal of simplifying the syntax of modules.

module Foo
  extend ActiveSupport::Concern

  module ClassMethods
    def some_method
      # stuff
    end
  end
end

It allowed us to save a few lines of "boilerplate" code in the module.

Comments

12

Just wanted to extend Oliver's answer Define Class methods and instance methods together in a module.

module Foo
 def self.included(base)
   base.extend(ClassMethods)
 end
 module ClassMethods
   def a_class_method
     puts "ClassMethod Inside Module"
   end
 end

 def not_a_class_method
   puts "Instance method of foo module"
 end
end

class FooBar
 include Foo
end

FooBar.a_class_method

FooBar.methods.include?(:a_class_method)

FooBar.methods.include?(:not_a_class_method)

fb = FooBar.new

fb.not_a_class_method

fb.methods.include?(:not_a_class_method)

fb.methods.include?(:a_class_method)

Comments

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.