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

Orion Edwards picture Orion Edwards · Nov 27, 2008 · Viewed 134.4k times · Source

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

Answer

dolzenko picture dolzenko · Sep 11, 2009

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