Rubyクイックスタート

文:Steve Hayes(Builder AU) 翻訳校正:村上雅章・野崎裕子
2007-12-13 08:00:00
  • このエントリーをはてなブックマークに追加

 ここで、Rubyが実際にどう記述されるのかを示す、Rubyのちょっとしたソースコードを見てみることにしよう。始めるにあたって必要なものは、Rubyインタープリタと、コマンドラインへのアクセスだけだ。Mac OS XではRubyが標準搭載されている。そしてWindowsではOne-Click Ruby Installer for Windowsが提供されている。また、Linuxではおそらく、Rubyパッケージをダウンロードし、インストールする必要があるだろう。以下のようにすることで、ファイルを作成することなく、コマンドラインから直接Rubyを実行することが可能である。

> ruby -e "puts('Hello World!')"
Hello World!

 -eフラグをつけることで、その次にくるパラメータを実行すべきコードとして扱うようRubyに命令している。この例で用いている"puts"は、与えられた引数を改行と共にSTDOUT(標準出力)に出力するメソッドである。Rubyにおけるメソッド起動では括弧がオプションとなっているため、次のような例の方がよく見かけるはずだ。

> ruby -e "puts 'Hello World!'"

 Rubyのコードは行によって区切られる(デフォルトでは行末がステートメントの最後と見なされる)が、以下の例のようにセミコロンを用いて区切ることも可能だ。

> ruby -e "puts 'Hello World!';puts 'Hello Ruby!'"
Hello World!
Hello Ruby!

 もちろん、コマンドラインからステートメントを実行することでできることには限りがあるため、Rubyではファイルの内容を実行することも可能となっている。Rubyファイルのデフォルトの拡張子は.rbである。

# file: hello_world.rb

puts 'Hello World!'
puts 'Hello Ruby!'

> ruby hello_world.rb
Hello World!
Hello Ruby!

 上記のコードでは、また別のRubyの規約が示されている--ファイル名やメソッド名、変数名は、Javaを始めとする他言語のようにキャメル記法(複合語をこういった名前に使用する場合に、各単語の1文字目のみを大文字にして連結する記述法)を用いて記述するのではなく、単語間をアンダースコアでつないで記述するのが一般的である。しかし、この後すぐに見てもらうように、Rubyでもクラス名にはキャメル記法が用いられる。なお、#文字の後に記述されている内容はすべてコメントとなる。

 Rubyは純粋なオブジェクト指向言語であると述べたことで、どのようなオブジェクトが先ほどのメソッド"puts"を受け取るのだろうかと考えている読者の方もおられるかもしれない。Rubyでは、疑似変数"self"を用いることでカレントオブジェクトを参照することができる。

> ruby -e "puts self.class"
Object

 コマンドラインからステートメントを実行した場合、それらのステートメントは、Rubyインタープリタによって生成されたObjectのインスタンスへと送られることになる。

 では、クラスを作成する際に用いるシンタックスについて簡単に説明してみよう。

# file: say_hello_01.rb

class SayHello

    def say_it
        puts 'Hello World!'
        puts 'Hello Ruby!'
    end

end

puts SayHello.new.say_it

 上記の例では、新しいクラスと、"say_it"というインスタンスメソッドを定義した後で、そのクラスのインスタンスを新たに生成し、そのインスタンスの"say_it"を起動している。この例からRubyの持つ柔軟性の一端を垣間見ることができる--クラスを作成し、同じファイル内でそのクラスに依存したスクリプトを実行することができるのだ。Rubyの場合においても、多くのファイルにはそのファイル名に対応したクラス定義が含まれているものの、ファイルにはどのような内容のものでも記述することができる。このことはRubyに高い柔軟性をもたらすものの、publicクラスを検索する際にその名前のファイルを検索することになるJavaのような言語に慣れているプログラマーにとっては、頭の切り替えが必要となる。

 以下の例は、同じクラスだがいくつかのパラメータを受け取るようになっている。

# file: say_hello_02.rb

class SayHello

    def say_it(message1, message2)
        puts message1
        puts message2
    end
  
end

SayHello.new.say_it('Hello World!', 'Hello Ruby!')

 パラメータには型宣言がなく、メソッドには戻り型がないという点に注意されたい。これは、Rubyが動的に型付けされる言語であるため、型を指定する必要がないためである(実際のところ、指定することはできない!)。

 ここまでの例では、組み込み型としてはStringのみしか使用していないため、よく使用される他の型のいくつかについても使ってみることにしよう。Rubyは配列やハッシュ/マップに対するサポートが充実している。リテラルの配列はブラケット([])を用いて作成するため、1〜5までの整数リテラルからなる配列は[1, 2, 3, 4, 5]のように記述することができる。しかし、配列内のオブジェクトは同じ型でなければならないという制限がないため、[1, 'ruby', 2.718, Magazine.new]といった配列も簡単に作成することができる。配列へのアクセスにはブラケット記法を用い、配列のインデックスは0から開始される。

# file: arrays.rb

array = [1, 'ruby', 2.718, Magazine.new]

array[0] # => 1
array[1] # => "ruby"
 また、ハッシュの区切りとして中括弧({})、そしてキーと値のペアの表示に=>を用いることでリテラルのハッシュを作成することもできる。キーに対する制限は一切無いため、どのようなオブジェクトでもキーとして使用することができ、値として使用することもできる。値へのアクセス方法は、配列の要素に対するものと同じである。

# file: hashes.rb

hash = { 1 => 'one', 'message' => 'Hello World!'}

hash[1] # => "one"
hash['message'] # => "Hello World!"

 Rubyでは配列とハッシュが多用される。その理由の1つとして、それらの内容に対して順番に同じ処理を繰り返すのが簡単であるという点を挙げることができる。Rubyにおける基本的な繰り返し手法は"each"である。これは、ブロックと呼ばれる構造によって定義されたアクションを、コレクション中の各要素に対して順番に適用することで繰り返し処理を行うというものである。ブロックというものは他の言語でも存在するが、Rubyでは、必要な時にその場でブロックを作成することが簡単にできるようになっているのである。例えば、1から5までの整数の2乗を出力するには、"each"を用いて次のようなコードを書けばよい。

[1, 2, 3, 4, 5].each { |n| puts n*n }

 {}の中に記述されているコードがブロックであり、||の中に記述されている変数がイテレータ変数である。そして、ブロックが起動されるたびに、イテレータ変数にはコレクションの要素が格納されることになり、ブロックは各要素に対して1度起動される。この例では配列を用いたが、"each"は、コレクションとして扱うことができる複数のクラスで実装されている。ハッシュの繰り返し処理に"each"を用いる場合、イテレータ変数にはキーと値の配列が格納されることになる。そのため、次のコードもまた、1から5までの整数の2乗を出力する(ただし、ハッシュではその順番が保証されない)。

hash = { 1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five' }
    hash.each { |key_value| puts key_value[0] * key_value[0] }

 また、RubyにはRangeというオブジェクトがあり、これにも"each"が実装されているため、以下のコードを用いても同様の結果が得られる。

(1..5).each { |n| puts n*n }

 Rubyの繰り返し処理は、この標準的なアプローチと、Enumerationモジュールに含まれている拡張を組み合わせることで実装されている(モジュールについての詳細は次回に説明する)。Enumerationモジュールには以下のメソッドが実装されている(そのうちのいくつかにはエイリアス、すなわち別名がつけられている)。

  • select / find_all: ブロック内に記述されている条件に適合する要素すべてからなるコレクションを返す
  • collect / map: ブロック内に記述されている処理を各要素に対して行い、それらの結果からなるコレクションを返す
  • detect / find: ブロック内に記述されている条件に適合する最初の要素を返す
  • reject: ブロック内に記述されている条件に適合しない要素すべてからなるコレクションを返す
  • any?: ブロック内に記述されている条件に適合する要素が1つでも存在している場合にtrueを返す
  • all?: ブロック内に記述されている条件にすべての要素が適合した場合にtrueを返す

 以下は、こういったメソッドそれぞれの実行例である。

(1..5).select {|n| n > 2}   # => [3, 4, 5]
(1..5).find_all {|n| n > 2} # => [3, 4, 5]
(1..5).collect {|n| n*n }   # => [1, 4, 9, 16, 25]
(1..5).map {|n| n*n }       # => [1, 4, 9, 16, 25]
(1..5).detect {|n| n > 2}   # => 3
(1..5).find {|n| n > 2}     # => 3
(1..5).reject {|n| n > 2}   # => [1, 2]
(1..5).any? {|n| n > 2}     # => true
(1..5).all? {|n| n > 2}     # => false

 Rubyではシンタックス上のオーバーヘッドがほとんどないうえ、車輪の再発明をしなくてもよいように数多くの有用な機能が基本ライブラリで提供されている。

 このため、Rubyはとっつきやすい言語となっており、ここまでの例でもそのとっつきやすさを感じてもらえたはずだ。また、Rubyはシンタックスの表現力が高く、柔軟性も高いため、ドメイン固有言語(DSL:Domain Specific Language)の作成に用いられることが多く、Ruby on Railsも、言うなればウェブアプリケーションの構築に用いられるDSLである。Rubyのメソッド定義には、オプションのパラメータに対するデフォルト値の提供や、可変長パラメータ(これらのパラメータは配列へとまとめられる)、名前付きキーを持つハッシュマップとして受け渡されるパラメータを含めることが可能である。そして、こういったことすべてのお陰で、適用分野の言語をうまく模倣したDSLの作成が、経験を少し積んだだけで行えるようになるのだ。

 Ruby on Railsの詳細を説明する時間もスペースもないが、Railsに付属している永続フレームワークであるActiveRecordの例をいくつか挙げて簡単に説明しておきたい。Libraries(図書館)とBooks(本)というテーブルを保持するデータベースがあり、Librariesには数多くのBooksが保持され、すべてのBooksはLibrariesの一部でなければならないという条件があるとした場合、こういったテーブルとその関係を以下のように表すことができる。

class Library < ActiveRecord::Base

has_many :books, :dependent => :destroy

end

class Book < ActiveRecord::Base

  belongs_to :library
  validates_presence_of :library

end

 これらのクラスを定義する際に行われるメソッド起動によって、こういったオブジェクトを管理するために必要なすべてのアクセッサが、直感的な名前で作成される。このため、次のような記述が可能になる。

book.library = a_different_library

 また、次のような記述も可能である。

library.books << a_new_book

 ここで出てきた<<は、コレクションに新たな要素を追加する演算子である。ActiveRecordを永続的DSLとして用いることで、データベースの内容を反映するドメインモデルを作成しておき、特定のドメインに特化した操作によってそれを拡張していくということが簡単に行えるわけだ。

 Rubyの特徴をまとめると、動的に型付けされ、テキスト指向であるうえ、DSLの作成を簡単に行えるだけの高い柔軟性と高い表現力を持ったシンタックスを備え、強力な組み込みライブラリが提供された完全なオブジェクト指向言語であるということになる。願わくば、このコラムでRubyの特徴について知ったあなたが、もう少し調べてみる価値のある言語だと思ってくれますように。あるいは少なくとも、Rubyに関する私の次回コラムを楽しみにしてくれますように。

この記事は海外CNET Networks発のニュースをシーネットネットワークスジャパン編集部が日本向けに編集したものです。海外CNET Networksの記事へ

このサイトでは、利用状況の把握や広告配信などのために、Cookieなどを使用してアクセスデータを取得・利用しています。 これ以降ページを遷移した場合、Cookieなどの設定や使用に同意したことになります。
Cookieなどの設定や使用の詳細、オプトアウトについては詳細をご覧ください。
[ 閉じる ]