1から始めるRuby

ブログを下記に移転しました。デザイン変更により移転先では記事が一層読みやすくなっていますので、よろしければ移動をお願い致します。

1から始めるRuby : melborne.github.com

                                                                                      • -


数学の世界で1は数である
3歳の子供でもそれを知っている
そして私やあなたが老いて死にゆくまで
1は数であり
そこに疑念の入る余地はない


プログラミングの世界でもふつう
1は数である
CでもJavaでもHaskellでも
1は数であり
それ以上でもそれ以下でもない


ところが驚くべきことに
Rubyの世界では
1は数ではないのである


嘘だと思うなら
irbを立ち上げて
次のようにしてみるといい

$ irb
>> 1.next
=> 2


あなたは今
1にnextというメッセージを送った
そうしたら1は
2という答えを返したのだ
つまりRubyの世界で
1は数以上のものであり
メッセージに返答する「何か」である


Rubyの世界でそれは「オブジェクト」と呼ばれている


1はメッセージに反応するオブジェクトである


しかしここで一つの疑問が湧いてくる
それならば今
1が返した2というのは何なのか
数なのかそれともオブジェクトなのか


この疑問にもirbが答えてくれる

>> 1.next.next
=> 3


1からの返答に
さらにnextというメッセージを送ってみる
つまり1.nextで返される2にメッセージを送ってみると
果たして3が返ってきた
そう 1から返答された2も
やはりオブジェクトだったのだ


疑い深いあなたは
これだけでは納得しないかも知れない
そしてirb
きっと次のように入力するのだろう

>> 1.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next.next
=> 100


納得した?


そうRubyの世界では入り口も出口も
そのすべてがオブジェクトなのである


さて
1がオブジェクトならnext以外の
どんなメッセージに反応するのかが気になるところだ
Rubyではその答えも1に聞けばいい
methodsというメッセージを1に送ってみよう

>> 1.methods
=> [:to_s, :-@, :+, :-, :*, :/, :div, :%, :modulo, :divmod, :fdiv, :**, :abs, :magnitude, :==, :===, :<=>, :>, :>=, :<, :<=, :~, :&, :|, :^, :[], :<<, :>>, :to_f, :size, :zero?, :odd?, :even?, :succ, :integer?, :upto, :downto, :times, :next, :pred, :chr, :ord, :to_i, :to_int, :floor, :ceil, :truncate, :round, :gcd, :lcm, :gcdlcm, :numerator, :denominator, :to_r, :rationalize, :singleton_method_added, :coerce, :i, :+@, :eql?, :quo, :remainder, :real?, :nonzero?, :step, :to_c, :real, :imaginary, :imag, :abs2, :arg, :angle, :phase, :rectangular, :rect, :polar, :conjugate, :conj, :between?, :nil?, :=~, :!~, :hash, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :inspect, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :__id__, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__]


これらは1が応答できるメッセージの集合で
Rubyでは「メソッド」と呼ばれている
つまり1はあなたからの問い合わせに対し
これら130個ものメソッドで応答する

クラス

上の説明を聞いてあなたは
Rubyの1って天才、スゲー」とつぶやいたに違いない


しかし事実はそうではない
実は1の中身は私やあなたのあたまの中同様
ほとんど空っぽなのである
空っぽなのに
1はこれらのメッセージに反応できるのである


このカラクリは難しいものではない
Rubyにおいて1は
先のメソッドの集合を実際に持っている
Fixnumというクラスにリンクされている
そして1があなたからのメッセージを受け取ると
それをFixnumに渡してその返答が得られたら
1はそれをあなたに返しているだけなのだ


つまり1は
「ググって」ばかりの私やあなたと同じで
問い合わせのたびにただ「クラスってる」だけで
FixnumこそがGoogle同様のスゲー存在なのである
そして私やあなたはWebの世界では
Rubyの1みたいな存在なのである..


Ruby設計者がこのような仕組みを採用した理由は
容易に想像がつくだろう
そう Rubyでは2も3も109も17320508も
Fixnumというクラスにリンクしていて
これらの数に対する問い合わせがあったときには
すべてFixnumが答えを用意しているのだ
そうすればこれらの数がそれぞれ個別に
130個のメソッドを持つ必要はなくなる

メソッド定義

Rubyで「プログラミングをする」というのは
「オブジェクトにメッセージを送る」とほぼ同義である
自由で柔軟なプログラミングを実現するため
Rubyの設計者は大量のメソッドを用意した
しかしもちろんそれだけでは
真に自由なプログラミングができるわけではない
独自メソッドが定義できてこそ
本当のプログラミングが実現できる
そしてRubyはそれをあなたに許す


今あなたが1に挨拶したら
返事がほしいとしよう
1の中身は空っぽで
Fixnumクラスがメソッドを持っていることを思い出そう
そう あなたのメソッドもFixnumクラスに追加すればいい

>> class Fixnum
>>  def hello
>>    "Yo!"
>>  end
>> end


さあ あなたから1に挨拶を!

>> 1.hello
=> "Yo!"


もう少し気の利いた返事がほしいなら
メッセージが別のオブジェクトを
受け取れるようにすればいい

>> class Fixnum
>>   def hello(name)
>>     "Yo! #{name}"
>>   end
>> end


そしてあなたの名前を渡す

>> 1.hello("Charlie")
=> "Yo! Charlie"


ここまでの説明が理解できたなら
挨拶に答えられるようになったのが
1だけではないということが分かるだろう

>> 2.hello("Ken")
=> "Yo! Ken"
>> 24.hello("ジャック・バウアー")
=> "Yo! ジャック・バウアー"
>> 365.hello(365)
=> "Yo! 365"


そう今やFixnumクラスに属する
すべての数字が
あなたが作ったhelloに答えられる



上のコードの最後の答えを見て
ドキリとする人もいるかもしれない
メソッドに渡すオブジェクトを「引数」と呼ぶけれども
渡されるものがオブジェクトである限り
Rubyはそれを引数として受け入れる
上の2つは文字列のオブジェクトを引数として渡し
最後のものは今まで見てきた数のオブジェクトを渡している
すでにオブジェクトからの応答がオブジェクトであることを
理解したあなたなら次のコードも理解できるだろう

>> 1.hello(2.hello("Ma"))
=> "Yo! Yo! Ma"


続き