a s e v a l u e w h e n 1 , 2 p u t s ' v a l u e = 1 o r 2 ' w h e n ' h o g e h o g e ' p u t s ' v a l u e = " h o g e h o g e " ' w h e n F l o a t p u t s ' v a l u e は浮動小数点数' w h e n / p a t t e r n / p u t s ' 正規表現/ p a t t e r n / にマッチ' e l s e p u t s ' それ以外' e n d
b ) a + b e n d a d d ( 1 , 2 ) # = > 3 a d d 1 , 2 # = > 3 C++ の関数・ メンバ関数にあたるもの 最後の式が暗黙的に return される 明示的な return も書ける メソッド呼び出し時には括弧を省略できる メソッドをキー ワー ドのようにして扱える
' s t r . u p c a s e # = > ' F O O ' s t r # = > ' f o o ' s t r . u p c a s e ! s t r # = > ' F O O ' 同じ名前のメソッドで 破壊的なものとそうでないものがあるとき、 破壊的な方に! を付ける習慣 破壊的 : 元のオブジェクトを変えてしまう C++ 的に言えば non‑const
l d e f t e x t @ t e x t e n d d e f t e x t = ( t ) @ t e x t = t e n d e n d L a b e l . n e w . t e x t = ' f o o ' メソッドの名前の最後に= をつけると オブジェクトのフィー ルドへの代入を 表せるようになる メソッド呼び出しの括弧の省略とあわせると setter / getter を綺麗に書ける
f C++ のt h i s 省略可能 c l a s s P u s h B u t t o n < B u t t o n d e f i n i t i a l i z e ( b u t t o n _ f i e l d , n a m e , p u s h e d ) @ n a m e = n a m e b u t t o n _ f i e l d . a d d ( s e l f ) p u s h i f p u s h e d # s e l f . p u s h i f p u s h e d と同じ e n d d e f p u s h @ p u s h e d = t r u e e n d e n d
P u s h B u t t o n . n e w ( f i e l d , ' p r e s s m e ' , f a l s e ) インスタンスを作る際は、 n e w というクラスメソッドを呼ぶ i n i t i a l i z e は インスタンスが作られた時に呼ばれるメソッド n e w に渡された引数がそのまま渡される C++ でいうコンストラクタ
d e f m o d u l e _ m e t h o d ' m e t h o d o f M ' e n d e n d c l a s s C i n c l u d e M e n d c = C . n e w c . m o d u l e _ m e t h o d # = > ' m e t h o d o f M ' クラスとよく似ているが、 インスタンスを作れない 他のクラスまたはモジュー ルから include して 機能の付加 (mixin) のために使う クラスは 1 つしか継承できないが モジュー ルは複数 include できる ( 多重継承 ) CRTP
' d e f s t r . h o g e ? s e l f = = ' h o g e ' e n d s t r . h o g e ? # = > t r u e クラスやモジュー ルに対してだけではなく オブジェクト単体にもメソッドを定義できる 特異メソッド オブジェクトに対して特異クラスが作られ 特異メソッドはそこに定義される 動的型付き言語らしい機能
p u t s ' d e f i n i n g F o o ' a t t r _ a c c e s s o r : h o g e # h o g e , h o g e = が定義される e n d クラス・ モジュー ル定義中には 普通にコー ドを実行できる Class/Module クラスの便利なメソッドも呼べる a t t r _ a c c e s s o r インスタンス変数の setter, getter を定義してくれる
l d ' f o o ' e n d f o o d o | s t r | p u t s s t r e n d # ' f o o ' と表示される f o o { | s t r | p u t s s t r } # ' b a r ' と表示される メソッドに対して引数とは別に渡される ラムダ式 ( 無名関数 ) にあたるもの do∼end, {∼} で囲む {∼} は一行の時によく使われる y i e l d で呼び出す
メソッドで作れる & を付けてメソッドに渡すとブロック代わりになる p r c = p r o c { | s t r | p u t s s t r } p r c . c l a s s # = > P r o c p r c . c a l l ( ' h o g e ' ) # ' h o g e ' f o o ( & p r c ) # ' f o o '
STL アルゴリズムのような機能を提供する # e a c h メソッドを元に機能が実装されている Ruby の# e a c h ≒ C++ のb e g i n ( ) , e n d ( ) ブロックを使った関数型プログラミング a r y = [ 1 , 2 , 3 ] a r y . e a c h d o | i | p u t s i e n d a r y . m a p { | i | i * 2 } # = > [ 2 , 4 , 6 ] a r y . s e l e c t { | i | i . e v e n ? } # = > [ 2 ]
= F i l e . o p e n ( ' s o m e _ f i l e ' ) # エラー があった時 r a i s e ' e r r o r ' r e s c u e p u t s ' e r r o r o c c u r e d ' e n s u r e f i l e . c l o s e e n d
e n ( ' s o m e _ f i l e ' ) d o | f i l e | # 処理 e n d F i l e . o p e n メソッド ファイルを開いた後、 受け取ったブロックを実行 例外の発生有無にかかわらず 最後にファイルを閉じる スコー プを抜けると自動的にリソー スが閉じられる RAII と共通している
t r ' s t r . c l a s s # = > S t r i n g s t r . m e t h o d s # = > インスタンスメソッドのリスト ( 特異メソッド含む) S t r i n g . i n s t a n c e _ m e t h o d s # = > S t r i n g のインスタンスメソッドのリスト S t r i n g . m e t h o d s # = > S t r i n g のクラスメソッドのリスト
o d ( : e v e n ? ) m . c l a s s # = > M e t h o d m . c a l l # = > f a l s e u = I n t e g e r . i n s t a n c e _ m e t h o d ( : e v e n ? ) u . c l a s s # = > U n b o u n d M e t h o d u . b i n d ( 2 ) . c a l l # = > t r u e Method オブジェクト オブジェクトと関連付けられている Proc とよく似ている C++ だと、std::bind で束縛されたメンバ関数 UnboundMethod オブジェクト オブジェクトと関連付けられていない # b i n d で関連付けて Method に C++ だと、 メンバ関数ポインタ
: h o g e , : p i y o ] . e a c h d o | m e t h | d e f i n e _ m e t h o d m e t h d o m e t h e n d e n d e n d f = F o o . n e w f . h o g e # = > : h o g e d e f i n e _ m e t h o d メソッド名とブロックを与えて メソッドを動的に定義
e f m e t h o d _ m i s s i n g ( n a m e , * a r g s , & b l o c k ) p u t s " m i s s i n g m e t h o d # { n a m e } " e n d e n d F o o . n e w . n o _ s u c h _ m e t h o d # m i s s i n g m e t h o d n o _ s u c h _ m e t h o d と表示される メソッドが見つからなかった時に呼ばれる デフォルトの挙動では NoMethodError を投げる
r e ' o s t r u c t ' s = O p e n S t r u c t . n e w s . m e t h o d s . g r e p ( / h o g e / ) # = > [ ] s . h o g e = ' h o g e ' s . m e t h o d s . g r e p ( / h o g e / ) # = > [ : h o g e , : h o g e = ] d e f i n e _ m e t h o d と組み合わせて 動的に新しいメソッドを定義可能 ORM (SQL などをラップするしくみ ) でも よく使われる ActiveRecord など
u l a t o r d e f i n i t i a l i z e @ v a l u e = 0 e n d d e f a d d ( x ) @ v a l u e + = x e n d e n d C a l c u l a t o r . n e w . i n s t a n c e _ e v a l d o a d d 2 a d d 1 0 p u t s @ v a l u e # 1 2 e n d このような DSL 風のコー ドを書くこともできるが インスタンス変数にアクセスできてしまうので 欠陥…
それに基づいて実装を行うという考え方 d e s c r i b e P e r s o n d o d e s c r i b e ' # g r e e t ' d o i t ' r e t u r n s " H e l l o " ' d o e x p e c t ( P e r s o n . n e w . g r e e t ) . t o e q ( ' H e l l o ' ) e n d e n d e n d テストコー ドであるが Person#greet が' H e l l o ' を返すという 「 仕様」 を規定している