Ruby とは
Ruby はスクリプト言語の手軽さで、本格的なオブジェクト指向プログラミングが可能な、オブジェクト指向スクリプト言語です。開発者は日本人、まつもと ゆきひろ 氏で、誕生日(初公開日)は1993年2月24日です。まだ比較的知名度は低いですが、着実にファンを増やしています。
まつもと氏によると、他のプログラミング言語に対する Ruby の特徴は以下のようになります。
- Perl に対して:素直で覚えやすく、オブジェクト指向である
- Python に対して:UNIX 風、純オブジェクト指向である
- Java に対して:インタプリタ型、変数に型がない
- Tcl に対して:豊富なデータ型を備える
Ruby のインストール
情報教育システムの Linux 環境には Ruby がすでにインストールされています。 自宅の Windows 環境で Ruby を試してみたくなったら、以下の手順でパッケージをインストールするとよいでしょう(2004年11月15日現在それぞれ最新)。
- Ruby 本体:ruby182-14RC9.exeを実行する。
- Ruby/GTK2:ruby-gtk2-0.10.0-2-i386-msvcrt-1.8.zipを展開して Ruby のインストールフォルダにコピーする。
- GLADE for Windows:gtk-win32-aio-2.4-rc22.exeを実行する。
- 環境変数 PATH に、ruby-install-dir\bin;gtk-install-dir\bin;gtk-install-dir\lib が含まれていることを確認して、なければ追加しておく。
これで準備完了(のはず)です。コマンドプロンプトを立ち上げて、以下がエラーなく実行できるか確かめましょう。
(例)
(バージョン確認)
C:\>ruby -v
ruby 1.8.2 (2004-07-29) [i386-mswin32]
C:\>
(gtk2 が利用できることの確認)
C:\>ruby -e "require 'gtk2'"
C:\>
(gtk2 のサンプルプログラムの実行。窓が現れれば正解。)
C:\>ruby -e "require 'gtk2';Gtk.init;Gtk::Window.new.set_title('Hello Ruby-GNOME2 World!').show;Gtk.main"
より詳しいインストール方法がここにあります。うまくいかない人は参照してください。
Ruby の実行
Ruby プログラムの実行方法を紹介します。
コマンドラインから実行する
コマンドラインから、Ruby の引数に直接プログラムを与えます。ワンライナーともいいます。
$ ruby -e 'print "Hello world\n"'
Hello world
$
スクリプトファイルから実行する(1)
プログラムをスクリプトファイルに記述し、Ruby の引数として与えます。
$cat hello.rb
print "Hello world\n" $ruby hello.rb
Hello world $
スクリプトファイルから実行する(2)
スクリプトファイルに実行権限を与え、直接スクリプトを起動します。
$cat hello2.rb
#!/usr/bin/ruby print "Hello world\n" $chmod +x hello2.rb
$./hello2.rb
Hello world $
Ruby の対話環境 irb を利用する
Ruby の対話環境 irb を利用して、対話的に Ruby を実行します。なお irb を終了するには exit か quit と入力するか、Ctrl-D を入力します。
$irb
irb(main):001:0>print "Hello world\n"
Hello world => nil irb(main):002:0>
irb は、手軽にスクリプトの動作を確認できるだけでなく、以下のような特長があります。
- 各行の返り値を確認できる。
- 変数名やメソッド名を補完できる。~/.irbrc に require "irb/completion" と書いておけばよい。
- サブirbでコンテキストを切り替えられる。
irbのより詳しい解説はここを参照してください。
Ruby の特徴
Ruby の詳細に入る前に、簡単なプログラム例を通して Ruby の強力さに触れてみましょう。
正規表現の例(grep)
$cat grep.rb
$pat = ARGV.shift while gets print if /#{$pat}/ end $ruby grep.rb e grep.rb
while gets end
〔補足〕
Python と違って、インデントの深さは自由です。
〔以上補足〕
異なるデータ型を共通に扱う例
$irb
irb(main):001:0>a = [123, "abc", [4, 5, 6]]
=> [123, "abc", [4, 5, 6]] irb(main):002:0>a.each do |i|
irb(main):003:1*puts i
irb(main):004:1>end
123 "abc" 4 5 6 => [123, "abc", [4, 5, 6]]
標準データ型クラスの関数オーバーライドの例
$irb
irb(main):001:0>1 + 2 + 3 + 4 + 5
=> 15 irb(main):002:0>class Fixnum
irb(main):003:1>def + (a)
irb(main):004:2>self * a
irb(main):005:2>end
irb(main):006:1>end
=> nil irb(main):007:0>1 + 2 + 3 + 4 + 5
=> 120
〔補足〕
もちろん、こんなことをしてしまっては以降二度と足し算ができなくなります。
〔以上補足〕
ブロック渡しの例
$irb
irb(main):001:0>def three_times
irb(main):002:1>yield
irb(main):003:1>yield
irb(main):004:1>yield
irb(main):005:1>end
=> nil irb(main):006:1>i = 1; three_times { i *= 2 }
=> 8 irb(main):007:1>three_times { print "abc\n" }
abc abc abc => nil
Ruby の基本文法
オブジェクト指向の原則
Ruby ではすべてがオブジェクトであり、オブジェクトが備えるメソッドを呼び出して処理を行います。
string = "ABCDE" len = string.length
コメント
print "Hello world\n" # シャープ以降はコメント =begin ↑この2行で挟まれた部分は ↓すべてコメント =end
セパレータ
print "abc"; print "def" # ';' はセパレータ print "123" # 1行に1文の場合は ';' は不要
データ型
a = 123 # 数値型 b = "abc" # 文字列型 c = [1, 2, 3] # 配列型 (c[0] == c[-3] == 1) d = {100 => "perfect", "absent" => 0} # ハッシュ型(d[100] == "perfect") e = 1..2 # 範囲型
〔補足〕
変数に型はなく、データに型があります。変数はオブジェクトへのリファレンスです。
〔以上補足〕
変数
VAR = "定数" # 大文字で始まる $var = "グローバル変数" # '$' で始まる def func var = "ローカル変数" # 小文字で始まる end class Class @@var = "クラス変数" # '@@' で始まる def initialize @var = "インスタンス変数" # '@' で始まる end end
演算子
a = 100 # 代入 a, b = 10, 20 # 多重代入 a = (1 + 2) / (3 - 4) * 5 # 四則演算 a = (1 && 2) and (3 || 4) or !(5) # 論理演算 a = 7 % 2 # 剰余 a = 3 ** 0.5 # 累乗(この場合√3) a = (1 == 2) or (3 != 4) or (5 < 6) or (7 <= 8) # 比較演算
〔補足〕
&& や || は and や or よりも優先順位が高いです。
演算子もやはり、実はすべてメソッドです。(先のオーバーライドの例参照)
〔以上補足〕
クラス
オブジェクト指向言語では、オブジェクトを単位として処理を行います。 クラスとは、あるオブジェクトに関する定義と挙動をまとめたものです。
$cat animal.rb
class Animal def initialize @leg = 4 @word = "ほげ" end def speak (n=1) n.times { print @word } print "\n" end end class Monkey < Animal # 継承 def initialize # オーバーライド @leg = 2 @word = "うっきー" end end class Lion < Animal # 継承 def initialize # オーバーライド @word = "がおー" end end animal = Animal.new # インスタンス生成 monkey = Monkey.new lion = Lion.new animal.speak(2) # 多態性の例 monkey.speak lion.speak(3) $ruby animal.rb
ほげほげ うっきー がおーがおーがおー
〔補足〕
〔以上補足〕
文字列
irb(main):001:0>p (("a" * 2) + "b") * 3
# 文字列の連結と繰り返し "aabaabaab" => nil irb(main):002:0>p "abcdefg"[3 .. 5]
# 部分文字列の参照 "def" => nil irb(main):003:0>a = "abcdefg"
=> "abcdefg" irb(main):004:0>a[3 .. 5] = "xyz"
# 部分文字列の置換 => "xyz" irb(main):005:0>a
=> "abcxyzg" irb(main):006:0>p "abc\n"
# 制御文字を解釈 "abc\n" => nil irb(main):007:0>p 'abc\n'
# 制御文字もそのまま "abc\\n" => nil irb(main):008:0>p 1.to_s + 2.3.to_s + [4, 5].to_s
# 文字列への変換 12.345 => nil irb(main):009:0>p "12".to_i + "34".to_i
# 整数への変換 46 => nil irb(main):010:0>p "a = #{a}"
# #{変数} は展開される "a = abcxyzg" => nil irb(main):011:0>p "abcdefg".length
# 文字列長 7 => nil irb(main):0123:0>p "abcde".reverse
# 反転する "edcba" => nil irb(main):013:0>p "abccabbcabbbccba".gsub(/ab+/, "xy")
# 文字列の置換 "xyccxycxyccba" => nil
配列
irb(main):001:0>a = [1, 3, 4, 5, 7]
# 配列の生成 => [1, 3, 4, 5, 7] irb(main):002:0>b = [2, 3, 5, 7, 9]
=> [2, 3, 5, 7, 9] irb(main):003:0>a.size
# 大きさを返す => 5 irb(main):004:0>a | b
# 和集合 => [1, 3, 4, 5, 7, 2, 9] irb(main):005:0>a & b
# 積集合 => [3, 5, 7] irb(main):006:0>a - b
# 差集合 => [1, 4] irb(main):007:0>a.shift
# 先頭を取り出して削除 => 1 irb(main):008:0>a
=> [3, 4, 5, 7] irb(main):009:0>a.join("/")
# 指定文字で区切って連結 => "3/4/5/7" irb(main):010:0>a << 6
# 要素の追加 => [3, 4, 5, 7, 6] irb(main):011:0>(a | b).sort
# ソート => [2, 3, 4, 5, 6, 7, 9] irb(main):012:0>a.map { |i| i * i }
# 各要素を加工した配列を生成 => [9, 16, 25, 49, 36]
正規表現
irb(main):001:0>reg = /osaka/
# 正規表現オブジェクトの生成。 => /osaka/ irb(main):002:0>reg = Regexp.new("osaka")
# 別の生成方法。 => /osaka/ irb(main):003:0>/osaka/ =~ "abc_osaka_xyz"
# マッチする時は出現位置を返す => 4 irb(main):004:0>/osaka/ =~ "tokyo"
# マッチしない時は nil を返す => nil irb(main):005:0>/^a(bc)*[d-f]g+h?i/
# 行頭がaで、bcが0個以上繰返し、 => /^a(bc)*[d-f]g+h?/ # d,e,fのどれかが続き、gが1個 # 以上あり、hが0か1個ありiがある irb(main):006:0>/^a(bc)*[d-f]g+h?i/ =~ "adgi"
=> 0 irb(main):006:0>/^a(bc)*[d-f]g+h?i/ =~ "abcbcfggghixyz"
=> 0 irb(main):006:0>/^a(bc)*[d-f]g+h?i/ =~ "acbcbfgggi"
=> nil
組込み変数
$_ : gets などで最後に読み込んだ文字列 $0 : 実行中の Ruby スクリプト名 $* : Ruby スクリプトに与えられた引数 $& : もっとも最近の正規表現にマッチした文字列 $. : 最後に読んだ入力ファイルの行番号 ARGV : $* と同義 ARGF : 指定した引数を連結した仮想的な1つのファイルを示すオブジェクト
制御構文
条件分岐
if 文
a = 1 if a == 1 puts "a は 1 です" elsif a == 2 puts "a は 2 です" else puts "a はたくさんです" end puts "a は 1 です" if a == 1 # 後置型(修飾詞)
〔補足〕
a == 1 and puts "a は 1 です" # and による条件文
〔以上補足〕
unless 文
a = 2 unless a == 1 puts "a は 1 ではないです" else puts "a は 1 です" end puts "a は 1 ではないです" unless a == 1 # 後置型(修飾詞)
〔補足〕
a == 1 or puts "a は 1 ではないです" # or による条件文
〔以上補足〕
case 文
case Time.now.hour # 現在時刻を整数で取得 when 6..9 # 範囲オブジェクトで条件分岐 puts "おはよう" when 9..17 puts "こんにちは" when 17..24 puts "こんばんわ" when 0..6 puts "おやすみ" else puts "そんな時計あるかい" # どれにも該当しない場合 end
〔補足〕
if (18..35) === age puts "ストライクゾーン" end
〔以上補足〕
繰り返し
while 文
$cat factorial.rb
def factorial (i) a = i; while i > 1 i -= 1 a *= i end a # 返り値(while 文は nil を返す) end print factorial(gets.chop.to_i) # 入力文字列.末尾の改行削除.数値化 $ruby factorial.rb
10
3628800
〔補足〕
$ruby factorial.rb
100
933262154439441526816992388562667004907159682643816214685929638952175999932 299156089414639761565182862536979208272237582511852109168640000000000000000 00000000
〔以上補足〕
until 文
def factorial (i) a = i; until i <= 1 # while a ⇔ until !a i -= 1 a *= i end a end print factorial(gets.chop.to_i)
for 文
a = [1, 2, 3] for i in a puts i end
times メソッド
10.times do # もちろん、変数にも使える puts "hello" end
サンプル(数当てゲーム)
srand a = rand(100) while 1 do print "いくつでしょう?" i = gets.chop.to_i if a == i then puts "あたり!" break elsif a > i then puts "もっとおおきいよ" else puts "もっとちいさいよ" end end
イテレータ
イテレータとは、ブロック付きのメソッド呼び出し(メソッドへのブロック渡し)を実現する機構で、Ruby の大きな特徴的機能です。
文字列のイテレータ
irb(main):001:0>a = "abc\ndef\nghi"
=> "abc\ndef\nghi" irb(main):002:0>a.each do |i|
# do ... end は { ... } としてもよい irb(main):003:1*puts i
irb(main):004:1>end
abc def ghi => "abc\ndef\nghi"
配列のイテレータ
irb(main):001:0>a = [1, 10, 100]
=> [1, 10, 100] irb(main):002:0>a.each do |i|
irb(main):003:1*puts i
irb(main):004:1>end
1 10 100 => [1, 10, 100]
ハッシュのイテレータ
irb(main):001:0>a = {"父" => 50, "母" => 48, "長男" => 20}
=> {"父" => 50, "母" => 48, "長男" => 20} irb(main):002:0>a.keys.each do |i|
# 値のリストは a.values irb(main):003:1*puts i, ":", a[i], "\n"
irb(main):004:1>end
長男:20 母:48 父:50 => ["長男", "母", "父"]
〔補足〕
〔以上補足〕
ファイル
指定したファイルの表示
infile = open("file") # 読み込みなので open("file", "r") でもよい while line = infile.gets # getc なら一文字ずつ print line end infile.close
infile = open("file") infile.each do |line| # 一行ずつ読む処理にイテレータを利用 print line end infile.close
open("file") do |infile| # open もブロックを受け付ける infile.each do |line| print line end end # この場合 close は自動で行われる
指定したファイルの配列への読み込み
infile = open("file") all = infile.readlines
指定したファイルをフィルタにかけた結果の読み込み
infile = open("| nkf -e file") infile.each do |line| ... end
サンプル(ファイルのマルチコピー)
if ARGV.size >= 2 infile = ARGV.shift inf = open(infile, "r") outf = [] ARGV.each do |i| outf << open(i, "w") end while (line = inf.gets) outf.each do |i| i.write(line) end end end
〔補足〕
〔以上補足〕
ソケット
※工事中です
スレッド
※工事中です
Ruby/GTK2
最小の Ruby/GTK2 プログラム
require 'gtk2' # 必須 Gtk.init # 必須(初期化) window = Gtk::Window.new # ウィンドウを作って window.show # 表示する Gtk.main # 必須(Gtk のイベント待ちループに入る)
Vine Linux での表示 | Windows での表示 |
〔補足〕
〔以上補足〕
Ruby/GTK2 で Hello world
require 'gtk2' Gtk.init button = Gtk::Button.new("Hello world") # ボタンを生成 button.signal_connect("clicked") { # クリック時の処理 puts "Hello world" } window = Gtk::Window.new # ウィンドウを生成 window.add(button) # ウィンドウにボタンを登録 window.signal_connect("delete_event") { # delete イベント発生時の処理 puts "delete event occurred" Gtk.main_quit # Gtk のループを終了 } window.show_all # 全オブジェクトを表示する Gtk.main
Vine Linux での表示 | Windows での表示 |
$ ruby hello_world.rb
Hello world
Hello world
Hello world
delete event occurred
$
コールバックの利用
require 'gtk2' Gtk.init def clicked(widget) # クリック時に呼ぶ関数 puts "I am #{widget.label}." # 引数のラベル名を表示 end window = Gtk::Window.new window.border_width = 10 # ボタンの周囲に隙間を空ける window.signal_connect('delete_event') { Gtk.main_quit } box = Gtk::HBox.new(false, 0) # ボタンを横に並べる箱を作る window.add(box) button1 = Gtk::Button.new("Button 1") # 1つ目のボタンの定義 button1.signal_connect("clicked") { |w| # ウィジェットを受取る clicked(w) # 受けたウィジェットを引数に } box.pack_start(button1, true, true, 0) # 箱にボタン1を収納 button2 = Gtk::Button.new("Button 2") # 2つ目のボタンを定義 button2.signal_connect("clicked") { |w| # シグナルハンドラも同様に定義 clicked(w) } box.pack_start(button2, true, true, 0) # 箱にボタン2を収納 window.show_all Gtk.main
Vine Linux での表示 | Windows での表示 |
$ ruby callback.rb
I am Button 1.
I am Button 1.
I am Button 2.
I am Button 1.
I am Button 2.
$
テキストエントリ
require 'gtk2' Gtk.init entry = Gtk::Entry.new entry.set_visibility(true) # false にしてみましょう button = Gtk::Button.new("click!") button.signal_connect("clicked") do p entry.text end vbox = Gtk::VBox.new vbox.pack_start(entry) vbox.pack_start(button) window = Gtk::Window.new window.signal_connect('delete_event') { Gtk.main_quit } window.add(vbox) window.show_all Gtk.main
Vine Linux での表示 | Windows での表示 |
開発環境・デバッグ
リファレンスマニュアル
- 本家ページのオンラインリファレンスマニュアル
- コマンドライン用のリファレンスマニュアル検索ツール Refe
- Windows HTML Help版
プロファイラ: profile.rb
require "profile" とするか ruby のオプションで -r profile とする。 メソッド毎に呼出し回数や処理時間を表示するが、動作が遅くなるという問題もある。 詳しくはこちら
デバッガ: debug.rb
require "debug" とするか ruby のオプションで -r debug とする。 詳しくはこちら
RDE (Ruby Development Environment)
Emacs 関係
- ruby-mode: 自動インデントや色づけなど
- inf-ruby: ruby-mode 下で irb を動かすための Emacs Lisp
- .emacs に以下を記述
(autoload 'ruby-mode "ruby-mode" "Mode for editing ruby source files") (setq auto-mode-alist (append '(("\\.rb$" . ruby-mode)) auto-mode-alist)) (setq interpreter-mode-alist (append '(("ruby" .ruby-mode)) interpreter-mode-alist)) (autoload 'run-ruby "inf-ruby" "Run an inferior Ruby process") (autoload 'inf-ruby-keys "inf-ruby" "set local key defs for inf-ruby in ruby-mode") (add-hook 'ruby-mode-hook '(lambda () (inf-ruby-keys) ))
課題
以下のそれぞれの課題のプログラムを作成し、メールで teachers@ime.cmc. ... まで送ること。 (期限: 11月10日午後6時)
その1
指定した英文テキストファイルを読み込み、各単語の先頭を大文字にする Ruby スクリプト upcase.rb を作りなさい。 (ヒント: String#split, String#upcase)
$cat test.txt
my name is osaka taro. $ruby upcase.rb test.txt
My Name Is Osaka Taro.
その2
はじめ "0" が表示され、クリックするたびに "1", "2", ... とラベルがインクリメントされるボタンと、 クリックするとプログラムを終了する "Quit" というラベルのボタンが縦に並んだウィンドウを表示するプログラム count.rb を作りなさい。
→ | → | … |
その3
テキストエントリから入力したファイルの行数と総バイト数をボタンのラベルに表示する Ruby/GTK2 プログラム filesize.rb を作りなさい。
→ | → |
参考情報
ポータル
- オブジェクト指向スクリプト言語 Ruby
- 日本Rubyの会
- RubyCentral(解説書"Programming Ruby"の旧版が全文読めます)
入門1(気楽に読めるもの)
- JAIST Hatakeyama さんの「Ruby入門」のページ
- Rubyist Magazine の「Ruby ではじめるプログラミング 第 1 回」
- Linux Life の「Ruby入門」ページ(オブジェクト指向に慣れている人向け)
- 木本さんの「Rubyでプログラムを書こう(入門編)」(Perlを知っている人向け)
- ono さんの「Ruby入門」のページ
- 浅桐さんの「数学のためのRuby入門」
- Rubyで関数プログラミング
入門2(やや詳しい解説)
- C MAGAZINE 2000年8月号〜2001年4月号 連載「極めよRuby道」
- UNIX USER 2002年02号「Ruby特集」
- 渡辺さんの「Rubyあれこれ」
- スンマさんの無料チュートリアル(PDF)
インタビュー・読み物
- 日本Rubyの会の Rubyist Magazine(るびま)
- IBM developerWorks の「新言語『Ruby』」(開発者インタビューつき)
- Slashdot の開発者インタビュー
GTK2関連
- Ruby-GNOME2 Project Website の「Ruby/GTK2 チュートリアル」
- Ruby/Gtk2 備忘録
リンク集
- 日本Rubyの会の「Ruby関連ドキュメント」
- スンマさんの Ruby リンク集
- プログラマーのためのリンク集の「Ruby」編
- Rubyの指輪の「Ruby関連ウェブペイジ リンク集」