Ruby: How to Define a Class Method in a Module

Ruby: Is it possible to define a class method in a module?

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

Ruby: Use module method inside a class method

By including the module, you make module_method is an instance method on TestClass, meaning you need to invoke it on an instance of the class, not the class itself.

If you want to make it a method on the class itself, you need to extend TestModule, not include it.

module TestModule
def module_method
"module"
end
end

class TestClass
extend TestModule # extend, not include

def self.testSelfMethod
str = module_method
puts str
end
TestClass.testSelfMethod # "method"
end

Is there a way to use class method in a module without extend it in rails?

Use Module#module_function to make a single function to be a module function:

module M
def m1; puts "m1"; end
def m2; puts "m2"; end
module_function :m2
end

or:

module M
def m1; puts "m1"; end
module_function # from now on all functions are defined as module_functions
def m2; puts "m2"; end
end

M.m1 #⇒ NoMethodError: undefined method `m1' for M:Module
M.m2 #⇒ "m2"

Defining a method inside a module in ruby (NoMethodError)

The Ruby documentation on Module answers this in its introduction text.

This form:

module Familiar
def ask_age
return "How old are you?"
end
end

defines #ask_age as an instance method on Familiar. However, you can't instantiate Modules, so you can't get to their instance methods directly; you mix them into other classes. Instance methods in modules are more or less unreachable directly.

This form, by comparison:

module Familiar
def self.ask_age
return "What's up?"
end
end

defines ::ask_age as a module function. It is directly callable, and does not appear on included classes when the module is mixed into another class.

Define a class method in a module

You can extend the module in your class, your code should be like this:

module Base
def all
puts "All Users"
end
end

class User
extend Base
end

When you do something like this:

module MyModule
def self.module_method
puts "module!"
end
end

You're actually adding the method in the module itself, you could call the previous method like this:

MyModule.module_method

There is a way to just include the module and get the behaviour that you want, but I don't think this could be considered the "way to go". Look at the example:

module Base
def self.included(klass)
def klass.all
puts "all users"
end
end
end

class User
include Base
end

But like I said, if you can go with the extend class method, it is a better suit.

self.included – including class methods from a module in Ruby

What's the difference between the two examples?

The first code block adds the class methods in ClassMethods to the including class and calls the scope method on it as well. The second one does neither of these things and will result in a NoMethodError because the module has no scope class method. self.some_class_method will not be available on the including class once the module is included.

For the full story on how module inclusion works in Ruby, read my answer here:

Inheriting class methods from modules / mixins in Ruby

What's the point of self.included if a module's sole purpose is to be included?

Inclusion is not the only purpose of modules. They are also used for other things such as namespacing or simply storing various class methods that are then callable on the module itself.

Why doesn't Ruby include class methods automatically?

Theoretically Ruby could automatically add all class methods defined in a module to the including class, but in practice that would be a bad idea, because you would not get to choose anymore whether you want to include class methods — all class methods would be included every time, whether or not they are intended to be included. Consider this example:

module M
def self.class_method
"foo"
end

def self.configure_module
# add configuration for this module
end
end

class C
include M
end

Here, the configure_module method is obviously not supposed to be added to C, as its purpose is to set the configuration for the module object. Yet, if we had auto-inclusion for class methods, you would not be able to prevent it from being included.

But all instance methods are already included! How is that okay then?

Instance methods in a module are only really useful if they are included into a class, since modules cannot have instances, only classes can. So in a module every instance method is expected to be included somewhere to work.

A "class" method on a module is different, because it can be called on the module itself, so it can be used just fine regardless of whether it's also added to the including class. That is why it is better that you have a choice there.

Can I add class methods and instance methods from the same module?

There is a common idiom for that. It makes use of included object model hook. This hook gets invoked every time when a module is included to a module/class

module MyExtensions
def self.included(base)
# base is our target class. Invoke `extend` on it and pass nested module with class methods.
base.extend ClassMethods
end

def mod1
"mod1"
end

module ClassMethods
def mod2
"mod2"
end
end
end

class Testing
include MyExtensions
end

t = Testing.new
puts t.mod1
puts Testing::mod2
# >> mod1
# >> mod2

I personally like to group instance method to a nested module as well. But this is less accepted practice, as far as I know.

module MyExtensions
def self.included(base)
base.extend ClassMethods
base.include(InstanceMethods)

# or this, if you have an old ruby and the line above doesn't work
# base.send :include, InstanceMethods
end

module InstanceMethods
def mod1
"mod1"
end
end

module ClassMethods
def mod2
"mod2"
end
end
end

How to access class method from the included hook of a Ruby module

There'a a method_added callback you could use:

module MyModule
def self.included(includer)
def includer.method_added(name)
puts "Method added #{name.inspect}"
end
end
end

class MyClass
include MyModule

def foo ; end
end

Output:

Method added :foo

If you want to track both, existing and future methods, you might need something like this:

module MyModule
def self.on_method(name)
puts "Method #{name.inspect}"
end

def self.included(includer)
includer.instance_methods(false).each do |name|
on_method(name)
end

def includer.method_added(name)
MyModule.on_method(name)
end
end
end

Example:

class MyClass
def foo ; end

include MyModule

def bar; end
end

# Method :foo
# Method :bar

Can I define class methods with Module#concerning?

https://github.com/basecamp/concerning/pull/2 fixed this:

class User < ActiveRecord::Base
concerning :Programmers do
class_methods do
def im_a_class_method
puts "Yes!"
end
end
end
end

Console:

> User.im_a_class_method
Yes!


Related Topics



Leave a reply



Submit