tags:

views:

44

answers:

3

In this Ruby code:

Module M
  Class C < Struct.new(:param)
    def work
      M::helper(param)
    end
  end

  def helper(param)
    puts "hello #{param}"
  end
end

I get a "undefined method 'helper' for 'M:Module'" error when I try to run

c = M::C.new("world")
c.work

but calling M::helper("world") directly from another class works fine. Can classes not call Module functions that are defined in the same Module they are defined in? Is there a way around this other than moving the class outside of the module?

+3  A: 

you should prepend module method with self:

module M
  class C < Struct.new(:param)
    def work
      M::helper(param)
    end
  end

  def self.helper(param)
    puts "hello #{param}"
  end
end
Eimantas
These weren't in the question, but `C.work` is called as a class method instead of instance method. Have you tried calling `M.helper("foo")`?
Eimantas
+1  A: 

In order to invoke M::helper you need to define it as def self.helper; end For the sake of comparison, take a look at helper and helper2 in the following modified snippet

module M
  class C < Struct.new(:param)
    include M     # include module to get helper2 mixed in
    def work
      M::helper(param)
      helper2(param)
    end
  end

  def self.helper(param)
    puts "hello #{param}"
  end

  def helper2(param)
    puts "Mixed in hello #{param}"
  end
end

c = M::C.new("world")
c.work
Gishu
thanks for the explanation of the difference between using self. and including the module.
Ryan Ahearn
+1  A: 

C is trying to call helper on M when helper is not in M's singleton class. Also, you keep saying that helper is a module function, when it is only a method. Making helper a module function will make the code work:

module M
  class C < Struct.new(:param)
    def work
      M::helper(param)
    end
  end

  module_function

  def helper(param)
    puts "hello #{param}"
  end
end

Including the module in the class will also work:

module M
  class C < Struct.new(:param)
    include M

    def work
      helper(param)
    end
  end

  def helper(param)
    puts "hello #{param}"
  end
end

In the first example, helper is put into M's singleton class with module_function. The second example imports M's methods into C so that C can use them. Another difference is that in the first, you will be able to call M.helper from anywhere in your code. In the second, you will be able to call helper from any instance of C in your code. To fix this, make helper private:

module M
  class C < Struct.new(:param)
    include M

    def work
      helper(param)
    end
  end

  private
  def helper(param)
    puts "hello #{param}"
  end
end
Adrian