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になります。 ただし、他のオブジェクト、特に配列オブジェクトやハッシュオブジェクトなどのデー