rubyのclass、moduleの違い。クラスオブジェクトとインスタンスオブジェクトについてなど わかっていそうでわかっていない点をメタプログラミングの本を用いて理解していく。
オープンクラス
文字列からアルファベットとスペース以外を取り除くメソッド
def to_alphanumeric(s) s.gsub /[^\w\s]/, '' end
オープンクラスを使った書き方
class String def to_alphanumeric gsub /[^\w\s]/, '' end end
標準のStringクラスへメソッドを追加。
標準のクラス書き換えていいんですか。。初心者の想い。。
普通の開発現場とかでもあり得る対応なのかなぁ。
現場のコーディングルールとかRubyのベストプラクティスを読んでみたい。
今回のメソッドは汎用的なメソッドのため、許容できる。らしい。
ただし、Stringなどの重要なクラスは慎重に考える必要はある。
クラス定義の中身
3.times do class C puts "Hello" end end Hello Hello Hello => 3
クラス定義時にputsが呼ばれている。
3つ定義しているわけではなく、クラスの再オープンで定義している。
あと、do〜end内にクラス定義!?
Java屋さんとしてはでっかいクエスチョンマークがつきました。
ブロック内での定義は特に縛りないのかな。
メソッド定義して呼び出すのも試してみる。
3.times do def hello puts "Hello" end hello end Hello Hello Hello => 3
特に問題ないみたい。ブロック内での処理記述はクラス内での
記述と変わらないのかな
オープンクラスの例
Moneyオブジェクトに数値をMoneyオブジェクトへ変換するメソッドNumeric#to_money()がある。
標準クラスNumericには元々ない。
price = 100.to_money()
標準クラスNumericを再オープンして書き換えている。
class Numeric def to_money Money.new(self * 100) end end
Money gemなどgemを取り込むとこのような書き換えが裏で発生したりしているんですね。
オブジェクトの中身
インスタンス変数
インスタンス変数はメソッドが呼ばれた時点で生成される
class MyClass def my_method @v = 1 end end => nil o = MyClass.new => #<MyClass:0x007fbe91102398> # この時点では@vは存在しない o.instance_variables => [] o.my_method => 1 o.instance_variables => [:@v]
インスタンスメソッドとメソッド
用語の違いを正しく理解する。
以下のようなインストロペクション(オブジェクト自身の内容調査する)で確認できる。
# クラスのインスタンスメソッドとオブジェクトのメソッドは同一 String.instance_methods == "abc".methods => true # クラスのメソッドとオブジェクトのメソッドは同一でない String.methods == "abc".methods => false
インスタンスメソッドというと、クラスが定義しているメソッドを呼び出しているという意味になるそうだ。まだ、よくわからない。。
クラスオブジェクト
# Stringのインスタンスが"hello" "hello".class => String # ClassのインスタンスがString String.class => Class # 継承メソッドを除いたClassで定義されたメソッドは以下 Class.instance_methods(false) => [:allocate, :new, :superclass] # Objectを継承してStringが実装されている String.superclass => Object # BasicObjectを継承してObjectが実装されている Object.superclass => BasicObject # BasicObjectがトップレベルオブジェクト BasicObject.superclass => nil # Moduleを継承してClassが実装されている Class.superclass => Module # Objectを継承してModuleが実装されている Module.superclass => Object
ClassはModuleに左記メソッドを追加したにすぎない [:allocate, :new, :superclass]
ほとんど同一のもの。
ClassとModuleの使い分け
Class:インスタンス生成、継承を行う
Module:インスタンスメソッドを適用させたい場合、またはネームスペースとして用いる。 継承できない。
moduleをネームスペースとして利用する
module Rake class Task
Taskクラスの名称は「Rake::Task」となる
他のクラスにTaskクラスが存在しても衝突を起こすことがなくなる。
Rake::としているのはクラス名Taskが定数だから。
Rakeのような定数をまとめるだけのモジュールのことをネームスペースと呼ぶらしい。
モジュールとメソッドの探索
モジュールのインクルードを行うと、クラスとスーパークラスの間に
無名クラスを作成し、継承関係が作成される。
module M def my_method 'M#method()' end end => nil class C include M end => C class D < C; end => nil D.new.my_method() => "M#method()" D.ancestors => [D, C, M, Object, Kernel, BasicObject] # モジュールMは表示されるが、裏で生成された無名クラスは意識させないため、隠れている
Rubyの達人になるための道 selfを理解する
irb起動時のself
self # mainはトップレベルコンテキストと呼ばれる。 => main self.class => Object
クラス定義とself
class MyClass self end => MyClass
privateキーワードとself
privateメソッドのルール:「明示的なレシーバーをつけて呼び出せない」
下記は明示的なselfをつけているのでエラーとなる。削除すると動作するようになる。
class C def public_method self.private_method end private def private_method; end end => nil C.new.public_method NoMethodError: private method `private_method'
privateメソッド呼び出しについて補足
・スーパークラスから継承したprivateメソッドは継承先クラスで呼び出せる。
・インスタンスメソッド内からしか呼び出せない。クラスには紐付かないメソッド。
第1章完了。。