この章では,GPhys, GGraph の基盤となっている Ruby という言語のごく初歩を学習します. ごく初歩ではありますが,(特に GPhys, GGraph を利用するうえで)非常に重要な概念についてはきちんと押さえていきます.
目次
Ruby は Perl やシェルスクリプトなどと同じ,スクリプト言語です. 「スクリプト」という言葉は「プログラム」とほとんど同じ意味ですが, 特に「コンパイルする必要がなくそのまま実行できるプログラム」のことを指します. Ruby では FORTRAN や C 言語のようなコンパイルは必要ありません.
Rubyプログラムを記述したファイルを ruby コマンドで呼ぶと,中身が実行されます.
まずエディタで以下のように書かれたファイルを作成し, hello_world_1.rb という名前で保存します.
ソースコード hello_world_1.rb
print("Hello, World\n")
そして
$ ruby hello_world_1.rb
とコマンドを実行すると,
Hello, World
と表示されます. プログラムの内容は「 " でくくられた部分(=文字列)を表示せよ」ですので,このような結果となります.\n は改行を表します.
また,ファイルの先頭に #!/usr/bin/env ruby という行をつけ加えて, chmod +x してファイルを実行可能にしておけば, そのファイルを実行すると Ruby プログラムとして動作します.
以下のような hello_world_2.rb を作成し,実行してみましょう.
ソースコード hello_world_2.rb
#! /usr/bin/env ruby print "Hello, World\n" # 曖昧でなければ括弧は省略可能です
実行:
$ chmod +x hello_world_2.rb $ ./hello_world_2.rb
結果:
Hello, World
# から行末まではコメントで,実行時には無視されます.
エディタでファイルを作成しなくても,Ruby コードをインラインで実行することも可能です. ruby コマンドの -e オプションを使います.
実行:
$ ruby -e 'print "Hello, World\n"'
結果:
Hello, World
はじめる前に ですでに紹介したように,Ruby には irb という対話型の実行環境も用意されています. 入力待ちのプロンプト(irb(main):001:0> といった文字列)が表示されたら,そこに Ruby コードを入力し,1行ずつ実行することができます(青字の部分がユーザーの入力です).
$ irb
print "Hello, World\n"
Hello, World
=> nil
これまでの例と同様,print "Hello, World\n" という Ruby コードの実行結果 Hello, World が下に表示されます. irb の場合はさらにその下に,=> に続いて「戻り値」が表示されます(この場合は nil)が,これはさしあたっては気にしなくていいでしょう.
以下では irb を使って,Ruby の重要な概念に適宜触れつつ,基本的な使い方を見ていくことにします.
Ruby では,変数は型宣言をせずに使います.
a = 2 # 整数 => 2 b = 3.5 # 実数 => 3.5 irb(main):004:0> c = "apple" # 文字列 => "apple"
= の両側の空白は入れても入れなくてもかまいません.
型宣言がないので,FORTRAN や C 言語を使ったことがある人は,おやっ,と思うかもしれません. こういった言語では,a, b, c という「箱」が整数や実数や文字列という型を持ち(プログラムの冒頭で定義する),そこに 2 や 3.5 や "apple" という「値を入れる」,という説明がされますが,Ruby は少し違った概念で設計されています.
Ruby では,2 や 3.5 や "apple" は「オブジェクト」と呼びます. Ruby で扱われるデータはすべてオブジェクトです. オブジェクトの型のことを「クラス」と呼びます. すべてのオブジェクトは何らかのクラスに属しています. 2 は整数クラスのオブジェクト,3.5 は実数クラスのオブジェクト,"apple" は文字列クラスのオブジェクトです. Ruby での変数は,「箱」ではなく「名札」です. 上でやった操作は,2 という整数オブジェクト, 3.5 という実数オブジェクト, "apple" という文字列オブジェクトに,それぞれ a, b, c という名札をつけたことに相当します.
オブジェクトはその値だけでなく,クラスやたとえば大きさなどの自分に関する諸々の情報(「属性」と呼びます)を自分で知っています.
a # オブジェクトの値 => 2 b.class # オブジェクトのクラス => Float c.size # オブジェクトの大きさ => 5
ここで出てくる class や size を「メソッド」と呼びます. オブジェクトに対して「クラスを述べよ」「大きさを答えよ」などとメッセージを送っていることになります. オブジェクトはそれに対して「実数だ」「5だ」などと答えてくれるわけです.
上の例のように,あるオブジェクト obj のメソッド method は obj.method のかたちで呼び出します(メソッドに引数 arg があれば obj.method(arg) です). オブジェクトがどんな属性を持っているか,どんなメソッドにどう答えるかは,属しているクラスで定義されています. あるクラスでは定義されているメソッドが別のクラスではなかったり,同じ名前のメソッドでもクラスが違うと動作が違ったり,ということがあります.
メソッドの一覧は次のように表示できます.
irb(main):007:0> b.methods.sort # メソッド一覧を取得し、sort する => ["%", "*", "**", "+", "+@", "-", "-@", "/", "<", "<=", "<=>", "==", "===", "=~", ">", ">=", "__id__", "__send__", "abs", "between?", "ceil", "class", "clone", "coerce", "display", "div", "divmod", "dup", "enum_for", "eql?", "equal?", "extend", "fdiv", "finite?", "floor", "freeze", "frozen?", "hash", "id", "infinite?", "inspect", "instance_eval", "instance_exec", "instance_of?", "instance_variable_defined?", "instance_variable_get", "instance_variable_set", "instance_variables", "integer?", "is_a?", "kind_of?", "method", "methods", "modulo", "nan?", "nil?", "nonzero?", "object_id", "prec", "prec_f", "prec_i", "private_methods", "protected_methods", "public_methods", "quo", "remainder", "respond_to?", "round", "send", "singleton_method_added", "singleton_methods", "step", "taint", "tainted?", "tap", "to_a", "to_enum", "to_f", "to_i", "to_int", "to_s", "truncate", "type", "untaint", "zero?"]
演算も当然できます.いろいろやってみてください. どの演算が先におこなわれるか,演算子の優先順位が Rubyリファレンスマニュアル に書いてありますので,参考にしてください.
d = a * ( b**2 + 3.0e2 ) => 624.5 e = c + "orange" => "appleorange" # 文字列の足し算は単に順に並べるだけ
上の例で,同じ + でも,数値オブジェクトの場合と文字列オブジェクトの場合では動作が違うことがわかると思います. Ruby では,演算子も(. をつけませんが)メソッド呼び出しである,というわけです.
オブジェクトをまとめたオブジェクトが配列です. オブジェクトを順番に並べて [ ] でくくると,それが配列クラスのオブジェクトになります. 配列中のオブジェクトは同じクラスである必要はありません.
ary1 = [ 3, b, d-3.0, "orange"] => [3, 3.5, 621.5, "orange"] ary1[0] => 3 # C言語と同じで最初の要素が0番 ary1[1..3] => [3.5, 621.5, "orange"] # 1番から3番まで ary1[-1] => "orange" # 負の数はうしろから数える ary2 = [a, ary1] => [2, [3, 3.5, 621.5, "orange"]] # 配列の中に配列があっても大丈夫 ary2[1][3] => "orange" # ary2[1]の3番の要素
もう一つ,オブジェクトをまとめたオブジェクトがあります. ハッシュと呼ばれるものです. 配列は整数のインデックスで値を参照しましたが,ハッシュは「キー」で値を参照します. キー => 値 の組を並べて { } でくくると,それがハッシュクラスのオブジェクトになります. キーはどんなオブジェクトでもかまいませんが,ふつうは文字列を使うことが多いです. もちろん値もどんなオブジェクトでもOKです.
hsh1 = {"name"=>"apple", "color"=>"red", "quantity"=>3} => {"name"=>"apple", "color"=>"red", "quantity"=>3} irb(main):017:0> hsh1["name"] # キーで値を参照 => "apple" irb(main):018:0> hsh1["price"] = 100.0 # 要素の追加 => 100.0 hsh1 => {"name"=>"apple", "color"=>"red", "quantity"=>3, "price"=>100.0}
プログラムの流れを変えるための制御構造は,Ruby にもあります. ここでは条件分岐と繰り返しの例を紹介します.
ある条件によってプログラムの挙動を変えたい場合,if 文を使います.
if (a == 3) then # then は省略可能,曖昧でなければ括弧も省略可能 print "Hello\n" else print a,"\n" if a != 4 # if 文は後付けも可能 end
プロンプト > の左の数字はネストの深さを表していて,この数字のぶんだけ end で閉じなければいけません. それまでのあいだ,ネストがなくなる3行目までは irb は何も実行しません. また,2, 4行目で > が * に変わっているのは,継続行をあらわしていて,コードが前の行から続いていることを示しています.
同じ(ような)ことを何度も繰り返しおこないたい場合,for 文を使います.
for i in 1..5 print i,"\n" end
繰り返しには,配列の各要素に対して順に処理をおこなうイテレータというものもあります.
["dog","cat","bird"].each do |i| print "a #{i}\n" # " "内の #{ } の中はRubyコードとして式展開される end
each は do ... end (または { ... } とも書けます)を引数にとるメソッドです. 配列の各要素を | | の中の変数(ここでは i)に格納し,その i に対する操作を記述します.つまり,
for i in ["dog","cat","bird"] print "a #{i}\n" end
と同じです. これだけだとあまりありがたみが感じられないかもしれませんが,イテレータにはいろいろなものがあり,より直接的にループを記述することができます. for を使うより便利なことが多いです. イテレータを使いこせるようになると,より「Rubyっぽい」プログラムが書けるようになります.
(1..10).each { |i| printf("%02d\n", i) # printf は書式つきの print } 10.times do # 10回繰り返し print "hoge" end
数学関数は,Math モジュールを使います.
モジュールとは,メソッドや定数やクラスを束ねる名前をつけるためのものだと考えてください. これまで見てきたオブジェクトのメソッドは,あるオブジェクトにメッセージに対応した処理をおこなわせるものでしたが,モジュールのメソッドは,ある種の処理そのものをおこなうためのものです(区別しやすいように,モジュールのメソッドを「モジュール関数」とも呼びます).
数学に関連する機能を集約したものが Math モジュールです. 三角関数などのメソッドや円周率などの定数が定義されています.
irb(main):040:0> a = Math::cos(0) # Math というモジュールの cos という関数を呼ぶ b = Math.sin(0) # メソッド呼び出しは . でもOK p = Math::PI
include 文を使うと、それ以降は Math:: の部分が不要になります。
include Math c = cos(PI)
日付や時刻を扱うには,DateTime クラスを使うと便利です. DateTime クラスは Ruby に標準添付されていますが,起動時には読み込まれていないので,まず,
require "date"
とします.これで定義が読み込まれます. このように,Ruby 本体と別になっているライブラリは require することではじめて使えるようになります(一方,前述のMathはRubyの組込モジュールのため最初から読み込まれています).
DateTime クラスのオブジェクトを作るには,
sakki = DateTime.new(2012,12,13,10,30) # 2012年12月13日10時30分
とします. およそどのクラスでも一般に,new というのが新しいオブジェクトを作るメソッドになっています. 他に,
irb(main):047:0> ima = DateTime.now # 現在
itsuka = DateTime.parse("2003-06-28") # 文字列を解釈して作成
といったやり方もあります.
DateTime クラスには足し算引き算他さまざまなメソッドが定義されています.
sakki.year => 2012 (sakki + 40).day # 40日後は何日か. => 22 sakki - itsuka # 差の日数(分数,単位は日.) => (55303/16) irb(main):052:0> (sakki >> 1).to_s # 1ヶ月後を文字列にする => "2013-01-13T10:30:00+00:00" irb(main):053:0> sakki.strftime("%H:%M (%y/%m/%d)") # 好きなフォーマットの文字列にする => "10:30 (12/12/13)"
ここまで見てきた基本的な機能の組み合わせだけでも,十分便利な Ruby プログラムを書いて使うことができると思います. でも,Ruby に慣れてきたら,プログラムをもっと見通しよくしたいとか,同じような処理をしているところをもっと汎用的に呼び出したいとかいった欲求がうまれてくるでしょう.
そのためには,既存のクラスに新しいメソッドを追加したり,自分で新しいクラスを作ったりすることになります. これは FORTRAN や C 言語でサブルーチンや関数を自分で作ることと対応しています. GPhys, GGraph は,こういった拡張がある程度大きなまとまりになったもの(ライブラリ)です.
(作成中)
(作成中)
[次へ進む]