最終更新日:

Ruby入門


  1. はじめに - いろいろ思うところ -
  2. 第1章 Rubyの特徴
  3. 第2章 Hello,Worldプログラム
  4. 第3章 変数
  5. 第4章 演算
  6. 第5章 制御構造
  7. 第6章 メソッド

はじめに - いろいろ思うところ -

最初にこのページを作成したのが私が大学院に入学したての頃(2002年ごろ?)だったので, それから考えると8年経ちました. 当時, 今は絶版のまつもとゆきひろさん著「
オブジェクト指向スクリプト言語 Ruby」を参考にこの Ruby 入門のページを書いていました. 現バージョンの Ruby では基本は変わらずもだいぶライブラリが改訂されているようです. このページを書いていたとき Ruby のバージョンは 1.4 くらいだった気がしますが, 現在2010年1月30日の Ruby の最新バージョンは 1.9.1 のようです (Ruby最新版ダウンロード). 最近では! Ruby技術者認定試験なるものもできていて, ちょっとびっくりです (私も受けみたいけど, スイスにいるから難しいかな...).

Ruby に興味を持つ多くの方はおそらく Perl との比較から正規表現を使ったテキスト処理や Ruby on Rails を使った Web プログラムへの応用として Ruby の使用を考えているだろうと思います. が, 私は特に といった場合に Ruby を使用することをぜひお勧めしたいです. 実際 Ruby の計算速度はそれほど速くはなく C 言語や Fortran に比べてたら日が暮れてしまうことも多いので, 本気で商用のアプリケーションを作成するなら Ruby はあまり向いていないと思います. また, Ruby でなくとも Perl や Python でも慣れれば同じでしょうし, C 言語のプロトタイプとしてなら Perl の方が言語仕様が似ている分, 良いかもしれません. が, こと上記のような作業では他の言語(やツール)ではなく Ruby を用いることをお勧めできます. その理由は, Rubyの言語仕様が本質的なアルゴリズム(計算手順)以外の部分で余計な手続きを書く必要性が少なくなっているから, です. これによって, 思考の流れを止めることなくプログラミング作業に集中でき, 目的のプログラムをいち早く作成できます. 「プログラム作成時間+プログラム実行時間」をトータルで比較した場合にC言語など高速実行できる処理系よりも速く仕事が済ませることが実際に多いからです. これは Java や C++ に比べて Ruby はオブジェクト指向を言語設計に貫いているせいでからはないかと, 個人的には考えています.

簡単な例を挙げると, 配列の内容を並べ替える(整列, ソート)とき C 言語なら整列のアルゴリズムを調べて自分で実装するか標準ライブラリの qsort 関数を呼びだす必要がありそうですが, Ruby なら
 array.sort
と一行(一メソッド)で終わりです. 中でどんなアルゴリズムが使われているかはボラックボックスですが, 整列アルゴリズムを開発する仕事に従事している訳でなければ, 大した問題ではありません. また実際は C 言語で実装されているので整列だけなら C 言語で作成されたコードに引けを取らず高速です. もし, Perl ならば
 sort @array;
こんな感じになります. 「なんだ Ruby と命令の並び順が逆なだけでは?」と思うかもしれませんが, ここにオブジェクト指向でないプログラミングスタイルが如実に現れています. 詳しくは後述しますが, これは Perl が

「 sort 関数を呼び出して, @array 配列に適用している」

という C 言語や Fortran のような「関数(サブルーチン)呼び出し」の見方をしているのに対して Ruby は

「 array データに sort メソッドを適用している」

というオブジェクト指向プログラミングになっています.

また Python でも
 array.sort()
と sort メソッドが用意されており, オブジェクト指向プログラミングのスタイルになっていますが, ソートしたもの自体をオブジェクトとして扱っていないのでソートしたものを逆順にソートし直す場合は
 array.sort()
 array.reverse()
と2回命令を記述する必要があります. ところが, Ruby はソートしたもの自体もオブジェクトとして扱っているので
 array.sort.reverse
と書くことができます. つまり, Ruby では「array.sort」自体を新しく一つの配列オブジェクトして見なしている訳です. 配列をソートしたものもきっと配列だろう, というユーザーの期待通りの動作をしてくれます. どれも大した違いではないかもしれませんが, この期待したところで期待したオブジェクトとして振る舞ってくれることがプログラミング作業を効率化させてくれます. (配列やソートの概念がわからない人には「?_?」な感じかもしれませんが, 上記のような違いとそれがもたらす効果はのちのち理解できるようになると思います)

実際, オブジェクト指向プログラミングの基礎概念を勉強するだけなら Ruby はうってつけだと思います (Java や C++ にはオブジェクト指向の本質以外の部分で覚えなければいけないことがたくさんありすぎるので). 裏を返せば, 本質以外の部分はブラックボックス化されているか, 省略可能な形で自動的に実行されておりユーザーからは見えないように言語が設計されています.

前置きはこのくらいにして.

基本的にここに書かれている内容は Ruby の文法に関しての説明と個人的に培ってきた Tips のようなものを書こうと思っています. 初心者向けの Ruby 入門サイトや本もたくさん出回っていますので, それらとあわせて参考にしてもらえれば, と思います. どんなプログラミング言語でも同じ処理をするのに何通りも書き方があるのが普通で, みんな共通の作法みたいなものから個人的に好きな書き方, エレガントな書き方などいろいろあるとおもいます. とくに Ruby は C 言語や Java にないエレガントな書き方ができるので, そこらへんを中心にまとめることができたら, とも思ってます.

ページ全体の構成は以下のようになっています.
  1. ページ目: Ruby 文法基礎
  2. ページ目: オブジェクト指向
  3. ページ目: 正規表現 (2010/3/1現在 改訂中)
  4. ページ目: Ruby 特有の仕様 (2010/3/1現在 改訂中)
  5. ページ目: Ruby 活用例集 (2010/3/1現在 改訂中)
1ページ目は, 変数, 制御構文など他の言語でも必須の項目で Ruby での書き方を説明します. 2ページ目はオブジェクト指向プログラミングに関わる Ruby の仕様. クラス, 継承などについて説明します. 3ページ目は Perl でもおなじみの正規表現について基礎的な部分を例文を通してご紹介します. 4ページ目は他の言語にはあまり出てこない Ruby 特有の部分について. 例えば, ブロック変数や多重継承の代わりに導入された mix-in という手法, 動的プログラミングなどについて紹介します. 5ページは私が培ってきたオリジナルの Tips をご紹介します.

ちなみに
通常, プログラミング言語を初めて学習しようとするならば次のステップで進めるのが良いと思います.
  1. プログラミング言語の書式(書き方)と使われる基礎概念(変数, 演算子, 制御構文や関数など)を理解する
  2. 基本アルゴリズム(整列や探索など)の学習を通して, 命令の組み合わせ方(アルゴリズム)の理解を進める
  3. 小さめな総合的アプリケーション作成を通して, アルゴリズムの組み合わせ方(ソフトウェア開発の流れ)を習得する
  4. (あとは応用, オブジェクト指向, デザインパターン, データベース処理, ネットワーク処理, などなど)
そして, 学習が終わったら, 今度は自分でアプリケーションを設計して, アルゴリズムを考えて, 自分でプログラムを作る作業が必須です. そして, 時に人の作ったプログラムを読む(理解する)ことで自分のプログラミングスキルを磨く作業も必要でしょう. 多くの入門の書籍は上記の「1. 基礎文法」を中心に「2. アルゴリズム」や「3. アプリケーション作成」が混在している場合がほとんどです. 自分は今どの作業に取り組んでいるのかというメタな視点を持つことで学習を効率よく進めることができるのではないでしょうか. プログラミング言語学習ではじめにどのプログラミング言語を選択するか, というのは人によって意見が分かれるところですが, Ruby はその一つの候補であるとは思います. 初学者にとって余計な部分はブラックボックスになっており(良くも悪くも)学習を始めやすく, それでいて奥深い仕様になっていると思います.

一応念のため: この Ruby 入門へのリンクは自由にどうぞ. 掲載されているコードも私的利用/商業利用問わず自由に利用してもらってかまいませんが, 使用した際の問題等に関してこのページの作者は責任を一切負いません. 間違った記述も多々あるかもしれませんのでご指摘/ご質問等は歓迎します. コンテンツの著作権は私(Masa)にあります (Copyright © 2010 Masa All right reserved) ということでどうぞよろしく.

参考サイト

現時点(2010年1月30日)で Google でサクッとヒットする Ruby 入門関係のサイトをピックアップしてみました.

メジャーなところで

サクッとググれた入門系サイト(個人的によさげに見えたもの)

とりあえず, 初心者な方はRubyのメーリングリストに加入されて質問してみるのがいいんじゃないでしょうか.

予備知識 - コンパイラ言語とインタープリタ言語 -

ちょこっと前置き
※ところどころで, これは最低知っておいたほうがいいんじゃないか, ということを「予備知識」という形でまとめておこうと思います.
※Rubyには直接関係ないかもしれませんが, 案外知らない人も多いのではないか, という気持ちから.
※そんなのあたりきしゃりきのとんとんちきだぜ!!屁のツッパリはいらんですょ!?という方はサクッと?すっ飛ばしていただきたい.

コンピュータ上での「プログラム」といったとき, 実は二つのファイルのことを指します. 一つは「実行形式ファイル」のこと, もう一つは「ソースコード(ファイル)」のこと. どちらもコンピュータをどのように動かすか, といった命令が書かれているのですが, その命令の種類が違います. 通常, われわれがコンピュータ上でプログラムをつくる, といった場合は,
  1. ソースコードを書く
  2. ソースコードファイルを実行形式ファイルに変換する
ということをしなくてはならなりません. 昔々には映画マトリックスのように機械語 (0と1の羅列?) を直接目で見て理解できて直接編集できる達人がいたらしいですが今となってはそんな変人?はまずいません. CPU を動かすのは機械語なので, ソースコードを作っただけではコンピュータを思い通りに動かすことができない. ので, Ruby の言語仕様とか文法とかいうのは, 「1」のソースコードの書き方になるわけです. ソースコードを書いた後にそれを機械語に変換するわけですが, この変換の仕方に二通りあります. コンパイル方式というのは, ソースコードを一気に全部機械語 (実行形式ファイル) に変換してしまうやり方. インタープリタ方式というのは, ソースコードの命令を逐次機械語に変換しながら実行する, という方式 (実行形式ファイルは作成しない). で, ソースコードをコンパイルするプログラム(実行形式ファイル)を「コンパイラ」, インタープリットするプログラム (実行形式ファイル) を「インタープリタ」といいます (ややこしいかもしれないが・・・).

コンパイラ方式をとる言語を一般に「コンパイラ言語」, インタープリタ方式をとる言語を「インタープリタ言語」と言ったりします.
例えば, C 言語の場合, コンパイラは数多く存在する (Intel コンパイラや GCC など) が C 言語用のインタープリタは数少ないです. 逆に Ruby の場合, まつもとさんが作ったのはインタープリタであって, わたしはこれまで Ruby 用のコンパイラは見たことがありません. なので, Ruby はインタープリタ言語と呼ばれても, まぁ, 間違いは少ないでしょう.

世の中多く見渡すと, このインタープリタ言語のことを「スクリプト言語」と呼ぶ場合がほとんどです. 厳密には違うのかもしれませんが,

インタープリタ言語=スクリプト言語

と思っていて良いと思います. Wikiペディアによると,
スクリプト言語とはもともと「簡易的な言語」という意味で使われていたらしいが, いまや Ruby や Perl は「簡易的な」と呼ぶレベルをはるかに超えている気はする. コンパイルする手間がなく手っ取りばやく実行できる, という意味で「簡易的な」という意味からインタープリタ言語をスクリプト言語と呼ぶようになったのではないか, と個人的には思っています.

第1章 Rubyの特徴

「Ruby 特徴」のキーワードでググって(Google検索して)まとめてみると
  1. オブジェクト指向言語
  2. スクリプト言語(インタープリタ言語)
  3. 文法がシンプル
  4. いろいろなプラットフォーム(OS)で動作する
より専門的な特徴としては
  1. Perl 並みの強力正規表現
  2. 動的な言語
  3. 多倍長整数(メモリの許す限り大きな整数を計算できる)
  4. ブロック付きメソッド(イテレータ)
  5. クロージャ
  6. モジュールによるMix-in
  7. ガベージコレクション(メモリ管理が不要)
  8. 例外処理
などが挙げられています. 個人的に「これだ!」というのを一つ挙げるとするなら,

完全オブジェクト指向

厳密な意味で本当にそうかと聞かれるとそこらへんの専門家ではないので自信がありません ( Python はメソッドもオブジェクトらしいですが Ruby はそうでないらしい(参照:[ruby-list:65] ruby vs python)) が, 少なくとも Perl や Python に比べて, 言語設計に一貫したオブジェクト指向観が漂っていると感じます. というのも Ruby は Perl や Python よりも後発で Ruby 開発者のまつもと氏は「Perlより強力で、Pythonよりオブジェクト指向の強い」と感じる言語が欲しいと考えていた, らしいです(参照:初歩の「Perl」「Python」「Ruby」). Java なども純粋なオブジェクト指向言語と言われていますが, プログラミングしようとするとどうしても C 言語風の(関数主体の機能中心的な、いわゆる手続き型)思考が必要になってしまう場面があります. 具体的にどうだというのは, おいおい説明されるだろうことを期待してここでは詳細に説明するつもりはありません, ざっくばらんにいうと,

他の言語に比べて非常にプログラミングしやすい

もちろん C 言語など他の言語に慣れている人は Ruby の文法や作法を覚えるまでその「プログラミングしやすさ」を実感できないかもしれませんが, 慣れるとこれがカッパえびせん?のようにやめられなくなります. なぜプログラミングしやすいかというのは, オブジェクト指向がもともと人間の世界の捉え方(認知の仕方)に非常に近いものだからではないか, と個人的には思っています. また, Ruby はそれを自然な形で表現できているのではないか, と思います. この「ストレスなくプログラミングできる」というのは Ruby の言語設計の根底に流れている哲学でもあるようです(参照:Ruby 哲学). そういったこともおいおい具体的な例を通して説明できたらとも思います.

予備知識 - オブジェクト指向型と手続き型 -

ざっくり個人的な見解に基づいて私の言葉でいうと なのかなぁとか漠然に思います. 絵で書いてみるとこんな↓感じでしょうか.



手続き型言語としては, C 言語, Fortran などが有名で, オブジェクト指向言語というと Java, C++ などが有名です. ただし, オブジェクト指向言語を使ったからといって必ずしもオブジェクト指向のプログラミングスタイルになるとは限りません. C++ の機能を使っていながらオブジェクト指向になってないコードは世の中たくさんあります. オブジェクト指向言語とはオブジェクト指向プログラミングをサポートする機能を備えた言語だと思っていて良いと思います. 一般にオブジェクト指向プログラミングは手続き型に比べて再利用性, 保守性が向上すると言われまていますが, 初期のコードタイプ量は手続き型に比べて増加し, 全般的に実行速度は下がる傾向にあるようです. また, データの抽象化が頻繁に行なわれるため, 例えばポリモフィズム(多態性)のため if 文(条件分岐)がなくても処理が分岐していたりするのでソースコードを読むだけでは実際の処理の流れが把握しにくく, 設計がしっかりと行なわれないと保守性, 再利用性が下がるだけでなくデバッグが困難になる傾向があるように思われます. そのためにもある程度規模の大きな開発では UML や RDoc によるドキュメントの整備や Test::Unit ライブラリによるテストコードの整備が必須だと思われます.

第2章 Hello, Worldプログラム

ちょこっと前置き
※ここでは, 環境設定やインストールに関しての説明はしません. 文法と Ruby のお作法?Tips?中心に解説していきます.
※想定する環境としては, Rubyインタープリタがインストールされていて, コマンドライン上で Ruby スクリプトファイルを呼び出して実行できる, ような環境を想定しています.
※OSや開発環境に依存するような部分の説明はしません.
※最近の Linux, Mac であれば, 初めから Ruby インタープリタはインストールされているだろうし, Windows でもインストールはサクッとできるはず.
※MacOSX を含む UNIX 系 OS であれば,ターミナルから実行、WindowsであればDOSプロンプトから実行することを想定して記事を書いていきます。

いしにえの昔からプログラミング言語の紹介をする時は, その言語で「Hello, World」と出力する例が最初に来ると決まっているそうです(参照:
オブジェクト指向スクリプト言語 Ruby).
(※ちなみに, 黄色い「まつもとゆきひろ著オブジェクト指向スクリプト言語Ruby」本(1999年初版4000円)はすでに絶版になっています.)

最初なので, 手順を丁寧に解説していきます.
  1. エディタ(メモ帳, Vi, Emacsなど)を起動.
  2. 次の1行を入力.

  3. print "Hello, World\n"

  4. ファイルを保存する(拡張子は「.rb」).
  5. ターミナル( Windows なら DOS プロンプト)を起動して
  6. ファイルのあるディレクトリに移動し( cd コマンドを使って)
  7. 次のコマンドをタイプ

  8. ruby ファイル名

  9. みごと次の行に「Hello, World」と表示されれば OK !
※されなければ, たいてい, Ruby のインストールがうまくいっていないか, ミスタイプがあるか, カレントディレクトリに Ruby のファイルがないか, のどれかです. もよりの Ruby 使いにご連絡しましょう!!

<ポイント>
printメソッド
文字を出力する
<書式>
print "文字列"

<メモ>
★ メソッドとは, オブジェクト指向言語で使われる「命令」のこと. 手続き型言語では「関数」や「プロシージャ」と呼ばれる.
★ 「\n」は改行を表す特殊文字.
★ 文字列を出力するときは「""(ダブルクォーテーション)」か「''(シングルクォーテーション)」で囲む.
★ 実は「" "」と「' '」で囲んだ時は, 解釈が異なるがそれはおいおい.
★ 引数はカッコをつけてもつけなくても良い. ( print("Hello, World") と書いても実行できる )
★ 引数とは, メソッドに引き渡すもののこと. ここでは「"Hello, World"」という文字列のことを指す.
★ 文の最後は, 改行かセミコロン(;)
★ オブジェクト指向のお話はおいおい.
★ おいおい^^;ゝ

問題2-1
それでは, さっそく問題!!
「GoodBye,World」と出力するには, どのようにプログラムすれば良いでしょう?
以下のプログラムの空白を埋めて「実行」をクリックしてください.

#GoodBye,Worldプログラム

print ""




<メモ>
★ 文の先頭に「#」があるとコメント行になり, プログラム実行とは関係がない文になります.
★ ちなみに上の処理は JavaScript で動作しています. Ruby が動いているわけではございません.


第3章 変数

「変数」とはデータを記憶しておく入れ物のようなもののことで, 計算した結果を記憶しておく場合に用います.



もともとは数学でいう「変数」から来ていると思いますが, 数学では化するのことを指しているのに対してプログラミング言語でいう「変数」はどちらかというと「データの記憶場所をメモリ上に確保するしてそこに名前を付ける」という意味合いが強いです. また変数名も x や y といった一文字ではなくプログラム中で意味のある文字列がよく使われます.

他の言語と比較して Ruby の変数に関する特徴は

  1. 変数の宣言がない
  2. データ型の宣言がない
というところです. 例えば, C 言語や Java では変数を利用する前にはどのようなデータ型で, どのような変数名の変数を使うかをあらかじめ明示(宣言)しておかなければなりません.

※ 特に整数に関してはメモリが許す限りどんな大きな数値も扱えます(多倍長整数をデフォルトでサポート). なので整数の場合オーバーフローというエラーが起きず 2 の 200 乗とかも計算できてしまいます
※ 実際は自動的にデータ型(実数, 整数, 文字列)を判別して処理されています.

ただ, 変数の前につける頭文字と大文字か小文字で, 変数の種類が限定されます。

変数の種類ルール説明
グローバル変数$で始まるプログラム全体で有効な変数
ローカル変数小文字で始まるメソッド内やブロック内で有効な変数
定数大文字で始まる一度値を定義(代入)すると変更できない
インスタンス変数@で始まるオブジェクト(インスタンス)固有の変数
クラス変数@@で始まるクラス固有の変数

<メモ>
★ プログラミング言語を一個もしらない方は(?_?)いう感じだと思うので、とりあえず例題を見て考えてみてください.
★ インスタンス変数, クラス変数は後ほど(オブジェクト指向の話のとき)説明します.
★ 定数は値を変更できないので「数」ではありませんが, 値を記憶して記憶領域に名前を付けておく, という意味で変数の一種と見なすことができると思います.

※ 上記以外にも, あらかじめ定義されている
疑似変数, 組み込み変数というのがあります.

例題3-1
# Hello,Worldプログラム2

hello="Hello,World\n"
print hello
print "hello\n"
print 'hello\n'




<メモ>
★ 「=」は他の言語でおなじみの代入演算子と呼ばれるもので変数に値を代入するときに使われます (数学の「等号」の意味ではないことに注意).
★ 適当な変数名を指定して値を代入するとそれが変数になります(上記の例では「hello」が変数になっています).
★ 「' '」で囲むと, \n (特殊文字) の解釈が行なわれない.
★ 「変」と言っても文字列もデータとして格納(記憶)できます.

ときに複数の値を一度に扱いたい場合があります. そのときに便利なデータ構造が配列です.


例題3-2
配列
x = [1,3,5]		# 配列の作成
y = ["good morning", "hello", "good bye"]

p x[0]			# 配列要素の表示
p y[2]




<メモ>
★ []で囲ったデータ列(データの区切りは「,(カンマ)」を使う)を変数に代入すると配列になります.
★ 配列の要素番号は「0」から自動的につけられます. 各要素にアクセスするときは 配列名[要素番号] と指定します.
★ C 言語のようにあらかじめ要素数を指定する必要はありません(可変長). メモリの許す限りいくらでも要素を追加できます.
★ 整数, 実数, 文字列が混在した配列も作成できます.
★ 配列は Ruby で一番良く使うデータ構造ですので, 後ほどオブジェクト指向の項目で詳しく説明します.


予備知識 - 変数のスコープ(有効範囲) -

まだ, メソッドの説明をしていませんのでメソッドを理解していない方はメソッドの項目を理解した後で再びここに目を通してもらえると理解が進むと思います.

変数の有効な範囲をスコープと言います. グローバル変数はプログラム全体で有効で, ローカル変数はある特定の範囲内(ブロック, メソッド, クラス, モジュール)でのみ有効な変数です. 具体例を以下に示します.

# ローカルスコープ

a = 100
def method
	a = 200
end
method print a




メソッドの中で a=200 という命令が実行されていますが, メソッド定義内はローカルスコープが作られるのでメソッドの外で使用されている変数 a とは別の変数として扱われます(別々の記憶領域を割り当てられます). 次の例を見てください.

# グローバルスコープ

$a = 100
def method
	$a = 200
end

method
print $a




$a はグローバル変数なのでプログラム中どこからでもアクセス可能です. メソッドの外で使われている $a もメソッド内の $a も同じ変数を指し示しています(同じ記憶領域を指し示しています).

一般に, グローバル変数を用いるとプログラム中のどこで変数の値を書き換えられたかを制御しにくくなりバグの原因になると言われており, できるだけグローバル変数をつかないことが推奨されています.



第4章 演算

演算とはプログラムにおける主要な計算のことでの演算に使われる記号のことを演算子と呼びます.
たくさんありますが, 主なものを以下にまとめます.
 
演算演算子説明
代入演算=変数に値を代入する
四則演算+,-,*,/足し算,引き算,掛け算,割り算
比較演算==,!=,<,<=,>,>=値を比較する
論理演算&&,||,and,or,!,not論理演算

<メモ>
★ 変数に代入するというのも演算している, といわれます。

それぞれの演算について例題を見ていきましょう.

例題4-1
代入演算
a = 10		# 整数値を変数 a に代入
b = "Hello"	# 文字列を変数 b に代入
p a
p b



<メモ>
★ p は print と似ていて変数の内容や文字列を出力する命令です.

例題4-2
四則演算
a = 10
b = 20
p a+b		# 足し算
p a-b		# 引き算
p a*b		# かけ算
p a/b		# 割り算

a = 10.0
b = 20.0
p a/b		# 実数の割り算

a += 10		# 複合代入演算
b -= 10
p a
p b

a = "hello"
b = "world"
p a + ", " + b	# 文字列の連結
p a*3		# 文字列の繰り返し



<メモ>
★ 整数の割り算と実数の割り算で答えが違うことに注意してください. (整数: 小数点以下の値がない数, 実数: 小数点以下を考える数)
★ 割る方(b)か割られる方(a)のどちらかが実数であれば実数の答えになります.
★ Ruby はデータ型の宣言がないですが代入された値によって内部でデータ型を判別しています.
★ 「-=」や「+=」は複合代入演算子と呼ばれ, たとえば「a+=10」は「a=a+10」と同じ意味になります. 「a=a+10」は数学的にはありえませんが「=」は等号ではなく代入の意味なので, まず「a+10」が計算されその結果が a に代入されると解釈します. つまり, 「a+=10」や「a=a+10」は「変数 a の値を 10 増やす」という意味になります.
★ C 言語でおなじみのインクリメント演算子(++)は Ruby にはありません.
★ 文字列に対して「+」を用いると文字列の連結になります.
★ 文字列に対して「*」を用いると文字列の繰り返しになります.

例題4-3
比較演算
a = 10
b = 20
p a > b		# a が b より大きいかどうか
p a < b		# a が b より小さいかどうか
p a == b	# a と b が等しいかどうか
p a != b	# a と b が等しくないかどうか



<メモ>
★ 比較演算の答えは「true(真)」か「false(偽)」のどちらかになります. 条件が成り立つ場合には「true」, 成り立たない場合には「false」となります.
★ 「true」「false」はそれ自体で「値」(論理値と呼ばれる)として扱われ, あらかじめ予約されている単語なので変数名に使うことはできません.

例題4-4
論理演算
a = true
b = false
p a && b	# 論理積
p a || b	# 論理和
p !a		# 否定



<メモ>
★ 論理演算とは, 「true(真)」「false(偽)」(論理値)に関する演算になります. 「&&(and)」を論理積, 「||(or)」を論理和と呼びます.
★ 論理積は両方が真(true)のときだけ真(true)になる演算で, 論理和はどちらかが真(true)ならば真(true)になると定義されています.
★ 「!(not)」は否定と呼ばれ, 真(true)ならば偽(false), 偽(false)ならば真(true), が答えとなる演算です.
★ 論理演算は制御構造の条件判定とともに使われることが多いです(後述).

演算の組み合わせを以下にまとめてみます.
 
ab論理積(&&)論理和(||)
truetruetruetrue
truefalsefalsetrue
falsetruefalsetrue
falsefalsefalsefalse

問題4-1
それでは、問題!!
以下のプログラムの空欄を埋めて、実行結果が「100」となるようにしなさい。
#+演算子
a="10"
b=
print a + b , "\n"




<ヒント>
★文字データと数値データは「+」ことができません。(エラーになります。)
★「""」か「''」で囲まれたデータは「文字データ」として扱われます。
★つまり「"a" + "b"」は「"ab"」(文字データ)になりますが、「a + b」は変数aと変数bの「+」演算が実行された結果になります。



予備知識 - 演算子の優先順位 -

演算子には実行される優先順位があります. 例えば「a=a+10」という式の中には二つの演算子「=」と「+」が入っていますがこの場合, 「+」が先に実行され「=」が後に実行されます.

例題 4-5
演算子の優先順位
p  10 * 2 + 20 * 3
p (10 * 2)+(20 * 3)
p  10 *(2 + 20)* 3



<メモ>
★ ()を用いると数学のように演算子の優先順位を無視して先に計算が行なわれます.
★ 「+」と「*」では「*」の方が優先順位が高いので1番目と2番目の計算は同じになりますが, 3番目の答えは変わります.
★ すべての演算子の優先順位は
Ruby リファレンスマニュアル(演算子式)を参考にしてください.

第5章 制御構造

基本的に上から順に命令が実行されていきます. 通常はこれだけでなく, 必要に応じて処理の流れを制御できます. その制御する命令(文)を制御構造とか制御文など言います. 制御構造は基本的に以下の二種類しかありません.

  1. 条件分岐
  2. 繰り返し
条件分岐, 繰り返しに対応するいくつかの命令が用意されています. 以下それぞれを例題を用いて紹介。

5-1 条件分岐(1)if文、unless文

if 文は「もしも〜なら〜せよ」的な命令.
unless文はその逆で「もしも〜でなかったら〜せよ」的な命令.

例題5-1-1
条件分岐1
a=123
b=234

print "a=",a," b=",b,"\n"
if a>b
 print "aの方が大きい\n"
else
 print "bの方が大きい\n"
end
unless a>b
 print "aの方が小さい\n"
else
 print "bの方が小さい\n"
end



<ポイント>
if 文
条件によって処理を切り替える
条件がのとき処理1を実行
そうでなければ処理2を実行
<書式>
if 条件式
 処理1
else
 処理2
end

unless 文
条件によって処理を切り替える
条件がのとき処理を実行
そうでなければ処理2を実行
<書式>
unless 条件式
 処理1
else
 処理2
end

<メモ>
★ else 以下を省略することも可能です.
★ 複数の条件分岐をさせたいときは elsif を使って分岐を増やします(elseif でないことに注意). unless に elsif を指定することはできません.

次は少し複雑な条件分岐の例を示します.
例題5-1-2
複雑な条件
a=123
b=234
c=345

print "a=",a," b=",b," c=",c,"\n"
if a>b && b>c
 print "a > b > c\n"
elsif a>c && c>b
 print "a > c > b\n"
elsif b>a && a>c
 print "b > a > c\n"
elsif b>c && c>a
 print "b > c > a\n"
elsif c>a && a>b
 print "c > a > b\n"
elsif c>b && b>a
 print "c > b > a\n"
end




<メモ>
★ && は論理積の演算です. 両辺が真(true)の場合にだけ真(true)を返す演算, つまり両方の条件が成り立つかどうか, ということをチェックしています.
★ 比較演算では 3 つの値を同時に比較することはできないのでこのように比較演算と論理演算を組み合わせます.
★ この他にもいくつかの条件が同時に成り立つ場合(&&, and)やどれかの条件が成り立つ場合(||, or)など複数の条件をチェックするときは論理演算を用います.

5-2 条件分岐(2)case文

case文は特に, 一つの値について調べていろいろ分岐する場合に簡潔に記述できます.

例題5-2
条件分岐2

a=200

print "a=",a,"\n"
case a
when 100
 print "100"
when 200
 print "200"
else
 print "300"
end




<ポイント>
case 文
変数の値によって処理を分岐する
<書式>
case 変数
when 値1
 処理1
when 値2
 処理2
・・・
else
 処理3
end

<メモ>
★ どの値にも当てはまらないときは「else」以下の処理が実行されます. else 以下は省略可能です.
★ こちらも最後は「end」を記述します.

5-3 繰り返し(1)while文、until文

while 文はある条件が満たされている間処理を繰り返す制御文で,
until 文はある条件が満たされるまで処理を繰り返す制御文です.

例題5-3 繰り返し1

a=0
while a<5
 print a
 a+=1
end
print "\n"
until a==10
 print a
 a+=1
end



<ポイント>
while 文
条件が真(true)の間, 処理を繰り返す.
<書式>
while 条件
 処理
end

<ポイント>
until 文
条件が偽(false)の間, 処理を繰り返す.
<書式>
until 条件
 処理
end


以下は引数として与えられたファイルをそのまま出力するプログラム(UNIX コマンドの cat と同じ).

while line=gets
 print line
end
<メモ>
★ gets はコマンドラインに引数で指定されたファイルを順番にオープンして1行ずつ読みこむ命令.

例えば, 以下のプログラムを実行するとユーザーからの入力した値がそのまま表示されます.
print "input>"
input=gets
print input




<メモ>
★ 上記のプログラムは今は JavaScript で動作しているのでウィンドウが表示されると思いますが, Ruby で実際に実行するとコマンドライン上で入力待ち状態になります.
★ gets で読み込んだデータは文字列データとして変数に記憶されます.
★ 数値を読み込みたい場合は文字列を整数値に変換する命令(to_i メソッド)もしくは, 実数値に変換する命令(to_f メソッド)を用います.

print "input (2 integers)>"
a = gets.to_i
b = gets.to_i
print a + b



<メモ>
★ 数字以外を入力すると上記の例 (JavaScript) ではエラーになりますが実際の Ruby で実行すると 0 に変換されます(参照:
Ruby リファレンス String).

5-4 繰り返し(2)for文

for 文は 90% 以上配列とともに用いられる構文です. 配列から一つずつ要素を取り出してそれぞれの要素に対して処理を行ないます.

for文
配列から要素を一つ一つ取り出して処理する
<書式>
for 変数 in 配列
  処理
end

例題5-4 繰り返し2

array=[1,2,3]
for i in array
 print i,"\n"
end



<メモ>
★ for 文は配列から順次, 値を一つずつ取り出して変数 i に格納し, 処理していく.
★ 実際は内部で each メソッド(ブロック付きメソッド, イテレータ)が呼び出されており, 次の例と等価です.
★ Ruby では以下のようなブロックを使われるのが好まれるので, 実際は for 分を使うことは滅多にありません.

例題5-5 繰り返し3

array=[1,2,3]
array.each do |i|
 print i,"\n"
end



<メモ>
★ do end をブロックと呼びます. || で囲まれた変数をブロック引数と呼びます.
★ ブロックについては 4 ページ目 Ruby 特有の仕様で詳しく説明します.

繰り返しの制御構造とともによく使われるものに
  1. break:繰り返しの中止
  2. next:繰り返しの残りを中止し、次の繰り返しを処理する
  3. redo:その回の繰り返しをもう一度
があります.

例題5-6
ファイルdata.txtが
100
200
skip
300
quit
400

であるとします.
プログラム prog.rb が

while line=gets
	if line =~ "skip"	# skipの行は処理しない
		next
	end
	if line =~ "quit"	# quitがあれば処理終了
		break
	end
	print line, "\n"	#1行ずつ表示
end

としたとき以下のコマンドを実行すると


<メモ>
★ =~ は「ある文字列が含まれるかどうか」という真偽値(true, false)を返す演算子(正規表現の項目で詳しく解説).

応用 Tips
比較演算を利用して簡単な条件分岐ができます(短絡演算子).

a=123
b=124
c=123
a == b and print "a==b\n"
a == c and print "a==c\n"



<メモ>
★ 論理演算子 ||, or は左の式が真ならば右の式を評価せず(実行せず)真を返します. また &&, and は左の式が偽ならば右の式を評価せずに偽を返します. この性質を利用して簡単な(if文のような)制御構造を表現できます.
★ 上記の例は以下の例と等価です.

a=123
b=124
c=123
print "a==b\n" if a == b
print "a==c\n" if a == c



<メモ>
★ 上記の if は「if 修飾子」と呼ばれ, その条件が満たされた場合だけ処理が実行されます. 処理が一行だけの場合など if 文で書くよりも簡潔に記述できます.
★ unless 修飾子, while 修飾子, until 修飾子もあります.(参考:Ruby リファレンス(制御構造)

予備知識 - 制御構造とスコープ -

スコープとは「変数の有効範囲」だということはすでに説明しました. Ruby ではこのスコープについてちょっと注意する点があります. 気になるものをリストアップしておくと,
  1. 制御構造(if, while, for など)はスコープを作らない.
  2. ブロックはローカルスコープを作るが, ブロック内から外側のスコープの変数にアクセスできる
for などの制御構造はローカルスコープを作らないので制御構造内で用いられる変数名と制御構造の外側で使われている変数名が同じだと変数の値を書き換えてしまいます. 特に注意するべきはブロックで, ブロックの引数はローカルスコープの変数なのですが, ブロック内からブロックの外側のスコープの変数にアクセスができるので, ブロック引数の名前とブロックの外側のスコープの変数名がかぶってしまうとこれも for 文と同様に変数の値を書き換えてしまいます. (参照:
Ruby のスコープと制御構造)

以下に例を示します.
# 制御構造の変数

a = [1,2,3]
i = 100
for i in a
end
print i




# ブロック引数

a = [1,2,3]
i = 100
a.each do |i|
end
print i



<メモ>
★ どちらの例でも, 配列の各要素を変数 i に代入していき最後に代入した 3 の値を保持しています.


第6章 メソッド

メソッドとは簡単に言うと「小さな処理のまとまり」と言えます. 手続き型言語では関数, 手続き, サブルーチンなどと呼ばれていいます. 手続き型言語でもオブジェクト指向言語でもある特定の処理のまとまりを切り分けて, それを呼び出すという形でプログラムの可読性, 再利用性を高めています.

メソッド定義
<書式>
def(仮引数)
  処理
end

<メモ>
★ メソッドにはどのような処理をするかという定義部と, それを実際に使う呼び出し部とがあります.
引数とは, メソッドにき渡す変のことで定義部で書かれる引数を仮引数, 呼び出し部で書かれる引数を実引数と呼びます.
★ メソッドの引数は「,」で区切って複数指定可能です.
★ 変数にデータ型がないので, C 言語のように仮引数にデータ型を指定する必要はありません.

例題6-1 メソッド

def show(a)		# 定義部
 print a,"\n"
end

b="Hello"
show(b)			# 呼び出し部



<メモ>
★ メソッドの定義は呼び出し部よりも先(上)に記述する必要があります.
★ 上記の show メソッドは引数を表示して改行するだけのメソッドです.
★ 上記の例では a が仮引数, b が実引数になります.
★ メソッドを呼び出すときは メソッド名(引数) とします. () は省略可能です.

メソッドは計算した値を呼び出し部で取り出すことができます.
その計算した結果戻す値のことを戻り値(返り値)といいます.

例題6-2 戻り値のあるメソッド

def pow(a)
 a*a
end

b=100
print pow(b)



<メモ>
★ powは引数の 2 乗を計算して返すメソッド.
★ 戻り値は最後に評価した式の値かreturn文で指定した値になります. 戻り値を明記したい場合は(C 言語のように) return(a*a) と書くと良いでしょう.
★ 上記の print メソッドの引数に pow(b) が指定されています. この場合は print(pow(b)) と書いても同じになりますが, print pow b と書く b が print メソッドの引数か, それとも pow メソッドの引数かがあいまいになるので () はつけて書くのが良いでしょう.

通常, Ruby ではメソッド内で仮引数の値を変更しても実引数の値は変更されません(参照:
Ruby FAQ 仮引数に代入すると実引数に影響を及ぼしますか, Ruby には値渡ししかない).

例題6-3 仮引数の変更

a = 100
def method(a)
 a = 200
end
method(a)
print a




ですが, 時に実引数の値を変更したいメソッドを作りたいときがあります(C 言語で言う参照渡しがしたい).
配列を代用することで実現することができます.
例題6-4 仮引数の変更

a = [100]
def method(a)
 a[0] = 200
end
method(a)
print a



<メモ>
★ これは仮引数に配列(オブジェクト)の参照が渡されるためです.
★ 例えば, 配列を代入演算子「=」で別の配列に代入するとすべての配列の要素がコピーされるのではなく, 配列を指し示している部分だけがコピーされます. そのため代入された配列の要素を変更すると元の配列の内容も書き換えられてしまいます.

例題6-5 配列の代入

a = [1, 2, 3]
b = a
b[0] = 100
p a



<メモ>
★ 配列の要素をすべてコピーして別の配列にするには clone メソッドを用います.



例題6-6 配列のコピー

a = [1, 2, 3]
b = a.clone
b[0] = 100
p a



<メモ>
★ 最後は少々難しかったかもしれませんが, オブジェクト指向の項目を読んだ後でまた読み返すと理解が進むかもしれません.

練習問題
それでは最後に1ページ目(Ruby 基礎文法)の復習問題です.
以下のプログラムはガンコおやじの八百屋さんシュミレーション.

★ 金持ちにしか売らない八百屋さん.
★ しかも「バナナ」しか売らない八百屋さん.
★ しかもちゃんと人間を見ている八百屋さん.
★ お金を持ってるくせにケチな人には売りません.
うまく値切ってただでバナナをゲットしてみてください.
★ プログラムコードを読むことでどうすれば良いかのヒントがつかめるはずです.


 price=30000
 count=0

 print "おやじ\n",
       "「へいらっしゃいッ!」\n",
       "「安いよ、安いよ!」\n",
       "「バナナ一本がたったの", price, "円だッ!」\n"
 print "「あんた、いくら持ってんだい?」\n"
 money=gets.to_i
 print money, "円です。\n"

 if money<price
   print "おやじ\n",
         "「けぇった、けぇったぁ!」\n",
         "「あんたに売るバナナはうちにゃねぇよッ!」\n"
   exit
 end

 while count<5
   # 選択
   print "【買う】->1、【値切る】->0\n"
   res=gets.to_i

   if res==1
	 break
   end

   # 値引き
   money=money/2
   price=price-money

   # おやじの思考
   if price<=0
	break
   end

   case	count
   when 0
       print "おやじ\n",
             "「よーし、わかった!これならどうだ!", price, "円だ!」\n"
   when 1
       print "おやじ\n",
             "「これならどうだ!", price, "円だ!」\n"
   when 2
       print "おやじ\n",
             "「これ以上はまけられねぇよ。」\n",
             "「", price, "円だ!」\n"
   when 3
       print "おやじ\n",
             "「ほんまにこれ以上は無理だぜよ!」\n",
             "「", price, "円でどうだ!」\n"
   when 4
       print "おやじ\n",
             "「あんたの根性、気に入った!」\n",
             "「持ってけどろぼーッ!ただだ!ただ!金なんかいらねぇやッ!」\n"
   end
   count+=1
end

 # 最後のセリフ
 if res==1
   print "おやじ\n「バナナ一本", price, "円!」\n「まいど!」\n"
 elsif count==5
   print "おやじ\n「まいど!」\n"
 else
   print "おやじ\n「金持ってるくせにケチるんじゃねぇよ。」\n"
 end



<ヒント>
★ 最初に入力する金額と繰り返し回数がポイントです.
[文字].to_iは文字データを数値データに変換する命令(メソッド)です.
★ gets メソッドで入力されたデータは「文字列」データとして変数に記憶されます.

一通り基本が終わったところで, 次はオブジェクト指向のお話。