Rails: I can't call a function in a module in /lib - what am I doing wrong?

I have a module saved in /lib as test_functions.rb that looks like this

module TestFunctions
  def abc
    puts 123
  end
end

Going into ruby script/runner, I can see that the module is loading automatically (good ol' convention over configuration and all that...)

>> TestFunctions.instance_methods
=> ["abc"]

so the method is known, let's try calling it

>> TestFunctions.abc
NoMethodError: undefined method `abc' for TestFunctions:Module from (irb):3

Nope. How about this?

>> TestFunctions::abc
NoMethodError: undefined method `abc' for TestFunctions:Module from (irb):4

Test Nope again.

defined?(TestFunctions::abc) #=> nil, but
TestFunctions.method_defined? :abc #=> true

Like I said at the top, I know I'm being dumb, can anyone de-dumb me?


If you want Module-level functions, define them in any of these ways:

module Foo
  def self.method_one
  end

  def Foo.method_two
  end

  class << self
    def method_three
    end
  end
end

All of these ways will make the methods available as Foo.method_one or Foo::method_one etc

As other people have mentioned, instance methods in Modules are the methods which are available in places where you've included the Module


I'm going to try to summarise the various answers myself, since each had something valuable to say, but none really got to what I now realise is probably the best response:

I was asking the wrong question because I was doing it wrong.

For reasons I can no longer explain, I wanted a set of completely stand-alone functions in a library, which represented methods I was trying to DRY out of my classes. That can be achieved, using things like

module Foo
  def self.method_one
  end

  def Foo.method_two
  end

  class << self
    def method_three
    end
  end

  def method_four
  end

  module_function :method_four
end

I could also include my module, either within a class, in which case the methods become part of the class or outside, in which case they are defined on whatever class I'm running inside (Object? Kernel? Irb, if I'm interactive? Probably not a great idea, then)

The thing is, there was no good reason not to have a class in the first place - I'd somehow got on to a train of thought that took me down an seldom-used and frankly slightly weird branch line. Probably a flashback to the days before OO became mainstream (I'm old enough that up to today I've spent a lot more years writing procedural code).

So the functions have moved into a class, where they seem pretty happy, and the class methods thus exposed are being cheerfully used wherever necessary.


You can also use module_function like so:

module TestFunctions
  def abc
    puts 123
  end

  module_function :abc
end

TestFunctions.abc  # => 123

Now you can include TestFunctions in class and call "abc" from within TestFunctions module.


I messed with this for a while and learned several things. Hopefully this will help someone else out. I am running Rails 3.2.8.

My module (utilities.rb) looks like this and is in the /lib directory of my rails app:

module Utilities

  def compute_hello(input_string)
     return "Hello #{input_string}"
  end

end

My test (my_test.rb) looks like this and is in the /test/unit directory of my rails app:

require "test_helper"
require "utilities"

class MyTest < ActiveSupport::TestCase
  include Utilities

  def test_compute_hello
    x = compute_hello(input_string="Miles")
    print x
    assert x=="Hello Miles", "Incorrect Response"
  end

end

Here are a few things to note: My test extends ActiveSupport::TestCase. This is important because ActiveSupport adds /lib to the $LOAD_PATH. (seehttp://stackoverflow.com/questions/1073076/rails-lib-modules-and)

Secondly, I needed to both "require" my module file, and also "include" the module. Lastly, it is important to note that the stuff that gets included from the module essentially gets placed in the test class. So... be careful that the module that you include doesn't start with "test_". Otherwise, Rails will attempt to run your module method as a test.