Code Fix

上級

def self.method と def method を混同すると NoMethodError になる

def self.methodはクラスメソッド(ClassName.methodで呼ぶ)を定義し、def methodはインスタンスメソッド(インスタンス.methodで呼ぶ)を定義します。どちらか一方しか定義していないのに、もう一方の呼び方をするとNoMethodErrorになります。

エラーメッセージの読み方

main.rb:7:in `<main>': undefined method `square' for class MathUtil (NoMethodError)
main.rb
ファイル名
7
行番号 — 実際にクラッシュした行
<main>
発生場所 — <main> ならトップレベル、メソッド名ならそのメソッドの中
NoMethodError
例外クラス — 何が起きたか。ここを検索するのが最短です
undefined method `square' for class MathUtil
詳細メッセージ — どの値が問題だったか

このエラーが出る典型パターン

パターン1

 1  class MathUtil
 2    def      square(n)
            ^
 3      n * n
 4    end
 5  end
 6  
 7  puts MathUtil.square(4)
main.rb:7:in `<main>': undefined method `square' for class MathUtil (NoMethodError)

self.を付けないと、squareはインスタンスメソッドとして定義されます。MathUtil.squareのようにクラス自身から呼ぶには、def self.squareにする必要があります。

直し方: (空)self. にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  class StringUtil
 2    def      shout(text)
            ^
 3      text.upcase + "!"
 4    end
 5  end
 6  
 7  puts StringUtil.shout("hi")
main.rb:7:in `<main>': undefined method `shout' for class StringUtil (NoMethodError)

インスタンスを作らずにクラス名から直接呼び出したいメソッドは、self.を付けたクラスメソッドとして定義します。

直し方: (空)self. にします。

この問題を解いてみる →

パターン3

 1  class ArrayUtil
 2    def      sum_all(list)
            ^
 3      list.sum
 4    end
 5  end
 6  
 7  puts ArrayUtil.sum_all([1, 2, 3])
main.rb:7:in `<main>': undefined method `sum_all' for class ArrayUtil (NoMethodError)

「クラスの中で定義すればどちらの呼び方でも使えるはず」という思い込みは誤りです。self.の有無で完全に別のメソッドになります。

直し方: (空)self. にします。

この問題を解いてみる →

パターン4

 1  class TimeUtil
 2    def      now_label
            ^
 3      "now"
 4    end
 5  end
 6  
 7  puts TimeUtil.now_label
main.rb:7:in `<main>': undefined method `now_label' for class TimeUtil (NoMethodError)

ユーティリティ的なメソッドをクラスメソッドとして提供したい場合、defにself.を付け忘れると呼び出せません。

直し方: (空)self. にします。

この問題を解いてみる →

パターン5

 1  class NumberUtil
 2    def      double(n)
            ^
 3      n * 2
 4    end
 5  end
 6  
 7  puts NumberUtil.double(5)
main.rb:7:in `<main>': undefined method `double' for class NumberUtil (NoMethodError)

self.を付けたメソッドはクラス自身に属し、self.を付けないメソッドはインスタンスに属します。混同すると呼び出し方が合わなくなります。

直し方: (空)self. にします。

この問題を解いてみる →

よくある誤解

「クラスの中で定義したメソッドは、クラスからでもインスタンスからでも呼べるはず」という思い込みは誤りです。self.の有無でどちらの側に属するメソッドかが完全に分かれており、混ぜて呼ぶことはできません。

まとめ

def self.method と def method を混同すると NoMethodError になるは上級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)