簡易版 Ruby チュートリアル

はじめに

本資料では Ruby のスクリプト言語としての基本的な使い方を紹介する.

本資料は以下の Web を元にしている.

また, 数値データの利用には numo-narray を用いる. numo-narray のメソッドについては以下を参照されたい.

Ruby を動かしてみる

RubyはPerlやシェルスクリプトと同じようなスクリプト言語です. スクリプトを記述したファイルをつくりRubyを呼ぶと, 中身が実行されます.

エディタ vi で中身が

print("Hello, World\n")

と書かれたファイルをつくり, test1.rb という名前で保存します. そして

$ ruby test1.rb

とコマンドを実行すると

Hello, World

と表示されます. スクリプトは「""でくくられた部分(=文字列)を表示せよ」というものです. 「\n」は改行を表します.

先頭に "#! /usr/bin/env ruby" と書いておき, chmod +x で実行可能にしておけば, $ ./〜.rb ですみます. 以下のような test2.rb を作成し,

#! /usr/bin/env ruby
print("こんにちわ, 世界\n")  # ここはコメント

これを実行してみましょう.

$ chmod +x test2.rb
$ ./test2.rb
こんにちわ, 世界

なお, #から行末まではコメントで, 実行時には無視されます.

エディタでファイルを編集しなくても, インラインで実行することも可能です. -e オプションを使います.

$ ruby -e 'print("Hello, World\n")'
Hello, World

また, irbという対話型のrubyも用意されています. irb(main):001:0> などというプロンプトが現れるので, そこにスクリプトを記述すると即座に結果が表示されます.

$ irb 
irb(main):001:0> print("Hello, World\n")
Hello, World                              ←標準出力
=> nil                                    ←irbでは戻り値も表示

2行目は 'print("Hello, World\n")' というコマンドの実行に対する戻り値を表しています. さしあたっては気にしなくていいでしょう. irbを終了するには exit です.

irb(main):002:0> exit
$

ruby の基本的な使い方

以下では irb (対話型の ruby) を使って ruby の基本的な使い方を見ていきます.

型宣言は不要

Rubyには型宣言は不要です.

$ irb
irb(main):001:0> a = 2       # 整数
=> 2
irb(main):002:0> b = 3.5     # 実数
=> 3.5
irb(main):003:0> c = "apple" # 文字列
=> "apple"

"="の両側の空白は入れても入れなくてもかまいません. これらは, a, b, c という変数に 2 という整数, 3.5という実数, "apple" という文字列を代入したと考えることもできますが, 実際には 2 という整数オブジェクト, 3.5という実数オブジェクト, "apple" という文字列オブジェクトに a, b, c という名札をつけたということに相当しています.

オブジェクトはその値だけでなく型や大きさなど諸々の情報も自分で持っています.

irb(main):004:0> a          # オブジェクトの値
=> 2
irb(main):005:0> b.class    # オブジェクトの型
=> Float
irb(main):006:0> c.size     # オブジェクトの大きさ
=> 5
irb(main):007:0> 3.5.class  # b.class と同じ
=> Float

上の class や size はメソッドと呼ばれます. オブジェクトに対して「型を述べよ」「大きさを答えよ」などとメッセージを送っていることになります. オブジェクトはそれに対して「実数だ」「5だ」などと答えてくれます.

演算

演算も当然できます. いろいろやってみてください.

irb(main):008:0> d = a * ( b**2 + 3.0e2 )
=> 624.5
irb(main):009:0> e = c + "orange"
=> "appleorange"             # 文字列の足し算は単に順に並べるだけ. 

ちなみに複数の変数をいっぺんに操作することもできます.

irb(main):010:0> e,f = a*b, e+"lemon"
=> [7.0, "appleorangelemon"]

大文字ではじめると定数になります. 定数を書きかえようとすると警告が出ます.

irb(main):011:0> A = 3.1415927
=> 3.1415927
irb(main):012:0> A = 1.7320508
(irb):22: warning: already initialized constant A
=> 1.7320508

シングルクォーテーション (') でくくった部分も文字列になりますが, こちら は制御文字もそのまま文字として扱います.

irb(main):013:0> print 'apple\n'
apple\n=> nil                      # 改行されずに\nが表示される

型変換

型変換は to_s, to_i, to_f といったメソッドを使います.

irb(main):101:0> g = b.to_s
=> "3.5"                       # to_s 文字列に変換
irb(main):102:0> h = b.to_i
=> 3                           # to_i 整数に変換
irb(main):103:0> a.to_f/3 - a/3
=> 0.666666666666667           # to_f 実数に変換

整数を整数で割っても整数しか返さないので, どちらかを実数に変換しておく必要が あります.

配列

オブジェクトを順番に並べて [ ] でくくったものが配列です. 配列の中は同じ型である必要はありません.

irb(main):113:0> ary1 = [ 3, b, d-3.0, "orange"]
=> [3, 3.5, 621.5, "orange"]
irb(main):114:0> ary1[0]
=> 3                           # Cと同じで最初の要素が0番
irb(main):115:0> ary1[1..3]
=> [3.5, 621.5, "orange"]      # 1番から3番まで
irb(main):116:0> ary1[-1]
=> "orange"                    # 負の数はうしろから数える
irb(main):117:0> ary2 = [a, ary1]
=> [2, [3, 3.5, 621.5, "orange"]]   # 配列の中に配列があっても大丈夫. 
irb(main):118:0> ary2[1][3]
=> "orange"                    # ary2[1]の3番の要素

配列の要素が最初に決まっていない場合は, 配列を定義し, 配列に要素を追加していくことができます.

irb(main):001:0> ary3= Array.new
=> []
irb(main):002:0> ary3.push( 100 )
=> [100]
irb(main):003:0> ary3.push( "apple" )
=> [100, "apple"]

乱数

乱数を生成するには組み込み関数の rand を使用する. 0 以外の引数を指定した場合, 0 からその値未満までの整数を生成し, 0 を指定するか引数を省略した場合は 0 以上 1 未満の実数で乱数を返す.

p rand #=> 0.2955039968 (for example)
p rand(100) #=> 17 (for example)

制御構文

プログラムの流れの制御には, for, while (繰り返し), if, case (条件分岐)などが使えます. もちろんirbの中でも使えます.

irb(main):121:0> for i in 1..3
irb(main):122:1>  print(i,"\n")
irb(main):123:1> end
1
2
3
=> 1..3

いずれも終わりを表すのは end です. プロンプトの">"の左の数字はネストの深さを表していて, ネストがなくなる3行目まではなにもおこなわれません.

irb(main):020:0> for i in 1..5
irb(main):021:1> if i == 3 then     # thenはなくてもよい
irb(main):022:2* print "Hello \n"
irb(main):023:2> else
irb(main):024:2* print "#{i} \n"    # "#{..}" とすると文字型に変換できる
irb(main):025:2> end
irb(main):026:1> end
1 
2 
Hello 
4 
5 
=> 1..5

配列の各要素に対して順に処理をおこなうイテレータというものもあります.

["dog","cat","bird"].each {|i|
 printf("a %s\n", i)
}

each は {...} (または do ... end) を引数にとるメソッドです. 配列の各要素を | | の中の変数(ここでは i )に格納し, その i に対する操作を記述します. つまり

for i in ["dog","cat","bird"]
 printf("a %s\n", i)
end

と同じです. これだけだとあまりありがたみが感じられないかもしれませんが, イテレータにはいろいろなものがあり, より直接的にループを記述することができます. for を使うより便利なことが多いです.

(1..10).each {|i|
  printf( "%02d\n", i )
}

10.times {|i|                  # 10回繰り返し
  printf( "%02d\n", i )
}

10.times do                    # 10回繰り返し
 print "hoge"
end

loop do                          # 無限ループ
 break if STDIN.gets=="\n"       # 空行を入力すればループを抜ける
end

loop do
 break if /^$/ =~ gets           # 上と同じ(/.../は正規表現, =~は正規表現とマッチしているかどうか, getsはSTDIN.gets
end

注:イテレータ(ブロック)は, 変数のスコープ(有効範囲)を作ります. 次のよ うなスクリプトはエラーになります.

(1..10).each{|i|
  b = i
}

puts b    # {…}の外では b が存在しないのでエラーになる

エラーを避けるには

b = 0
(1..10).each{|i|
  b = i
}
puts b   # 10

のようにします.

数学関数 (モジュールの例)

数学関数は, Mathモジュールを使います. Mathモジュールの中に, 三角関数などのメソッドや円周率などの定数が定義されています.

irb(main):027:0> a = Math::cos(0)
=> 1.0
irb(main):028:0> b = Math::PI
=> 3.141592653589793

include文を使うと, それ以降は"Math::"の部分が不要になります.

irb(main):029:0> include Math
=> Object
irb(main):030:0> c = cos(PI)
=> -1.0

日付と時刻 (クラスの例)

日付や時刻を扱うには, DateTimeクラスを使うと便利です. DateTimeクラスの定義は起動時に読み込まれていないので, まず

irb(main):032:0> require "date"
=> true

とします. これで定義が読み込まれます. DateTimeクラスのオブジェクトを作るには

irb(main):033:0> sakki = DateTime.new(2010,3,8,9,30) 

とします. およそどのクラスでも一般に new というのが新しいオブジェクトを作る メソッドです. 他に

irb(main):034:0> ima = DateTime.now  # 現在
irb(main):035:0> itsuka = DateTime.parse("2003-04-05")  # 文字列を解釈して作成

といったやり方もあります.

DateTimeクラスには足し算引き算他さまざまなメソッドが定義されています.

irb(main):037:0> sakki.year     # 40日後は何日か. 
=> 2010
irb(main):038:0> (sakki + 40).day  # 差の日数(121411/48日)
=> 17
irb(main):039:0> sakki - itsuka
=> (121411/48)
irb(main):040:0> (sakki>>1).to_s   # 1ヶ月後を文字列にする
=> "2010-04-08T09:30:00+00:00"
irb(main):041:0> sakki.strftime("%H:%M (%y/%m/%d)")  # 好きなフォーマットの文字列にする
=> "09:30 (10/03/08)"

手続き定義

def を使ってメソッドを定義することにより, 他の言語と同じような形で 手続きを定義できます.

def wa(a,b,c)
 d = a+b+c
 return d        # 戻り値の指定. なければ最後の文の戻り値が返される. 
end
e = wa(3,4,6)    # 定義前に実行することはできない. 

テキストデータの書き出し

ファイルの入出力には File クラスを用います.

file1 = File.open("test.txt","w")    # "w"を付けると書き込み可能で開く. 
file1.print("Hello, World\n")
for i in 1..10
  file1.printf( "%02d %02d\n", i, i*2 )
end
file1.puts("Hello, Hello, World")    # 改行付きで出力される
file1.close

file1がファイル"test.txt"に対応するFileクラスのオブジェクトになります. これに print printf puts などのメソッドを作用させるとファイルに書き出されます. puts は引数を1行分として書き出すので最後に必ず改行が入るようになっています. print や printf では改行も自分で制御します. 実際に書き出されているか確かめてみましょう.

テキストデータの読み込み

ファイルをオープンするには組込み関数のopen, File::openメソッドを, ファ イルの読み込みは組込み関数のIO#eachメソッド, IO#getsメソッドを使用する ことができます.

# 
# IO#eachを使う例
#
f = open("foo")
f.each {|line| print line}
f.close

#
# IO#getsを使う例
#
f = open("foo")
while line = f.gets
  print line
end
f.close

#
# IO#each_lineを使う例
#
f = open("foo")
  f.each_line {|line|
    print line
  }
f.close

NArray を使って配列演算

Rubyに標準装備されている配列(Array)は, オブジェクトを順番に並べたものであり, これもまた1つのオブジェクトです. 上の例にあったように, 配列の要素は同じ型である必要はなく 任意のオブジェクトを格納できるという柔軟なものなので, その分計算速度は犠牲になっています. 扱うデータが数値である場合には, NArray というクラスパッケージを用いると高速に計算できます. さらに, 平均や標準偏差といった統計処理も簡単に行うことができます.

詳しくはNumo::NArray 概要を適宜参照してください.

NArray クラスのつくりかた

NArrayクラスを用いるには, まず

require "numo/narray"

とします. これでNArrayクラスの定義が読み込まれます. 新たに倍精度実数型の配列を生成するには, Numo::DFloat.new(大きさ,大きさ,...) とします. 倍精度実数配列を作るには例えば以下のようにします. ".seq" をつけると通し番号で初期化されます.

irb(main):008:0> ary1 = Numo::DFloat.new(3,4).seq
=> Numo::DFloat#shape=[3,4]
[[0, 1, 2, 3], 
 [4, 5, 6, 7], 
 [8, 9, 10, 11]]

irb(main):009:0>  ary2 = Numo::DFloat[ 2, 3, 4.5, 8 ] 
=> Numo::DFloat#shape=[4]
[2, 3, 4.5, 8]

irb(main):017:0> ary3 = Numo::DFloat[ [2, 3, 4.5, 8], [1, 2] ] 
=> Numo::DFloat#shape=[2,4]
[[2, 3, 4.5, 8], 
 [1, 2, 0, 0]]

shape, ndim, class, size などのメソッドも使えます.

irb(main):010:0> ary1.shape 
=> [3, 4]

irb(main):011:0> ary1.ndim
=> 2

irb(main):012:0> ary1.class
=> Numo::DFloat

irb(main):013:0> ary1.size
=> 12

また, 通常の配列(Array)とNArrayの間で型変換するには

irb(main):058:0>  ary4 = [ 2, 3, 4.5, 8 ] 
=> [2, 3, 4.5, 8]

irb(main):059:0> Numo::NArray[ary4]
=> Numo::DFloat#shape=[1,4]
[[2, 3, 4.5, 8]]

NArray を通常の配列 (Array) へ変換する場合は以下のようにします.

irb(main):019:0> ary5 = ary2.to_a
=> [2.0, 3.0, 4.5, 8.0]

NArrayでは, 例えば中に1つでも実数が含まれていれば実数の配列となり, 要素はすべて実数になります.

要素番号

インデックスはArrayやC言語と同じで, 最初の要素番号は0, 最後の要素番号は要素数-1です. 添字の付け方に注意してください.

irb(main):031:0> ary1
=> Numo::DFloat#shape=[3,4]
[[0, 1, 2, 3], 
 [4, 5, 6, 7], 
 [8, 9, 10, 11]]

irb(main):026:0> ary1[0,0]
=> 0.0

irb(main):027:0> ary1[1,1]
=> 5.0

irb(main):029:0> ary1[0..2,0]
=> Numo::DFloat(view)#shape=[3]
[0, 4, 8]

irb(main):030:0> ary1[0,0..3]
=> Numo::DFloat(view)#shape=[4]
[0, 1, 2, 3]

irb(main):032:0> ary1[0,0..-1]
=> Numo::DFloat(view)#shape=[4]
[0, 1, 2, 3]

算術演算

演算は要素ごとにやってくれます. +, -, *, /, % などが使えます.

irb(main):033:0>  ary10 = Numo::DFloat[ 2, 3, 4, 5 ] 
=> Numo::DFloat#shape=[4]
[2, 3, 4, 5]

irb(main):034:0>  ary11 = Numo::DFloat[ 9, 8, 7, 6 ]
=> Numo::DFloat#shape=[4]
[9, 8, 7, 6]

irb(main):035:0> ary10 + ary11
=> Numo::DFloat#shape=[4]
[11, 11, 11, 11]

irb(main):036:0> ary10 - ary11
=> Numo::DFloat#shape=[4]
[-7, -5, -3, -1]

統計量

次の統計メソッドが定義されています. メソッド名を見れば何をしているか想像つくでしょう.

sum
prod
mean
stddev
var
rms
min
min_index
max
max_index
minmax
cumsum
cumprod
sort
sort_index
median

たとえば, 以下のように計算できる.

irb(main):033:0>  ary10 = Numo::DFloat[ 2, 3, 4, 5 ] 
=> Numo::DFloat#shape=[4]
[2, 3, 4, 5]

合計
irb(main):037:0> ary10.sum
=> 14.0

平均
irb(main):038:0> ary10.mean
=> 3.5

標準偏差
irb(main):039:0> ary10.stddev
=> 1.2909944487358056