Rubyメソッドルックアップを理解する
メソッドを呼び出すとどうなると思いますか?同じ名前の別のメソッドがある場合、Rubyはどのメソッドを呼び出すかをどのように決定しますか?メソッドがどこに格納または供給されているのか疑問に思ったことはありますか?
Rubyは、定義された「ウェイ」または「パターン」を使用して、呼び出す適切なメソッドと「メソッドエラーなし」を返す適切なタイミングを決定します。この「ウェイ」をRubyメソッドルックアップパス> 。このチュートリアルでは、Rubyのメソッドルックアップについて詳しく説明します。最後に、Rubyがオブジェクトの階層をどのように通過して、参照しているメソッドを判別するかを十分に理解できます。
私たちが何を学ぶかを完全に理解するには、Rubyの基本を理解している必要があります。モジュールやクラスのようなものについて言及しますが、これはそれらが何をするのかを深く掘り下げることにはなりません。このチュートリアルの目標を達成するために必要な深さのみをカバーします。Rubyがオブジェクトに渡すメッセージ(メソッド)をどのように決定するかを示します。
first_person.valid?
などのメソッドを呼び出す場合 、Rubyはいくつかのことを決定する必要があります:
- メソッド
.valid?
はどこにありますか? 定義されています。 -
.valid?
がある場所は複数ありますか? メソッドが定義されていますか?もしそうなら、これはこの文脈で使用するのに適切なものです。
これを理解するためにRubyが従うプロセス(またはパス)は、メソッドルックアップと呼ばれるものです。 。 Rubyは、メソッドを呼び出すことができるように、メソッドが作成された場所を見つける必要があります。次の場所を検索して、正しいメソッドを呼び出していることを確認する必要があります。
- シングルトンメソッド:Rubyは、オブジェクトが独自のメソッドを定義する方法を提供します。これらのメソッドはそのオブジェクトでのみ使用可能であり、オブジェクトのインスタンスからはアクセスできません。
- 混合モジュールのメソッド:モジュールは、
prepend
を使用してクラスに混合できます。 、include
、またはextend
。これが発生すると、クラスはモジュールで定義されたメソッドにアクセスでき、Rubyはモジュールに入り、呼び出されたメソッドを検索します。他のモジュールを最初のモジュールに混在させることができ、検索もこれらに進むことを知っておくことも重要です。 - インスタンスメソッド:これらはクラスで定義され、そのクラスのインスタンスからアクセスできるメソッドです。
- 親クラスのメソッドまたはモジュール:クラスが別のクラスの子である場合、Rubyは親クラスを検索します。検索は、親クラスのシングルトンメソッド、混合モジュール、およびその親クラスに行われます。
- Object、Kernel、およびBasicObject:これらはRubyが検索する最後の場所です。これは、Rubyのすべてのオブジェクトが祖先の一部としてこれらを持っているためです。
多くの場合、メソッドはオブジェクトに対して呼び出されます。これらのオブジェクトは、Rubyの組み込みクラスまたは開発者によって作成されたクラスである可能性がある特定のクラスによって作成されます。
class Human
attr_reader :name
def initialize(name)
@name = name
end
def hello
put "Hello! #{name}"
end
end
その後、 hello
を呼び出すことができます Human
のインスタンスで上記で作成したメソッド クラス;たとえば、
john = Human.new("John")
john.hello # Output -> Hello John
hello
メソッドはインスタンスメソッドです。これが、 Human
のインスタンスで呼び出すことができる理由です。 クラス。インスタンスでメソッドを呼び出さない場合があります。このような場合、クラス自体でメソッドを呼び出します。これを実現するには、クラスメソッドを作成する必要があります。上記のクラスのクラスメソッドを定義すると、次のようになります。
def self.me
puts "I am a class method"
end
次に、 Human.me
を実行してこれを呼び出すことができます。 。アプリケーションの複雑さが増すにつれて(ここで新しいスタートアップを構築していると想像してください)、2つ以上のクラスに同じことを行う複数のメソッドがある場合があります。これが起こった場合、それは私たちが物事を乾いた状態に保ち、自分自身を繰り返さないようにする必要があることを意味します。問題は、これらのクラス間で機能を共有する方法に関係しています。
以前にモジュールを使用したことがない場合は、これらの「共有」メソッド専用の新しいクラスを作成したくなるかもしれません。ただし、そうすると、特に多重継承を利用する必要がある場合に、Rubyがサポートしていない悪影響が生じる可能性があります。モジュールは、このケースを処理するための最良の手段です。モジュールはクラスに似ていますが、いくつかの違いがあります。まず、モジュールがどのように見えるかの例を次に示します。
module Movement
def walk
puts "I can walk!"
end
end
- 定義は
module
で始まりますclass
の代わりにキーワード 。 - モジュールにインスタンスを含めることはできないため、
Movement.new
を使用することはできません。 。
メソッドは、特定のオブジェクトによって実行されるアクションと見なすことができます。 [2、3、4]
のような配列がある場合 numberList
という変数に割り当てられます 、 .push
メソッドは、配列が置くために実行できるアクションです。 配列に受け取る値。このコードスニペットは一例です:
john.walk
「オブジェクトのメソッドを呼び出しています」のように言うのが一般的かもしれません。ここで、 john
Human
のインスタンスであるオブジェクトを参照します 、および walk
方法です。ただし、推測されるメソッドはオブジェクトのクラス、スーパークラス、または混合から取得される傾向があるため、これは完全には当てはまりません。 モジュール。
john
のようなオブジェクトであっても、オブジェクトにメソッドを定義できることを追加することが重要です。 、すべてがRubyのオブジェクトであるため、オブジェクトの作成に使用されるクラスですら。
def john.drip
puts "My drip is eternal"
end
ドリップコード> メソッドには、
john
に割り当てられたオブジェクトからのみアクセスできます。 。 ドリップコード>
john
が利用できるシングルトンメソッドです。 物体。このStackOverflowの回答からわかるように、シングルトンメソッドとクラスメソッドの間に違いはないことを知っておくことが重要です。上記の例のようにオブジェクトで定義されたメソッドを参照しているのでない限り、メソッドが特定のオブジェクトに属していると言うのは誤りです。この例では、 walk
メソッドはMovement
に属しています モジュール、 hello
メソッドはHuman
に属しています クラス。この理解により、これをさらに一歩進めることが容易になります。つまり、オブジェクトで呼び出されている正確なメソッドを判別するには、Rubyはオブジェクトのクラスまたはスーパークラスまたは混合されたモジュールをチェックする必要があります。 オブジェクトの階層内。
Rubyは単一継承のみをサポートします。クラスは1つのクラスからのみ継承できます。これにより、子クラスが別のクラスの動作(メソッド)を継承できるようになります。異なるクラス間で共有する必要のある動作がある場合はどうなりますか?たとえば、 walk
を作成するには Human
のインスタンスで使用可能なメソッド クラスでは、ミックスインできます Movement
Human
のモジュール クラス。したがって、 Human
の書き直し include
を使用するクラス 次のようになります:
require "movement" # Assuming we have the module in a file called movement.rb
class Human
include Movement
attr_reader :name
def initialize(name)
@name = name
end
def hello
put "Hello! #{name}"
end
end
これで、 walk
を呼び出すことができます インスタンスのメソッド:
john = Human.new("John")
john.walk
インクルードを利用する場合 上記のように、キーワードは、含まれているモジュールのメソッドがインスタンスメソッドとしてクラスに追加されます。これは、含まれているためです モジュールは祖先の間に追加されます Human
Movement
などのクラス モジュールはHuman
の親と見なすことができます クラス。上に示した例でわかるように、 walk
と呼んでいます。 Human
のインスタンスのメソッド クラス。
含めるに加えて 、Rubyは拡張を提供します キーワード。これにより、モジュールのメソッドがクラスメソッドとしてクラスで使用できるようになります。これは、以前に学習したように、シングルトンメソッドとも呼ばれます。したがって、 Feeding
というモジュールがある場合
module Feeding
def food
"I make my food :)"
end
end
次に、この動作を Human
で共有できます。 クラスを要求し、 extend Feeding
を追加します 。ただし、 food
を呼び出す代わりに、それを使用するには クラスのインスタンスのメソッド。クラスのメソッドを呼び出すのと同じ方法で、クラス自体のメソッドを呼び出します。
Human.food
これはincludeに似ています ただし、この投稿で述べられているように、いくつかの違いがあります。
モジュールをクラスとチェーン内のそのスーパークラスの間に挿入する代わりに、クラス自体の前であっても、チェーンの最下部に挿入することを除いて、実際にはincludeのように機能します。
つまり、クラスインスタンスでメソッドを呼び出すとき、Rubyはクラスを調べる前にモジュールメソッドを調べます。
hello
を定義するモジュールがある場合 次に、 Human
にミックスするメソッド prepend
を使用したクラス 、Rubyは、クラスにあるメソッドではなく、モジュールにあるメソッドを呼び出します。
Rubyの追加
の方法を正しく理解するため 動作します。この記事をご覧になることをお勧めします。
メソッドを呼び出そうとしたときにRubyインタープリターが最初に見るのは、シングルトンメソッドです。私はこのreplを作成しました。これを試して、可能な結果を確認できます。
次のようなモジュールとクラスがたくさんあるとします。
module One
def another
puts "From one module"
end
end
module Two
def another
puts "From two module"
end
end
module Three
def another
puts "From three module"
end
end
class Creature
def another
puts "From creature class"
end
end
これらをHuman
に混ぜてみましょう クラス。
class Human < Creature
prepend Three
extend Two
include One
def another
puts "Instance method"
end
def self.another
puts "From Human class singleton"
end
end
モジュールの混合の他に、インスタンスとクラスのメソッドがあります。 Human
classは、 Creature
のサブクラスです。 クラス。
Human.another
を実行すると 、印刷されるのは From Human class singleton
、これはクラスメソッドにあるものです。クラスメソッドをコメントアウトして再度実行すると、 From two module
が出力されます。 コンソールに。これは、 extend
を使用して混合したモジュールに由来します 。これは、ルックアップがシングルトンメソッド間で開始されることを示しています。 extend Two
を削除(またはコメントアウト)した場合 コマンドを再度実行すると、メソッド欠落エラーがスローされます。 。 Rubyがanother
を見つけられなかったため、このエラーが発生します シングルトンメソッドの中でメソッド。
先に進み、インスタンスを作成してクラスインスタンスを利用します:
n = Human.new
インスタンスのシングルトンメソッドも作成します:
def n.another
puts "From n object"
end
ここで、 n.another
を実行すると 、呼び出されるバージョンは、 n
で定義されたシングルトンメソッドです。 物体。 Rubyがextend
を使用して混合されたモジュールを呼び出さないように見える理由 この場合は、クラスのインスタンスでメソッドを呼び出しているためです。シングルトンメソッドは、 extend
を使用して混合されたモジュールを含むメソッドよりも関連性が高いことを知っておくことが重要です。 。
2番目のルックアップ-preprend
を使用して混合されたモジュール
n
でシングルトンメソッドをコメントアウトすると オブジェクトを作成してコマンドを実行すると、呼び出されるメソッドのバージョンは、 prepend
を使用して混合したモジュールです。 。これは、 prepend
を使用するためです。 クラス自体の前にモジュールを挿入します。
モジュールをコメントアウトするとThree
、 another
のバージョン 呼び出されるメソッドは、クラスで定義されたインスタンスメソッドです。
4番目のルックアップ-include
を使用して混合されたモジュール
次にRubyがメソッドを検索する場所は、 include
を使用して混合されたモジュールです。 。したがって、インスタンスメソッドをコメントアウトすると、取得するバージョンはモジュール One
にあるバージョンになります。 。
5番目のルックアップ-親クラス
クラスに親クラスがある場合、Rubyはクラスを検索します。検索には、親クラスに混合されたモジュールへのアクセスが含まれます。モジュールで定義されたメソッドがCreature
に混在している場合 クラスの場合、メソッドが呼び出されます。
メソッドの検索がどこで終了するかは、その祖先を確認することでわかります。 .ancestors
を呼び出す クラスで。 Human
に対してこれを行う クラスは[Three、Human、One、Creature、Object、Kernel、BasicObject]
を返します。 。メソッドの検索はBasicObject
で終了します クラス。Rubyのルートクラスです。あるクラスのインスタンスであるすべてのオブジェクトは、 BasicObject
から発生しました クラス。
メソッド検索が開発者定義の親クラスを通過すると、次のようになります。
オブジェクト
クラスカーネル
モジュール-
BasicObject
クラス
method_missing
方法
Rubyをしばらく使用している場合は、おそらく NoMethodError
に出くわしたことでしょう。 、これは、オブジェクトで不明なメソッドを試行したときに発生します。これは、Rubyがオブジェクトの祖先を調べて、呼び出されたメソッドを見つけられなかった後に発生します。受け取ったエラーメッセージは、 method_missing
によって処理されます。 BasicObject
で定義されたメソッド クラス。メソッドを呼び出しているオブジェクトのメソッドをオーバーライドすることができます。これについては、これを確認することで確認できます。
これで、Rubyがオブジェクトで呼び出されたメソッドを理解するためにたどるパスがわかりました。このことを理解すれば、オブジェクトで不明なメソッドを呼び出した結果として発生するエラーを簡単に修正できるはずです。
-
RubyのGsubメソッドを使用する3つの素晴らしい方法
Rubyのgsubについて話しましょう 方法と使い方。まず、このメソッドを使用するには文字列が必要です。 なぜですか? gsubの要点は 文字列の一部を置き換えることです。 実際 : 「gsub」の「sub」は「substitute」を表し、「g」は「global」を表します。 ここに文字列の例があります : str = white chocolate 「白」という単語を「暗い」という単語に置き換えたいとしましょう。 方法は次のとおりです : str.gsub(white, dark) これは言っています : 与えられた文字列str 、最初の単語のすべての出現箇所を置き換
-
Ruby Freezeメソッド–オブジェクトの可変性を理解する
オブジェクトが可変であるとはどういう意味ですか? 派手な言葉で混乱させないでください。「可変性 」は、オブジェクトの内部状態を変更できることを意味します。これは、凍結されたオブジェクトを除く、すべてのオブジェクトのデフォルトです。 、または特別なオブジェクトのリストの一部であるもの。 つまり、Rubyのすべてのオブジェクトが変更可能というわけではありません! 例 : 数字や記号、さらにはtrueには意味がありません またはfalse (オブジェクトでもあります)変更します。 数字の1は常に1になります。 ただし、他のオブジェクト、特に配列オブジェクトやハッシュオブジェクトなどのデー