Ruby - Module :: NoMethodError
Asked Answered
R

4

33

I have a module like this:

module Prober
  def probe_invoke(type, data = {})
    p = Probe.new({:probe_type => type.to_s,
        :data => data.to_json, :probe_status => 0, :retries => 0})
    p.save
  end
end

And I am trying to access this from my main program like this:

require 'prober'
Prober.probe_invoke("send_sms", sms_text)

But it generate error:

undefined method `probe_invoke' for Prober:Module (NoMethodError)

Redingote answered 1/6, 2011 at 7:18 Comment(0)
L
25

Apart from the answers that give you the option of defining the function as self., you have another option of including the module and calling it without the module reference like this:

module Prober
  def probe_invoke(type, data = {})
    p = Probe.new({:probe_type => type.to_s,
        :data => data.to_json, :probe_status => 0, :retries => 0})
    p.save
  end
end

and you can call it like this:

require 'prober'
include Prober
probe_invoke("send_sms", sms_text)
Louannlouanna answered 1/6, 2011 at 8:54 Comment(3)
Why do we have to put the include there ? I thought requiring a file is enough.Hoekstra
requiring file will get the code of the module out there. But it will be inside the module namespace. If the method was declared as def self.probe_invoke(type, data = {}), then the code would be like require 'prober'; Prober.probe_invoke("send_sms", sms_text), since we are declaring the method as a module method (class level method). But here I have declared the method as an instance method of the module. Since modules cannot be instantiated, these methods is used by including the module. By including the module, all the instance methods of the module will be added to the current scope.Louannlouanna
In my answer, the current scope is the main scope of the file itself, so after including the module, we will be able to call the method without any mention of the module name like this probe_invoke("send_sms", sms_text). The include functionality of module is useful in case where two classes have same functionality. eg: module FullName; def full_name; first_name.to_s + ' ' + last_name.to_s; end; class Person; attr_accessor :first_name, :last_name; include FullName; end; then p = Person.new; p.first_name = 'Prince'; p.last_name = 'Joseph'; p.full_name => 'Prince Joseph'Louannlouanna
H
14

The easiest way is to turn your method into a module-level method:

module Prober
  def Prober.probe_invoke(type, data = {})
    p = Probe.new({:probe_type => type.to_s,
        :data => data.to_json, :probe_status => 0, :retries => 0})
    p.save
  end
end

def self.probe_invoke would also work, because at the time that line is run, self is the module definition.

Heterogynous answered 1/6, 2011 at 7:23 Comment(0)
F
7

Next to the answers here you also can do the following:

module Prober
  class << self
    def probe_invoke(type, data = {})
      p = Probe.new({:probe_type => type.to_s,
          :data => data.to_json, :probe_status => 0, :retries => 0})
      p.save
    end

    # more module instance methods ...
  end
end

The class << self block will define also every method in it as instance methods of your module.

(It's functionality is the same like to define every single methods by def Prober.mymethod ... or def self.mymethod ...)


Update (2014-11-22)

According to the Ruby Style Guide you should use module_function instead:

module Prober
  module_function # <-- preferred style nowadays

  def probe_invoke(type, data = {})
    Probe.new(probe_type:   type.to_s,
              data:         data.to_json,
              probe_status: 0,
              retries:      0)
      .save # no need for a temporary variable
  end

  # more module methods ...
end

I'd call this utility modules.

BTW: In the past it was more common to use extend self instead of wrapping the methods in a class << self block.

I also adapted the code above to other style guide recommendations.

Fulmar answered 1/6, 2011 at 8:39 Comment(1)
class << self is better if you have a ton of class methods and you don't want to write self.blah a million times. It's just slightly less verbose, that's all. Either works.Evannia
S
3

The answer is:

module Prober
  def Prober.probe_invoke(type, data = {})
    p = Probe.new({:probe_type => type.to_s,
        :data => data.to_json, :probe_status => 0, :retries => 0})
    p.save
  end
end

Prober.probe_invoke("send_sms", sms_text)

Because otherwise you define the method as an instance method of the module, but you actually want to define it statically.

Skyjack answered 1/6, 2011 at 7:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.