Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

メタプログラミングruby 5章

More than 1 year has passed since last update.

注 classは高性能なmoduleなので、classにおいてできることはmoduleにも適用できる場合が多い

classとmoduleの比較

classはインスタンスをもつ
moduleはメソッド群

メソッドを定義するとself(カレントクラス)のインスタンスメソッドになる
クラスの定義の中ではカレントクラスとカレントobject(self)は同じである
クラスへの参照を持っていれば、クラスはclass_evalで参照できる

クラスインスタンス変数

インスタンス変数の定義する場所によって、そのインスタンス変数をもつclassが異なることに気をつけなくてはいけない
メソッドの中ではメソッドのレシーバがselfになる、よって、インスタンスメソッドの中ではそのインスタンスがselfに、classの定義の中ではclass自身がselfになる。(あらゆるクラスはclassクラスのインスタンス クラスの定義内ではselfはclassクラスのインスタンスである、そのクラス自身を参照する)
classクラスのsuperclassはmoduleでmoduleのsuperclassはobjectとなる。だが、objectはclassクラスのインスタンスである。
よってあらゆるクラスはclassクラスのインスタンスである。また、新しく生成されたclassのsuperclassはobjectだが、これもクラスはclassである。また、class自身も例外ではなく、classクラスはclassクラスのインスタンスである。
ただ、ここで注意しなくてはならないのは継承しているということとそのクラスのインスタンスであるということは違うということ。継承はメソッドの引き継ぎ、インスタンスは継承されてきたものによって作られたクラスを用いた物体。

meta.rb
class Myclass
  @my_var = 1
end

クラス定義の中ではselfはクラス自身になるので、@my_varはクラスに属していることになる。
よって、クラスのインスタンス変数とクラスのオブジェクトのインスタンス変数は別物になることを注意しなくてはならない

meta.rb
class Myclass
  @my_var = 1
  def self.read; @my_var; end
  def write; @my_var = 2; end
  def read; @my_var; end
end
obj = Myclass.new
obj.read #=> nil
obj.write
obj.read #=> 2
Myclass.read #=> 1

Myclassのインスタンスメソッドはwriteとreadで、objのメソッドでもある。

特異メソッド

rubyでは特定のobjectに対してメソッドを追加できる。
例えば、

a = User.find(3)
def a.black?
  true if self.name == "ウエハラ"
end

的な
これはclassメソッドも実は特異メソッドで、classクラスの特定のobjectに対してメソッドを追加していることになるから。
特異メソッドが出た場合、メソッドの継承チェーンに特異クラスが挟まれる。つまり、そのobjectは特異クラスのインスタンスになる。特異クラスのインスタンスは通常のclassを継承しているので、それまで通りに使うことができる。つまり、moduleを挟み込むのと同じイメージ。

ダックタイピング

静的型付け言語ではそのobjectがTの型を持つのはそのTクラスに属しているからだと考える。
動的型付け言語ではそのobjectがDuckクラスに属しているかどうかは重要ではない、そのメソッドが反応するかどうかである。
rubyではインスタンスのクラスがどのような継承関係をもっていても、ある特定のメソッドに応答できさえすればレシーバーとして振る舞うような処理がかける。

メソッドラッパー

メソッドの書き換えに3つの方法がある。

 アラウンドエイリアス

meta.rb
class String
  alias_method :real_length, :length

  def length
    real_length > 5 ? 'long' : 'short'
  end
end
"War and Peace".length # => "long" ①
"War and Peace".real_length # => 13 ②

①の場合:まず、新しく定義されているlengthに入る。その中で、real_lengthが呼ばれ、aliasにしたがって、もともとのlengthが呼ばれ、13が返ってくる。13に対し評価を行い"long"という結果になる。
②の場合:real_lengthを呼ぶとaliasにしたがってlengthが返ってくる。
このようにlengthを再定義することが可能である。
他にもmodule内でsuperを使って再定義したメソッドを使うという手もある。

meta.rb
module ExplicitString
  def length
    super > 5 ? 'long' : 'short'
  end
end

String.class_eval do
  prepend ExplicitString
end

"War and Peace".length # => "long" 
Aerial-Partners
Aerial Partners(エアリアル・パートナーズ)は「ブロックチェーンを社会に広めるための基盤をつくる」ことを目指し事業展開している、仮想通貨・ブロックチェーンを得意とした会社です。仮想通貨の確定申告サポート『Guardian(ガーディアン)』、仮想通貨のクラウド会計ソフト『Gtax』の2つの事業を展開しています。
https://www.aerial-p.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away