Can I invoke an instance method on a Ruby module without including it?
If a method on a module is turned into a module function you can simply call it off of Mods as if it had been declared as
module Mods
def self.foo
puts "Mods.foo(self)"
end
end
The module_function approach below will avoid breaking any classes which include all of Mods.
module Mods
def foo
puts "Mods.foo"
end
end
class Includer
include Mods
end
Includer.new.foo
Mods.module_eval do
module_function(:foo)
public :foo
end
Includer.new.foo # this would break without public :foo above
class Thing
def bar
Mods.foo
end
end
Thing.new.bar
However, I'm curious why a set of unrelated functions are all contained within the same module in the first place?
Edited to show that includes still work if public :foo
is called after module_function :foo
How to call any instance method in ruby object without instantiating it?
Despite the fact method_missing
would do the job, I'd probably avoid it in this case in favor of a more explicit delegation. Simple and dirty example:
module InstanceDelegator
def delegate_to_instance(*methods)
methods.each do |method_name|
define_singleton_method method_name do |*args|
new(*args).public_send(method_name)
end
end
end
end
class Foo
extend InstanceDelegator
delegate_to_instance :bar # <- define explicitly which instance methods
# should be mirrored by the class ones
def bar
puts "bar is called"
end
def baz
puts "baz is called"
end
end
# and then
Foo.bar # => bar is called
Foo.baz # NoMethodError ...
# reopening works too
class Foo
delegate_to_instance :baz
end
Foo.baz # baz is called
Pros:
- you don't need to redefine
method_missing
(less magic -> less pain when you debug the code) - you control precisely which instance methods to be wrapped with the class level "shorthand" (fewer chances to delegate something you don't want to - more robust code)
- (minor) no need to raise NoMethodError explicitly - you can fully rely on the core dispatching as it is...
Calling a method on a Ruby module
Simple method:
module MyModule
def self.my_method(*args)
MyModule::MyClass.my_method(*args)
end
end
Harder method:
Use metaprogramming to write a function for all cases (like attr_accessor).
How to call a method from a module of an other ruby file
Require needs the absolute path to the file unless the file is located in one of Ruby's load paths. You can view the default load paths with puts $:
. It is common to do one of the following to load a file:
Add the main file's directory to the load path and then use relative paths with require:
$: << File.dirname(__FILE__)
require "my_module"
Ruby 1.8 code that only loads a single file will often contain a one-liner like:
require File.expand_path("../my_module", __FILE__)
Ruby 1.9 added require_relative:
require_relative "my_module"
In the module you will need to define the methods as class methods, or use Module#module_function:
module MyModule
def self.method1 ary
...
end
def method2
...
end
module_function :method2
end
a = [1,2,3,4]
MyModule.method1(a)
How do I access a module from an instance method in Ruby?
Usually, in a module
, it's a good practice to have class-methods and instance-methods separate, like this:
module M
def bar
puts "BAR"
self.class.foo
end
module ClassMethods
def foo
puts "FOO"
end
end
end
Now, in a class, I would ideally want to include
this module M
in a way that I get A.foo
as class method and A.new.bar
as instance method. The trick for that is Module.included
.
module M
def bar
puts "BAR"
self.class.foo
end
module ClassMethods
def foo
puts "FOO"
end
end
# when module is included, extend the class with ClassMethods
def self.included(base)
base.extend ClassMethods
end
end
class A
include M
end
A.singleton_methods #=> [:foo]
A.new.foo
#=> BAR
#=> FOO
With this approach, you can refer the class method with self.class
and it will automagically work.
Hope it helps.
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
Can I invoke a class method from an ActiveRecord::Concern without mixing it into another class?
No, you can't because the methods defined in the block of class_methods
are actually defined in the module Foo::ClassMethods
(Foo
is your concern). Here is the relevant source code of ActiveSupport::Concern
module ActiveSupport
# ...
module Concern
# ...
def class_methods(&class_methods_module_definition)
mod = const_defined?(:ClassMethods, false) ?
const_get(:ClassMethods) :
const_set(:ClassMethods, Module.new)
mod.module_eval(&class_methods_module_definition)
end
end
end
You can see that class_methods
just creates the module ClassMethods
for you if it is not defined by yourself. The methods you defined are just instance methods in that module, so you can't call it at the module level.
Later on, the module ClassMethods
will be extended by the class that includes your concern. Here is the relevant source code:
module ActiveSupport
# ...
module Concern
def append_features(base)
if base.instance_variable_defined?(:@_dependencies)
# ...
else
# ...
base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods) # <-- Notice this line
# ...
end
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
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"
ruby - how to dynamically call instance method in a module
Disclaimer: Bad practice and it makes little to no sense:
MyModule.instance_method(:Foo) # #<UnboundMethod: MyModule#Foo>
.bind(Object) # #<Method: MyModule#Foo>
.call #=> hello
You can't call an unbound method, thus you have to first bind it to some object.
References:
Module#
instance_method
UnboundMethod#
bind
Method#
call
It would be much easier if you make the method singleton method:
module MyModule
def self.Foo
puts "hello"
end
end
MyModule.Foo
#=> "hello"
Another option is to use module_function
(read up on the method's visibility for the including object when using this option):
module MyModule
def Foo
puts "hello"
end
module_function :Foo
end
MyModule.Foo
#=> "hello"
And yet another one is using extend self
:
module MyModule
def Foo
puts "hello"
end
extend self
end
MyModule.Foo
#=> "hello"
P.S. It is not conventional to use capital letters in method names. It is very rare case in Ruby where it can be used and your case is 100% not the one :)
Related Topics
Ruby Sleep or Delay Less Than a Second
Where to Put Ruby Helper Methods for Rails Controllers
How to Convert a Ruby Hash So That All of Its Keys Are Symbols
Ruby: How to Convert a String to Boolean
Simple Way of Turning Off Observers During Rake Task
How to Deal with the Conflict Between Activesupport::JSON and the JSON Gem
Differencebetween Integer and Fixnum
How to Decompress Gzip String in Ruby
Installing Ruby on MAC Os X 10.8.2
Ruby: How to Add "# Encoding: Utf-8" Automatically
Ruby on Rails - Drop Down Box on Change Event
Add Method to an Instanced Object
Convert a .Doc or .Pdf to an Image and Display a Thumbnail in Ruby