他言語からのRuby入門

Rubyのコードを目にすると、 他の言語と似た部分があることに気が付くはずです。 構文の多くは、(他の言語の中でも特に)PerlやPython、 Javaプログラマーにとって馴染みのあるものになっています。 もしあなたがそうした言語に慣れ親しんでいるのなら、 Rubyを学ぶのはおそらくどうってことないはずです。

このドキュメントは2部構成になっています。 このページでは、プログラミング言語XからRubyへ移ってくる際に役立つ情報をざっと紹介します。 個別のページでは、Rubyの主な言語機能を紹介しつつ、 あなたが慣れ親しんできた言語との比較を行います。

求められていること: 言語XからRubyへ

重要な言語機能と知っておくべきこと

ここでは、Rubyを学習する中で出会ういくつかの主要な機能について、 参照先やヒントを示します。

イテレーション

Rubyの特徴であるブロックとイテレータは、 これまでにあまり見たことがない、あるいは使い慣れていないものかもしれません。 (CやC++、1.5以前のJavaのような)インデックスを使った繰り返し処理や、 (Perlのfor (@a) {...}やPythonのfor i in aList: ...のような) リストをループする処理の代わりに、 Rubyでは次のようなコードをよく見ることになるでしょう。

some_list.each do |this_item|
  # ここはブロックの中になります。
  # this_itemを扱う処理をここに書きます。
end

each(やcollectfindinjectsortなど)について詳しくは、 ri Enumerableを参照してみてください(そして、次に ri Enumerable#some_methodとして具体的なメソッドを参照してみてください)。

すべては値

式と文に違いはありません。 すべては値を持ちます。nilであっても例外ではありません。 Rubyでは次のように書くことが可能です。

x = 10
y = 11
z = if x < y
      true
    else
      false
    end
z # => true

シンボルは軽量文字列ではない

多くのRuby初学者はシンボルが何であるか、どう使えばよいのかを理解するのに苦戦します。

シンボルは識別子として記述するのに適しています。 シンボルは、どんな物かではなく、何者であるかがすべてです。 irbを立ち上げて、次の違いを見てみてください。

irb(main):001:0> :george.object_id == :george.object_id
=> true
irb(main):002:0> "george".object_id == "george".object_id
=> false
irb(main):003:0>

object_idメソッドはオブジェクトのIDを返します。 もし二つのオブジェクトが同じobject_idを持っていれば、 それらはメモリ上の同じ実体を指すものであると言えます。

上記で見たとおり、一度でもシンボルを使ったなら、 同じ文字からなるシンボルは、いずれもメモリ内の同じオブジェクトを参照します。 同じ文字で表された2つのシンボルは、同じobject_idを指します。

次に文字列(“george”)の方を見てみましょう。 object_idは一致していません。 これは、二つの文字列が異なる実体を指していることを示しています。 新しい文字列を使うと、Rubyは毎回その文字列のために新しいメモリ領域を確保します。

シンボルを使うか文字列を使うかで迷ったなら、 ハッシュのキーのようにオブジェクトを識別したいのか、 それとも前述の”george”などのようにコンテンツを表したいのかを、 選択の指針にしてください。

すべてはオブジェクト

「すべてはオブジェクト」は誇張ではありません。 クラスや整数でさえオブジェクトです。 他のオブジェクトと同じように扱うことができます。

# 以下のクラス定義と同じことを行っています
# class MyClass
#   attr_accessor :instance_var
# end
MyClass = Class.new do
  attr_accessor :instance_var
end

可変な定数

定数は厳密な意味での定数ではありません。 初期化済みの定数を変更したとしても、 警告はされますが、プログラムは停止しません。 だからと言って、定数を再定義するべきだということではありません。

名前付けの規約

Rubyにはいくつか名前付けについての規約があります。 大文字から始まる識別子は定数です。 ドルマーク($)から始まる識別子はグローバル変数、 @から始まる識別子はインスタンス変数、 @@から始まる識別子はクラス変数になります。

メソッド名は大文字から始めることもできます。 けれど、それは次のような混乱を招くことになるでしょう。

Constant = 10
def Constant
  11
end

こうすると、Constantは10ですが、Constant()は11になります。

キーワード引数

メソッドはRuby 2.0から、Pythonのように、 キーワード引数を定義できるようになりました。

def deliver(from: "A", to: nil, via: "mail")
  "Sending from #{from} to #{to} via #{via}."
end

deliver(to: "B")
# => "Sending from A to B via mail."
deliver(via: "Pony Express", from: "B", to: "A")
# => "Sending from B to A via Pony Express."

普遍の真理

Rubyでは、nilfalseを除くすべてのものは真と評価されます。 CやPythonを始めとする多くの言語では、0あるいはその他の値、空のリストなどは 偽と評価されます。次に示すPythonコードをみてください (他の言語でもだいたい同じようなコードになるでしょう)。

# Python版
if 0:
  print("0 is true")
else:
  print("0 is false")

このコードを実行すると「0 is false」と出力されます。 同じコードをRubyで書くと以下のようになります。

# Ruby版
if 0
  puts "0 is true"
else
  puts "0 is false"
end

このコードを実行すると、 「0 is true」が出力されることになります。

アクセス修飾子はスコープの最後まで適用される

次のRubyコードを見てください。

class MyClass
  private
  def a_method; true; end
  def another_method; false; end
end

another_methodがpublicメソッドになることを期待するかもしれませんが、 結果はそうなりません。 privateアクセス修飾子はスコープの終わりか、他のアクセス修飾子が あらわれるまで継続されます。 デフォルトでは、メソッドはpublicになります。

class MyClass
  # a_methodはpublicです
  def a_method; true; end

  private

  # another_methodはprivateです
  def another_method; false; end
end

publicprivateprotectedは実際にはメソッドになるので、 引数を受けることができます。これらにシンボルを渡した場合には、 そのメソッドの可視性が変更されます。

アクセス制御

Javaでは、publicは誰でもアクセスできることを意味しています。 そして、protectedはクラスおよび継承関係にあるクラスのインスタンス、 クラスと同じパッケージにあるクラスのインスタンスからアクセスできること、 privateはクラスのインスタンスからのみアクセスできることを、 ぞれぞれ意味します。

Rubyでは扱いが若干異なります。 publicはそのままの意味になります。 privateは、レシーバなしで呼び出すことができる場合に、 そのメソッドへアクセス可能となります。 つまり、selfのみがprivateメソッドを呼び出す際のレシーバとなります。

protectedは気をつけて扱う必要があります。 protectedメソッドはクラスか継承関係にあるクラスのインスタンスからのみ 呼び出すことができます。しかしまた、 レシーバとしてインスタンスを指定しても呼び出すことができてしまいます。 以下に例を示します(The Ruby Language FAQから引用)。

class Test
  # デフォルトはpublic
  def identifier
    99
  end

  def ==(other)
    identifier == other.identifier
  end
end

t1 = Test.new  # => #<Test:0x34ab50>
t2 = Test.new  # => #<Test:0x342784>
t1 == t2       # => true

# ここで`identifier'をprotectedにする。
# protected はレシーバとして`other'を許容するため、これは動作する。

class Test
  protected :identifier
end

t1 == t2  # => true

# ここで`identifier'をprivateにする。

class Test
  private :identifier
end

t1 == t2
# NoMethodError: private method `identifier' called for #<Test:0x342784>

クラスは開いている

Rubyのクラスは開いています。 いつでもクラスを開いて、定義を足したり、変更することができます。 Integerや、すべてのオブジェクトの祖先であるObjectのようなクラスであっても、 自由に再定義することが可能です。Ruby on Railsは、次のような Integerに時間を扱うメソッド群を定義しています。

class Integer
  def hours
    self * 3600 # 1時間あたりの秒数を返します
  end
  alias hour hours
end

# 1月1日の0時0分から14時間後
Time.mktime(2006, 01, 01) + 14.hours # => Sun Jan 01 14:00:00

不思議なメソッド名

Rubyでは、メソッド名の最後に疑問符(?)や感嘆符(!)が使われることがあります。 慣習的に、問い合わせ系のメソッドの最後には疑問符が使われます (例: レシーバが空の場合にtrueを返すArray#empty?)。 また、使用に危険を伴うメソッドの最後には感嘆符が使われます (例: selfあるいは引数の内容を書き換えるようなメソッド。exit!など)。 けれど、危険なメソッドすべてがこの慣習に従っているわけでも ないことに注意してください。 Array#replaceは、与えられた配列の内容で配列の内容を置き換えます。 この操作は、自身を変更しないようなメソッド名とは意に反する振る舞いをします。

特異メソッド

特異メソッドはオブジェクト単位のメソッドです。 特異メソッドは、定義したオブジェクトからだけ利用できるメソッドになります。

class Car
  def inspect
    "Cheap car"
  end
end

porsche = Car.new
porsche.inspect # => Cheap car
def porsche.inspect
  "Expensive car"
end

porsche.inspect # => Expensive car

# 他のオブジェクトには影響しない
other_car = Car.new
other_car.inspect # => Cheap car

「存在しなかった」メソッド

Rubyはメッセージに対応するメソッドを見つけられなかったとしても諦めません。 その場合は、見つけられなかったメソッド名と引数と共に、 method_missingメソッドを呼び出します。 method_missingメソッドはデフォルトではNameError例外を投げますが、 アプリケーションに合うように再定義することもできます。 実際、多くのライブラリがそのようにしています。 以下がその例です。

# idは呼び出されたメソッド名です。
# *構文は「arguments」という名前の配列に
# 呼び出されたメソッドに渡されたすべての引数を格納します。
def method_missing(id, *arguments)
  puts "Method #{id} was called, but not found. It has " +
       "these arguments: #{arguments.join(", ")}"
end

__ :a, :b, 10
# => Method __ was called, but not found. It has these
# arguments: a, b, 10

このコードは単に呼び出されたメソッドの詳細を出力しているだけですが、 ここには何を書いても良いので、メッセージを受け取って適切な処理を行えます。

関数呼び出しではなくメッセージ送信

メソッド呼び出しは実際には他のオブジェクトへのメッセージ送信です。

# これは
1 + 2
# これと同じで...
1.+(2)
# つまりこういうことです。
1.send "+", 2

ブロックは作りかけのオブジェクト

ブロック(実際にはクロージャ)は標準ライブラリでもすごく使われています。 ブロックを呼び出すには、yieldを使うか、引数リストに特別な引数を追加して それをProcオブジェクトにします。以下がその例です。

def block(&the_block)
  # この内側では、the_blockはメソッドに渡されたブロックになります。
  the_block # ブロックが返ります
end
adder = block { |a, b| a + b }
# adderはここでProcオブジェクトになります
adder.class # => Proc

Proc.newにブロックを渡すか、lambdaメソッドを呼び出すことで、 メソッド呼び出しの外側でブロックを作成することもできます。

同様に、メソッドもまた作りかけのオブジェクトです。

method(:puts).call "putsはオブジェクト!"
# => putsはオブジェクト!

演算子は糖衣構文(シンタックスシュガー)

Rubyにおけるほとんどの演算子は糖衣構文です。 いくつかの優先順位規則にもとづいて、メソッド呼び出しを単に書き換えているだけです。 たとえば、Integerクラスの+メソッドを次のようにオーバーライドすることもできます。

class Integer
  # できるけれど、しないほうがいいでしょう
  def +(other)
    self - other
  end
end

C++のoperator+などは必要ありません。

[][]=といったメソッドを定義すれば、配列のようなスタイルでアクセスすることもできます。 (+1や-2みたいな)単項の+や-を定義するには、+@-@といったメソッドを定義する必要があります。 けれど、以下の演算子は糖衣構文ではありません。 これらはメソッドではないので、再定義できません。

=, .., ..., not, &&, and, ||, or, ::

加えて+=*=などはvar = var + other_varvar = var * other_var などの処理の略記法になり、これらも再定義できません。

もっと知りたい

Rubyについてもっと知りたくなったのなら、 ドキュメントの その他のコンテンツを見てみてください。