一時間で覚える Ruby

C/C++, Java は使える、大学で ML とか Scheme もやった、そろそろスクリプト言語を覚えたい、という人向けに、 一時間で Ruby がある程度 (日常的な処理が少しは出来る程度) 使える様になるまでをまとめます。他のスクリプト言語の知識は仮定しません。

このページでは、例示による学習を期待しています。 すなわち、例と結果を与えられることでその意味を理解するということです。 これが出来ないと一時間で使えるようになるのは厳しい。 オブジェクト指向、正規表現と聞いて一つでも意味が分からない人は別のところで勉強してください。 速習を目指しているので、細かいところは全部割愛しています。 とりあえず使えるようになった後にちゃんとした入門書を読んでください。

とりあえず動かす (10 分)

Ruby はインストールされているものとします。とりあえず ruby と叩いて起動。

$ ruby

出力できなければ話にならないので、まず出力を覚えます。 puts, print ぐらいを覚えておけば良いでしょう。 前者は勝手に改行し、後者はしません。

print "fugahoge\n"
puts  "fugahoge"
[EOF]
fugahoge
fugahoge

ruby と叩いて得られるものは対話実行環境ではないので、明示的に EOF を送らないと実行されません。 それは面倒なので irb と叩いて interactive ruby を起動します。

irb(main):001:0> puts "fugahoge"
fugahoge
=> nil

これで interactive に結果を得られます。 => 以下は式を評価した結果が返ります。この場合 nil が返っています。 > の前はプロンプトですが、 ここでごちゃごちゃ書くのは面倒なので以降では省略します。

puts, print 以外に p も覚えましょう。Ruby では任意のものはオブジェクトであり、p はその中身を見るための関数です。

> p "fugahoge"
"fugahoge"
=> nil

文字列はそのまま文字列が返される、と。

あと足し算とか適当に試してみること。例えば次の文達。

> puts (1 + 2)
> puts ("fugahoge" * 3)
> puts
> puts "Hellow"; puts "Hellow"

Ruby はスクリプト言語らしく行指向なので、改行で区切りになってしまいます。 ; で同じ行に二つの命令を書けます。

以降では irb と ruby を混同して使います。ruby スクリプトは、ruby script.rb と起動するか、script の先頭に #!/usr/bin/ruby (もしくは #!/usr/local/bin/ruby) を付けて実行します。

いくつかのデータ型とそのメソッド (10 分)

大体のオブジェクトはあなたが思っている通りの型がつきます。1 は Integer だとか、”fugahoge” は String だとか。

Ruby では全てはオブジェクトだから、Integer もオブジェクトです。Integer にはいくつかメソッドがあり、例によってobject.method でメソッドを呼べます。

> 10.divmod(3)
=> [3, 1]

おっと、Array が返ってきました。Array はあなたが思っている通りにアクセス可能です。

> s = [1, 2, "fugahoge"]
> s[0]
> s[1]
> s[2]

Array の添え字を負の数にすると、末尾からの要素をさすようになります。

> s[-1]

とりあえず to_s を覚えておきましょう。String になります。

> s.to_s

あとは to_i (Integer へ), to_f (Float へ) は覚えておきましょう。

ちなみに、string で n 番目の文字を取り出す場合 s[n] としてしまうと、n 番目の文字の文字コードが得られてしまうので注意。s[n, 1] とすれば、n 番目の文字だけからなる string が返ります。

Array で覚えて便利なのは、each, size あたり。

> [1, 2].size
=> 2
> [1, 2].each { |x| puts x }
1
2
=> [1, 2]

each の後の { |x| ... } の部分をブロックといいます。まあ、ただのラムダクロージャだと思えば生活できます(実際には違うが)。each の後にブロックを持ってくることで各要素に対してイテレーションが可能です。もちろん x に値が入っています。

ちなみに、こんなことも出来ます。

10.times { |x| print x }

Array 以外の構造としては Hash を覚えておくと便利です。C++ の (hash)map だと思えば OK.

> h = {"a" => 1, "b" => 2 }
> h["a"]
=> 1
> h["b"]
=> 2
> h["c"]
=> nil

対応する要素がない場合は nil が返ります。

いくつかの制御構造 (5 分)

if, while は使えないと話になりません。

if は次のような形で使います。

if condition
  expr1
elsif cond # else if ではなく elsif
  expr2
else
  expr3
end

# else を省略した場合
if condition
  expr
end

condition では、false, nil 以外は true とみなされます。Integer の 0 も true であることに注意。

while は次の形で使います。途中で break することも可能です。

while condition
  expr
end

if, while とも、一行で書きたいときは ; をうまく使いましょう。

> i = 0; while i < 10; puts i; i = i + 1; end

繰り返しには、上で述べた times メソッドを使うのもあり。

関数やクラスの作成 (10 分)

関数も作れないと話にならないので、関数を作る方法を学びます。関数は def で定義します。

def add(x, y)
  x + y
end

def say_hello
  puts "hello"
end

最後に評価した値が返り値になります。引数がないものは引数部分を省略できます。なお、普通に return 文を書くことも可能です。

次にクラスを作ります。Ruby では色々なものがクラスで定義されているので、クラスが使えないとたぶんまずいでしょう。

class Foo
  def initialize(x)
    @var = x
  end

  def method1
    ...
  end

  def method2(x, y)
    ...
  end
end

x = Foo.new(10)</pre>

これで class Foo が定義されました。Foo のコンストラクタは initialize という名前で定義します。インスタンス変数は@var というように頭に @ を付けます。クラス変数は @@var と頭に二個 @ を付けます。インスタンス変数は、いわゆる private なので、必要ならば get/set アクセッサを定義しましょう。

ちなみに、変数は何もつけないとローカル変数、$ を付けるとグローバル変数になります。先頭を大文字で始めると定数となり、値が変更できなくなります。変数 var が定義されているかどうかは、defined? var の真偽値で判定できます。

Ruby のクラスは、何も指定しなければ Object というクラスから派生することになっています。Object には .to_s 等のメソッドが定義されています。

正規表現 (10 分)

せっかくスクリプトを使うのだから正規表現を使わないともったいない、ということで正規表現の使い方を覚えましょう。正規表現自体は知っていると仮定します。

とりあえず、マッチしているかどうかの判定、マッチしている部分を抽出、そしてマッチしている部分を置換、これら3つが出来る様になればかなり生活出来ます。

正規表現は、/ で前後をくくって表します。

/a.*b/ # a で始まり b で終わる文字列

文字列に正規表現がマッチしている部分があるかどうかを判定するには、=~ を使います。

"abc" =~ /a.*c/ #=> 真
"bde" =~ /a.*c/ #=> 偽

括弧を使えば、左から数えて n 番目の括弧の中の正規表現にマッチした文字列を $n で得られます。

> "spring summer fall winter" =~ /((\w*)\s)*/
=> 0
> $1
"fall "
> $2
"fall"

何度も括弧の中でマッチする場合は最後にマッチしたものが得られます。

バックスラッシュ表記が出てきましたが、次のものを覚えておけばよいでしょう。

  • \, ., *, +, \?
    • \, ., *, +, ? そのもの。
  • \d
    • [0-9]。数字一文字。数字のクラス。
  • \w
    • 英数字一文字。英数字のクラス。
  • \s
    • 空白一文字。スペース・タブ・改行。空白のクラス。
  • \D, \W, \S
    • それぞれ \d, \w, \s の補クラス

置換には、sub, gsub を使いましょう。sub は最初にマッチした部分だけを書き換え、gsub はマッチした部分全部を書き換えます。

> s = "spring summer fall winter"
> s.sub(/\w+/, "w")
=> "w summer fall winter"
> s.gsub(/\w+/, "w")
=> "w w w w"

ファイル出入力 (5 分)

いくら処理が出来るようになっても入力が出来ないと意味がないので出入力を覚えましょう。

とりあえずファイルを一行ずつ読めれば生活に困らないでしょう。次のようにかければよいでしょう。

f = open(readfile, "r")
g = open(writefile, "w")
while x = f.gets
  g.print x
end
f.close
g.close

スクリプトを指定したときに、いくつかファイルを引数として指定したとします。このとき、ARGF は、それらのファイルを全部つなげた様なものになります。引数を指定しなければ標準入力になります。ということで、Ruby では cat は次のように書けます。

while line = ARGF.gets
  print line
end

ちなみに、諸般の理由により ARGF.getsgets とだけ書いても OK.

例 (10 分)

これだけ知ってれば簡易な word count が作れるかと思いますが、はたして。

$lc = $wc = $cc = 0

def wc(line)
  in_word = false
  i = r = 0
  while i < line.size do
    if line[i, 1] == " " || line[i, 1] == "\t" || line[i, 1] == "\n" || line[i, 1] == "\r"
      if in_word; r += 1; end
      in_word = false
    else in_word = true; end
    i += 1
  end
  if in_word; r += 1; end
  r
end

while line = gets
  $lc += 1
  $cc += line.size
  $wc += wc(line)
end

printf("line -- %d\nword -- %d\nbyte -- %d\n", $lc, $wc, $cc)

もっと簡単に書く方法はあるのだけれど。挙動を wc にあわせているわけではないので、行の数が一行ずれる場合有り。さらに、このコードはここで解説したことをなるべく盛り込もうという趣旨のため必要以上にめんどうくさいことをしているので注意。

参考文献

2004-01-02