Rubyメタプログラミング-Week-1


沈小黒の菜園へようこそ~
魔都に転入する
あはは~アリ実習生をしなくなってから、学校でぼんやりして1週間ぐらい経って、やっと実習を探し始めました~猿題庫を先に投げて、仕方なく10月中旬になってから面接することができて、eBayに会って、意外にも順調に過ぎて、このように杭州の二大家の前で上海に行って実習生活を始めました~~P.S.6日にoffer 13号をもらって入社して、今になってやっとこの話を書く効率も心配ですね~
ルビーに初めて会った
ルビープログラミングというのは、『ルビープログラミング』を読むためのメモを書くつもりですが、その前に、ルビーの勉強を始めた理由を話しておきましょう.
10月13日、それは穏やかな朝だった.eBayに来る前から暇な会社だと噂されていましたが、私がeBayで実習したことを知った七爺の最初の返事は「ああ!暇だ!」でした.担当者が私にやるべきことを話してくれたとき、ルビー開発を使う必要があることを知った.実は普通はすべてこのような心理状態があります:使うのがもっと小さい衆の言語を使うのがもっとひどく見えます...もちろん残っている理性は私に教えて、プログラマーは言語を変えるためにひどくなることができなくて、ましてJavaさえ精通しているプログラマーとは言えません.
勉強する前はドキドキしていましたが、私の怠け者で、12時ごろ出勤して、6時ごろ退勤するmentorは私に「これは簡単ですから、勝手に見てください」と言いました.そこで私は気持ちを片付けて、一晩かけてルビーの文法を見て、え~pythonに似ているような気がして、本当に簡単かもしれません!
こうして、ルビーの勉強の旅を始めます~!上のこのような文式はいつも人にあなたが今すでに某某の大家だと感じさせて、実は私は今まだ何も分かりませんハハ!
Rubyメタプログラミング
さあ、いよいよ本編開始です.
実は1つの言語の文法はとても簡単で、1冊の本は大体《7日間7つの言語を勉強します》と言って、7日間以内に7つの言語の文法を掌握して、これは1つのプログラミングの言語に熟知する人にとって実は難しくありません.しかし、言語の真髄は実はその設計思想にあり、本当に一つの言語の設計思想を理解した後、私は後で他の言語を勉強するとき、文法をすぐにマスターできるだけでなく、この言語の特性を迅速に利用して優秀なコードを書くことができると思います.そこで「ルビー菜鳥教程」という文法科を見てから、「ルビーメタプログラミング」を見始めました.
『Ruby元プログラミング』は実は1つのストーリです...本の中の主人公は私と同じように会社に入ったばかりの実習生で、彼とプログラミングを兼ねてmentorを兼任しているのはRubyマスターです~そして彼らのストーリは1日を1章として...実は本はとても薄くて、もちろん十分な時間があるかどうかを見て、だから~章に従ってノートを書きましょう.
今日は「月曜日」です.
内省
多くの言語、例えばC++では、言語コンポーネント(変数、クラス、メソッドなど)はコンパイラが完了すると、見えないものになり、メモリの位置にすぎません.
Rubyや他の多くの言語では、実行時のほとんどの言語コンポーネントが依然として存在します.コンポーネントから独自の情報を取得できます.これを内省と呼ぶ.
内省の例:
class Greeting 
    def initialize(text) 
        @text = text 
    end  

    def welcome 
        @text 
    end
end 

my_obj = Greeting.new("Hello")


puts my_obj.class ,my_obj.class.instance_methods(false) ,my_obj.instance_variables

このようなコードにより,オブジェクト自体に関する多くの情報を得ることができる.そういえば、Javaも内省の言語です.
C運転時には、マシンコードが山積みになっているだけです.C++では、いくつかの言語コンポーネントはコンパイル後に残ることができます.Javaでは,コンパイル時と実行時の境界があいまいで,クラスのメソッドや継承関係などをリストするのに十分な内省能力がある.
最も徹底しているのはRubyであり,Rubyにはコンパイル時の概念がなく,すべてのコンポーネントが実行時に利用可能である.
メタプログラミング
メタプログラミングは、内省よりも言語コンポーネントの修正を可能にします.例を挙げます.
Javaでは、DBMModelを書く場合は、データベースのフィールドをクラスに1つずつ対応させてgetterとsetterを追加する必要があります.データベースフィールドが変更されると、クラスのインスタンス変数と対応するインスタンスメソッドも変更する必要があります.Rubyでは、次のようなコードを書けば、データテーブルのマッピングが自動的に完了します.
class Movie < ActiveRecord::Base
end

これにより、Movie#title()を直接使用してtitleフィールドにアクセスできます.これらのメソッドも変数も定義されていませんが、ActiveRecorderはどのように実現されていますか?
クラス名がMovieなので、ActiveRecordはmoviesというテーブルにマッピングします.プロパティにアクセスする方法は、ActiveRecordがテーブルモードからフィールド名を取得した後、自動的に定義する方法です.
言語コンポーネントを書き込む能力がその時に発揮され、その能力がどのように実現されるのかは、後述の本で説明します.
メタプログラミングは、実行時に言語コンポーネントを操作するコードを記述する.
これがメタプログラミングの概念です~
Open Class特性
Open ClassプロパティRubyでは、2回目に定義したクラスは、既存のクラスのみが変更されます.たとえば、次のようになります.
class D
    def x
    end
end

class D
    def y
    end
end

これでDにはxとyの2つの方法があります.
注意すべきは...これにより、元の他の場所で使用されていた方法が書き換えられ、実行に問題が発生する可能性が高いことです.これはOpen Classの隠れた危険で、よくサルパッチMonkeypatchと呼ばれています
サルパッチの問題を回避するために、クラスをモジュールに配置することで、名前の競合を大幅に回避できます.(2つのモジュール名が同じでクラス名が同じであれば、サルパッチの問題が発生する可能性もあります)
他にも解決策があり、サブスペースを選ぶなど...もちろん、本の中のmentorは本の後ろで話すと言っていますが、後で見てからにしましょう.
ルビー類の真実
Rubyのような動的言語では、オブジェクトのクラスとインスタンス変数は関係なく、インスタンス変数に値を割り当てると生成されます.次の例では、my_が呼び出されていない場合に出力されます.method、出力する変数のリストは空です
class MyClass 
    def my_method 
        @v=1 
    end
end 

obj = MyClass.new  
puts obj.instance_variables

インスタンス変数はオブジェクトに格納され、メソッド(クラスメソッドとオブジェクトメソッドを含む)はクラスに格納されます.
クラス自体もオブジェクトです.クラス自体のクラスをClassと言います.ここでクラスはオブジェクトであり、そのオブジェクトのクラス:Classもそのオブジェクトのインスタンスメソッドを持っています.クラスのメソッドはクラスのインスタンスメソッドです.
ClassのsuperclassがModule Moduleのsuperclassの場合Object ObjectのsuperclassはBasicObject…MyClass BasicObjectのsuperclassはnil
したがって、ClassはModuleに基づいてnew、allocate、superclassの3つの方法の強化モジュールを追加したにすぎない.
しかし、Moduleを実行します.methodsはこの3つの方法を見つけることができますか?
まず、methods、private_methodsはObjectクラスのインスタンスメソッドです.instance_methodsはModuleクラスのインスタンスメソッドです.Rubyオブジェクトは2つのクラスに分けられます.1つは普通のオブジェクトで、もう1つはクラス(クラス自体もオブジェクト)で、String、Classのような種類で、このようなオブジェクトをクラスオブジェクトと言います.通常オブジェクトの祖先チェーンは、String->Comparable->Object->Kernel->BasicObjectクラスオブジェクトの祖先チェーンです.Stringを例にとると、Class->Module->Object->Kernel->BasicObjectクラスオブジェクトにはinstance_がありません.Methodsメソッドは、その祖先チェーンにModuleクラスがないためです.したがって、一般的なオブジェクトでは、メソッドまたはプライベートメソッドがあるとしか言いようがありません.インスタンスメソッドがあるとは言えません.インスタンスメソッドはクラスにとってです.(slef-motivationのブログから引用http://blog.csdn.net/happyanger6/article/details/42436879)
だからModuleを実行します.methodsが見つけたのはObjectクラスのメソッドで、その時自然にこの3つのメソッドがあります.Moduleでinstance_methodsではこの3つの方法が見つからない.
Moduleクラスは2つのconstants()メソッドを提供し、インスタンスメソッドModule#constants()は現在の範囲内の定数を返し、クラスメソッドModule.constants()は、クラス名を含む現在のプログラム内のすべての最上位定数を返します.
module MyClass   AAA = 'aaa'   def my_method  @v=1  end end  
MyClass.constsants #  AAA
Module.constants    #  Object,Module,Class,BasicObject......MyClass。        (        ), AAA         ,         

クラスにモジュールが含まれている場合、Rubyはモジュールをカプセル化した匿名クラスを作成し、この匿名クラスを祖先チェーンに挿入します.
module M  
    def my_method   
    end 
end  

class C  
    include M 
end  

puts C.ancestors

結果出力:
C
M
Object
Kernel
BasicObject

祖先チェーンにはモジュールが含まれています.ここではMとKernelです.
では、Kernelモジュールは何でしょうか.
Rubyにはprint()のような方法があり,実際にはKernelモジュールのプライベートメソッドである任意のコード空間で呼び出すことができる.ObjectクラスにはKernelモジュールが含まれていますが、Objectクラスはどのクラスのsuperclassなので、どのクラスにもKernelモジュールが含まれており、Kernel内のプライベートメソッドもあります.
self
オブジェクトとクラスのメソッドが分離されているため、オブジェクトはself参照を持っていなければ、現在の呼び出し元が誰であるかをメソッドに知らせることはできません.
通常selfはメソッド呼び出しを受信した最後のオブジェクトであるが、クラスおよびモジュールで定義されると、selfの役割はクラス/モジュールによって担当される.
class MyClass
    self                    # => MyClass
end

だからクラスの中で方法を定義する前にselfを加えるのがクラスの方法/単例の方法で、この時selfはクラス自身だからです
class MyClass
  def self.claz_method
    p 'this is a class method'
  end

end

MyClass.claz_method

puts MyClass.singleton_methods(false)  # => claz_method

Rubyにおける特殊なprivateルール
Rubyでは,受信者を明示的に指定してプライベートメソッドを呼び出すことは許されない.すなわち、プライベートメソッドが呼び出されるたびに、隠された受信者であるselfにのみ呼び出される.
class C  
    def public_method  
        self.private_method 
    end   

    private  
    def private_method   
    end 
end   

C.new.public_method

それでもselfを指定すると、暗黙のselfにのみ呼び出す必要があるため、呼び出しに失敗します.
selfの一例について
module Printable  
    def print
      puts 'print in Printable'
    end 
end  

module Document
  def print_to_screen
    print 
  end   

  def print  
    puts 'print in document'  
  end 
end  

class Book  
    include Document  
    include Printable 
end   

Book.new.print_to_screen

ここでの出力結果は「print in Printable」
祖先チェーンは[Book,Printable,Document,Object,Kernel,BasicObject]なので
だからselfはprint_to_screenでprintメソッドを検索するとselfが属するBookクラスにprintメソッドがないため、Bookクラスから上を検索し、Printableでメソッドが見つかった場合、Printableのprintメソッドが呼び出されます.
まとめ
これが今日の『Ruby元プログラミング』の書き写しです.ありがとうございます.