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のクラスやメソッドを調べるとき_

たとえば、配列(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

戻る_