Search code examples
rubyselfinstance-methods

NoMethodError: Calling an instance method correctly in Ruby with the use of self


I was reading Why's (Poignant) guide to Ruby, and came across a method that didn't quite work out as expected. The method is aimed to return a value (from a hash) for a given string, somewhat like an encoder-decoder. Originally, the method was written inside a class String, but I modified it to change the classname. Here's the code:

class NameReplacer
  @@syllables = [

      {"Paij" => "Personal","Gonk" => "Business", "Blon" => "Slave", "Stro" => "Master", "Wert" => "Father", "Onnn" => "Mother"},
      {"ree" => "AM", "plo" => "PM"}
  ]

  # method to determine what a certain name of his means
  def name_significance
    # split string by -
    parts = self.split("-")
    # make duplicate of syllables
    syllables = @@syllables.dup
    signif = parts.collect {|name| syllables.shift[name]}
    #join array returned by " " forming a string
    signif.join(" ")
  end
end

To run this code, the book simply uses "Paij-ree".name_significance. But when I tried doing the same thing, I got a NoMethodError - in <top (required)>: undefined method NameReplacer for "Paij-ree":String (NoMethodError).

I got the same error when I tried: print "Paij-ree".NameReplacer.new.name_significance

I assume this worked in the book because the method was written in a class String, which, I guess, would be equal to having this method in Ruby's String class. Due to that, something like "paij-ree".name_significance" would not throw an error, because the "paij-ree" would be a String object, and String class does have the method name_significance.

However, how do I accomplish this with my current code? Apologies if this question seems stupid.


Solution

  • Three approaches with same result:

    # monkey-patching a class
    class String
      def appendFoo
        self + "foo"
      end
    end
    
    "a".appendFoo
    # => "afoo"
    
    # using an external class method
    class FooAppender
      def self.appendFoo(string)
        string + "foo"
      end
    end
    
    FooAppender.appendFoo("a")
    # => "afoo"
    
    # using an external instance method
    class StuffAppender
      def initialize(what)
        @what = what
      end
    
      def append_to(string)
        string + @what
      end
    end
    
    new StuffAppender("foo").append_to("a")
    # => "afoo"
    

    self means the object the method is defined on. You can't use self in the NameReplacer class to refer to a string, it will be the NameReplacer instance (inside an instance method like yours).