218

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

2
  • 1
    If you take the 4th approach (splitting up the module), you could make it so that one module always automatically includes the other by using the Module#included callback to trigger an include of the other. The format_text method could be moved into it's own module, since it seems to be useful on it's own. This would make management a little less burdensome. Commented Jan 31, 2013 at 17:19
  • I'm perplexed by all the references in the answers to module functions. Suppose you have module UT; def add1; self+1; end; def add2; self+2; end; end and you want to use add1 but not add2 in class Fixnum. How would it help to have module functions for that? Am I missing something? Commented Aug 13, 2015 at 4:24

11 Answers 11

189

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 
Sign up to request clarification or add additional context in comments.

3 Comments

Very usefull for files erb. html.erb, or js.erb. thanks ! I wonder if this system wastes memory
@AlbertCatalà according to my tests and stackoverflow.com/a/23645285/54247 the anonymous classes are garbage collected just as everything else, so it shouldn't waste memory.
If you don't like to make an anonymous class as proxy you could also use an object as proxy for the method. Object.new.extend(UsefulThings).get_file
151

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

3 Comments

As an aside, module_function turns the method into a private one, which would break other code - otherwise this'd be the accepted answer
I ended up doing the decent thing and refactoring my code into seperate modules. It wasn't as bad as I thought it might be. Your answer is would still solve it most correctly WRT my original constraints, so accepted!
@dgtized related functions may end up in one module all the time, that doesn't mean that I want to pollute my namespace with all of them. A simple example if there's a Files.truncate and a Strings.truncate and I want to use both in the same class, explicitly. Creating a new class/instance each time I need a specific method or modifying the original is not a nice approach, though I'm not a Ruby dev.
103

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 

7 Comments

And for the case where you don't own it: UsefulThings.send :module_function, :b
module_function converts the method to a private one (well it does in my IRB anyway), which would break other callers :-(
I actually like this approach, for my purposes at least. Now I can call ModuleName.method :method_name to get a method object and call it via method_obj.call. Otherwise I would have to bind the method to an instance of the original object, which isn't possible if the original object is a Module. In response to Orion Edwards, module_function does make the original instance method private. ruby-doc.org/core/classes/Module.html#M001642
Orion - I don't believe that's true. According to ruby-doc.org/docs/ProgrammingRuby/html/…, module_function "creates module functions for the named methods. These functions may be called with the module as a receiver, and also become available as instance methods to classes that mix in the module. Module functions are copies of the original, and so may be changed independently. The instance-method versions are made private. If used with no arguments, subsequently defined methods become module functions."
you could also define it as def self.a; puts 'aaay'; end
|
26

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.

Comments

22

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 

2 Comments

Be careful with this approach: binding to self may not provide the method with everything it expects. For example, perhaps format_text assumes the existence of another method provided by the module, which (generally) won't be present.
This is the way , can load any module , no matter if module support method can be load directly. Even it is better to change in Module level. But in some cases, This line is What askers want to get.
11

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" 

Comments

8

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 

Comments

6

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.

1 Comment

extend self is a common idiom.
5

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.

Comments

1

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 

2 Comments

Well, your approach like the majority of responses we can see here don't address the original problem and load all the methods. The only good answer is to unbind the method from the original module and bind it in the targeted class, as @renier already responds 3 years ago.
@JoelAZEMAR I think you're misunderstanding this solution. It is to be added to the module you want to use. As a result none of its methods will have to be included in order to use them. As suggested by OP as one of possible solutions: "1, Somehow invoke the method directly on the module without including it anywhere". This is how it works.
1

This old question comes to me today when I am studing Ruby and found interesting so I want to answer with my new knowlege.

Assume that you have the module

module MyModule def say 'I say' end def cheer 'I cheer' end end 

then with the class so call Animal I can take cheer method from MyModule as following

class Animal define_method(:happy, MyModule.method(:cheer)) end 

This is so called unbound method, so you can take a callable object and bind it to another place(s).

From this point, you can use the method as usual, such as

my_dog = Animal.new my_dog.happy # => "I cheer" 

Hope this help as I also learned something new today.

To learn further, you can use irb and take a look at Method object.

1 Comment

I like this. Super useful for borrowing functionality in tests.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.