Rubyクラスメソッドがありません


待って.whaaaaaaaaaaaaaaaaaaaat?



私はあなたのことを知りません、しかし、私が最初に聞いたとき、それは私の正確な反応でしたNadia Odunayo ’sの話RubyConf KL 2018 (心は、私が今まで聞いた中で最も魅惑的な話の一つ!)そのルビーにはクラスメソッドがないことを示した.
Rubyを初めて学び始めたとき、Rubyは基本的に二つのタイプのメソッドを持っていると言われました.
  • クラスメソッド
  • インスタンスメソッド
  • class Foo
      def self.class_method
        puts "This is a class method of #{self}"
      end
    
      def an_instance_method
        puts "This is an instance method of #{self}"
      end
    end
    
    Foo.class_method #=> "This is a class method of Foo"
    Foo.new.class_method #=> undefined method `class_method' for #<Foo:0x007f83960d2228> (NoMethodError)
    
    Foo.an_instance_method #=> undefined method `an_instance_method' for Foo:Class (NoMethodError)
    Foo.new.an_instance_method #=> This is an instance method of #<Foo:0x007f80aa92d150>
    
    まず最初に、それは多くの感覚を作ります

    A class is an object, and when you call .new on a class, you create a new instance of that object.

    Hence, instance methods are only available on instances of that class.


    それなら大丈夫Rubyがクラスメソッドを持っていないと言ったとき、私は何を話していますか?

    両親。祖父母。祖先..


    私たちが理解する必要がある最初のものはルビーの祖先鎖と呼ばれるものです.
    先祖の鎖はルビーがどのように働くかを理解するのに不可欠ですチェーンを呼び出している全体のメソッドはチェーンのために働きます、しかし、ここで、私は過度に簡単な説明を試みます.
    Rubyではすべてが継承するObject , あらゆるObject Aから継承するBasicObject .
    簡単にチェックしましょう!
    2.3.1 :001 > Foo.ancestors
     => [Foo, Object, Kernel, BasicObject]
    2.3.1 :002 > Foo.superclass #superclass allow us to see what class the receiver inherited from. AKA, the parent of current class.
     => Object
    
    2.3.1 :003 > Object.superclass
     => BasicObject
    
    (Kernel is a Module, you could quickly verify it by doing Kernel.class)
    
    メソッドを呼び出すと、現在のクラスのメソッドを呼び出します.現在のクラスがそのメソッドを持たない場合、それが1つを見つけるまで、それは祖先鎖を遡ります.
    まだ明確?私はgotchu!奇妙な比喩

    Imagine you’re just a kid, and that annoying Little Johnny who is trying to outsmart you asks you sheepishly: “Do you know what .planets are in our solar system? I bet you don’t!”.

    Well you actually don’t know the answer, but you wouldn’t let Little Johnny get his victory, and so you make this your life goal to find out, and you ask your parents: “What are the .planets in our solar system?”. And well, your parents don’t know that either, so they go on and ask their parents, who happen to know the answer.

    Now it’s your turn to smirk sheepishly back at Little Johnny and tell him what the answer is.

    So now whenever someone asks you what are the .planets in our solar system, you have the answer, from your Grandparents.


    これはどうですか.さて、私たちは方法ルックアップの仕事について話しました、そしてlast post 私は、再利用方法について話しましたModule ) with include , extend and prepend . では、それぞれの祖先チェーンを見てみましょうinclude , extend and prepend モジュールです.
    Awesome = Module.new
    
    class IncludeModule
      include Awesome
    end
    IncludeModule.ancestors #=> [IncludeModule, Awesome, Object, Kernel, BasicObject]
    
    class ExtendModule
      extend Awesome
    end
    ExtendModule #=> [ExtendModule, Object, Kernel, BasicObject]
    # WHERE IS THE MODULE?!
    
    class PrependModule
      prepend Awesome
    end
    PrependModule.ancestors #=> [Awesome, PrependModule, Object, Kernel, BasicObject]
    
    何か変なことがわかるでしょう.
  • ときにinclude , モジュールは現在のクラスの後に挿入されています.これは、現在のクラスのメソッドを見つけることができないときに最初に打つことになります.
  • prepend の反対ですinclude ; それは前に挿入するので、技術的に、あなたはまだそれを呼び出すことができないでしょう.
  • モジュールを拡張するときに、先祖鎖のモジュールが見えません
  • 私たちは、私たちが知っているときにextend モジュールは、クラスメソッドへのアクセスを取得し、また、メソッドの呼び出しは、祖先鎖を介して発生することを知っているが、..どうしたらextend モジュールが先祖鎖にない場合は動作しますか?
    その理由は、Singletonクラスと呼ばれるRubyの何かのためですMetaclass , Anonymous Class or Eigenclass )
    Rubyクラスを初期化するたびに、2つのオブジェクトが生成されます.Foo そしてFoo’s Singleton Class . これを証明するために、彼女の話で、ナディアは、使用しているクラスの現在のカウントを調べる素晴らしい方法を示しましたObjectSpace . ObjectSpace 基本的には、メモリ内のすべての現在の生きているRubyオブジェクトと対話する方法です.
    ObjectSpace.count_objects[:T_CLASS] #=> 920
    Foo = Class.new
    ObjectSpace.count_objects[:T_CLASS] #=> 922
    
    今、何を理解する前にextend している、我々は最初に理解する必要がありますSingleton Class , だから、私と一緒に、次のセクションを取得し、我々はその後、理解することができますextend マジック!

    シングルトンクラスについて

    Singleton Class , 別名のようにAnonymous Class このようにして、アノニマス型のチェーン(!!!)では匿名であることが示唆されています.それは私たちがシングルトンクラスにアクセスできないことを意味しません.singleton_class 我々が使うことができるそれ.
    class Foo
    end
    
    Foo.singleton_class #=> #<Class:Foo>
    
    何を見てみましょう.class クラスのクラスを作成します.
    class Foo
    end
    
    Foo.class #=> Class
    
    以前にも気づいたかもしれませんが、以下のようにクラスを初期化する方法もあります.
    Foo = Class.new
    
    今は本当に身近なルックス?fooはクラスのインスタンスです.
    なぜこれが重要ですか?これは、あなたが実行していると思うようになった通常のクラスメソッドを意味するからですFoo 実際には、インスタンスメソッドClass . — それは働くFoo のインスタンスClass !
    私たちは、Singletonクラスが祖先鎖で見えないということを知っています.他のチェーンに表示されなかった覚えていますか?モジュールを使用するとextend !
    Singletonクラス自体の祖先鎖をチェックすることができます.
    HiddenModule = Module.new
    class Foo
      extend HiddenModule
    end
    
    Foo.singleton_class.ancestors #=> [#<Class:Foo>, HiddenModule, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
    
    # Well HiddenModule is not so hidden anymore!
    
    また、私たちが知るようになるものを証明することもできますclass_method , Singletonクラスのインスタンスメソッドです.
    module Mystery
      def resolved?
          true
      end
    end
    
    class Foo
      extend Mystery
    end
    
    Foo.resolved? #=> true
    Foo.singleton_class.instance_methods.grep(/resolved?/) #=> [:resolved?]
    Foo.method(:resolved?) #=> #<Method: Class(Mystery)#resolved?>
    
    だから今我々は知っているextend 実際にシーンの後ろには基本的にはinclude Singletonクラスそのものについてそれを証明しましょう!
    class Bar
      Bar.singleton_class.include Mystery
    end
    
    Bar.resolved? #=> true
    Bar.singleton_class.instance_methods.grep(/resolved?/) #=> [:resolved?]
    Bar.method(:resolved?) #=> #<Method: Class(Mystery)#resolved?>
    
    まだ動作!
    しかし、ええ、完全な形を書くことは驚異的な3つの語を必要としますextend 代わりにキーストローク私たちを救うために!

    著者注


    私はいくつかのより多くの記事をポンピングアウトしますlast post on included , extended and prepended フック!
    Phew、それは私の2番目のブログのためのそれです.を楽しみにして共有を学ぶ!