Ruby入門
- はじめに
- Ruby概要
- Rubyのクラスやメソッドを調べるとき
- Windows Subsystem for LinuxでLinux環境を整えた場合
- Rubyをインタラクティブに使う場合
- 基本操作
- 標準組み込みライブラリ
- 標準添付ライブラリ
- 戻る
はじめに_
Ruby on Railsを試しに使う程度のRubyの使い方を練習する。
注意点はRubyはバージョンによって、メソッドが一部異なる(後方互換性が一部ない)。このページではバージョン3.1を使っているが、バージョンが異なっていても本ページの練習は実行できる。なお、検索エンジンなどで調べるときは自分の使っているバージョンの記述を探すこと。特にバージョン1.8および1.9とはかなり異なるので注意する。
Ruby概要_
Ruby公式にある「他言語からのRuby入門」を一通り読みましょう。
Rubyの特徴
- JavaやC言語、C++はコンパイル言語(プログラムをコンパイルして実行ファイルを生成する言語)だが、Rubyはインタープリタ言語(プログラムを1行ずつ解釈して、実行していく言語)である。このため、エラーが発生した時点で処理は終了する。
- JavaやC言語、C++は静的型付け言語(変数は最初に型を宣言してから使用する言語)だが、Rubyは動的型付け言語(変数の型は代入される値に応じて定まる・変更される言語)である。
- RubyはJavaと同様にオブジェクト指向言語である。
- Rubyは文末を表すセミコロンは必要ない。
- 繰り返し処理は for 文よりも イテレーション(each)を使うことが推奨される。
Rubyのクラスやメソッドを調べるとき_
- クラス名やメソッド名が分かっている場合は[ルリマサーチ]で検索する。
- クラス名やメソッド名が分からない場合はRuby 3.1 リファレンスマニュアルの組み込みライブラリの項から探す。
たとえば、配列(Arrayクラス)のメソッドを知りたい場合は組み込みライブラリの項からclass Arrayに進み、所望の働きをするメソッドがないかを探す。
Windows Subsystem for LinuxでLinux環境を整えた場合_
VcxSrv(XLaunch)の起動_
gnome-terminalを利用するので、まず、VcxSrv(XLaunch)を起動する。VcxSrvのインストールで設定したVcxSrvのアイコンをクリックし、VcxSrvを起動する。
gnome-terminalの起動_
gnome-terminalの利用で設定したgnome-terminalを起動する。
Ubuntuターミナルを起動し、ターミナル上で以下を起動する。
% gterm &
Rubyをインタラクティブに使う場合_
まず、Rubyのバージョンを調べる。
% cd % which ruby /home/gotoh/.rbenv/shims/ruby % ruby -v ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-darwin21]
irbをインストールする。
% gem install irb % which irb /home/gotoh/.rbenv/shims/irb
irbは、1行ごとにrubyのコードが実行できるので、動作確認を行える。起動までに少し時間がかかるので待つこと。以後はしばらくirb上で動作確認をする。
% irb >> >> exit
基本操作_
Hello World!_
プログラムの定番であるHello World!を実行してみる。
% irb >> puts("Hello World!") Hello World! => nil >>
Rubyではメソッド(関数)の括弧を省略してよい。このため以下は同等の結果を返す。
% irb >> puts "Hello World!" Hello World! => nil >>
- puts(文字列):文字列に改行を加えて標準出力に出力する。
- 文字列:ダブルクォーテーション""、シングルクォーテーションで囲まれたもの。
コメントアウト_
シャープ記号#を記述するとそれ以降はコメントとして扱われる。
>> 200 + 4 /2 => 202 >> # 200 + 4 /2 => nil >> >> 200 + 4 / 2 # - 1 => 202
Rubyでは、すべての文(ステートメント, statement)が値をとる。数字の四則演算の文は演算結果を返しているが、コメントの場合はnilを返している。irbでは各文の値を表示してくれる。
メソッドの定義_
以下を入力する。
?> def three_times ?> puts "Hello World!" ?> puts "Hello World!!" ?> puts "Hello World!!!" >> end => :three_times
Rubyでは def メソッド名 ~ end でメソッドを定義できる。
def メソッド名(引数) 文 end
実行はメソッド名を入力する。
>> three_times Hello World! Hello World!! Hello World!!! => nil
メソッドに引数を付け加えたい場合は以下のようにする。
?> def three_times(value) ?> puts value ?> puts value ?> puts value >> end => :three_times
実行する場合は以下のとおり。
>> three_times("Hi World!") Hi World! Hi World! Hi World! => nil >> three_times("Aroha World!") Aroha World! Aroha World! Aroha World! => nil
引数の初期値を決めることもできる。
?> def three_times(value = 'Good morning') ?> puts value ?> puts value ?> puts value >> end => :three_times
実行してみる。
>> three_times Good morning Good morning Good morning => nil >> three_times("Good evening") Good evening Good evening Good evening => nil
Rubyではメソッド中の一番最後の文が返す値が返り値として用いられる。このため、明確に返り値を指定したい場合はreturnを用いる。
?> def three_times(value) ?> puts value ?> puts value ?> puts value ?> return true >> end => :three_times
メソッドからの返り値は以下のように利用することができる。
>> x = three_times("Good afternoon") Good afternoon Good afternoon Good afternoon => true >> puts x true => nil
分岐_
分岐は以下のように書く。
?> def branch_test(value) ?> if value < 12 ?> puts "Good morning" ?> elsif value >= 12 && value < 18 ?> puts "Good afternoon" ?> else ?> puts "Good evening" ?> end >> end => :branch_test
実行してみる。
>> branch_test(8) Good morning => nil >> branch_test(12) Good afternoon => nil >> branch_test(18) Good evening => nil
- Rubyの分岐は以下のように記述する。
if 式 文 elsif 式 文 else 文 end
- 条件演算子として <, > <=, >=, ==, != などがある。
- 式を結合する論理結合子として、&&, || などがある。
- より詳しくはこちら→リファレンス:演算子
「~でないならば」という条件分岐も行える。
?> def branch_test(value) ?> unless value == 0 ?> puts "Not zero" ?> else ?> puts "Zero" ?> end >> end => :branch_test >> branch_test(0) Zero => nil >> branch_test(100) Not zero => nil
以下の2つの書き方は同じ結果をもたらす。
>> x = 10 => 10 ?> if x > 9 ?> puts "x is more than 9." >> end x is more than 9. => nil >> puts "x is more than 9." if x > 9 x is more than 9. => nil
練習:分岐_
上記のメソッド branch_testを以下の条件を満たすように書き直せ。
- Good morningは6時から12時前までとする。
- Good afternoonは 12時から18時前までとする。
- Good eveningは 0時から6時前、また、18時から24時までとする。
- 1日は24時間とする。
解答例はこちら
代入_
Rubyは変数の型を動的に定める言語であるため、事前に定義する必要がない。
>> x = "4" => "4" >> x.class => String >> x = [1, 2, 3, 4] => [1, 2, 3, 4] >> x.class => Array >> x = {"one":1, "two":2, "three":3, "four":4} => {:one=>1, :two=>2, :three=>3, :four=>4} >> x.class => Hash >> x = 1.2 => 1.2 >> x.class => Float >> x = true => true >> x.class => TrueClass >> x = false => false >> x.class => FalseClass >> x = nil => nil >> x.class => NilClass
- 変数.class:変数の型(クラス)を提示するメソッド。
繰り返し処理(イテレータ)_
RubyではC言語やJavaでよく使われるfor文はあまり使われない。4回処理を繰り返す場合は以下の構文がよくつかわれる。
?> 4.times do |x| ?> puts x >> end 0 1 2 3 => 4
構文は以下のとおり。
数字.times do | 変数 | 文 end
この構文は以下のように中括弧を用いても記述できる。
>> 4.times {|x| puts x} 0 1 2 3 => 4
配列(Array)やハッシュ(Hash)の要素すべてに対して処理を行う場合は、eachメソッドを用いる。配列の場合。
>> week = ["Mon", "Tue", "Wed", "Thi", "Fri", "Sat", "Sun"] => ["Mon", "Tue", "Wed", "Thi", "Fri", "Sat", "Sun"] ?> week.each do | weekday | ?> puts weekday >> end Mon Tue Wed Thi Fri Sat Sun => ["Mon", "Tue", "Wed", "Thi", "Fri", "Sat", "Sun"]
ハッシュの場合。ハッシュはキー(key)とバリュー(value)の組み合わせの集合である。
>> week = {"Mon":1, "Tue":2, "Wed":3, "Thi":4, "Fri":5, "Sat":6, "Sun":0} => {:Mon=>1, :Tue=>2, :Wed=>3, :Thi=>4, :Fri=>5, :Sat=>6, :Sun=>0} ?> week.each do | key, value| ?> puts "#{key} is #{value}" >> end Mon is 1 Tue is 2 Wed is 3 Thi is 4 Fri is 5 Sat is 6 Sun is 0 => {:Mon=>1, :Tue=>2, :Wed=>3, :Thi=>4, :Fri=>5, :Sat=>6, :Sun=>0}
- 文字列中での変数の利用:ダブルクォーテーションで囲んだ文字列中で#{変数 or 文}を記載する。
- 配列 or ハッシュ.each do | 要素を代入する変数 | 文 end
繰り返し処理(while)_
while文も使える。
while 式 文 end
10回ループしてみる。
>> x = 1 => 1 ?> while x < 11 ?> puts x ?> x = x + 1 >> end 1 2 3 4 5 6 7 8 9 10 => nil
無限ループを作って、break文で抜け出してみる。
>> x = 1 => 1 ?> while true ?> puts x ?> x = x + 1 ?> if x >= 11 ?> break ?> end >> end 1 2 3 4 5 6 7 8 9 10 => nil
練習:繰り返し処理_
先に作成したthree_times(value)を繰り返し処理を使って、many_times(num, str)に拡張せよ。なお、many_timesはstrをnum回表示するメソッドとする。
解答例はこちら
クラス:基本_
Rubyではクラスは以下の書式で定義する。
class クラス名(1文字目大文字) # 初期化メソッド def initialize 文 end def メソッド名 文 end end
先ほどのthree_timesメソッドをクラスで定義してみる。
?> class ThisAndThat ?> def three_times(value = "Good morning") ?> 3.times do |x| ?> puts "#{x}: #{value}" ?> end ?> end >> end => :three_times
このように定義したクラスを利用する場合はインスタンスを生成する。
>> newObject = ThisAndThat.new => #<ThisAndThat:0x0000000105f5fab8>
クラスで定義されているメソッドは以下のようにインスタンスにピリオドをつなげることで呼び出す。
>> newObject.three_times 0: Good morning 1: Good morning 2: Good morning => 3 >> newObject.three_times("Hello World!") 0: Hello World! 1: Hello World! 2: Hello World! => 3
インスタンスの型(クラス)を確認してみる。
>> newObject.class => ThisAndThat >>
クラス:プライベートメソッド_
クラス内のみで使用するメソッドはプライベートメソッドとして定義する。
?> class Examples ?> def a ?> puts "a" ?> end ?> ?> private ?> def b ?> puts "b" ?> end >> end => :b
メソッドbがプライベートメソッドとなる。試してみる。
>> abc = Examples.new => #<Examples:0x00000001061fe508> >> abc.a a => nil >> abc.b (irb):130:in `<main>': private method `b' called for #<Examples:0x00000001061fe508> (NoMethodError) from /Users/gotoh/.rbenv/gems/3.1.0/gems/irb-1.4.2/exe/irb:11:in `<top (required)>' from /Users/gotoh/.rbenv/versions/3.1.2/bin/irb:25:in `load' from /Users/gotoh/.rbenv/versions/3.1.2/bin/irb:25:in `<main>'
クラス内でしか使用しないメソッドに関してはプライベートメソッドとすることにより、意図しない呼び出しなどを防ぐことができる。
クラス:初期化(initialize)_
インスタンス生成時に行いたい処理については初期化メソッド initialize を定義する。初期化メソッドinitializeは「クラス名.new」を実行する際に自動的に呼び出される。
?> class Room ?> def initialize ?> puts "abc" ?> end >> end => :initialize
実行してみる。
>> x = Room.new abc => #<Room:0x000000010618f978>
インスタンス生成時に引数を与えることもできる。
?> class Room ?> def initialize(value) ?> puts value ?> end >> end => :initialize
実行してみる。
>> x = Room.new("OK, Google") OK, Google => #<Room:0x0000000105da65c8> >> y = Room.new("Hey, Alexa") Hey, Alexa => #<Room:0x000000010632a6c0>
クラス:継承_
継承は以下のように行う。
class 子クラス < 親クラス end
ゾウとインドゾウのクラスを考えてみる。
?> class Elephant ?> def ear ?> puts "big" ?> end ?> ?> def color ?> puts "gray" ?> end >> end => :color
ゾウのインスタンスを確かめてみる。
>> john = Elephant.new => #<Elephant:0x000000010613e870> >> john.ear big => nil >> john.color gray => nil
ゾウのクラスを継承したインドゾウのクラスは以下の通り。
?> class IndianElephant < Elephant ?> def ear ?> puts "small" ?> end >> end => :ear
インスタンスを確認してみる。
>> siva = IndianElephant.new => #<IndianElephant:0x0000000105f8ca40> >> siva.ear small => nil >> siva.color gray => nil
IndianElephantクラスでは未定義のcolorメソッドがElephantクラスを継承しているため使用することができる。また、IndianElephantクラスで定義されているearメソッドについては上書きされている。この上書きをオーバーライドという。
どういうクラスを継承しているかどうかを調べるメソッドとしてsuperclassが用意されている。これを使って、親クラスを調べてみる。
>> IndianElephant.superclass => Elephant >> Elephant.superclass => Object >> Object.superclass => BasicObject >> BasicObject.superclass => nil
まとめて調べることもできる。
>> IndianElephant.ancestors => [IndianElephant, Elephant, Object, PP::ObjectMixin, Kernel, BasicObject]
RubyにおいてはすべてのクラスはObjectクラスを継承している。最上位クラスはBasicObjectクラスとなっている。
どのようなメソッドが定義済み(継承している)かを調べるメソッドとしてinstance_methodsというメソッドが用意されている。すべてのクラスはObjectクラスを継承しているため、Objectクラスで定義されているメソッドはどのクラスでも使用できる。
>> Elephant.instance_methods => [:color, :ear, :pretty_print, :pretty_print_cycle, 〜省略〜 :!=, :equal?, :__id__] >> Object.instance_methods => [:pretty_print, :pretty_print_cycle, 〜省略〜 :!=, :equal?, :__id__]
クラス:クラスメソッドとインスタンスメソッド_
ここまでの例で二種類のメソッドが登場している。
- インスタンス.メソッド(例えば siva.ear, siva.color)
- クラス名.メソッド(例えば、 Elephant.ancestors, Object.instance_methods)
前者をインスタンスメソッド、後者をクラスメソッドという。ここまでのメソッドの定義方法はインスタンスメソッドとなる。
?> class Examples ?> def i_method ?> puts "I'm an instance method." ?> end ?> ?> def self.c_method ?> puts "I'm a class method." ?> end >> end => :c_method
二つのメソッドの動作を確認してみる。まず、クラスメソッドの動作確認。i_methodはインスタンスメソッドのため呼び出しはエラーがでる。
>> Examples.i_method (irb):247:in `<main>': undefined method `i_method' for Examples:Class (NoMethodError) Did you mean? method c_method from /Users/gotoh/.rbenv/gems/3.1.0/gems/irb-1.4.2/exe/irb:11:in `<top (required)>' from /Users/gotoh/.rbenv/versions/3.1.2/bin/irb:25:in `load' from /Users/gotoh/.rbenv/versions/3.1.2/bin/irb:25:in `<main>' >> Examples.c_method I'm a class method. => nil
次にインスタンスメソッドの動作確認をする。c_methodはクラスメソッドのため呼び出しはエラーがでる。
>> x = Examples.new => #<Examples:0x00000001060b57f0> >> x.i_method I'm an instance method. => nil >> x.c_method (irb):252:in `<main>': undefined method `c_method' for #<Examples:0x00000001060b57f0> (NoMethodError) Did you mean? method i_method from /Users/gotoh/.rbenv/gems/3.1.0/gems/irb-1.4.2/exe/irb:11:in `<top (required)>' from /Users/gotoh/.rbenv/versions/3.1.2/bin/irb:25:in `load' from /Users/gotoh/.rbenv/versions/3.1.2/bin/irb:25:in `<main>'
ファイルからの読み込み_
テキストファイルに記述したRubyのプログラム(Rubyスクリプトなどとも呼ばれる)を実行する場合を練習する。
irbを終了する。
>> exit
練習用ディレクトリを作成する。
% cd % mkdir -p Sandbox % cd Sandbox
Rubyスクリプトの拡張子は多くの場合 .rb が使われている。練習用のファイルを作成する。
% touch test.rb
お好きなエディタを起動する。先ほど作成した~/Sandbox/test.rbをエディタで開く。
以下をコピーする。
puts "Hello World!"
保存する。
作成したRubyスクリプトを実行する。
% ls % ruby test.rb Hello World!
変数の種類:ローカル変数、インスタンス変数、クラス変数、定数_
- 定数:すべて大文字で記載する。メソッド内での定義は許されない。
- ローカル変数:1文字目を小文字で記載する。定義されたブロックの範囲内のみ読み書き可能な変数。
- インスタンス変数:変数名の前にアットマーク(@)を記載する。インスタンス内で共通に読み書き可能な変数。
- クラス変数:変数名の前にアットマークを2つ記載する。クラス内(複数のインスタンス間)で共通に読み書き可能な変数。
まず、定数の働きを確認する。
% irb >> CONSTANT = 100 => 100 >> CONSTANT => 100 >> CONSTANT = 200 (irb):3: warning: already initialized constant CONSTANT (irb):1: warning: previous definition of CONSTANT was here => 200 >> CONSTANT => 200 ?> def def_cons ?> CONS = 100 >> end /Users/gotoh/.rbenv/gems/3.1.0/gems/irb-1.4.2/lib/irb/workspace.rb:119:in `eval': (irb):6: dynamic constant assignment (SyntaxError) CONS = 100 ^~~~ from /Users/gotoh/.rbenv/gems/3.1.0/gems/irb-1.4.2/exe/irb:11:in `<top (required)>' from /Users/gotoh/.rbenv/versions/3.1.2/bin/irb:25:in `load' from /Users/gotoh/.rbenv/versions/3.1.2/bin/irb:25:in `<main>'
Rubyでは警告(warning)は出るが定数への再代入ができてしまう。メソッド内での定数の定義はエラーがでる。
ローカル変数の動きを確かめてみる。あるブロック内で定義された変数はそのブロック終了後に破棄される。
>> x = 100 => 100 ?> 5.times do | x | ?> puts x >> end 0 1 2 3 4 => 5 >> puts x 100 => nil
同じ変数名がついているので混乱しやすいが、オブジェクトIDを合わせて表示してみるとわかりやすい。なお、オブジェクトIDは実行環境ごとに異なるので、みなさんの実行結果がこの例のとおりにならなくても問題ない。
>> x = 100 => 100 >> puts "x = #{x}, object_id = #{x.object_id}" x = 100, object_id = 201 => nil ?> 5.times do |x| ?> puts "x = #{x}, object_id = #{x.object_id}" >> end x = 0, object_id = 1 x = 1, object_id = 3 x = 2, object_id = 5 x = 3, object_id = 7 x = 4, object_id = 9 => 5 >> puts "x = #{x}, object_id = #{x.object_id}" x = 100, object_id = 201 => nil >> exit
オブジェクトIDが異なるということは、変数名は同じであってもRubyの処理系上では異なる変数として扱われているということ。このため、変数に代入した値の上書きが起こっていない。
ローカル変数はブロック(class ~ end, def ~ end, do ~ end, if ~ endなど)内で定義された場合、同ブロック内でしか読み書きできない。
インスタンス変数とクラス変数の挙動を試してみる。先ほど作成した ~/Sandbox/test.rb を以下の内容で上書きする。
class KindsOfVariables CONSTANT = "This is a constant." def initialize @@cVar = "This is a class variable." @iVar = "This is an instance variable." end # Javaでいう @@cVarのセッター (setter) # Rubyでは書き込みアクセサー(accessor)という def cVar=(var) @@cVar = var end # Javaでいう @@cVarのゲッター (getter) # Rubyでは読み込みアクセサー(accessor)という def cVar @@cVar end # Javaでいう @iVarのセッター (setter) def iVar=(var) @iVar = var end # Javaでいう @iVarのゲッター (getter) def iVar @iVar end end
test.rbをirb内で読み込む。
% pwd (現在いるディレクトリが~/Sandboxかを確認する) % ls (test.rbが存在するか調べる) % irb >> require "./test.rb" => true
インスタンスを二つ作成する。
>> obj1 = KindsOfVariables.new => #<KindsOfVariables:0x0000000104e75c48 @iVar="This is an instance variabl... >> obj2 = KindsOfVariables.new => #<KindsOfVariables:0x00000001053bd5c0 @iVar="This is an instance variabl...
クラス変数とインスタンス変数の値の確認をする。
>> obj1.cVar => "This is a class variable." >> obj1.iVar => "This is an instance variable." >> obj2.cVar => "This is a class variable." >> obj2.iVar => "This is an instance variable."
インスタンス変数の挙動を確認する。@iVarの値を書き換える。その後、その影響範囲を確認する。インスタンス変数はそのインスタンスのみがアクセスできる変数であるため、あるインスタンスのインスタンス変数の値を変更しても、他のインスタンスのインスタンス変数の値は変更されない。
>> obj1.iVar = 100 => 100 >> obj1.iVar => 100 >> obj2.iVar => "This is an instance variable."
クラス変数の挙動を確認する。@@cVarの値を書き換える。その後、その影響範囲を確認する。クラス変数は同じクラスから生成されたすべてのインスタンスが共通で参照する変数であるため、あるインスタンスにおいてクラス変数を変更した場合、そのクラスから生成された他のインスタンスにおいてもクラス変数の変更は反映される。
>> obj1.cVar = 200 => 200 >> obj1.cVar => 200 >> obj2.cVar => 200
新たにもう一つインスタンスを作成してみる。このとき、@@cVarの値はどのようになっているか?(このクラスの初期化メソッドを参照のこと)
>> obj3 = KindsOfVariables.new => #<KindsOfVariables:0x00000001053cecd0 @iVar="This is an instance variabl... >> obj3.cVar => "This is a class variable." >> obj3.iVar => "This is an instance variable." >> obj1.cVar => "This is a class variable." >> obj1.iVar => 100 >> obj2.cVar => "This is a class variable." >> obj2.iVar => "This is an instance variable."
test.rbではクラスKindsOfVariables内で定数CONSTANTが定義されている。クラス内で定義されている定数や別のクラスを呼び出したい場合は「クラス名::定数/クラス名」と記述して呼び出す。
>> KindsOfVariables::CONSTANT => "This is a constant."
なお、Rubyではインスタンス変数に関しては読み込みアクセサ(ゲッター)および書き込みアクセサ(セッター)をattr_readerおよびattr_writerで簡単に定義することができる。読み込みと書き込みを同時に行いたい場合は attr_accessorと定義する。上述のtest.rbと全く同じ働きをするスクリプトは以下の通り。
class KindsOfVariables CONSTANT = "This is a constant." def initialize @@cVar = "This is a class variable." @iVar = "This is an instance variable." end def cVar=(var) @@cVar = var end def cVar @@cVar end # @iVarのゲッターとリーダーについては以下のように定義できる attr_reader :iVar attr_writer :iVar # 読み書き合わせたものは以下の通り # attr_accessor :iVar end
別ファイル、ライブラリの読み込み(require)_
前述のとおり、作成済みのRubyスクリプトやライブラリを読み込む場合は以下のように記述する。
require "ライブラリ名" require "Rubyスクリプトの相対パス or 絶対パス"
例外処理_
プログラム上許されない処理(0除算)や実行できない処理(たとえばファイルを開こうとしているが該当ファイルがない)を行ったときにインタープリターが返してくるのが例外(exception)である。Rubyでは普通は例外が発生した段階でプログラムの実行が終了する。
>> 1/0 (irb):22:in `/': divided by 0 (ZeroDivisionError) from (irb):22:in `<main>' from /Users/gotoh/.rbenv/gems/3.1.0/gems/irb-1.4.2/exe/irb:11:in `<top (required)>' from /Users/gotoh/.rbenv/versions/3.1.2/bin/irb:25:in `load' from /Users/gotoh/.rbenv/versions/3.1.2/bin/irb:25:in `<main>'
例外が発生したときに対応する処理を用意し、対応することを例外処理という。Rubyでは以下のように記載する。
begin 例外が発生する可能性のある文 rescue 例外が発生した場合の処理 end
以下のように働く。
?> begin ?> 1/0 ?> rescue ?> puts "Some exception occurs" >> end Some exception occurs => nil
上の例は0除算(ZeroDivisionError)という例外が発生しているが、多くの例外が用意されている。どういう例外が発生したのかは以下のように記載することで取得できる。
?> begin ?> 1/0 ?> rescue => ex ?> puts ex >> end divided by 0 => nil
Webサービスのようにプログラムを異常終了してはまずいアプリケーションは、例外処理をしてプログラムを止まらないようにする必要がある。
ファイルの読み込み、ファイルへの書き込み_
irbを一度終了する。
>> exit
読み込み用ファイルと書き込み用ファイルを準備する。
% cd ~/Sandbox % touch readfile.txt % echo 'Hello World!' >> readfile.txt % echo 'Hello World!' >> readfile.txt % more readfile.txt % touch writefile.txt % ls -l writefile.txt -rw-r--r-- 1 gotoh staff 0 1 10 21:43 writefile.txt (ファイルサイズが0であることを確認する)
1行ずつファイルの中身を読み込むときは以下のように記述する。
% irb ?> File.open("./readfile.txt", "r") do |f| ?> f.each_line do |line| ?> puts line ?> end >> end Hello World! Hello World! => #<File:./readfile.txt (closed)>
1行ずつファイルに書き込むときは以下のように記述する。
?> File.open("./writefile.txt", "w") do |f| ?> f.puts "Hello universe." >> end => nil >> exit
書き込めているか確認する。
% more writefile.txt
1行ずつ読み込みつつ、書き込む場合は以下のように記述する。
% irb # ファイルの内容を丸ごと読み込んでbuffへ代入 >> buff = File.read("./readfile.txt") => "Hello World!\nHello World!\n" # ファイルを書き込みで開く ?> File.open("./writefile.txt", "w") do |f| ?> buff.split(/\n/).each do |line| # buffの内容を改行で区切って、配列に変換し、各要素ごとに処理 ?> f.puts line.gsub(/Hello/, "Hi") # line中の"Hello"という語を"Hi"に置き換えて、ファイルに書き出し ?> end >> end => ["Hello World!", "Hello World!"] >> exit
書き込めているか確認する。
% more writefile.txt Hi World! Hi World!
標準組み込みライブラリ_
requireで呼び出さなくても使えるライブラリ群。Rubyでは型(クラス)ごとに特有のメソッドが用意されている。
文字列 String_
ダブルクォーテーションやシングルクォーテーションで囲まれた文字列はString型になる。
% irb >> str = "This is a string." => "This is a string."
さまざまなメソッドが用意されている。
>> str.size => 17 >> str[0] => "T" >> str[2] => "I" >> str[-1] => "."
Rubyには非破壊的な変更(変数の値を変更しない)と破壊的な変更(変数の値を変更する)がある。Rubyの慣習的な名前の付け方ではメソッド名の後ろにエクスクラメーションマーク(!)がついているのが破壊的な変更である。
>> str.upcase => "THIS IS A STRING." >> str => "This is a string." >> str.upcase! => "THIS IS A STRING." >> str => "THIS IS A STRING."
Ruby 3.1での標準の文字コードはUTF-8となっている。このため日本語も特別な処理を行うことなく扱うことができる。
>> jstr = String.new("Ruby 3.1での標準の文字コードはUTF-8となっている。") => "Ruby 3.1での標準の文字コードはUTF-8となっている。" >> jstr.size => 31 >> jstr.reverse => "。るいてっなと8-FTUはドーコ字文の準標ので1.3 ybuR"
文字列でよく使われる処理として、splitというメソッドがある。特定の文字で文字列を切り分ける(配列にする)ことができる。たとえば「の」で上述の文字列を区切ってみる。splitの返り値は配列になる。
>> x = jstr.split(/の/) => ["Ruby 3.1で", "標準", "文字コードはUTF-8となっている。"] >> x.class => Array
Rubyではある条件を満たしているかどうかを調べるメソッド(trueかfalseで返すメソッド)はメソッド名の最後にクエスチョンマーク「?」をつけることになっている。String型でよく使われるメソッドに空列かどうかを調べるempty?がある。
>> jstr.empty? => false >> jstr = "" => "" >> jstr.empty? => true
組み込みライブラリで定義されている型においては、文字列への型変換(to_s)、数字への型変換(to_i)などのメソッドが用意されている。
>> str = "10000" => "10000" >> str.class => String >> str.to_i => 10000 >> str.to_i.class => Integer
正規表現(Ruby 3.1 リファレンスマニュアル :正規表現)を用いることで、文字列に対していろいろな処理を行うことができる。
>> str = "I like a dog very much." >> str.sub(/dog/, "cat") # dogという文字列をcatに置き換える >> str.sub(/I/, "we") >> str.sub(/I/, "we").sub(/dog/, "cat")
数字 Integer, Float_
四則演算が用意されている。ただし、Integer(整数)での演算とFloat(小数許可)での演算は結果が異なる。
>> 1.class >> 1.0.class >> 1/3 >> 1.0/3.0
標準出力へ出力する場合(たとえばputsメソッドを用いて出力する場合)、自動的にto_sメソッドが用いられて、String型に変換される。
>> 1.to_s >> (1/3).to_s
配列 Array_
配列は大変良くつかわれるため、多くのメソッドが用意されている。
配列の初期化は以下のように行う。
>> ary = Array.new >> ary.class >> ary.to_s >> ary = [10, 9, 8, 7] >> ary.class >> ary.to_s
各要素へのアクセスは以下のように行う。
>> ary[0] >> ary[1] >> ary[-1] #文字列の末尾から1文字目の意味になる。 >> ary[-2]
Rubyでは複数の型を1つの配列に格納することができる。
>> ary = [100, "Hello", 3.0] >> ary[0].class >> ary[1].class >> ary[2].class
ある特定の値が配列の中に含まれるかどうかを調べるメソッドがある。
>> ary.include?("Hello") >> ary.include?(200)
データベースからの返り値は配列で受け取ることが多いため、以下のイテレーション(繰り返し処理)をよく使う。
>> ary.each do | val | ?> puts val >> puts val.class >> end
配列の順番(index)も併せて取得したい場合は以下のように記述する。
>> ary.each_with_index do | val, idx | ?> puts "#{val}, #{idx}" >> end
Rubyの配列は可変長である。以下のように配列に追加したり、配列から取り除いたりする。
>> ary = Array.new >> ary.size >> ary << "first" # これで末尾に追加できる >> ary.push(2) # これで末尾に追加できる >> ary = ary + [3.0, "4th"] # 他の配列を末尾に連結する >> ary.size >> ary.pop # 末尾の値を取り除く >> ary.size >> ary >> ary.shift # 先頭の値を取り除く >> ary
ハッシュ Hash_
別のプログラミング言語だと連想配列や辞書型と言われているデータ型。
キーと値の組み合わせで記述する。
>> price = Hash.new >> price.class >> price.empty? >> price = {"egg" => 100, "water" => 120, "milk" => 120} >> price.class >> price.count >> price.to_s
値のアクセスは以下のように行う。
>> price["egg"] >> price["water"] >> price["milk"] >> price["meat"]
最後の例のようにRubyでは配列やハッシュにおいて存在しないインデックスやキーにアクセスした場合はnilが返される。そこで、それを利用して処理を書くことが多い。
>> price["meat"].nil? >> price["egg"].nil?
ハッシュについて繰り返し処理をする場合にはeachメソッドを用いる。
>> price.each do | key, value | ?> puts "key = #{key}, value = #{value}" >> end
ハッシュへの追加は以下のように行える。
>> price.store("meat", 200) >> price["fish"] = 300 >> price
キーや値のみを操作するメソッドも用意されている。
>> price.key?("egg") >> price.keys >> price.value?(100) >> price.values
シンボル Symbol_
以下のページより「シンボルを表すクラス。シンボルは任意の文字列と一対一に対応するオブジェクトです。」
Ruby on Railsなどでよく使われる。String型とよく似ているが働きが異なる。String型のオブジェクトの場合同じ値でも別のオブジェクトとして生成されている。
>> 'white'.object_id >> 'white'.object_id >> 'white'.object_id >> 'white'.object_id >> 'white'.object_id
Symbol型はコロンを変数名前につけて定義する。Symbol型は常にオブジェクトIDが同じになる。
>> :white.object_id >> :white.object_id >> :white.object_id >> :white.object_id
StringとSymbol型の相互変換を行うことができる。
>> x = "white" >> x.class >> x.to_sym >> x.to_sym.class
Ruby on Railsでは引数の意図を明確にするためにハッシュのキーとしてよく使われている。
正規表現 Regexp_
Rubyをはじめとするスクリプト言語(Perl, Python, PHPなど)がコンパイル言語に比べて得意なのは文字列操作である。正規表現を用いることで文字列のパターンを記述することができ、特定の文字列の検出、置き換え、削除などを行うことができる。正規表現の記法はプログラミング言語ごとに多少違うが、大まかな点は同じである。
正規表現クラスRegexpは以下のように定義される。以下の正規表現[aou]はaかoかuの少なくともどれか一つが含まれているという意味である。
>> reg = Regexp.new(/[aou]/) >> reg.class >> reg = /[aou]/ >> reg.class
多くのプログラミング言語ではRubyと同様にスラッシュで囲われた文字列を正規表現として扱う。正規表現クラスのメソッド match(文字列)を使うと、与えられた文字列が正規表現とマッチしているかどうかを確認し、マッチした部分を取り出すことができる。
>> reg.match("tokyo") >> reg.match("souel") >> reg.match("paris") >> reg.match("london")
正規表現を用いると1文字目がaかAで、最後の文字がeである文字列というものを表現することができる。
>> reg = /^[aA].*e$/ >> reg.match("apple") >> reg.match("apples") >> reg.match("ale") >> reg.match("apricot")
上の正規表現は以下のメタ文字(正規表現内で特別な役割を果たす文字)を使っている。
- 行頭を表す: ^
- 行末を表す: $
- 記載されているうちの1文字を表す: [文字]
- 任意の1文字を表す: .
- 0文字以上を表す: *
文字数を制限した繰り返しも可能となる。
>> reg = /^[0-9]{1}[a-z]{2,4}[A-Z]+$/ >> reg.match("1adcA") >> reg.match("12adcA") >> reg.match("3adceAZ")
繰り返し表現を表すメタ文字は以下のとおり
- X回繰り返す: {X}
- X回以上、Y以下繰り返す: {X, Y}
- 1文字以上: +
正規表現の練習_
東京理科大の学籍番号を検出する正規表現を書き、matchメソッドを使って正しいかどうか確かめよ。 なお、正規表現の書き方については Ruby 3.1 リファレンスマニュアル:正規表現 を参照にせよ。
解答例はこちら
時刻 Time_
時刻を表すクラスです。 Time.now は現在の時刻を返します。 File.mtime などが返すファイルのタイムスタンプは Time オブジェクトです。 Time オブジェクトは時刻を起算時からの経過秒数で保持しています。 起算時は協定世界時(UTC、もしくはその旧称から GMT とも表記されます) の 1970年1月1日午前0時です。なお、うるう秒を勘定するかどうかはシステムに よります。 現在の Unix システムでの最大時刻は、 協定世界時の2038年1月19日午前3時14分7秒 です。
>> t = Time.now >> t.year >> t.mon >> t.day >> t.wday # 曜日を日~土を0~6で表現している。 >> t.hour >> t.min >> t.sec >> t.zone # タイムゾーンを示す。グリニッジ標準時に時差を加えて現地時間を表現している。この国ごとの時差をタイムゾーンという。日本はJST(日本標準時間) >> t.strftime("%Y/%m/%d %A") >> t.strftime("%Y-%m-%d %H:%M")
標準添付ライブラリ_
標準添付ライブラリとはなにか?_
Rubyをインストールすると標準でインストールされているが、プログラム中で利用するときには require でライブラリを呼び出さないといけないもの。以下によく使うものを紹介する。
CSVライブラリ_
CSV(カンマ区切りデータ)ファイルを読み書きできるライブラリ。ExcelはCSVファイルで読み書きできるため、実験データをExcelで入力し、それを加工するためにRubyを使うとか、Rubyで生成した値をCSVファイルに書き出して、Excelでグラフにするとかいろいろとできる。ただし、Excelで生成されるCSVは標準で文字コードがCP932(Shift JISの拡張)であるため、UTF-8に変換する必要がある。
基本的に配列をCSVファイルの1行として記載できる。
>> require 'csv' >> CSV.open("./test.csv", "wb") do |csv| ?> csv << ["row", "of", "CSV", "data"] >> csv << ["another", "row"] >> end >> exit
作成したCSVファイルを確認してみる。
% more test.csv
CSVの読み込みは以下のように行う。
% irb >> require 'csv' >> CSV.foreach("./test.csv") do | row | ?> puts row.class >> puts row.to_s >> end