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
Why Word 'Translate' Is Messing Irb
How to Input Integer Value to an Array, Based Preceeding Row + Column Values
Will Uuid as Primary Key in Postgresql Give Bad Index Performance
Rubocop Line Length: How to Ignore Lines with Comments
Find or Create Record Through Factory_Girl Association
Error Installing Gem Capybara-Webkit
Failed to Build Gem Native Extension When Install Redcloth-4.2.9 Install Linux
In Ruby, When Should You Use Self. in Your Classes
Phusion Passenger Error: You Have Activated Rack 1.2.1, But Your Gemfile Requires Rack 1.2.2
How to Read a Password from the Command Line in Ruby
Nicely Formatting Output to Console, Specifying Number of Tabs
Generate Letters to Represent Number Using Ruby
Fresh Installs of Rvm and Ruby 2.1.1 - Dyld Library/Pathing Error
Error Installing Pg Gem on Osx