[ruby] Can I invoke an instance method on a Ruby module without including it?

Background:

I have a module which declares a number of instance methods

module UsefulThings
  def get_file; ...
  def delete_file; ...

  def format_text(x); ...
end

And I want to call some of these methods from within a class. How you normally do this in ruby is like this:

class UsefulWorker
  include UsefulThings

  def do_work
    format_text("abc")
    ...
  end
end

Problem

include UsefulThings brings in all of the methods from UsefulThings. In this case I only want format_text and explicitly do not want get_file and delete_file.

I can see several possible solutions to this:

  1. Somehow invoke the method directly on the module without including it anywhere
    • I don't know how/if this can be done. (Hence this question)
  2. Somehow include Usefulthings and only bring in some of it's methods
    • I also don't know how/if this can be done
  3. Create a proxy class, include UsefulThings in that, then delegate format_text to that proxy instance
    • This would work, but anonymous proxy classes are a hack. Yuck.
  4. Split up the module into 2 or more smaller modules
    • This would also work, and is probably the best solution I can think of, but I'd prefer to avoid it as I'd end up with a proliferation of dozens and dozens of modules - managing this would be burdensome

Why are there lots of unrelated functions in a single module? It's ApplicationHelper from a rails app, which our team has de-facto decided on as the dumping ground for anything not specific enough to belong anywhere else. Mostly standalone utility methods that get used everywhere. I could break it up into seperate helpers, but there'd be 30 of them, all with 1 method each... this seems unproductive

This question is related to ruby module methods

The answer is


If you want to call these methods without including module in another class then you need to define them as module methods:

module UsefulThings
  def self.get_file; ...
  def self.delete_file; ...

  def self.format_text(x); ...
end

and then you can call them with

UsefulThings.format_text("xxx")

or

UsefulThings::format_text("xxx")

But anyway I would recommend that you put just related methods in one module or in one class. If you have problem that you want to include just one method from module then it sounds like a bad code smell and it is not good Ruby style to put unrelated methods together.


If you want to call these methods without including module in another class then you need to define them as module methods:

module UsefulThings
  def self.get_file; ...
  def self.delete_file; ...

  def self.format_text(x); ...
end

and then you can call them with

UsefulThings.format_text("xxx")

or

UsefulThings::format_text("xxx")

But anyway I would recommend that you put just related methods in one module or in one class. If you have problem that you want to include just one method from module then it sounds like a bad code smell and it is not good Ruby style to put unrelated methods together.


As I understand the question, you want to mix some of a module's instance methods into a class.

Let's begin by considering how Module#include works. Suppose we have a module UsefulThings that contains two instance methods:

module UsefulThings
  def add1
    self + 1
  end
  def add3
    self + 3
  end
end

UsefulThings.instance_methods
  #=> [:add1, :add3]

and Fixnum includes that module:

class Fixnum
  def add2
    puts "cat"
  end
  def add3
    puts "dog"
  end
  include UsefulThings
end

We see that:

Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
  #=> [:add2, :add3, :add1] 
1.add1
2 
1.add2
cat
1.add3
dog

Were you expecting UsefulThings#add3 to override Fixnum#add3, so that 1.add3 would return 4? Consider this:

Fixnum.ancestors
  #=> [Fixnum, UsefulThings, Integer, Numeric, Comparable,
  #    Object, Kernel, BasicObject] 

When the class includes the module, the module becomes the class' superclass. So, because of how inheritance works, sending add3 to an instance of Fixnum will cause Fixnum#add3 to be invoked, returning dog.

Now let's add a method :add2 to UsefulThings:

module UsefulThings
  def add1
    self + 1
  end
  def add2
    self + 2
  end
  def add3
    self + 3
  end
end

We now wish Fixnum to include only the methods add1 and add3. Is so doing, we expect to get the same results as above.

Suppose, as above, we execute:

class Fixnum
  def add2
    puts "cat"
  end
  def add3
    puts "dog"
  end
  include UsefulThings
end

What is the result? The unwanted method :add2 is added to Fixnum, :add1 is added and, for reasons I explained above, :add3 is not added. So all we have to do is undef :add2. We can do that with a simple helper method:

module Helpers
  def self.include_some(mod, klass, *args)
    klass.send(:include, mod)
    (mod.instance_methods - args - klass.instance_methods).each do |m|
      klass.send(:undef_method, m)
    end
  end
end

which we invoke like this:

class Fixnum
  def add2
    puts "cat"
  end
  def add3
    puts "dog"
  end
  Helpers.include_some(UsefulThings, self, :add1, :add3)
end

Then:

Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
  #=> [:add2, :add3, :add1] 
1.add1
2 
1.add2
cat
1.add3
dog

which is the result we want.


After almost 9 years here's a generic solution:

module CreateModuleFunctions
  def self.included(base)
    base.instance_methods.each do |method|
      base.module_eval do
        module_function(method)
        public(method)
      end
    end
  end
end

RSpec.describe CreateModuleFunctions do
  context "when included into a Module" do
    it "makes the Module's methods invokable via the Module" do
      module ModuleIncluded
        def instance_method_1;end
        def instance_method_2;end

        include CreateModuleFunctions
      end

      expect { ModuleIncluded.instance_method_1 }.to_not raise_error
    end
  end
end

The unfortunate trick you need to apply is to include the module after the methods have been defined. Alternatively you may also include it after the context is defined as ModuleIncluded.send(:include, CreateModuleFunctions).

Or you can use it via the reflection_utils gem.

spec.add_dependency "reflection_utils", ">= 0.3.0"

require 'reflection_utils'
include ReflectionUtils::CreateModuleFunctions

Another way to do it if you "own" the module is to use module_function.

module UsefulThings
  def a
    puts "aaay"
  end
  module_function :a

  def b
    puts "beee"
  end
end

def test
  UsefulThings.a
  UsefulThings.b # Fails!  Not a module method
end

test

To invoke a module instance method without including the module (and without creating intermediary objects):

class UsefulWorker
  def do_work
    UsefulThings.instance_method(:format_text).bind(self).call("abc")
    ...
  end
end

Firstly, I'd recommend breaking the module up into the useful things you need. But you can always create a class extending that for your invocation:

module UsefulThings
  def a
    puts "aaay"
  end
  def b
    puts "beee"
  end
end

def test
  ob = Class.new.send(:include, UsefulThings).new
  ob.a
end

test

Another way to do it if you "own" the module is to use module_function.

module UsefulThings
  def a
    puts "aaay"
  end
  module_function :a

  def b
    puts "beee"
  end
end

def test
  UsefulThings.a
  UsefulThings.b # Fails!  Not a module method
end

test

If you want to call these methods without including module in another class then you need to define them as module methods:

module UsefulThings
  def self.get_file; ...
  def self.delete_file; ...

  def self.format_text(x); ...
end

and then you can call them with

UsefulThings.format_text("xxx")

or

UsefulThings::format_text("xxx")

But anyway I would recommend that you put just related methods in one module or in one class. If you have problem that you want to include just one method from module then it sounds like a bad code smell and it is not good Ruby style to put unrelated methods together.


Not sure if someone still needs it after 10 years but I solved it using eigenclass.

module UsefulThings
  def useful_thing_1
    "thing_1"
  end

  class << self
    include UsefulThings
  end
end

class A
  include UsefulThings
end

class B
  extend UsefulThings
end

UsefulThings.useful_thing_1 # => "thing_1"
A.new.useful_thing_1 # => "thing_1"
B.useful_thing_1 # => "thing_1"

As I understand the question, you want to mix some of a module's instance methods into a class.

Let's begin by considering how Module#include works. Suppose we have a module UsefulThings that contains two instance methods:

module UsefulThings
  def add1
    self + 1
  end
  def add3
    self + 3
  end
end

UsefulThings.instance_methods
  #=> [:add1, :add3]

and Fixnum includes that module:

class Fixnum
  def add2
    puts "cat"
  end
  def add3
    puts "dog"
  end
  include UsefulThings
end

We see that:

Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
  #=> [:add2, :add3, :add1] 
1.add1
2 
1.add2
cat
1.add3
dog

Were you expecting UsefulThings#add3 to override Fixnum#add3, so that 1.add3 would return 4? Consider this:

Fixnum.ancestors
  #=> [Fixnum, UsefulThings, Integer, Numeric, Comparable,
  #    Object, Kernel, BasicObject] 

When the class includes the module, the module becomes the class' superclass. So, because of how inheritance works, sending add3 to an instance of Fixnum will cause Fixnum#add3 to be invoked, returning dog.

Now let's add a method :add2 to UsefulThings:

module UsefulThings
  def add1
    self + 1
  end
  def add2
    self + 2
  end
  def add3
    self + 3
  end
end

We now wish Fixnum to include only the methods add1 and add3. Is so doing, we expect to get the same results as above.

Suppose, as above, we execute:

class Fixnum
  def add2
    puts "cat"
  end
  def add3
    puts "dog"
  end
  include UsefulThings
end

What is the result? The unwanted method :add2 is added to Fixnum, :add1 is added and, for reasons I explained above, :add3 is not added. So all we have to do is undef :add2. We can do that with a simple helper method:

module Helpers
  def self.include_some(mod, klass, *args)
    klass.send(:include, mod)
    (mod.instance_methods - args - klass.instance_methods).each do |m|
      klass.send(:undef_method, m)
    end
  end
end

which we invoke like this:

class Fixnum
  def add2
    puts "cat"
  end
  def add3
    puts "dog"
  end
  Helpers.include_some(UsefulThings, self, :add1, :add3)
end

Then:

Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
  #=> [:add2, :add3, :add1] 
1.add1
2 
1.add2
cat
1.add3
dog

which is the result we want.


To invoke a module instance method without including the module (and without creating intermediary objects):

class UsefulWorker
  def do_work
    UsefulThings.instance_method(:format_text).bind(self).call("abc")
    ...
  end
end

A. In case you, always want to call them in a "qualified", standalone way (UsefulThings.get_file), then just make them static as others pointed out,

module UsefulThings
  def self.get_file; ...
  def self.delete_file; ...

  def self.format_text(x); ...

  # Or.. make all of the "static"
  class << self
     def write_file; ...
     def commit_file; ...
  end

end

B. If you still want to keep the mixin approach in same cases, as well the one-off standalone invocation, you can have a one-liner module that extends itself with the mixin:

module UsefulThingsMixin
  def get_file; ...
  def delete_file; ...

  def format_text(x); ...
end

module UsefulThings
  extend UsefulThingsMixin
end

So both works then:

  UsefulThings.get_file()       # one off

   class MyUser
      include UsefulThingsMixin  
      def f
         format_text             # all useful things available directly
      end
   end 

IMHO it's cleaner than module_function for every single method - in case want all of them.


Another way to do it if you "own" the module is to use module_function.

module UsefulThings
  def a
    puts "aaay"
  end
  module_function :a

  def b
    puts "beee"
  end
end

def test
  UsefulThings.a
  UsefulThings.b # Fails!  Not a module method
end

test

Firstly, I'd recommend breaking the module up into the useful things you need. But you can always create a class extending that for your invocation:

module UsefulThings
  def a
    puts "aaay"
  end
  def b
    puts "beee"
  end
end

def test
  ob = Class.new.send(:include, UsefulThings).new
  ob.a
end

test

If you want to call these methods without including module in another class then you need to define them as module methods:

module UsefulThings
  def self.get_file; ...
  def self.delete_file; ...

  def self.format_text(x); ...
end

and then you can call them with

UsefulThings.format_text("xxx")

or

UsefulThings::format_text("xxx")

But anyway I would recommend that you put just related methods in one module or in one class. If you have problem that you want to include just one method from module then it sounds like a bad code smell and it is not good Ruby style to put unrelated methods together.


After almost 9 years here's a generic solution:

module CreateModuleFunctions
  def self.included(base)
    base.instance_methods.each do |method|
      base.module_eval do
        module_function(method)
        public(method)
      end
    end
  end
end

RSpec.describe CreateModuleFunctions do
  context "when included into a Module" do
    it "makes the Module's methods invokable via the Module" do
      module ModuleIncluded
        def instance_method_1;end
        def instance_method_2;end

        include CreateModuleFunctions
      end

      expect { ModuleIncluded.instance_method_1 }.to_not raise_error
    end
  end
end

The unfortunate trick you need to apply is to include the module after the methods have been defined. Alternatively you may also include it after the context is defined as ModuleIncluded.send(:include, CreateModuleFunctions).

Or you can use it via the reflection_utils gem.

spec.add_dependency "reflection_utils", ">= 0.3.0"

require 'reflection_utils'
include ReflectionUtils::CreateModuleFunctions

A. In case you, always want to call them in a "qualified", standalone way (UsefulThings.get_file), then just make them static as others pointed out,

module UsefulThings
  def self.get_file; ...
  def self.delete_file; ...

  def self.format_text(x); ...

  # Or.. make all of the "static"
  class << self
     def write_file; ...
     def commit_file; ...
  end

end

B. If you still want to keep the mixin approach in same cases, as well the one-off standalone invocation, you can have a one-liner module that extends itself with the mixin:

module UsefulThingsMixin
  def get_file; ...
  def delete_file; ...

  def format_text(x); ...
end

module UsefulThings
  extend UsefulThingsMixin
end

So both works then:

  UsefulThings.get_file()       # one off

   class MyUser
      include UsefulThingsMixin  
      def f
         format_text             # all useful things available directly
      end
   end 

IMHO it's cleaner than module_function for every single method - in case want all of them.


I think the shortest way to do just throw-away single call (without altering existing modules or creating new ones) would be as follows:

Class.new.extend(UsefulThings).get_file

Firstly, I'd recommend breaking the module up into the useful things you need. But you can always create a class extending that for your invocation:

module UsefulThings
  def a
    puts "aaay"
  end
  def b
    puts "beee"
  end
end

def test
  ob = Class.new.send(:include, UsefulThings).new
  ob.a
end

test

Firstly, I'd recommend breaking the module up into the useful things you need. But you can always create a class extending that for your invocation:

module UsefulThings
  def a
    puts "aaay"
  end
  def b
    puts "beee"
  end
end

def test
  ob = Class.new.send(:include, UsefulThings).new
  ob.a
end

test

Another way to do it if you "own" the module is to use module_function.

module UsefulThings
  def a
    puts "aaay"
  end
  module_function :a

  def b
    puts "beee"
  end
end

def test
  UsefulThings.a
  UsefulThings.b # Fails!  Not a module method
end

test

Not sure if someone still needs it after 10 years but I solved it using eigenclass.

module UsefulThings
  def useful_thing_1
    "thing_1"
  end

  class << self
    include UsefulThings
  end
end

class A
  include UsefulThings
end

class B
  extend UsefulThings
end

UsefulThings.useful_thing_1 # => "thing_1"
A.new.useful_thing_1 # => "thing_1"
B.useful_thing_1 # => "thing_1"

Examples related to ruby

Uninitialized Constant MessagesController Embed ruby within URL : Middleman Blog Titlecase all entries into a form_for text field Ruby - ignore "exit" in code Empty brackets '[]' appearing when using .where find_spec_for_exe': can't find gem bundler (>= 0.a) (Gem::GemNotFoundException) How to update Ruby Version 2.0.0 to the latest version in Mac OSX Yosemite? How to fix "Your Ruby version is 2.3.0, but your Gemfile specified 2.2.5" while server starting Is the server running on host "localhost" (::1) and accepting TCP/IP connections on port 5432? How to update Ruby with Homebrew?

Examples related to module

How to fix: fatal error: openssl/opensslv.h: No such file or directory in RedHat 7 How to import functions from different js file in a Vue+webpack+vue-loader project Typescript ReferenceError: exports is not defined ImportError: No module named tensorflow ModuleNotFoundError: What does it mean __main__ is not a package? ES6 modules in the browser: Uncaught SyntaxError: Unexpected token import module.exports vs. export default in Node.js and ES6 What's the difference between an Angular component and module Export multiple classes in ES6 modules Python - Module Not Found

Examples related to methods

String method cannot be found in a main class method Calling another method java GUI ReactJS - Call One Component Method From Another Component multiple conditions for JavaScript .includes() method java, get set methods includes() not working in all browsers Python safe method to get value of nested dictionary Calling one method from another within same class in Python TypeError: method() takes 1 positional argument but 2 were given Android ListView with onClick items