本書は、Rubyのチュートリアルです。 Rubyは、比較的習得が容易なオブジェクト指向スクリプティング言語です。 まつもとゆきひろによって開発されました。 Ruby on Railsの記述言語として選ばれたことで有名になりましたが、ウェブアプリケーション以外にもシステム管理やネットワークアプリケーションなどさまざまな用途に用いられます。

Wikipedia
Wikipedia
ウィキペディアRubyの記事があります。

Rubyとは 編集

Rubyの特徴 編集

Rubyには、強力で多用途な言語とするための多くの特徴があります。その特徴とは以下の通りです:

オブジェクト指向のプログラミング
Rubyは完全なオブジェクト指向言語であり、Rubyのすべてがオブジェクトであることを意味します。このため、複雑なプログラムを簡単に作成することができ、メンテナンスも容易です。
動的な型付け
Rubyは動的型付け言語であり、コンパイル時に変数の型がチェックされることはありません。このため、プログラムを再コンパイルすることなく、変数の型を簡単に変更することができます。
インタプリタ型言語
Rubyはインタープリタ型言語であり、機械語にコンパイルされるのではなく、コードが1行ずつ実行されます。そのため、Rubyのプログラムの開発やデバッグが容易に行えます。
簡潔な構文
Rubyには簡潔な構文があり、コードを書くのが簡単です。そのため、初心者から経験豊富なプログラマーまで、幅広く利用することができます。
大規模なコミュニティ
Rubyには、言語やライブラリに貢献する開発者たちの大規模で活発なコミュニティがあります。そのため、Rubyプログラミングのヘルプやサポートを簡単に見つけることができます。

Rubyは強力で汎用性の高い言語であり、さまざまなタスクに適しています。Rubyの学習と使用は簡単で、開発者の大規模で活発なコミュニティがあります。強力で汎用性が高く、習得が容易な言語をお探しなら、Rubyは良い選択です。

準備 編集

rubyインタープリターの準備 編集

既にあなたのコンピュータにrubyインタープリター[1]がインストールされていないか確認しましょう[2]。 コマンドプロンプトから、次のようにrubyのバージョンを確かめます。

% ruby -v
インストールされている場合
ruby 3.2.0 (2022-12-25 revision a528908271) [amd64-freebsd13]
のようにバージョンが表示されます。
バージョンは、環境によって異なります。
インストールされていない場合
ruby: Command not found.
や、これに類する「rubyが見つからない」旨をあらわすメッセージが表示されます。
この場合は、新規にインストールが必要です。

準備ができたら、試しにコマンドラインからインタープリターを呼び出してみましょう。

2023年4月現在、ruby-1.x は全てEoL(End-of-Life;サポート終了)、 ruby-2.x は 2.7 がセキュリティメンテナンス、それ以外はEoL、 ruby-3.x は 3.0 がセキュリティメンテナンス、3.1, 3.2 がノーマルメンテナンスです[3]

もしご自身の環境の ruby のバージョンが既にサポート終了しているのであれば、サポートされているバージョンへのアップデートを検討してください。 本書では ruby-3.1 以降を想定しています。

基本的な使い方 編集

出力 編集

Rubyでは、putsprintメソッドを使って文字列を出力します。putsは改行付きで出力され、printは改行無しで出力されます。

puts "Hello, world!"
print "Hello, Ruby!"

変数 編集

変数を定義するには、変数名の前に=を使って値を代入します。

name = "Alice"
age = 20

Rubyでは、変数の型は動的に決定されます。つまり、変数にどんな値を代入してもエラーが発生せず、適切な型に変換されます。

条件分岐 編集

Rubyでは、if文を使って条件分岐を行います。

x = 10
if x > 5
  puts "x is greater than 5"
elsif x < 5
  puts "x is less than 5"
else
  puts "x is equal to 5"
end

繰り返し 編集

Rubyでは、while文やfor文を使って繰り返し処理を行います。

i = 0
while i < 5 do
  puts i
  i += 1
end

for i in 0..4 do
  puts i
end

配列 編集

Rubyでは、配列を使って複数の値を一つの変数にまとめることができます。

fruits = ["apple", "banana", "orange"]
puts fruits[0] #=> "apple"
puts fruits[1] #=> "banana"
puts fruits[2] #=> "orange"
puts fruits.length #=> 3

配列の要素には、インデックス番号を使ってアクセスすることができます。また、配列の要素数は、lengthメソッドを使って取得することができます。

メソッド 編集

Rubyでは、メソッドを定義して再利用することができます。

def say_hello(name)
  puts "Hello, #{name}!"
end

say_hello("Alice") #=> "Hello, Alice!"
say_hello("Bob") #=> "Hello, Bob!"

メソッドを定義するには、defキーワードを使います。引数を取る場合は、引数の名前を括弧で囲みます。また、メソッド内でputsなどのメソッドやreturnなどのキーワードを使って処理を記述します。

以上が、Rubyの特徴や基本的な使い方の一部です。Rubyは、簡単な文法と豊富なライブラリを持っているため、初心者からプロのプログラマーまで幅広く利用されています。

コメント 編集

Rubyのコメントは、ソースコードに対するメモや説明を記述するためのもので、実行時には無視されます。Rubyでは、以下の2種類のコメントが使用できます。

行コメント
行コメントは、#(井桁)記号から行末までの部分をコメントとして扱います。行コメントは、一行に一つだけ記述できます。
# これは行コメントです
範囲コメント

範囲コメントは、=beginと=endで囲まれた部分をコメントとして扱います。範囲コメント内のすべての行がコメントとして扱われます。範囲コメントは、複数行のコメントを記述するために使用されます。

=begin
これは
範囲コメント
です
=end

Rubyでは、コメントが実行時に無視されるため、コメントを使用して、コードの解説や説明を行うことができます。また、コメントを使用して、デバッグ用の情報を残すこともできます。ただし、コメントが多すぎるとコードの読みやすさが低下するため、必要最低限のコメントにとどめることが望ましいとされています。

Rubyのマジックコメント 編集

Rubyのマジックコメントとは、スクリプトファイルの先頭にコメントとして記述する特別なコメントのことを指します。

マジックコメントは、スクリプトファイルの先頭に記述される特別なコメントで、文字エンコーディングを指定するために使用されます。これは、Rubyがソースコードを解析する際に、文字エンコーディングを正しく解釈できるようにするために必要なものです。 マジックコメントには、以下のような形式があります。

# coding: エンコーディング名

または、

# -*- coding: エンコーディング名 -*-

エンコーディング名には、UTF-8、Shift_JIS、EUC-JPなど、使用する文字エンコーディングの名前を指定します。これらの文字エンコーディング名は、Rubyがサポートしているものに限ります。 マジックコメントは、スクリプトファイルの先頭に記述する必要があります。これは、スクリプトファイルの先頭に書かれた文字列を認識するためにRubyが特別な処理を行うためです。 なお、マジックコメントは、Ruby 2.3以降では必要ありません。これは、Ruby 2.3からは、デフォルトでUTF-8エンコーディングが使用されるためです。ただし、Ruby 2.2以前のバージョンでは、マジックコメントを記述する必要があります。

shebang! 編集

shebang!とは、UNIX系のOSでスクリプトファイルを実行するときに、どのプログラムを使ってスクリプトを解釈するかを指定するための特殊なコメントです。

Rubyのshebang!は、以下のようになります。

#!/usr/bin/env ruby

このコメントは、スクリプトの先頭行に記述します。先頭行にshebang!を記述することで、スクリプトを実行する際に、Rubyインタプリタを使用することを指定します。また、/usr/bin/envを使用することで、PATH環境変数に設定された最初のRubyインタプリタを使用するように指定します。

shebang!を使用することで、スクリプトファイルを実行するときに、以下のようにコマンドを実行することができます。

$ ./script.rb

shebang!を使用することで、スクリプトを実行するときに、Rubyのパスを指定する必要がなくなり、スクリプトを実行するためのコマンドが簡潔になります。

変数 編集

Rubyの変数は、オブジェクトに名前をつけるために使われます。

Rubyでは、変数は宣言する必要はありません。

オブジェクトを変数に代入するには

変数名 = オブジェクト

の様に代入演算子 = を使います。

変数へのオブジェクトの代入と参照
a = 1
p a           # => 1
a = "abc"
p a           # => "abc"
a = [1, 2, 3]
p a           # => [1, 2, 3]
b = a
p b           # => [1, 2, 3]
b[1] = 999
p a           # => [1, 999, 3]
puts メソッドと p メソッド
putsメソッドはオブジェクトにto_sメソッドで適用した結果を表示します。

これに対し、pメソッドはオブジェクトにinspectメソッドで適用した結果を表示します。

putsとp
puts "Hello, world!" # => Hello, world!
p "Hello, world!"    # => "Hello, world!"


定数 編集

Rubyにおける定数は、変更できない値のことです。定数は大文字で始まり、一度値を代入するとその後変更することができません。定数を宣言するには、変数名の先頭に大文字のアルファベットを付けます。

定数は、クラスやモジュールの定義内で宣言される場合、そのクラスやモジュールのスコープにのみ存在します。クラスやモジュール外で宣言された定数は、グローバルスコープに属します。

定数にアクセスするには、定数名を参照します。定数が未定義の場合、RubyはNameError例外を発生させます。

以下は、定数を宣言して参照する例です。

# クラス内で定数を宣言する
class MyClass
  MY_CONSTANT = 100
end

# クラス外で定数を参照する
puts MyClass::MY_CONSTANT   #=> 100

また、Rubyでは組み込み定数もいくつか存在します。例えば、Math::PIは円周率を表す定数です。

グローバル変数 編集

グローバル変数は、プログラム中のどこからでもアクセス可能な変数です。グローバル変数は、$記号で始まる変数名を持ちます。一般的に、グローバル変数は、複数のメソッドで共有するデータを格納するために使用されます。ただし、グローバル変数は多用すべきではなく、できるだけ避けるべきです。

$global_variable = 10

def print_global
  puts "Global variable is #$global_variable"
end

print_global

特殊変数 編集

特殊変数は、Rubyがあらかじめ定義している変数で、プログラム中で直接代入することができません。これらの変数は、プログラムの実行中に自動的に設定され、Rubyの様々な機能で使用されます。

  • $0: 現在のプログラムファイル名
  • $~: 最後にマッチした正規表現
  • $&: 最後にマッチした文字列
  • $': 最後にマッチした文字列より後ろの文字列
  • $': 最後にマッチした文字列より後ろの文字列
  • $1, $2, $3...: 最後にマッチした正規表現の1番目、2番目、3番目...のキャプチャグループにマッチした文字列
  • $stdin: 標準入力
  • $stdout: 標準出力
  • $stderr: 標準エラー出力
  • $LOAD_PATH: ライブラリの検索パス
  • $:: ライブラリの検索パス($LOAD_PATHの別名)
puts "This program's name is #{$0}"
puts "The Ruby version is #{RUBY_VERSION}"
puts "The current line number is #{$.}"

オブジェクト 編集

Rubyは完全なオブジェクト指向言語であり、すべてがオブジェクトです。オブジェクトは、データとそれに対する操作をカプセル化したものであり、オブジェクトを操作するためにメソッドを使用します。

以下は、オブジェクトについての基本的な説明です。

  • オブジェクトは、Rubyの世界で唯一の存在であり、それぞれが固有の状態と振る舞いを持っています。
  • オブジェクトは、何らかのデータ(文字列、数値、配列、ハッシュ、ファイルなど)を表します。例えば、整数、浮動小数点数、有理数や複素数などの数値を表すオブジェクトがあり、文字列オブジェクトはテキストを表します。
  • オブジェクトは、そのデータを操作するためのメソッドを提供します。メソッドは、オブジェクトの状態を変更することができます。例えば、数値オブジェクトには、加算や減算などの算術演算を行うためのメソッドがあります(演算子もメソッドです)。文字列オブジェクトには、文字列の結合や部分文字列の取得などのメソッドがあります。
  • オブジェクトは、クラスと呼ばれるテンプレートから作成されます。クラスは、オブジェクトのデータやメソッドを定義するための設計図です。オブジェクトは、クラスのインスタンスとして作成されます。
  • オブジェクトは、他のオブジェクトとやり取りすることができます。オブジェクトは、別のオブジェクトをメソッドの引数として受け取ることができ、戻り値としても返すことができます。

これらのオブジェクトのクラスを知ることは、そのオブジェクトがどのような振る舞いをするかを理解するために非常に重要です。

Objectクラス 編集

Rubyにおけるすべてのオブジェクトは、Objectから継承されています。Objectには、すべてのオブジェクトに共通するメソッドが定義されています。

以下は、Objectに関する基本的な説明です。

  • Rubyのすべてのオブジェクトは、Objectのサブクラスであるため、Objectに定義されているメソッドはすべてのオブジェクトで利用できます。
  • Objectには、例外を発生させるraiseメソッドや、オブジェクトのクラスを取得するclassメソッド、オブジェクトが同一かどうかを判定するequal?メソッドなど、多くの便利なメソッドが定義されています。
  • Objectには、to_sメソッドも定義されており、すべてのオブジェクトはto_sメソッドを呼び出すことができます。to_sメソッドは、オブジェクトを文字列に変換します。このメソッドは、デバッグやログ出力などに活用されます。
  • Objectには、同一性比較に使用される==メソッドも定義されています。==メソッドは、2つのオブジェクトが同じかどうかを比較します。オブジェクトの同一性を比較する場合は、equal?メソッドを使用します。
  • Objectには、.initializeメソッドも定義されており、新しいオブジェクトを作成する際に呼び出されます。.initializeメソッドをオーバーライドすることで、新しいオブジェクトが初期化される際の処理をカスタマイズすることができます。

オブジェクトのクラスを調べる 編集

オブジェクトのクラスを調べるには、Objectクラスのclassメソッドを使います。

puts "Hello, world!".class  # ==> String
puts 10.class               # ==> Integer
puts 3.14.class             # ==> Float
puts [2, 3, 5, 7, 11].class # ==> Array
puts ({"key1" => "value1", "key2" => "value2"}).class   # ==> Hash
puts /hello/.class          # ==> Regexp
puts (1..10).class          # ==> Range
puts :abc.class             # ==> Symbol
puts false.class            # ==> FalseClass
puts true.class             # ==> TrueClass
puts nil.class              # ==> NilClass
puts (lambda {|x, y| x + y }).class # ==> Proc
puts Complex(3, 4).class    # ==> Complex
puts Rational(22, 7).class  # ==> Rational
puts Time.now.class         # ==> Time
puts Struct.new("Cat", :sex, :age).class    # ==> Class
Objectクラスの代表的なメソッド
メソッド名 引数の数 説明
!= 1 オブジェクトと引数が等しくない場合にtrue、等しい場合にfalseを返す
! 0 オブジェクトがfalseまたはnilの場合にtrueを返す
== 1 オブジェクトと引数が等しい場合にtrue、等しくない場合にfalseを返す
=== 1 引数がオブジェクトと等しい場合にtrue、そうでない場合にfalseを返す
__id__ 0 オブジェクトのobject_idを返す
__send__ 1以上 メソッドを動的に呼び出す
class 0 オブジェクトのクラスを返す
clone 0 オブジェクトを複製して返す
dup 0 オブジェクトを浅く複製して返す
equal? 1 オブジェクトと引数が同じオブジェクトである場合にtrue、そうでない場合にfalseを返す
instance_eval 0または1 レシーバーオブジェクトに対してブロックを評価する
instance_of? 1 オブジェクトが指定したクラスのインスタンスである場合にtrue、そうでない場合にfalseを返す
instance_variable_defined? 1 指定されたインスタンス変数が定義されている場合にtrue、そうでない場合にfalseを返す
instance_variable_get 1 指定されたインスタンス変数の値を取得する
instance_variable_set 2 指定されたインスタンス変数に値を設定する
kind_of? 1 オブジェクトが指定したクラスのインスタンスである場合にtrue、そうでない場合にfalseを返す
method 1 指定されたメソッドオブジェクトを返す
nil? 0 オブジェクトがnil

式と演算子 編集

Rubyにおける式と演算子について説明します。

編集

Rubyにおける式とは、ある値を評価するためのコードのことを指します。例えば、以下のような式があります。

1 + 2

この式は、12を足した結果を評価するための式です。この式を実行すると、3という値が返されます。

演算子 編集

演算子は、式を組み合わせたり、値を変更するために使用されます。Rubyにはさまざまな種類の演算子があります。以下はいくつかの例です。

数値演算子 編集

数値演算子には、加算、減算、乗算、除算、剰余演算子などがあります。

以下はいくつかの例です。

# 整数
p 10 + 3 # 13: 加算
p 10 - 3 #  7: 減算
p 10 * 3 # 30: 乗算
p 10 / 3 #  3: 除算
p 10 % 3 #  1: 剰余演算

# 文字列
p "abc" + "xyz" # abcxyz: 連結
p "abc" * 3     # abcabcabc: 反復
p "%x" % 77     # 4d: 書式化

# 配列
p [1, 2, 3] + [7, 8, 9] # [1, 2, 3, 7, 8, 9]: 連結

# 有理数
p Rational(2, 3) + 3 # (11/3)
p Rational(2, 3) - 3 # (-7/3)
p Rational(2, 3) * 3 # (2/1)
p Rational(2, 3) / 3 # (2/9)

# 複素数
p Complex(2, 3) + 3 # (5+3i)
p Complex(2, 3) - 3 # (-1+3i)
p Complex(2, 3) * 3 # (6+9i)
p Complex(2, 3) / 3 # ((2/3)+1i)

Rubyの四則演算子と剰余演算子は、通常の数値演算に使用されることが一般的ですが、オブジェクト指向プログラミング言語であるRubyでは、これらの演算子がオーバーロードされることがあります。

比較演算子 編集

比較演算子には、等しい、等しくない、より大きい、より小さい、以上、以下などがあります。以下はいくつかの例です。

a = 1
b = 2

puts a == b # 等しい
puts a != b # 等しくない
puts a > b  # より大きい
puts a < b  # より小さい
puts a >= b # 以上
puts a <= b # 以下
Comparableモジュール 編集

RubyのComparableモジュールは、比較演算子(<, <=, ==, >, >=, between?)をオーバーライドすることで、クラスの比較を実装するためのモジュールです。

Comparableモジュールを使用することで、クラスのインスタンスを比較可能にすることができます。具体的には、インスタンス変数に格納された値を比較するために、<=>演算子を定義する必要があります。<=>演算子は、引数と自身のインスタンスを比較して、以下のように返します。

  • 引数より小さい場合は、負の整数を返します。
  • 引数と等しい場合は、ゼロを返します。
  • 引数より大きい場合は、正の整数を返します。

Comparableモジュールを使用するためには、クラス内でinclude Comparableを宣言する必要があります。例えば、以下のようにPersonクラスを定義して、Comparableモジュールを使用することができます。

class Person
  include Comparable

  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def <=>(other)
    @age <=> other.age
  end
end

p1 = Person.new("Alice", 25)
p2 = Person.new("Bob", 30)

puts p1 < p2   # true
puts p1 == p2  # false
puts p1 > p2   # false

Personクラスでは、<=>演算子を定義して、ageインスタンス変数を比較しています。そのため、Personクラスのインスタンスは、<, <=, ==, >, >=, between?演算子によって比較可能になります。

論理演算子 編集

論理演算子には、AND、OR、NOT演算子があります。以下はいくつかの例です。

a = true
b = false

puts a && b  # false: AND
puts a and b # true: AND(低い優先度なのでputsと先に結合)
puts a || b  # true: OR
puts a or b  # true: OR(低い優先度)
puts !a      # false: NOT
  • && の優先度は || より強いです(論理と論理なので)。
  • || の優先度は and より強いです(単語版の方が弱いとおぼえてください)。
  • and の優先度は or より強いです(論理積と論理和なので)。

以下に、論理積 (AND)、論理和 (OR)、論理否定 (NOT) を表現するための真理値表を示します。

論理積 (AND)
A B A AND B
0 0 0
0 1 0
1 0 0
1 1 1
論理和 (OR)
A B A OR B
0 0 0
0 1 1
1 0 1
1 1 1
論理否定 (NOT)
A NOT A
0 1
1 0


上記の表で、A と B はそれぞれ真 (1) または偽 (0) の値を表し、AND や OR などの論理演算子によって表された結果は、真 (1) または偽 (0) のいずれかです。 また、論理否定では、NOT A は A の真偽を反転させた値となります。

短絡評価 編集

Rubyの短絡評価とは、論理式の評価において、最初の式で結果が確定した場合に、その後の式を評価しないことを指します。つまり、式が最初の部分で真偽値が確定した場合、後続の式を評価せずに即座に結果を返します。

例えば、以下のようなコードがあったとします。

def check_name(name = nil)
    if name && name.length > 0
        puts "名前は#{name}です"
    else
        puts "名前が未入力です"
    end
end
check_name() # => "名前が未入力です"
check_name("") # => "名前が未入力です" 
check_name("John") # => "名前はJohnです"

このコードでは、namenil でないかつ文字列の長さが0より大きいかを同時にチェックしています。 具体的には、条件式 name && name.length > 0 によってチェックしています。

この条件式では、短絡評価 (short-circuit evaluation) が利用されています。短絡評価とは、条件式の全ての部分を評価せずに、最初に結果が確定した部分で評価を終了するという評価方法です。 具体的には、この場合はnamenilである場合、name.length > 0 の評価は行われず、条件式全体がfalseと判定されます。

このような短絡評価の利用により、コードのパフォーマンスを向上させることができます。また、namenil の場合に name.length を呼び出すことがなくなるため、エラーを避けることができます。

しかし、短絡評価を乱用すると、プログラムの可読性が低下したり、バグを引き起こしたりすることがあります。適切な場面でのみ利用するようにしましょう。

論理演算子(AND, OR)は演算子の姿をしていますが、内実は制御構造です。そのため論理演算子は演算子オーバーロード出来ません。

Rubyでは演算子もメソッド 編集

「Rubyでは演算子もメソッド」とは、Rubyにおいて演算子 (たとえば +, -, *, / など) が単なる記号ではなく、それぞれが対応するメソッドとして定義されているということを指します。

例えば、+ 演算子は、2つの数値を足し合わせるために使われますが、実際には + メソッドとして定義されています。以下のように + メソッドを使って足し算を行うことができます。

a = 1
b = 2
c = a.+(b)  # a + b と同じ
puts c  # => 3

また、* 演算子も同様に * メソッドとして定義されています。以下のように、文字列に対して * メソッドを使って、指定した回数だけ繰り返した新しい文字列を作ることができます。

str = "hello"
new_str = str.*(3)  # str * 3 と同じ
puts new_str  # => "hellohellohello"

このように、Rubyでは演算子も単なる記号ではなく、それぞれが対応するメソッドとして定義されているため、オブジェクト指向の考え方に基づいた柔軟なプログラミングが可能になっています。

Rubyで演算子メソッドをオーバーロード 編集

Rubyでは、クラスやモジュールで演算子に対応するメソッドを定義することができます。このようにして定義された演算子メソッドをオーバーロードと呼びます。

以下は、Vector2 クラスで + 演算子に対応するメソッドを定義する例です。このメソッドでは、Vector2 クラスのインスタンス同士を足し合わせることができます。

class Vector2
  attr_accessor :x, :y
  
  def initialize(x, y)
    @x = x
    @y = y
  end
  
  def +(other)
    Vector2.new(@x + other.x, @y + other.y)
  end
  
  def to_s()
    "[#{@x}, #{@y}]"
  end
end

v1 = Vector2.new(1, 2)
v2 = Vector2.new(3, 4)
v3 = v1 + v2  # => Vector2オブジェクト
puts v3  # => [4, 6]

このコードは、2次元ベクトルを表す Vector2 クラスを定義し、2つのベクトルを足し合わせるメソッドを実装しています。

まず、attr_accessor によって、xy のインスタンス変数に対する getter/setter メソッドが定義されています。これによって、外部から v1.x のようにしてインスタンス変数にアクセスしたり、v1.x = 10 のようにしてインスタンス変数に値を代入したりできます。

次に、initialize メソッドが定義されています。これは、new メソッドが呼ばれた時に、引数として渡された xy をインスタンス変数 @x@y に代入するためのコンストラクタです。

+ メソッドは、引数として与えられた other という別の Vector2 オブジェクトを足し合わせ、新しい Vector2 オブジェクトを作成して返します。これによって、v1 + v2 のようにして2つのベクトルを足し合わせることができます。

最後に、to_s メソッドが定義されています。これは、オブジェクトを文字列に変換するためのメソッドで、ベクトルの座標を [x, y] のような形式の文字列に変換して返します。

実際に、v1v2 を足し合わせた結果を v3 に代入し、puts v3v3 を表示しています。v3 の値は [4, 6] となります。

このように演算子メソッドをオーバーロードすることで、プログラムの読みやすさや柔軟性を高めることができます。ただし、意図しない挙動を招くこともあるため、注意して使いましょう。

演算子オーバーロード 編集

Rubyでは、演算子をオーバーロードすることが出来ます。 オーバーロード可能なの演算子には、組み込みクラスの演算子も含まれます。

class String
  def /(s) self.split(s) end
end

ary = "The quick brown fox jumps over the lazy dog" / " "
p ary # => ["The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"]

str = ary * " ! " 
p str # => "The ! quick ! brown ! fox ! jumps ! over ! the ! lazy ! dog"

このコードは、Rubyの String クラスに、新しいメソッド / を追加しています。

/ メソッドは、文字列を引数 s で分割するためのメソッドです。 実装は split メソッドを呼び出すだけで、文字列オブジェクト自身を self で表しています。

まず、/ メソッドによって、文字列 "The quick brown fox jumps over the lazy dog" がスペース " " で分割され、配列 ary に格納されます。 ここで ary は、["The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"] という値を持ちます。

次に、* メソッドによって、配列 ary が感嘆符 "!" で連結され、文字列 str が作成されます。 ここで str は、"The ! quick ! brown ! fox ! jumps ! over ! the ! lazy ! dog" という値を持ちます。

このように、/* メソッドを利用することで、簡単に文字列の分割や連結を行うことができます。 ただし、他の開発者がこのようなメソッドを利用しているコードを読む場合、このような振る舞いを予想できない可能性があるため、注意が必要です。

/* を、それぞれ文字列の分割と結合に割り当てる例は、Pikeに見ることが出来ます。

演算子の優先順位と結合方向 編集

演算子の優先順位

演算子には優先順位があります。

例えば、以下のようなコードがあった場合、演算子の優先順位に従って評価されます。

a = 2 + 3 * 4 ** 2 / 2

ここで、**は先に評価されます。次に、*と/が同じ優先順位なので、左から右に評価されます。最後に+が-よりも優先度が高いので、+が評価されます。

a = 2 + ( ( 3 * ( 4 ** 2 ) ) / 2 )

つまり、aの値は50になります。

演算子の結合方向

同じ優先順位の演算子が続いた場合、演算子の結合方向により実行順序が決まります。

例えば、以下のコードがある場合、

a = 2 ** 3 ** 2

**右結合なので、3 ** 2が先に評価されます。そして、2 ** 9が評価されて、aは512になります。

a = 2 ** ( 3 ** 2 )

以下は、Rubyの演算子の優先順位と結合方向の表です。

Rubyの演算子の優先順位と結合方向
演算子 説明 優先順位 結合方向
:: クラスやオブジェクトのネスト 1 左結合
[] 配列やハッシュから要素を取得する 2 左結合
+ 単項演算子(正) 3 右結合
! 論理否定
~ ビット否定
** べき乗 4 右結合
- 単項演算子(負) 5 右結合
* 乗算 6 左結合
/ 除算
% 剰余算
+ 加算 7 左結合
- 減算
<< ビットシフト(左) 8 左結合
>> ビットシフト(右)
& ビット積 9 左結合
| ビット和 10 左結合
^ ビット排他的論理和
> 大なり 11 左結合
>= 以上
< 未満
<= 以下
<=> 比較 12 左結合
== 一致
=== 厳密に一致
!= 不一致
=~ パターンマッチング
!~ アンマッチ
&& 論理積 13 左結合
|| 論理和 14 左結合
.. 範囲を生成する(終端を含む) 15 左結合
... 範囲を生成する(終端を含まない)
? : 条件演算子 16 右結合
= 代入 17 右結合
op= 代入演算子
not 論理否定 18 右結合
and 論理積 19 左結合
or 論理和
優先順位が高い演算子から順に、結合方向の左右を記載しています。
表中の "op= " は、代入演算子の一般形を表しています。具体的な代入演算子には、"+= "、"-= "、"*= "、"/= "、"%= "、"||= "、"&&= "、"||= "、"|= "、"&= "、"^= "などがあります。
コード例
a = 5
b = 10
puts "a = #{a}"
puts "b = #{b}"
puts "-" * 20

# 算術演算子
puts "算術演算子:"
puts "a + b = #{a + b}"
puts "a - b = #{a - b}"
puts "a * b = #{a * b}"
puts "b / a = #{b / a}"
puts "b % a = #{b % a}"
puts "a ** 2 = #{a ** 2}"
puts "-" * 20

# 比較演算子
puts "比較演算子:"
puts "a == b : #{a == b}"
puts "a != b : #{a != b}"
puts "a > b : #{a > b}"
puts "a < b : #{a < b}"
puts "b >= a : #{b >= a}"
puts "a <= b : #{a <= b}"
puts "-" * 20

# 論理演算子
puts "論理演算子:"
puts "a == 5 && b == 10 : #{a == 5 && b == 10}"
puts "a == 5 || b == 5 : #{a == 5 || b == 5}"
puts "! (a == 5) : #{!(a == 5)}"
puts "-" * 20

# 代入演算子
puts "代入演算子:"
puts "a += b : #{a += b}"
puts "a -= b : #{a -= b}"
puts "a *= b : #{a *= b}"
puts "a /= b : #{a /= b}"
puts "a %= b : #{a %= b}"
puts "a **= 2 : #{a **= 2}"
puts "-" * 20

# 三項演算子
puts "三項演算子:"
puts "a > b ? 'a is greater than b' : 'a is less than or equal to b'"
puts "-" * 20

# ビット演算子
puts "ビット演算子:"
puts "a & b : #{a & b}"
puts "a | b : #{a | b}"
puts "a ^ b : #{a ^ b}"
puts "~a : #{~a}"
puts "a << 1 : #{a << 1}"
puts "a >> 1 : #{a >> 1}"
puts "-" * 20

# 演算子メソッド
puts "演算子メソッド:"
puts "a == b : #{a.==(b)}"
puts "a != b : #{a.!=(b)}"
puts "a > b : #{a.>(b)}"
puts "a < b : #{a.<(b)}"
puts "b >= a : #{b.>=(a)}"
puts "a <= b : #{a.<=(b)}"
puts "a <=> b : #{a.<=>(b)}"
puts "a === b : #{a.===(b)}"
puts "a =~ b : #{a.=~(b)}"
puts "-" * 20

# その他の演算子
puts "その他の演算子:"
puts "defined? a : #{defined?(a)}"
puts "(1..10).each do |i| puts i end"
puts ":symbol.to_s : #{:symbol.to_s}"
puts "%w(one two three) : #{%w(one two three)}"
puts "-" * 20
実行結果
a = 5
b = 10
--------------------
算術演算子:
a + b = 15
a - b = -5
a * b = 50
b / a = 2
b % a = 0
a ** 2 = 25
--------------------
比較演算子:
a == b : false
a != b : true
a > b : false
a < b : true
b >= a : true
a <= b : true
--------------------
論理演算子:
a == 5 && b == 10 : true
a == 5 || b == 5 : true
! (a == 5) : false
--------------------
代入演算子:
a += b : 15
a -= b : 5
a *= b : 50
a /= b : 5
a %= b : 5
a **= 2 : 25
--------------------
三項演算子:
a > b ? 'a is greater than b' : 'a is less than or equal to b'
--------------------
ビット演算子:
a & b : 8
a | b : 27
a ^ b : 19
~a : -26
a << 1 : 50
a >> 1 : 12
--------------------
演算子メソッド:
a == b : false
a != b : true
a > b : true
a < b : false
b >= a : false
a <= b : false
a <=> b : 1
a === b : false
a =~ b :
--------------------
その他の演算子:
defined? a : local-variable
(1..10).each do |i| puts i end
:symbol.to_s : symbol
%w(one two three) : ["one", "two", "three"]
--------------------

制御構造 編集

Rubyには、if-else-elsif-end、unless-else-end、case-when-else-end、while文、until文、for文、loop文そしてbegin-rescue-else-ensure-endのような例外処理構文など、様々な制御構造があります。 これらの制御構造を使うことで、プログラムの実行を条件に応じたループや分岐によって制御することができます。 制御構造を正しく理解し、適切に使用することで、効率的で洗練されたプログラムを書くことができます。

書式概観
# if-elsif-else-end
if 条件式1 then
  処理1
elsif 条件式2 then
  処理2
else
  処理3
end

# if修飾子
 if 条件式

# unless-else-end
unless 条件式 then
  処理1
else
  処理2
end

# unless修飾子
 unless 条件式

# case-when-else-end
case 対象のオブジェクト
when 条件式1 then
  処理1
when 条件式2 then
  処理2
when 条件式3 then
  処理3
else
  処理4
end

# while文
while 条件式 do
  処理
end

# while修飾子
 while 条件式

# until文
until 条件式 do
  処理
end

# until修飾子
 until 条件式

# for文
for 変数 in 範囲 do
  処理
end

# loop文
loop do
  処理
end

# eachメソッド
配列.each do |変数|
  処理
end

# timesメソッド
回数.times do |変数|
  処理
end

条件分岐 編集

Rubyの条件分岐には、if-elsif-else-end、unless-else-end、そしてcase-when-else-endがあります。 また、if, unless には修飾子構文もあります。

if-elsif-else-end 編集

if-elsif-else-endは、条件に応じて処理を分岐するためのもっとも基本的な構文です。

if 条件式1
  処理1
elsif 条件式2
  処理2
else
  処理3
end

例えば、ある数値変数numが0未満なら「negative」、0なら「zero」、0より大きいなら「positive」と表示するプログラムは以下のように書けます。

num = -3

if num < 0
  puts "negative"
elsif num == 0
  puts "zero"
else
  puts "positive"
end

if修飾子 編集

if修飾子は、条件式が肯定されたとき式を評価する構文です。

 if 条件式

例えば、ある数値変数numが0未満なら「negative」と表示するプログラムは以下のように書けます。

num = -3

puts "negative" if num < 0

unless-else-end 編集

unless-else-endは、if-elsif-else-endと似たような構文ですが、条件式が否定されたときに処理が実行されます。

unless 条件式
  処理1
else
  処理2
end

例えば、ある数値変数numが0以上なら「non-negative」、0未満なら「negative」と表示するプログラムは以下のように書けます。

num = -3

unless num >= 0
  puts "negative"
else
  puts "non-negative"
end

unless修飾子 編集

unless修飾子は、if修飾子に似ていますが、条件式が否定されたときに式を評価する構文です。

 unless 条件式

例えば、ある数値変数numが0以上でなければ「negative」と表示するプログラムは以下のように書けます。

num = -3

puts "negative" unless num >= 0

case-when-else-end 編集

case-when-else-endは、複数の値に応じて処理を分岐するための構文です。if-elsif-else-endと比較して、1つのオブジェクトに対して複数の条件式を一度に評価できるという利点があります。

case オブジェクト
when 条件式1
  処理1
when 条件式2
  処理2
else
  処理3
end

例えば、ある文字変数cに対して、それが母音なら「vowel」、子音なら「consonant」、数字なら「number」、それ以外なら「other」と表示するプログラムは以下のように書けます。

c = 'a'

case c
when 'a', 'e', 'i', 'o', 'u'
  puts "vowel"
when '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
  puts "number"
when 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z'
  puts "consonant"
else
  puts "other"
end
when へのオブジェクト 編集

Rubyの case 文では、比較に用いるオブジェクトの型に応じて条件分岐することができます。具体的には、case 文の式の型が以下のいずれかである場合に、対応する条件分岐が行われます。

  • 整数型 (Integer) の場合
  • 文字列型 (String) の場合
  • 正規表現型 (Regexp) の場合
  • クラスオブジェクト (Class) の場合

以下に、それぞれの場合の例を示します。

整数型の場合
case num
when 0
  puts "num is zero"
when 1
  puts "num is one"
when 2
  puts "num is two"
else
  puts "num is something else"
end
文字列型の場合
case str
when "foo"
  puts "str is foo"
when "bar"
  puts "str is bar"
when /baz/
  puts "str includes baz"
else
  puts "str is something else"
end
正規表現型の場合
case str
when /foo/
  puts "str includes foo"
when /bar/
  puts "str includes bar"
when Regexp.new("baz")
  puts "str includes baz"
else
  puts "str is something else"
end
クラスオブジェクトの場合
case obj
when Integer
  puts "obj is an instance of Integer"
when String
  puts "obj is an instance of String"
when Array
  puts "obj is an instance of Array"
else
  puts "obj is an instance of something else"
end

これらの例では、case 文の式の型によって、比較に用いるオブジェクトの型や正規表現パターンが異なることに注意してください。また、どの条件にも一致しない場合に実行される else 節は省略可能です。

Rubyのif,unless,caseは式
Rubyの ifunlesscase は、制御フロー構文としての使い方に加えて、式としても使うことができます。

例えば、if 式を使ってみましょう。通常の if は、条件が true ならば処理を実行します。

if x > 10
  puts "x is greater than 10"
end

この if 文を式として使うこともできます。具体的には、以下のように if の後ろに式を書き、式の値が true であれば、if の条件式の評価値が式の値となります。

a = if x > 10
      "x is greater than 10"
    else
      "x is less than or equal to 10"
    end
puts a

同様に、unless も式として使うことができます。

a = unless x > 10
      "x is less than or equal to 10"
    else
      "x is greater than 10"
    end
puts a

また、case 式もあります。case 式は、複数の条件に対する分岐処理を行う場合に使われます。以下は、case 式の例です。

a = case x
    when 1
      "one"
    when 2
      "two"
    else
      "other"
    end
puts a

case 式では、when 句を使って、複数の条件式を書くことができます。case 式の評価値は、when 句の条件式と一致する最初のものの右辺の式の値となります。


反復 編集

Rubyの反復構文は、特定の条件が満たされるまでコードのブロックを繰り返すことができる文のセットです。最も一般的な反復文は、while、until、for、loop です。

  • while文は、ある条件が真である限り、コードのブロックを実行します。
  • until文は、ある条件が偽である限り、コードのブロックを実行します。
  • for文は、要素のコレクションを繰り返し処理し、各要素に対してコードのブロックを実行します。
  • loop文は、コードのブロックを永久に実行します。

また、while, until には修飾子構文もあります。

これらの基本的な反復処理文に加えて、Ruby には break、next、redo、lazy などの反復処理文があります。これらの文により、コードの実行の流れを制御することができます。

while文 編集

# このコードでは、1から10までの数字を表示します。
while i <= 10 do
  puts i
  i += 1 
end

while文の構文は以下の通り:

構文
while 条件 do
  # 処理
end

条件とは、ループの実行を継続するためにtrueと評価されなければならないブール値の式です。 処理の部分は、条件が真である限って実行されるコードのブロックです。

まえの例では、条件は「i <= 10」です。これは、iの値が10以下である限り、ループが実行され続けることを意味します。 処理の部分は、puts i行です。この行はiの値をコンソールに出力します。

while文は、特定の条件が満たされる限り、コードのブロックを繰り返すことができる強力なツールです。

while修飾子 編集

while修飾子は、if修飾子に似ていますが、条件式が肯定されている間は式を評価し続ける構文です。

 while 条件式

例えば、ある数値変数numが0未満の間、num に 2 を足し続けるプログラムは以下のように書けます。

num = -3

num += 2 while num < 0

until文 編集

# このコードでは、10から1までの数字を表示します。
i = 10 
until i <= 1 do
  puts i
  i -= 1 
end

until文の構文は以下の通り:

構文
unril 条件 do
  # 処理
end

条件とは、ループの実行を継続するためにfalseと評価されなければならないブール値の式です。 処理の部分は、条件が偽である限って実行されるコードのブロックです。

まえの例では、条件はi <= 1である。これは、iの値が1以上である限り、ループが実行され続けることを意味します。 処理の部分は、puts i行です。この行はiの値をコンソールに出力します。

until文は、特定の条件が満たされない限り、コードのブロックを繰り返すために使用できる強力なツールです。

until修飾子 編集

until修飾子は、while修飾子に似ていますが、条件式が否定されている間は式を評価し続ける構文です。

 until 条件式

例えば、ある数値変数numが0以上でない間、num に 2 を足し続けるプログラムは以下のように書けます。

num = -3

num += 2 until num >= 0

for文 編集

# このコードでは、配列の要素を順に表示します。
array = [2, 3, 5, 7, 11] 
for element in array
  puts element 
end

until文の構文は以下の通り:

構文
for ループ変数 in コレクション
  # ループ変数にまつわる処理
end

ループ変数は、コレクション内の現在の要素のプレースホルダーです。 コレクションは、配列、範囲、その他の反復可能なオブジェクトのいずれでもかまいません。 ループ変数にまつわる処理の部分は、コレクション内の各要素に対して実行されるコードのブロックです。

この例では、コレクションは配列[2, 3, 5, 7, 11]です。ループ変数はelementです。 ループ変数にまつわる処理の部分は、puts element行です。この行は、elementの値をコンソールに表示します。

for文は、要素のコレクションを繰り返し処理するために使用できる強力なツールです。

loop文 編集

# このコードは、永久に "This will print forever!" を表示します。
loop do 
 puts "This will print forever!" 
end

loop文の構文は以下の通り:

構文
loop do
  # 処理
end

処理の部分は、無限に実行されるコードのブロックです。

この例では、処理パートは puts "This will print forever!"です。 この行は、"This will print forever!"というメッセージをコンソールに無限に出力します。

loop文は、コードのブロックを無限に繰り返すために使用できる強力なツールです。

反復制御文 編集

Rubyには、反復制御を行う文が3つあります。

  • break : break文は、現在のループを終了させる。
  • next : 現在のループの繰り返しをスキップする。
  • redo : 現在のループの繰り返しを再び実行する。

反復制御文は、Rubyのコードをより効率的に、より読みやすくするために使用できる強力なツールです。

break 編集

break文は、現在のループを終了させます。

for i in 1..10
  if i == 5
    break
  end
  puts i 
end

このコードは、1から4までの数字を表示し、ループを終了させます。

next 編集

next文は、ループの現在の反復をスキップさせます。

for i in 1..10
  if i == 5
    next
  end
  puts i
end

このコードは、1から10までの数字を表示し、iが5である反復をスキップします。

redo 編集

redo文は、現在のループの繰り返しを再度実行します。

for i in 1..10
  puts i
  redo if i == 5 
end

このコードでは、1から4までの数字を印刷し、さらに5を永久にします。

反復メソッド 編集

Rubyでは、反復処理を用いて演算を行うメソッドを反復処理メソッドと呼びます。 反復処理とは、コードのブロックを指定された回数だけ、あるいは特定の条件が満たされるまで繰り返す処理のことです。

コレクションのイテレーションメソッド 編集

Rubyには、ArrayやHashなどのコレクションオブジェクトを簡単にイテレーションできる多数のメソッドがあります。以下はいくつかの例です:

# eachメソッド
array = [1, 2, 3]
array.each { |x| puts x }

# mapメソッド
array = [1, 2, 3]
new_array = array.map { |x| x * 2 }

# selectメソッド
array = [1, 2, 3]
new_array = array.select { |x| x.even? }

# reduceメソッド
array = [1, 2, 3]
sum = array.reduce(0) { |total, x| total + x }

# each_with_indexメソッド
array = [1, 2, 3]
array.each_with_index { |value, index| puts "#{index}: #{value}" }

上記の例では、以下のように動作しています。

eachメソッド
配列の各要素に対して、ブロック内の処理を1回ずつ実行します。この例では、配列の各要素を出力しています。
mapメソッド
配列の各要素に対して、ブロック内の処理を1回ずつ実行し、その結果を新しい配列に格納します。この例では、配列の各要素を2倍にして新しい配列を作成しています。
selectメソッド
配列の各要素に対して、ブロック内の条件がtrueになる要素だけを抽出して、新しい配列に格納します。この例では、配列の偶数要素だけを抽出して新しい配列を作成しています。
reduceメソッド
配列の各要素に対して、ブロック内の演算を順番に適用して、最終的な結果を返します。この例では、配列の各要素を加算して合計を求めています。
each_with_indexメソッド
配列の各要素とそのインデックスに対して、ブロック内の処理を1回ずつ実行します。この例では、配列の各要素とそのインデックスを出力しています。

これらのメソッドを使用することで、コレクションの要素に簡単にアクセスできます。また、each_with_indexを使用することで、要素のインデックスにも簡単にアクセスできます。

整数のイテレーションメソッド 編集

Rubyには、数値を連続して扱うための便利なメソッドがあります。その中でもupto、downto、stepはよく使われるものです。これらのメソッドについて解説します。

# uptoの例
1.upto(5) do |i|
  puts i
end
# 実行結果: 1 2 3 4 5

# downtoの例
5.downto(1) do |i|
  puts i
end
# 実行結果: 5 4 3 2 1

# stepの例
1.step(10, 2) do |i|
  puts i
end
# 実行結果: 1 3 5 7 9

上記の例では、以下のように動作しています。

uptoメソッド
整数オブジェクトから別の整数オブジェクトまで、1ずつ増加させながら、ブロック内の処理を繰り返します。この例では、1から5までの整数を順に出力しています。
downtoメソッド
整数オブジェクトから別の整数オブジェクトまで、1ずつ減少させながら、ブロック内の処理を繰り返します。この例では、5から1までの整数を順に出力しています。
stepメソッド
開始値から終了値まで、指定されたステップで数値を増加させながら、ブロック内の処理を繰り返します。この例では、1から10までの奇数を順に出力しています。stepメソッドで

は、第2引数に指定した数値が増加量として使用されます。この例では、2ずつ増加しているため、1, 3, 5, 7, 9という結果になっています。

反復メソッドと反復制御文 編集

break、next、redo文もこれらのメソッドと一緒に使うことができます。

たとえば、次のようなものです:

  • break : break 文は、ループの現在の繰り返しを終了させます。
array = [1, 2, 3]
array.each do |element|
  puts element
  break if element == 2
end

このコードでは、配列の要素のうち、要素2までを表示します。

  • next : next文は、ループの現在の繰り返しをスキップする。
array = [1, 2, 3]
array.each do |element|
  puts element
  next if element == 2
end

このコードでは、配列の要素を、要素2をスキップして表示します。

  • redo : redo文は、ループの現在の繰り返しを再度実行します。
array = [1, 2, 3]
array.each do |element|
  puts element
  redo if element == 2
end

このコードは、配列の要素を表示しますが、要素2を無限に表示します。

イテレーションとブロック 編集

Rubyのイテレーションメソッドは、繰り返し処理を行うためのメソッドで、通常はブロックを引数に取ります。ブロックは、繰り返し処理を行うためのコードブロックで、メソッドに渡されたオブジェクトの要素に対して、一つずつ実行されます。

イテレーションメソッドに渡されるブロックには、引数を指定することができます。引数は、ブロック内で処理する要素を表します。引数を指定する方法には、以下の2つがあります。

パイプ(| |)で囲んだ引数を指定する方法
array = [1, 2, 3]
array.each do |x|
  puts x
end
# 出力結果: 1, 2, 3
ブロック引数を指定する方法
array = [1, 2, 3]
array.each { puts _1 }
# 出力結果: 1, 2, 3

このように、イテレーションメソッドは、ブロックを引数に取り、ブロック内で要素に対する処理を実行するため、とても柔軟性が高く、コードの再利用性を高めることができます。

eachメソッドを使ったハック
普段あまり使うことはありませんが、配列のeachメソッドは戻値を返します。

通常は配列自身ですが、breakでループを中断すると nil を返します。 この特徴を利用すると、ZigやPythonのループと結合したelseの様に「ループを完走したときだけ実行する処理」を記述できます。

100以下の素数を求めるコード
primes = []
(2..100).each do |i|
  primes.push(i) if primes.each do |prime|
    break if i % prime == 0
  end
end
p primes
実行結果:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
素数集合(primes)から1つ素数(prime)を取出し、候補(i)をそれで割り、割切れたら break します。
break すると each は nil を返し、素数集合への候補の追加は行われません。


例外処理 編集

Rubyにおける例外処理は、プログラムが想定外のエラーに遭遇した場合に、プログラムの強制終了を防ぐために使用されます。例外処理を使用すると、プログラムはエラーが発生しても継続して実行されるため、エラーに含まれる情報をログファイルに記録したり、エラーメッセージを表示したりすることができます。

以下は、Rubyで例外処理を行うための基本的な書式です。

begin
  # 例外が発生する可能性のある処理
rescue [エラークラス => 変数]
  # エラークラスが発生した場合に実行する処理
else
  # 例外が発生しなかった場合に実行する処理
ensure
  # 必ず実行される処理
end

例外処理の流れは、まずbeginブロック内で例外が発生する可能性のある処理を書きます。そして、rescueブロックで発生しうる例外の種類を指定し、例外が発生した場合に行う処理を書きます。elseブロックは、例外が発生しなかった場合に実行する処理を書く部分です。ensureブロックには、必ず実行される処理を書きます。

以下は、例外処理を用いたコードの例です。

def divide(a, b)
  begin
    result = a / b
  rescue ZeroDivisionError => e
    puts "Error: #{e.message}"
    result = nil
  else
    puts "Result is #{result}"
  ensure
    puts "Process finished"
  end
  return result
end

puts divide(10, 0)
puts divide(10, 2)

この例では、divideメソッド内で引数bが0である場合にZeroDivisionErrorが発生する可能性があるため、beginブロック内で計算を行っています。また、rescueブロックではZeroDivisionErrorを補足して、エラーメッセージを表示しています。elseブロックでは、計算結果を表示しています。ensureブロックでは、処理が必ず実行されるように設定しています。

このコードを実行すると、以下のような結果が得られます。

Error: divided by 0
Process finished
nil
Result is 5
Process finished
5

rescue修飾子 編集

Rubyのrescue修飾子は、単一行のコードで例外処理を行うことができます。通常のrescue文との違いは、修飾子が「行末」に付加されることです。

例えば、次のようなコードがあるとします。

result = nil
begin
  # 何らかの処理
  result = 1 / 0
rescue StandardError => e
  puts "エラーが発生しました:#{e.message}"
end

puts result # => nil

この処理では、beginブロック内の処理で例外が発生した場合、rescueブロック内の処理が実行され、putsメソッドでエラーメッセージが出力されます。

一方、rescue修飾子を使うと、次のように書き換えることができます。

result = nil
result = 1 / 0 rescue nil

puts result # => nil

この場合、処理中に例外が発生すると、例外が捕捉され、結果としてnilresultに代入されます。rescue修飾子は単一行のコードで書きやすく、コードの可読性を向上させることもできます。ただし、過剰な使用は可読性を下げることがあるため、注意して使いましょう。

メソッド 編集

Rubyのメソッドとは、ある一定の処理をまとめて名前をつけたもので、複数の場所で同じような処理を書く必要がある場合に便利です。

以下は、Rubyでメソッドを定義する方法の例です。

def メソッド名(仮引数)
  処理 
end

上記のコードでは、defキーワードを使ってメソッドを定義します。メソッド名は自分で決定し、仮引数は必要に応じて任意の数を指定できます。また、endキーワードでメソッドの終わりを示します。

このように、トップレベルで定義されたメソッドは、スクリプト中どこならでも呼び出すことができ、関数と呼ばれことがあります。


以下は Ruby における関数定義における引数に関する機能の例です。

# 固定順位引数
def greet(name)
  puts "Hello, #{name}!"
end

greet("Alice")   # => "Hello, Alice!"
greet("Bob")     # => "Hello, Bob!"

# 固定順位引数のデフォルト値
def greet_with_default(name="world")
  puts "Hello, #{name}!"
end

greet_with_default   # => "Hello, world!"
greet_with_default("Alice")   # => "Hello, Alice!"

# キーワード引数
def greet_with_keyword(name:)
  puts "Hello, #{name}!"
end

greet_with_keyword(name: "Alice")   # => "Hello, Alice!"
greet_with_keyword(name: "Bob")     # => "Hello, Bob!"

# キーワード引数のデフォルト値
def greet_with_keyword_default(name: "world")
  puts "Hello, #{name}!"
end

greet_with_keyword_default   # => "Hello, world!"
greet_with_keyword_default(name: "Alice")   # => "Hello, Alice!"

# ブロック引数
def greet_with_block(name)
  puts "Hello, #{name}!"
  yield
end

greet_with_block("Alice") { puts "Glad to see you!" }
# => "Hello, Alice!"
# => "Glad to see you!"

# 残余引数
def greet_with_remainder(*names)
  names.each { |name| puts "Hello, #{name}!" }
end

greet_with_remainder("Alice", "Bob", "Charlie")
# => "Hello, Alice!"
# => "Hello, Bob!"
# => "Hello, Charlie!"

greet 関数は固定順位引数を使用しています。greet_with_default 関数では、name のデフォルト引数が指定されています。greet_with_keyword 関数では、キーワード引数を使用しています。greet_with_keyword_default 関数では、キーワード引数のデフォルト引数が指定されています。greet_with_block 関数では、ブロック引数を使用しています。最後に、greet_with_remainder 関数は残余引数を使用しています。

これらの機能を駆使することで、より柔軟かつ読みやすいコードを作成することができます。

固定順位引数 編集

例えば、以下のようなメソッドを定義してみましょう。

def say_hello(name)
  puts "Hello, #{name}!" 
end

このメソッドは、引数に渡した名前に対して「Hello, 〇〇!」というメッセージを出力します。引数の「name」には、任意の名前を指定することができます。

このメソッドを呼び出すためには、以下のように書きます。

say_hello("John") #=> Hello, John!

引数に指定した名前が、「name」の部分に代入され、putsメソッドによってメッセージが出力されます。

固定順位引数のディフォルト値 編集

また、Rubyには引数を指定しないデフォルト値を設定する方法もあります。以下は、デフォルト値を設定したメソッドの例です。

def say_hello(name = "World")
  puts "Hello, #{name}!" 
end

この場合、引数を指定しなかった場合は「World」という名前が、引数を指定した場合は指定した名前が代入されます。例えば、以下のように呼び出します。

say_hello         #=> Hello, World! 
say_hello("Mary") #=> Hello, Mary!

キーワード引数 編集

キーワード引数では、引数名を指定することができます。これにより、引数の並び順を気にすることなく、任意の引数を指定することができます。

def person(name:, age:)
  puts "名前は#{name}、年齢は#{age}才です。"
end

person(name: "山田太郎", age: 30) #=> 名前は山田太郎、年齢は30才です。

キワード引数の実引数でに順序は任意です。

キーワード引数のディフォルト値 編集

キーワード引数もディフォルト値を設定することができます。引数を指定しなかった場合は、初期値が使われるようになります。

def person(name: "名無し", age: 0)
  puts "名前は#{name}、年齢は#{age}才です。"
end

person(name: "山田太郎") #=> 名前は山田太郎、年齢は0才です。

ブロック引数 編集

ブロック引数とは、メソッドの引数としてブロックを受け取るための仕組みです。 ブロックを受け取るメソッドの引数リストの最後に、"&ブロック名"という形式の引数を指定することで、ブロックをメソッド内で扱うことができます。

以下に例を示します。

def my_method(&block)
  block.call
end

my_method do
  puts "Hello, World!"
end
# => "Hello, World!"

上記の例では、my_methodメソッドにブロックを渡しています。my_methodメソッド内では、ブロックを扱うための引数として"&block"を指定しており、ブロックを呼び出すために"block.call"を用いています。

yield 編集

yieldは、メソッドに渡されたブロックを実行するためのキーワードです。yieldを使用することで、メソッド内でブロックを実行することができます。

以下に例を示します。

def my_method
  yield
end

my_method do
  puts "Hello, World!"
end
# => "Hello, World!"

上記の例では、my_methodメソッド内でyieldを用いてブロックを実行しています。my_methodメソッドが呼び出されると、引数として渡されたブロックが実行されます。

ブロック呼び出しへの引数 編集

ブロック引数の呼び出しやyieldは引数を渡すこともできます。

ブロック引数の呼び出しへの引数 編集
def my_method(name, &block)
  block.call(name)
end

my_method("John") do |name|
  puts "Hello, #{name}!"
end
# => "Hello, John!"

上記の例では、my_methodメソッドにブロックを渡し、ブロック引数に"name"を指定しています。 ブロック内で引数を使用するために、block.callで"name"を渡しています。 ブロック内では、引数として渡された"name"を使用して文字列を出力しています。

yield への引数 編集
def my_method(name)
  yield(name)
end

my_method("John") do |name|
  puts "Hello, #{name}!"
end
# => "Hello, John!"

上記の例では、my_methodメソッドに引数として"name"を渡し、yield"name"を引数として渡しています。 ブロック内では、引数として渡された"name"を使用して文字列を出力しています。

ブロック引数と yield どちらを使うべきか? 編集

ブロック引数と yield は、基本的に同じことが出来ますが、メソッド呼び出しがブロックを伴っているか判断する必要がある場合はブロック引数が適用です。

def my_method(name, &block)
  if block then
    block.call(name)
  else
    puts "!!! No block given !!!"
  end
end

my_method("John") do |name|
  puts "Hello, #{name}!"
end
#==> Hello, John!

my_method("Alice") #==> !!! No block given !!!

上記のRubyコードは、引数で渡された名前に対して、ブロックを実行するかどうかを判断するメソッド my_method です。

このメソッドは、通常の引数として name を受け取り、ブロック引数として &block を受け取っています。&block はブロックをメソッド内で扱うための引数です。

このメソッドは、引数として渡された name に対して、ブロックを実行します。渡されたブロックがない場合は、!!! No block given !!! というメッセージを表示します。

残余引数 編集

Rubyのメソッドは、引数の数が可変長であることができます。この場合、メソッドの引数リストのうち最後の引数に「*引数名」という形式を指定します。

def my_method(arg1, arg2, *rest)
  p arg1 # => "foo"
  p arg2 # => "bar"
  p rest # => ["baz", "qux"]
end

my_method("foo", "bar", "baz", "qux")

このように、可変長引数を指定したメソッドでは、引数リストの最後に「*引数名」という形式を指定することによって、可変長引数を配列として扱うことができます。

戻り値 編集

メソッド内で最後に評価される値が、そのメソッドの戻り値になります。例えば、次のようなメソッドを考えてみましょう。

def add(a, b)
  return a + b 
end

このメソッドは2つの引数を受け取り、それらの和を返します。return キーワードを使用して、明示的に戻り値を指定しています。このように return を使わずに値を返すと、メソッドの最後に評価された値が自動的に戻り値として返されます。

def add(a, b)
  a + b 
end

このように、明示的に return を書かなくても、メソッド内で最後に評価された値が自動的に戻り値となります。

メソッドを呼び出す際には、その戻り値を変数に代入したり、別のメソッドの引数として渡したりすることができます。 戻り値が必要な場合や、逆に必要ではない場合など、メソッドの設計時にはしっかりと考慮して実装する必要があります。

スコープ 編集

Rubyには4つのスコープがあります。以下にそれぞれのスコープとコード例を示します。

ローカルスコープ: 変数が定義されたブロック内でしか使用できません。

def local_scope
  x = 10
end

puts x # undefined local variable or method `x' for main:Object (NameError)

インスタンススコープ: インスタンス変数は同じインスタンスの中であればどこでも使用できます。

class Person
  def initialize(name)
    @name = name
  end
  
  def greet
    puts "Hello, #{@name}!"
  end
end

person = Person.new("Alice")
person.greet # Hello, Alice!
puts @name # undefined method `name' for main:Object (NameError)

クラススコープ: クラス変数はそのクラス及びサブクラスのどこからでも使用できます。

class Counter
  @@count = 0
  
  def initialize
    @@count += 1
  end
  
  def self.count
    @@count
  end
end

counter1 = Counter.new
counter2 = Counter.new

puts Counter.count # 2

グローバルスコープ: グローバル変数はどこからでも使用できます。ただし、他のスコープで同じ名前の変数が定義されている場合はその変数が使用されます。

$global_var = "I'm global"

def check_global_var
  puts $global_var
end

check_global_var # I'm global

def set_global_var
  $global_var = "I'm changed globally"
end

set_global_var
check_global_var # I'm changed globally

以上がRubyの4つのスコープです。

メソッドの引数リストを囲む括弧の省略
メソッドの引数リストを囲む括弧 p() は、曖昧さのない場合は省略可能です。

上の例は、puts(s)と書く代わりに、put s と書く事ができます。

コード
s = 'Hello World!'
puts s
実行結果
Hello World!


再帰的呼び出し 編集

Rubyでは、メソッド内で再帰を行うことができます。以下は、再帰を行うシンプルな例です。

def countdown(num)
  if num > 0
    puts num
    countdown(num - 1)
  else
    puts "Blast off!"
  end
end

countdown(5)

このコードでは、countdownメソッドが自分自身を呼び出して、カウントダウンを実行しています。呼び出し結果は以下の通りです。

5 
4 
3 
2 
1 
Blast off!

このように、再帰を使うと、同じ処理を繰り返し実行することができます。

クロージャー 編集

Rubyにはクロージャーという概念があります。クロージャーとは、変数とブロックを組み合わせたもので、後からブロック内で変数が参照された場合でも、当時の変数の値を保持している特殊なオブジェクトです。

以下は、クロージャーを使った例です。

def greeting_proc(name)
  Proc.new { puts "Hello, #{name}!" }
end

hello = greeting_proc("Alice")
hello.call # => "Hello, Alice!"

changing_name = "Bob"
hello.call # => "Hello, Alice!" (value of name is retained)

上記の例では、greeting_procメソッドがブロックを返し、そのブロックがhello変数に代入されます。このブロック内で参照される変数nameの値が保持され、hello.callを複数回実行しても、最初に指定した名前が表示されます。

また、changing_nameという変数を新しく定義しても、クロージャー内で参照されるnameの値には影響がなく、hello.callを実行すると、"Hello, Alice!"が表示されます。

クラス 編集

Rubyにおけるクラスは、オブジェクト指向プログラミングにおいて重要な役割を持ちます。クラスは、同じ構造や属性を持つオブジェクトの集合を定義するもので、それぞれのオブジェクトはクラスのインスタンスであると考えることができます。

クラス定義とインスタンスの生成とメソッドの呼び出し 編集

# クラス定義
class MyClass
  # クラス変数
  @@class_variable = "Class Variable"

  # インスタンス変数
  attr_accessor :instance_variable

  # コンストラクター
  def initialize(arg)
    @instance_variable = arg
  end

  # クラスメソッド
  def self.class_method
    puts @@class_variable
  end

  # インスタンスメソッド
  def instance_method
    puts @instance_variable
  end
end

# クラスの利用
my_object = MyClass.new("Instance Variable")
MyClass.class_method #=> "Class Variable"
my_object.instance_method #=> "Instance Variable"
my_object.instance_variable = "New Instance Variable"
my_object.instance_method #=> "New Instance Variable"

クラス定義はclassキーワードを使い、インスタンス変数を作成するためにattr_accessorを使っています。コンストラクターはinitializeメソッドを使い、引数を受け取ってインスタンス変数を初期化します。

クラスメソッド、インスタンスメソッドはそれぞれdef self.method_namedef method_nameの形式で定義されます。また、クラス変数は@@で始められ、インスタンス変数は@で始められます。

このように、Rubyのクラスを使用することで、簡単にオブジェクト指向プログラミングを実現することができます。

アクセス修飾子 編集

Rubyには3種類のアクセス修飾子があります。

public
どこからでもアクセス可能なメソッドや変数を定義するときに使用します。
クラスの外部からもアクセス可能です。
protected
自クラスまたはそのサブクラスであればアクセス可能なメソッドや変数を定義するときに使用します。
クラスの外部からはアクセスできません。
private
同じオブジェクト内でしかアクセスできないメソッドや変数を定義するときに使用します。
クラスの外部からはアクセスできません。

以下は、それぞれのアクセス修飾子を使用した例です。

class Animal
  def swim # public
    puts "I can swim!"
  end

  protected

  def run # protected
    puts "I can run!"
  end

  private

  def fly # private
    puts "I can fly!"
  end
end

class Cat < Animal
  def can_run
    run # protectedなのでAnimalクラスのサブクラス内から呼び出し可能
  end

  def can_fly
    fly # privateなので呼び出し不可能
  end
end

cat = Cat.new
cat.swim # publicなので呼び出し可能
cat.can_run # protectedなので呼び出し可能
cat.can_fly # privateなので呼び出し不可能

上記の例では、Animalクラスに swimrunfly メソッドを定義しています。 swimメソッドは publicrun メソッドは protectedfly メソッドは private となっています。

また、Cat クラスを Animal クラスのサブクラスとして定義し、can_runメソッドで、Animalクラスで protected として定義した run メソッドを呼び出しています。一方で、can_fly メソッドで private として定義した fly メソッドを呼び出しているため、エラーが発生しています。

クラスの継承 編集

# 親クラス
class Animal
  def speak
    puts "動物が鳴いています"
  end
end

# 子クラス
class Dog < Animal
  def speak
    puts "わんわん"
  end
end

# 子クラス
class Cat < Animal
  def speak
    puts "にゃーにゃー"
  end
end

# 子クラスのインスタンス化
dog = Dog.new
cat = Cat.new

# 子クラスのメソッドを呼び出し
dog.speak #=> わんわん
cat.speak #=> にゃーにゃー

# 親クラスのメソッドも呼び出し可能
dog.superclass #=> Animal
dog.superclass.superclass #=> Object(親クラスの親クラス)

この例では、Animal という親クラスを作成し、 DogCat という子クラスを作成しています。 DogCat はそれぞれ speak メソッドを持っており、それぞれ異なる出力をします。

DogCatAnimal クラスを継承しています。このため、 DogCatAnimal クラスの speak メソッドを呼び出すことができます。

演算子オーバーロード 編集

以下はRubyにおける演算子オーバーロードの例です。

class Person
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def +(other)
    Person.new("#{self.name} #{other.name}", self.age + other.age)
  end

  def ==(other)
    self.name == other.name && self.age == other.age
  end
end

person1 = Person.new("John", 30)
person2 = Person.new("Doe", 40)

# カスタム演算子 '+' の利用
person3 = person1 + person2
puts person3.name #=> John Doe
puts person3.age #=> 70

# カスタム演算子 '==' の利用
puts person1 == person3 #=> false
person4 = Person.new("John Doe", 70)
puts person3 == person4 #=> true
  • この例では、Personクラスで+演算子と==演算子をオーバーロードしています。
  • +演算子は2つのPersonオブジェクトを受け取り、新しいPersonオブジェクトを返します。
  • ==演算子は2つのPersonオブジェクトを比較し、nameプロパティとageプロパティが両方とも同じ場合にtrueを返します。

クラスへの動的なメソッドの追加 編集

class MyClass
  def initialize(name)
    @name = name
  end
end

my_object = MyClass.new("Bob")

class MyClass
  def greet()
    puts "Hello, #{@name}!"
  end
end

my_object.greet #=> "Hello, Bob!"
  • 最初に、「MyClass」というクラスを定義します。
  • 次に、MyClassのインスタンスを生成し変数my_objectに代入しています。
  • その後、件のMyClassに新しいメソッドgreet()を定義しています。
  • 最後の行で、「my_object.greet」というコードが実行され、オブジェクトの「greet」メソッドが呼び出されます。これにより、「Hello, Bob!」という文字列が出力されます。

注目すべきは:

  • クラス定義の後でもメソッドの追加はできる
  • インスタンス化とメソッドの追加定義が前後しても、メソッド呼び出しは可能である

の2点です。

特異メソッド 編集

Rubyでは、オブジェクトに固有のメソッドを定義することができます。これを特異メソッドと呼びます。通常、メソッドはクラス定義内で定義されますが、特異メソッドは特定のオブジェクトに対して定義されます。

特異メソッドの定義 編集

特異メソッドを定義するには、以下のように書きます。

オブジェクト名.define_singleton_method(シンボル) do |引数|
  # メソッドの中身
end

例えば、以下のように書くことで、特定のオブジェクトにhelloメソッドを定義することができます。

str = "Hello, world!"
str.define_singleton_method(:hello) do
  puts "Hello!"
end

これで、strオブジェクトにhelloメソッドが定義されました。呼び出すには以下のようにします。

str.hello  #=> "Hello!"

特異クラスと特異メソッド 編集

Rubyでは、オブジェクトに対して特異クラスというものが存在します。これは、そのオブジェクトだけが持つクラスのことです。この特異クラスに対して特異メソッドを定義することで、そのオブジェクトだけにメソッドを追加できます。

特異クラスは、以下のように記述します。

class << オブジェクト名
  # メソッドの定義
end

例えば、以下のように記述することで、上記のstrオブジェクトに対してメソッドを定義することができます。

class << str
  def goodbye
    puts "Goodbye!"
  end
end

これで、strオブジェクトにgoodbyeメソッドが定義されました。呼び出すには以下のようにします。

str.goodbye  #=> "Goodbye!"

まとめ 編集

以上が、Rubyの特異メソッドについてのチュートリアルです。オブジェクトに対して固有のメソッドを定義することで、便利なプログラミングをすることができます。

Rubyにデストラクタはありますか?
Rubyにはデストラクタという名前のメソッドはありませんが、オブジェクトが破棄される前に自動的に実行される処理を定義する方法があります。その方法は、Objectクラスに定義されているfinalizeメソッドをオーバーライドすることです。

finalizeメソッドは、オブジェクトがガベージコレクターによって回収される際に呼び出されます。オブジェクトが破棄される直前に、このメソッドが呼び出されることが保証されています。したがって、finalizeメソッド内で、オブジェクトの破棄に関連する処理を行うことができます。

以下は、finalizeメソッドをオーバーライドして、オブジェクトの破棄時にメッセージを表示する例です。

class MyClass
  def initialize(name)
    @name = name
  end
  
  def finalize
    puts "Object #{@name} is being destroyed"
  end
end

obj = MyClass.new("example")
# do something with obj
obj = nil # objが不要になったときにfinalizeが呼び出される

# 出力結果: Object example is being destroyed

ただし、finalizeメソッドは、ガベージコレクションが発生するまで呼び出されないため、オブジェクトが即座に破棄されることは保証されません。 そのため、finalizeメソッドを使用してメモリリークを防止することはできません。 むしろ、ensureブロックなどのより信頼性の高い方法を使用して、リソースの解放を行うことをお勧めします。


クラス定義の例 編集

都市間の大圏距離 編集

Go/メソッドとインターフェースの都市間の大圏距離を求めるメソッドを追加した例を、Rubyに移植しました。

都市間の大圏距離
class GeoCoord
    attr_accessor :longitude, :latitude

    def initialize(longitude, latitude)
        @longitude, @latitude = longitude, latitude
    end
    def to_s() 
	    ew, ns = "東経", "北緯"
	    long, lat = @longitude, @latitude
	    ew, long = "西経", -long if long < 0.0
	    ns, lat = "南緯", -lat if lat < 0.0
	    "(#{ew}: #{long}, #{ns}: #{lat})"
    end
    def distance(other)
    	i, r = Math::PI / 180, 6371.008
	    Math.acos(Math.sin(@latitude * i) * Math.sin(other.latitude * i) +
		    Math.cos(@latitude * i) * Math.cos(other.latitude * i) * Math.cos(@longitude * i - other.longitude * i)) * r
	end
end
def GeoCoord(longitude, latitude)
    GeoCoord.new(longitude, latitude)
end

Sites = {
    "東京駅":                   GeoCoord(139.7673068, 35.6809591),
    "シドニー・オペラハウス":   GeoCoord(151.215278, -33.856778),
    "グリニッジ天文台":         GeoCoord(-0.0014, 51.4778),
}

Sites.each{|name, gc|
    puts "#{name}: #{gc}"
}

keys, len = Sites.keys, Sites.size
keys.each_with_index{|x, i|
    y = keys[(i + 1) % len]
	puts "#{x} - #{y}: #{Sites[x].distance(Sites[y])} [km]"
}
実行結果
東京駅: (東経: 139.7673068, 北緯: 35.6809591)
シドニー・オペラハウス: (東経: 151.215278, 南緯: 33.856778)
グリニッジ天文台: (西経: 0.0014, 北緯: 51.4778)
東京駅 - シドニー・オペラハウス: 7823.269299386704 [km]
シドニー・オペラハウス - グリニッジ天文台: 16987.2708377249 [km]
グリニッジ天文台 - 東京駅: 9560.546566490015 [km]

このコードは、GeoCoordというクラスを定義し、そこに緯度と経度を持つ「地球上の位置」を表現しています。それを利用して、Sitesというディクショナリに都市名と位置を紐付けています。

このコードのメインの処理は、各都市に対して、その距離を計算して出力しています。すなわち、都市の位置情報から、地球上での距離を求めることができます。

この「地球上の距離を求める」処理は、distanceメソッドで定義されており、球面三角法を使って計算されています。具体的には、2点の緯度経度から、その2点間の地表面上の距離を求める数式を用いています。

また、都市名と位置情報を紐付けたSitesに対しては、各都市の位置を出力しています。それぞれの都市の位置は、東経か西経か、北緯か南緯かで表され、丸括弧でくくられ、「東京駅」の場合は (東経: 139.7673068, 北緯: 35.6809591)という文字列が出力されます。

包含と継承 編集

JavaScript/クラス#包含と継承を、Rubyに移植しました。

包含と継承
class Point
  def initialize(x = 0, y = 0)
    @x, @y = x, y
  end
  def inspect() "x:#{@x}, y:#{@y}" end
  def move(dx = 0, dy = 0)
    @x, @y = @x + dx, @y + dy
    self
  end
end

class Shape
  def initialize(x = 0, y = 0)
    @location = Point.new(x, y)
  end
  def inspect() @location.inspect() end
  def move(x, y)
    @location.move(x, y)
    self
  end
end

class Rectangle < Shape 
  def initialize(x = 0, y = 0, width = 0, height = 0)
    super(x, y)
    @width, @height = width, height
  end
  def inspect() "#{super()}, width:#{@width}, height:#{@height}" end
end

rct = Rectangle.new(12, 32, 100, 50)

p ["rct=", rct]
p ['rct.instance_of?( Rectangle ) => ', rct.instance_of?(Rectangle)]
p ['rct.instance_of?( Shape ) => ', rct.instance_of?(Shape)]
p ['rct.instance_of?( Point ) => ', rct.instance_of?(Point)]
rct.move(11, 21)
p ["rct=", rct]
実行結果
["rct=", x:12, y:32, width:100, height:50]
["rct.instance_of?( Rectangle ) => ", true]
["rct.instance_of?( Shape ) => ", false]
["rct.instance_of?( Point ) => ", false]
["rct=", x:23, y:53, width:100, height:50]

このコードは、Rubyでオブジェクト指向プログラミングを用いた簡単な図形クラスの例です。

Pointクラスは、座標を表現するためのクラスであり、xyの2つのインスタンス変数を持っています。 コンストラクタで、xyの初期値が設定できます。inspectメソッドは、オブジェクトを文字列に変換するために使用されます。moveメソッドにより、(dx, dy)だけ点を移動することができます。

Shapeクラスは、点の座標を持つ図形を表すためのクラスであり、initializeメソッド内で、Pointクラスのオブジェクトを作成して、点の座標を設定します。inspectメソッドは、点の座標を返します。 moveメソッドによって、図形を(dx, dy)だけ移動することができます。

Rectangleクラスは、Shapeクラスを継承しています。コンストラクタで、左上の点の座標と幅と高さを設定できます。inspectメソッドは、左上の点の座標と、幅と高さを表現する文字列を返します。

最後の行では、Rectangleクラスのインスタンスrctを作成し、その後、rctRectangleクラス、Shapeクラス、Pointクラスのどれに対してインスタンスかを調べるようにしています。また、rctの位置を(11, 21)だけ移動させます。

高階関数 編集

Rubyの高階関数とは、関数を引数や戻り値として扱うことができる関数のことを指します。これにより、コードの再利用性が向上し、より柔軟なプログラミングが可能になります。

例えば、以下のような高階関数があります。

def manipulate_array(arr, func)
  arr.map(&func)
end

この関数は、配列と関数を受け取り、配列の各要素に対してその関数を適用した新しい配列を返します。このように、関数自体を引数として渡せることで、どのような処理でも適用することができます。

また、RubyのProcオブジェクトを使うことで、無名関数を定義して高階関数に渡すこともできます。例えば、以下のようなコードです。

add_num = Proc.new {|x| x + 1 }
puts manipulate_array([1, 2, 3], add_num)
# => [2, 3, 4]

このように、Procオブジェクトを定義して関数に渡すことで、より柔軟なプログラミングが可能になります。

lambda 編集

Rubyのlambdaとは、無名関数(関数を名前を付けずに定義すること)の一種であり、関数をオブジェクトとして扱うことができます。

以下は、lambda式の基本構文です。

lambda { |引数| 処理 }

lambdaには引数を渡すことができ、渡された引数を処理に渡すことができます。また、処理の中で return を使うことができ、lambdaの戻り値として処理結果を返すことができます。以下が、lambdaを利用した簡単な例です。

# lambda式を変数に代入する
add = lambda { |x, y| x + y }

# lambda式を直接呼び出す
puts lambda { |x, y| x + y }.call(2, 3) #=> 5

# lambda式を変数に代入したものを呼び出す
puts add.call(2, 3) #=> 5

# ブラケット記法による呼び出し
puts add[2, 3] #=> 5

以上が、Rubyのlambdaの基本的な使い方です。

Procとlambdaの違い 編集

RubyのProcとlambdaは、両方とも無名関数を定義するための方法ですが、いくつかの違いがあります。

引数の扱い方 Procの場合、渡された引数の数が関係なく、無視されます。一方、lambdaの場合は、正確な数の引数が期待されます。引数が足りない場合はエラーが発生します。

return文の扱い方 Procの場合、return文は元の呼び出し元に戻りますが、そのブロック内の後続のコードも実行されます。lambdaの場合、return文はただちにブロックから返され、コードの後続部分は実行されません。

以下は、Procとlambdaの振る舞いの違いを示す例です。

def proc_test
  p = Proc.new { return "Proc" }
  p.call
  return "proc_test method"
end

def lambda_test
  l = lambda { return "Lambda" }
  l.call
  return "lambda_test method"
end

puts proc_test # 出力結果: Proc
puts lambda_test # 出力結果: lambda_test method

この例では、Procはブロック内でreturn文を呼び出していますが、lambdaは呼び出していません。そのため、Procはreturn文で元の呼び出し元に戻って、その後のコードも実行されなくなっています。一方、lambdaはreturn文を呼び出すことがないので、lambda_testメソッドが正常に終了します。

並行処理 編集

Rubyには以下のような並行処理の仕組みが提供されています。

Threadクラス
Threadクラスを使用することで、Rubyでのマルチスレッドプログラミングが可能になります。Thread.newメソッドを呼び出すことで新しいスレッドを作成し、その中で並列に実行したい処理をブロックとして渡します。スレッド間でのデータ共有については、QueueやMutexといった同期プリミティブを使用することができます。
Fiberクラス
Fiberクラスを使用することで、Rubyでのコルーチンを実現できます。コルーチンは一般的なスレッドとは異なり、スケジューラを持っておらず、明示的に切り替える必要があります。Fiber.yieldメソッドを呼び出すことで一旦コルーチンの実行を中断し、Fiber.resumeメソッドを呼び出すことで再開します。
Processクラス
Processクラスを使用することで、Rubyでのプロセス間通信が可能になります。プロセス同士はメモリを共有せず、別々のプロセスとして実行されます。プロセス間で通信を行うには、パイプや共有メモリなどの仕組みを使用する必要があります。

なお、Rubyには以上の他にも、ThreadクラスやFiberクラスと同様に、GVL(Global VM Lock)によってスレッドセーフに実行されるイベントマシンであるEventMachineや、並行処理のためのツールキットであるCelluloidなどが存在します。

スレッド(Thread) 編集

Rubyにおけるスレッドは、軽量な並列処理を実現するための機能であり、プログラム内で独立して動作する変数やメソッドの集合を表します。スレッドは、複数のタスクを同時に処理することで、CPUを最大限活用することができます。

スレッドは、Threadクラスを使用して作成することができます。Thread.newメソッドを使用して、新しいスレッドを作成した後、startメソッドを呼び出すことでスレッドを開始します。また、Thread.currentメソッドを使用することで、現在のスレッドを取得することができます。

以下は、スレッドを使用した簡単な例です。

t1 = Thread.new {
  # スレッド1の処理
  puts "Thread 1 started"
  sleep(2)
  puts "Thread 1 ended"
}

t2 = Thread.new {
  # スレッド2の処理
  puts "Thread 2 started"
  sleep(1)
  puts "Thread 2 ended"
}

t1.join
t2.join

この例では、スレッド1とスレッド2が開始されます。それぞれのスレッドは、sleepメソッドを使用して一定時間待機した後、メッセージを出力します。joinメソッドを呼び出すことで、スレッドが完了するまでプログラムの実行をブロックします。

Rubyにおけるスレッドには、マルチスレッドに関する問題がいくつか存在します。例えば、同一のリソースにアクセスする複数のスレッドによる競合状態や、デッドロックに陥ってしまう可能性があります。これらの問題を回避するため、適切なロック処理や排他制御が必要な場合があります。

ファイバー(Fiber) 編集

Rubyのファイバー(Fiber)は、擬似並行処理を実現するための仕組みです。標準的なスレッドと異なり、Rubyのファイバーはコルーチン的な動作をし、明示的に制御を渡す必要があります。

ファイバーは、Ruby 1.9以降から標準機能として組み込まれています。ファイバーを利用することで、特定の処理を中断したあと再開したり、独自のスケジューリングに基づいた処理を実現したりすることができます。

ファイバーは以下のように作成できます。

fiber = Fiber.new do
  puts "start"
  Fiber.yield
  puts "end"
end

このコードでは、Fiber.newメソッドにブロックを渡してファイバーを作成します。puts "start"を実行した後、Fiber.yieldで処理を中断しています。この時点でプログラムは停止しており、puts "end"はまだ実行されていません。

ファイバーを再開するには、Fiber#resumeメソッドを呼び出します。

fiber.resume

このコードを実行すると、puts "start"が表示された後にプログラムが停止します。その後、再びfiber.resumeを実行すると、puts "end"が表示されます。

このように、ファイバーを利用することで、特定の処理を中断してから再開することができます。また、ファイバーを複数作成し、独自のスケジューリングに基づいた処理を行うことができます。

以下は、複数のファイバーを作成し、それぞれの処理を交互に実行する例です。

f1 = Fiber.new do
  loop do
    puts "1"
    Fiber.yield
  end
end

f2 = Fiber.new do
  loop do
    puts "2"
    Fiber.yield
  end
end

f1.resume
f2.resume
f1.resume
f2.resume
# ...

このように、ファイバーを利用することで、擬似的な並行処理を実現することができます。しかし、ファイバーはスレッドと異なり、OSレベルでのスケジューリングを行わないため、適切な制御を行わないとデッドロックや競合状態などの問題が生じることがあります。注意して使用する必要があります。

プロセス(Process) 編集

Rubyには、プロセスを管理するための Process モジュールが用意されています。このモジュールを使用することで、現在のプロセスや子プロセスを管理することができます。以下に、Processモジュールの主な機能をコードを交えて解説します。

現在のプロセス情報の取得 編集

Process モジュールに用意されている、 Process.pid メソッドを使用することで、現在のプロセスのIDを取得することができます。以下は、 Process.pid を使用して現在のプロセスIDを取得し、表示する例です。

puts "現在のプロセスID: #{Process.pid}"

プロセスの生成 編集

Process モジュールには、新しいプロセスを生成するためのメソッドが複数用意されています。ここでは、代表的な2つのメソッドを紹介します。

Process.spawn メソッド 編集

Process.spawn メソッドを使用することで、外部プログラムを実行する新しいプロセスを生成することができます。以下は、 ls コマンドを実行する新しいプロセスを生成する例です。

pid = Process.spawn("ls")
fork メソッド 編集

fork メソッドを使用することで、現在のプロセスの子プロセスを生成することができます。 fork メソッドは、呼び出し元のプロセスからコピーされた新しいプロセスを生成します。以下は、 fork メソッドを使用して子プロセスを生成し、子プロセス内で puts メソッドを呼び出す例です。

pid = fork
if pid.nil?
  puts "子プロセスのID: #{Process.pid}"
else
  puts "親プロセスのID: #{Process.pid}, 子プロセスのID: #{pid}"
end

プロセスの終了 編集

生成したプロセスを適切に終了することも重要です。以下は、プロセスを終了するためのメソッドを紹介します。

Process.kill メソッド 編集

Process.kill メソッドを使用することで、指定したシグナルを送信してプロセスを終了することができます。以下は、 kill メソッドを使用して、先程生成した ls コマンドを実行しているプロセスを終了する例です。

pid = Process.spawn("ls")
puts "新しいプロセスのID: #{pid}"
sleep 1
Process.kill("TERM", pid)
puts "プロセスを終了しました"

まとめ 編集

このように、Rubyの Process モジュールを使用することで、プロセスの生成や管理を容易に行うことができます。プロセスを扱う場合は、適切な終了処理も行うようにしましょう。

組み込みライブラリ 編集

「組み込みライブラリ」とは、Ruby言語に最初から組み込まれているライブラリのことです。Ruby言語は非常に豊富な組み込みライブラリを備えており、これらのライブラリを使用することで、ファイル入出力、数学計算、正規表現、日付や時間の処理など、多岐にわたる処理を簡単かつ効率的に行うことができます。

このチュートリアルでは、組み込みライブラリの一部を紹介し、基本的な使い方を説明しています。また、組み込みライブラリを使用する際に知っておくべき注意点や、より高度な使い方についても触れています。組み込みライブラリをうまく活用し、より効率的なRubyプログラムを作成できるようになりましょう。

数値(Number) 編集

Rubyにおける数値(Number)は、整数(Integer)、浮動小数点数(Float)、有理数(Rational)、複素数(Complex)の4種類があります。それぞれについて説明します。

整数(Integer) 編集

Rubyには整数を扱うためのIntegerクラスがあります。Integerクラスは、以下のような数値リテラルで整数値を表現することができます。

123    #=> 123
0b1111 #=> 15
0o777  #=> 511
0xFF   #=> 255

また、整数の四則演算や比較演算子なども、Integerクラスで定義されています。

1 + 2 #=> 3
3 - 4 #=> -1
5 * 6 #=> 30
7 / 8 #=> 0
9 % 4 #=> 1

1 == 1 #=> true
2 < 3  #=> true
4 > 5  #=> false

浮動小数点数(Float) 編集

Rubyには浮動小数点数を扱うためのFloatクラスがあります。Floatクラスは、以下のような数値リテラルで浮動小数点数を表現することができます。

1.23   #=> 1.23
1.2e3  #=> 1200.0
-4.56  #=> -4.56
4E10   #=> 40000000000.0

また、浮動小数点数の四則演算や比較演算子なども、Floatクラスで定義されています。

1.2 + 3.4 #=> 4.6
5.6 - 7.8 #=> -2.1999999999999997
9.0 * 1.2 #=> 10.8
3.4 / 5.6 #=> 0.6071428571428571

1.2 == 1.2 #=> true
2.3 < 4.5  #=> true
6.7 > 8.9  #=> false

1.0 / 0.0  #==> Infinity
1.0 / -0.0 #==> -Infinity
0.0 / 0.0  #==> NaN
整数と浮動小数点数の混在した式の答えの型 編集

Rubyにおいて、整数と浮動小数点数が混在した式の結果の型は、浮動小数点数になります。 つまり、少数点以下がある数値で割る、などの計算を行った場合、結果は浮動小数点数になります。

5 / 2 #=> 2  整数同士の計算なので、結果は整数の2になります。
5.0 / 2 #=> 2.5  小数点以下がある数値と整数の計算なので、結果は浮動小数点数の2.5になります。

整数同士の計算で割り切れない場合、結果は整数になります。

4 / 3   #=> 1  整数同士の計算なので、結果は整数の1になります。
4.0 / 3 #=> 1.3333333333333333  小数点以下がある数値と整数の計算なので、結果は浮動小数点数の1.3333333333333333になります。

有理数(Rational) 編集

Rubyでは、Rationalクラスを用いて有理数を表現することができます。有理数は、分数の形で表現されます。例えば、以下のように定義することができます。

a = Rational(2, 3)  # 2/3という有理数を定義する
b = Rational(4, 5)  # 4/5という有理数を定義する

また、Rationalクラスでは、有理数の四則演算や比較演算を行うことができます。

a = Rational(2, 3)
b = Rational(4, 5)

c = a + b  # 22/15 (2/3 + 4/5)
d = a - b  # -2/15 (2/3 - 4/5)
e = a * b  # 8/15 (2/3 * 4/5)
f = a / b  # 10/9 (2/3 ÷ 4/5)

g = a == b  # false (2/3 と 4/5 は等しくない)
h = a != b  # true (2/3 と 4/5 は等しくない)
i = a > b  # false (2/3 は 4/5 よりも小さい)
j = a >= b  # false (2/3 は 4/5 よりも小さい)

複素数(Complex) 編集

Rubyでは、複素数を Complex クラスで表現することができます。 Complex クラスは、実数と虚数の2つの要素を持ちます。

複素数を表現するには、以下のように実数部と虚数部をそれぞれ指定します。

c = Complex(3, 4) # 3 + 4i

また、虚数単位 i を用いた表現も可能です。

c = 3 + 4i

複素数の実数部と虚数部は、それぞれ real メソッドと imaginary メソッドを使って取得することができます。

c = Complex(3, 4)
puts c.real      # 3
puts c.imaginary # 4

Complex クラスでは、複素数の演算もサポートされています。例えば、加算や乗算、除算などが可能です。

a = Complex(2, 3)
b = Complex(4, 5)

c = a + b   # 6 + 8i
d = a - b   # -2 - 2i
e = a * b   # -7 + 22i
f = a / b   # 0.5609756097560976 + 0.0487804878048781i

また、複素数同士の比較も可能です。== 演算子を用いることで、2つの複素数が等しいかどうかを比較することができます。

a = Complex(2, 3)
b = Complex(2, 3)

puts a == b  # true

複素数の演算や比較において、実数と複素数の演算や比較も可能です。この場合、実数は複素数の虚数部が0のものとして扱われます。例えば、以下のような計算が可能です。

a = Complex(2, 3)
b = 4

c = a + b   # 6 + 3i
d = a * b   # 8 + 12i
e = a > b   # true

文字列(String) 編集

Rubyでは、文字列(String)はダブルクォート(")で囲まれた文字列リテラルで表します。シングルクォート(')で囲まれた文字列リテラルは、単なる文字列であり、式の展開やエスケープシーケンスの展開が行われません。

name = "Alice"
puts "Hello, #{name}!" #=> "Hello, Alice!"
puts 'Hello, #{name}!' #=> "Hello, \#{name}!"

文字列中の式の展開 編集

Rubyでは、ダブルクォートで囲まれた文字列リテラルの中で式を展開することができます。式を展開する場合は、#{}を使います。式を#{}で囲んで文字列中に埋め込むことができます。

x = 10
puts "xの値は#{x}です" #=> "xの値は10です"
puts "xの二乗は#{x ** 2}です" #=> "xの二乗は100です"

また、式を展開する場合は、式が評価されてから文字列中に埋め込まれます。そのため、式の中で定義された変数などの値も展開されます。

x = 10
puts "xの値は#{x}です" #=> "xの値は10です"
x = 20
puts "xの値は#{x}です" #=> "xの値は20です"

なお、シングルクォートで囲まれた文字列リテラルでは、式の展開は行われず、文字列中にそのまま#{...}が表示されます。

x = 10
puts 'xの値は#{x}です' #=> "xの値は\#{x}です"

エスケープシーケンス 編集

以下がRubyで使用できる主なエスケープシーケンスです。

エスケープシーケンス
エスケープシーケンス 意味
\\ バックスラッシュ
\' シングルクォート
\" ダブルクォート
\a ベル音(BEL)
\b バックスペース
\f 改ページ(FF)
\n 改行
\r キャリッジリターン(CR)
\t 水平タブ
\v 垂直タブ
\e エスケープ文字(ESC)
\s 空白
\nnn 8進数表記の文字コード(nは0〜7の数字)
\xnn 16進数表記の文字コード(nは0〜9またはA〜F)
\unnnn Unicode文字コード(nは0〜9またはA〜F)
\Unnnnnnnn Unicode文字コード(nは0〜9またはA〜F)

なお、Rubyではダブルクォートで囲まれた文字列リテラル内でエスケープシーケンスが展開されますが、シングルクォートで囲まれた文字列リテラル内では展開されません。

文字リテラル 編集

Rubyにおける「文字リテラル」は、?を前置した1文字で表します。

p ?a         #==> "a"
p ?字        #==> "字"
p ?😈       #==> "😈"
p ?😈.class #==> String

Rubyに文字型はなく、文字リテラルは長さ1文字の文字列です。

エンコーディング 編集

Ruby では、文字列のエンコーディングを指定することができます。通常、UTF-8 エンコーディングが使われますが、別のエンコーディングを指定することもできます。

文字列のエンコーディングを指定するには、文字列の前に encoding: を付けて指定します。例えば、UTF-8 エンコーディングの文字列を扱う場合は以下のように書きます。

str = "こんにちは".encoding("UTF-8")

別のエンコーディングを指定する場合は、指定したいエンコーディング名を文字列で渡します。

str = "こんにちは".encoding("Shift_JIS")

上記のコードでは、文字列 "こんにちは" が Shift_JIS エンコーディングの文字列として扱われます。

文字列のエンコーディングを指定することで、文字列の変換時にエラーが発生することを防ぐことができます。

正規表現(Regexp) 編集

Rubyにおける「正規表現クラス」と「正規表現リテラル」は、文字列をパターンとして表現するための機能です。

まず、「正規表現クラス」は Regexp クラスを使用して表現されます。以下のように、Regexp.new メソッドを使用して正規表現を作成することができます。

pattern = Regexp.new("Hello, world!")

また、正規表現オプションを指定する場合は、第2引数にオプションを渡すことができます。

pattern = Regexp.new("hello, world!", Regexp::IGNORECASE)

次に、「正規表現リテラル」はスラッシュ / で囲まれた文字列で表現されます。以下のように、スラッシュで正規表現を作成することができます。

pattern = /Hello, world!/

また、正規表現オプションを指定する場合は、スラッシュの後ろにオプションを付けることができます。

pattern = /hello, world!/i

正規表現クラスと正規表現リテラルはどちらも同じ機能を持っており、どちらを使用しても正規表現を表現することができます。 ただし、リテラル表現の方が簡潔に表現することができ、可読性が高くなります。

Rubyで使用できる正規表現
正規表現 ユースケース
/pattern/ 文字列に一致するパターンを検索します。
/./ 任意の一文字に一致します。
/^pattern/ 文字列の先頭に一致するパターンを検索します。
/pattern$/ 文字列の末尾に一致するパターンを検索します。
/[abc]/ a、b、cのいずれかに一致するものを検索します。
/[^abc]/ a、b、c以外のものに一致するものを検索します。
/pattern*/ 0回以上の繰り返しに一致するパターンを検索します。
/pattern+/ 1回以上の繰り返しに一致するパターンを検索します。
/pattern?/ 0回または1回の繰り返しに一致するパターンを検索します。
/pattern{n}/ n回の繰り返しに一致するパターンを検索します。
/pattern{n,}/ n回以上の繰り返しに一致するパターンを検索します。
/pattern{n,m}/ n回以上、m回以下の繰り返しに一致するパターンを検索します。
/(pattern)/ 一致する部分をグループ化します。
/(?<name>pattern)/ 一致する部分を名前でグループ化します。
/(?#comment)/ 正規表現内のコメントを書くことができます。
/\Apattern/ 文字列の先頭に一致するパターンを検索します。
/pattern\z/ 文字列の末尾に一致するパターンを検索します。
/\bpattern/ 単語の先頭に一致するパターンを検索します。
/pattern\b/ 単語の末尾
/pattern/i 大文字小文字を区別せずに文字列に一致するパターンを検索します。
/pattern/m 複数行の文字列に一致するパターンを検索します。
/pattern/x 正規表現内で空白を無視します。
/pattern/o 正規表現を一度だけコンパイルします。

配列(Array) 編集

Rubyの配列は、複数のオブジェクトを格納するためのデータ構造です。配列を作成するには、[]内に要素をカンマで区切って列挙します。例えば、以下のように記述します。

fruits = ["apple", "banana", "orange"]

この場合、fruitsは配列オブジェクトで、"apple""banana""orange"の3つの要素を格納しています。

%表記を使うと

fruits = %w(apple banana orange)

と書くことも出来ます。

また、配列オブジェクトは、様々なメソッドを持っています。例えば、配列の要素を取り出すための[]メソッドや、配列の長さを取得するためのlengthメソッドなどがあります。以下に、いくつかの配列メソッドの例を示します。

fruits[0]     # "apple"を取得する
fruits[1..2]  # ["banana", "orange"]を取得する
fruits.length # 配列の要素数である3を取得する

このように、配列を使うことで、複数のオブジェクトを効率的に扱うことができます。

配列と繰り返し 編集

Rubyの配列は、繰り返し処理とともにしばしば使われるデータ構造です。配列の要素を1つずつ処理する場合には、以下のような繰り返し処理がよく用いられます。

fruits = ["apple", "banana", "orange"]

fruits.each do |fruit|
  puts fruit
end

このコードでは、eachメソッドを用いて、fruits配列の要素を順番に取り出しています。そして、ブロック引数fruitに格納された各要素をputsメソッドで出力しています。

また、配列の要素をインデックスで処理する場合には、以下のような繰り返し処理がよく用いられます。

fruits = ["apple", "banana", "orange"]

fruits.each_with_index do |fruit, i|
  puts "#{i+1}: #{fruit}"
end

このコードでは、each_with_indexメソッドを用いて、fruits配列の要素とインデックスを順番に取り出しています。そして、ブロック引数fruitに格納された各要素とブロック引数iに格納された各インデックスを使って、putsメソッドで出力しています。

このように、Rubyの配列は繰り返し処理との相性が良く、繰り返し処理をうまく活用することで、配列の要素を効率的に処理することができます。

配列操作メソッド 編集

Rubyには、配列を操作するための便利なメソッドが豊富に用意されています。その中でも、mapfilterreduceは特によく使われるメソッドです。

まず、mapメソッドは、配列の各要素に対して処理を適用し、その結果を新しい配列として返すメソッドです。以下は、mapメソッドを使って、配列の各要素を2倍にして新しい配列を作成する例です。

numbers = [1, 2, 3, 4, 5]

doubled_numbers = numbers.map do |n|
  n * 2
end

puts doubled_numbers #=> [2, 4, 6, 8, 10]

次に、filterメソッドは、配列の各要素に対して条件を適用し、条件に合致する要素だけを集めた新しい配列を返すメソッドです。以下は、filterメソッドを使って、偶数だけを集めた新しい配列を作成する例です。

numbers = [1, 2, 3, 4, 5]

even_numbers = numbers.filter do |n|
  n.even?
end

puts even_numbers #=> [2, 4]

最後に、reduceメソッドは、配列の各要素を順番に処理し、最終的な結果を返すメソッドです。以下は、reduceメソッドを使って、配列の各要素を足し合わせた結果を求める例です。

numbers = [1, 2, 3, 4, 5]

sum = numbers.reduce do |result, n|
  result + n
end

puts sum #=> 15

これらのメソッドをうまく活用することで、繰り返し処理を簡潔に記述することができます。また、これらのメソッドは関数型プログラミングの考え方に基づいているため、可読性や保守性が高くなります。

メソッドチェイン 編集

Rubyには、複数のメソッドを連鎖して呼び出す「メソッドチェイン」という機能があります。メソッドチェインを使うことで、1つのオブジェクトに対して複数のメソッドを簡潔につなげて処理することができます。

例えば、以下のような配列があるとします。

fruits = ["apple", "banana", "orange"]

この配列に対して、mapメソッドで各要素を大文字にし、さらにjoinメソッドでカンマ区切りの文字列に変換する場合、通常の記法では以下のように書くことができます。

fruits = ["apple", "banana", "orange"]

upcase_fruits = fruits.map do |fruit|
  fruit.upcase
end

result = upcase_fruits.join(",")
puts result #=> "APPLE,BANANA,ORANGE"

しかし、メソッドチェインを使うと以下のように簡潔に書くことができます。

fruits = ["apple", "banana", "orange"]

result = fruits.map {|fruit| fruit.upcase}.join(",")
puts result #=> "APPLE,BANANA,ORANGE"

このように、複数のメソッドを簡潔につなげて処理することができます。ただし、メソッドチェインは読みやすさを損なうことがあるため、適切に使うようにしましょう。また、チェイン中にエラーが発生した場合、どこでエラーが起きたのかを特定するのが難しくなるため、注意が必要です。

ハッシュ(Hash) 編集

Rubyの「ハッシュ(Hash)」は、キー(key)と値(value)のペアを保持するデータ構造であり、連想配列やマップとも呼ばれます。

ハッシュは波括弧({})で囲まれたキーと値のペアのリストで表され、キーと値の間には=>を使って対応付けます。例えば、以下のように定義することができます。

my_hash = { "key1" => "value1", "key2" => "value2" }

この場合、my_hashは、"key1"というキーに対応する"value1""key2"というキーに対応する"value2"という値を持ちます。

ハッシュは、キーを使って値を取得することができます。例えば、上記のmy_hashから値を取得するには、以下のように書きます。

my_hash["key1"]  # => "value1"

また、Hashクラスのeachメソッドを使うことで、ハッシュ内の全てのキーと値に対して繰り返し処理を行うことができます。以下は、my_hashの全てのキーと値を出力する例です。

my_hash.each do |key, value|
  puts "#{key}: #{value}"
end

出力結果は以下のようになります。

key1: value1
key2: value2

このように、ハッシュはRubyで非常に重要なデータ構造の一つであり、プログラムで様々な用途に利用されます。

シンボルをキーとした特別なハッシュリテラル 編集

例えば、以下のようなハッシュを考えます。

my_hash = { :key1 => "value1", :key2 => "value2" }

このハッシュでは、キーとしてシンボルを使っています。ただし、この記法は少し冗長であり、Rubyでは以下のように短縮して書くことができます。

my_hash = { key1: "value1", key2: "value2" }

このように、キーをシンボルで表す場合は、コロン(:)をキー名の前に付けることで簡潔に表現できます。これにより、より見やすく、読みやすいコードを書くことができます。

また、シンボルを使うことで、文字列を使う場合に比べて、ハッシュの検索速度が速くなることがあります。これは、シンボルはRuby内部で一度だけ生成され、それ以降は同じオブジェクトを使い回すため、検索時にオブジェクトの比較を高速に行えるためです。

なお、シンボルは、文字列と異なりイミュータブルなオブジェクトであり、文字列と同様に、to_symメソッドを使って文字列からシンボルを生成することもできます。

シンボル(Symbol) 編集

Rubyの「シンボル(Symbol)」は、一度定義されたら変更できないイミュータブルなオブジェクトで、文字列に似たデータ型です。シンボルは、コロン(:)の後ろに名前を付けて表します。例えば、:apple:bananaなどがシンボルの例です。

シンボルは、主にキーとして使われることが多く、文字列と比較して以下のようなメリットがあります。

  • シンボルは一度生成されたら変更できないため、ハッシュのキーとして使うときに、キーの値が変更される心配がありません。
  • 同じ名前のシンボルは必ず同じオブジェクトIDを持つため、検索が高速になります。
  • 文字列よりもメモリ消費量が少ないため、大量のデータを扱う場合や、ハッシュのキーとして多用する場合に有効です。

シンボルを使う場合、通常はコロン(:)をつけて定義しますが、:"apple"のようにダブルクォーテーション(")で囲って文字列として生成することもできます。また、文字列からシンボルを生成するには、to_symメソッドまたはinternメソッドを使います。

例えば、以下のようにハッシュのキーとしてシンボルを使うことができます。

fruits = { :apple => 100, :banana => 200, :orange => 300 }
puts fruits[:banana]  # => 200

また、以下のように、コロン(:)を使ってシンボルを直接定義することもできます。

status = :success
puts status  # => success

範囲(Range) 編集

Rubyの「範囲(Range)」は、ある値から別の値までの連続する要素を表すオブジェクトです。Rubyでは、範囲は..または...の範囲演算子を使って作成することができます。以下に例を示します。

range1 = 1..5    # 1から5までの範囲を表すRangeオブジェクトを作成
range2 = 1...5   # 1から5未満までの範囲を表すRangeオブジェクトを作成

..を使うと、範囲に終端の値が含まれますが、...を使うと、範囲に終端の値は含まれません。

範囲は主に繰り返し処理に使われ、以下のように使うことができます。

range = 1..5
range.each { |i| puts i }  # 1から5までの値を1つずつ表示する

このコードでは、eachメソッドを使って、範囲内の値を1つずつ取り出し、ブロック内で処理しています。

また、範囲を使うことで、配列の一部を切り出すこともできます。例えば、以下のように範囲を使って、配列から一部の要素を取り出すことができます。

array = [1, 2, 3, 4, 5]
sub_array = array[1..3]  # 2番目から4番目までの要素を取り出す
puts sub_array  # => [2, 3, 4]

このように、範囲はRubyで様々な場面で使われ、プログラミングをより効率的に行うための重要な要素の1つです。

ファイル (File) 編集

Rubyにはファイル操作を行う標準ライブラリ File があります。これを使用することで、ファイルの読み込み・書き込み、存在確認・削除、ディレクトリの作成・削除などが簡単に行えます。

以下は、ファイル操作の基本的な使い方の例です。

# ファイルの読み込み
File.open('sample.txt', 'r') do |file|
  puts file.read
end

# ファイルの書き込み
File.open('output.txt', 'w') do |file|
  file.write('Hello, world!')
end

# ファイルの存在確認
puts File.exist?('sample.txt') #=> true

# ファイルの削除
File.delete('output.txt')

# ディレクトリの作成
Dir.mkdir('mydir')

# ディレクトリの削除
Dir.delete('mydir')

数学(Math) 編集

RubyのMathモジュールは、数学関数を提供するライブラリです。このモジュールに含まれる関数を使用することで、三角関数、指数関数、対数関数などの計算を簡単に行うことができます。

例えば、sin関数を使用する場合は、以下のように記述します。

Math.sin(30 * Math::PI / 180)  #=> 0.5

この例では、30度の正弦(sin)を計算しています。Math::PIは円周率を表しており、角度をラジアンに変換しています。

他にも、cos関数、tan関数、exp関数、log関数などがあります。詳細は公式ドキュメントを参照してください。

Rubyの標準ライブラリとMix-in 編集

Rubyの標準ライブラリには、多数のクラスやモジュールが含まれています。これらのクラスやモジュールは、Rubyプログラムで頻繁に使用される共通機能を提供しています。例えば、文字列(String)クラス、配列(Array)クラス、ファイル操作(File)クラスなどがあります。

また、RubyではMix-inという概念もあります。Mix-inとは、あるクラスに他のモジュールを取り込んで機能を追加することです。これにより、クラスを継承することなく、複数のモジュールから機能を組み合わせて利用することができます。

例えば、Enumerableモジュールは、Rubyの多くのクラスにEnumerableという機能を提供するためのモジュールです。Enumerableモジュールには、eachメソッドやmapメソッド、selectメソッドなどが含まれており、これらのメソッドを利用することで、配列やハッシュなどのオブジェクトに対して繰り返し処理を簡単に行うことができます。

以下に、標準ライブラリからいくつかの代表的なクラスやMix-inを挙げます。

  • Stringクラス:文字列を扱うためのクラス
  • Arrayクラス:配列を扱うためのクラス
  • Hashクラス:ハッシュを扱うためのクラス
  • Fileクラス:ファイルを扱うためのクラス
  • Enumerableモジュール:繰り返し処理を行うためのモジュール
  • Comparableモジュール:比較演算を行うためのモジュール
  • Kernelモジュール:基本的なメソッドを提供するためのモジュール

これらのクラスやMix-inは、Rubyプログラムの中で頻繁に使用されるため、覚えておくと便利です。詳細は公式ドキュメントを参照してください。

列挙(Enumerator) 編集

RubyのEnumeratorクラスは、反復処理を行うためのクラスです。配列やハッシュなどのオブジェクトに対して繰り返し処理を行うことができます。

例えば、以下のようなコードを考えてみましょう。

array = [1, 2, 3, 4, 5]
array.each do |num|
  puts num
end

この場合、eachメソッドを使用して、配列の要素を順番に取り出していることがわかります。しかし、この方法では要素の途中で処理を中断したり、要素を複数回利用することができません。

ここでEnumeratorクラスを使用すると、以下のように書くことができます。

array = [1, 2, 3, 4, 5]
enum = array.to_enum
loop do
  num = enum.next
  puts num
end

この場合、to_enumメソッドを使用して、Enumeratorオブジェクトを生成しています。そして、nextメソッドを使用して、順番に要素を取り出しています。この方法を使用することで、要素の途中で処理を中断することができますし、要素を複数回利用することもできます。

Enumeratorを使ったジェネレータ 編集

def primegen
  n = 2
  sieve = {}

  Enumerator.new do |y|
    loop do
      if sieve[n].nil? || sieve[n] == 0
        y << n
        sieve[n * n] = n
      else
        factor = sieve[n]
        sieve[n + factor] = factor
        sieve[n] = 0
      end
      n += 1
    end
  end.lazy
end

p primegen.first(10)
[2, 3, 5, 7, 11, 13, 15, 17, 19, 21]

%記法 編集

Rubyの%記法は、文字列や正規表現、配列、シンボルなどを作成するための簡潔な書き方のことを指します。%記法を使うことで、コードの可読性を高めることができます。

以下に、Rubyの%記法の使い方を表にまとめました。

%記法
記号 役割
%q シングルクォートで囲んだ文字列を作成する %q(Hello, world!) => "Hello, world!"
%Q ダブルクォートで囲んだ文字列を作成する %Q(Hello, #{name}!) => "Hello, Alice!"
%r 正規表現リテラルを作成する %r(\d+-\d+-\d+) => /\\d+-\\d+-\\d+/
%w 単語の配列を作成する %w(apple banana orange) => ["apple", "banana", "orange"]
%W ダブルクォートで展開される単語の配列を作成する %W(#{fruit1} #{fruit2} #{fruit3}) => ["apple", "banana", "orange"]
%s シンボルを作成する %s(hello) => :hello
%i シンボルの配列を作成する %i(apple banana orange) => [:apple, :banana, :orange]

上の例ではパッターンを丸括弧()で囲みましたが、波括弧{}・角括弧[]で囲むことも出来、括弧でない文字(例えば!)で始めたら、同じ文字(この場合は!)で閉じることが出来ます。

# {} を使う例
puts %q{Hello, #{name}!}  # => Hello, Ruby!

# [] を使う例
puts %w[apple banana orange]  # => ["apple", "banana", "orange"]
puts %i[foo bar baz]  # => [:foo, :bar, :baz]

# ! を使う例
puts %Q!It's raining outside!  # => It's raining outside
puts %w!apple banana orange!  # => ["apple", "banana", "orange"]

# | を使う例
puts %Q|Hello, #{name}!|  # => Hello, Ruby!
puts %i|foo bar baz|  # => [:foo, :bar, :baz]

これらの例では、%記法の丸括弧 ()の部分を、波括弧 {}、角括弧 []、感嘆符 !、縦棒 | に置き換えています。%記法では、括弧以外にも様々な文字を使うことができますが、適切な文字を選んで使用することが重要です。

RDoc 編集

RDocとは、Rubyドキュメンテーションの生成ツールであり、Rubyのプログラムに対する文書化を支援するためのツールです。RDocを使用すると、Rubyのプログラムに関する情報をドキュメントとして出力することができます。これにより、ユーザーは作成されたコードを理解するための情報が提供され、開発者は自分たちのコードを文書化することができます。RDocは、Rubyの標準ライブラリに含まれています。

構文 編集

RDocは、Rubyのための文書作成システムで、コード内で注釈コメントを書くことで、自動的にドキュメントを生成します。以下はRDocの構文についての解説です。

RDocの注釈コメントは、通常のRubyコメントとして記述されますが、一つ上に「#」の代わりに「=begin」と「=end」を使ってマークアップを開始し、終了します。

以下は、RDocのマークアップの例です。

=begin
This class does some cool things.

== Example

An example of how to use this class:

  MyClass.new.do_cool_thing

== Copyright

Copyright (c) 2022 John Doe. All rights reserved.
=end

RDocは、以下の形式のマークアップタグをサポートしています。

  • #: コメント
  • =begin/=end: ドキュメントの開始/終了
  • ==: セクションの開始
  • *: 箇条書きの開始
  • +: リストの開始
  • -: リストの終了
  • !>: コードブロックの開始
  • <pre>/</pre>: コードブロックの開始/終了
  • +methodName+(args)+: メソッドの定義
  • (arg), (arg=default): 引数の指定
  • returns (type): 戻り値の指定
  • \: ラインコンティニュー

RDocの実行 編集

RDocの実行には、次のコマンドを使用します。

$ rdoc [options] [names...]

オプションには、ドキュメンテーションを生成するFormattersや、ドキュメント化するファイルの指定などが含まれます。namesには、ドキュメンテーションを生成するファイルまたはディレクトリを指定します。

以上が、RDocの構文解説です。

附録 編集

コードギャラリー 編集

エラトステネスの篩 編集

エラトステネスの篩を、若干 Ruby らしく書いてみました。

エラトステネスの篩
def eratosthenes(n)
  is_prime = [true] * (n + 1)
  is_prime[0] = false
  is_prime[1] = false

  (2..Math.sqrt(n)).each do |i|
    if is_prime[i]
      (i*i..n).step(i) do |j|
        is_prime[j] = false
      end
    end
  end

  primes = (2..n).select { |i| is_prime[i] }
  return primes
end

p eratosthenes(100)
実行結果
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

最大公約数と最小公倍数 編集

最大公約数と最小公倍数を、若干 Ruby らしく書いてみました。

最大公約数と最小公倍数
def gcd2(m, n) n == 0 ? m : gcd2(n, m % n) end
def gcd(*ints) ints.reduce(&method(:gcd2)) end
def lcm2(m, n) m * n / gcd2(m, n) end
def lcm(*ints) ints.reduce(&method(:lcm2)) end

puts "gcd2(30, 45) => #{gcd2(30, 45)}"
puts "gcd(30, 72, 12) => #{gcd(30, 72, 12)}"
puts "lcm2(30, 72) => #{lcm2(30, 72)}"
puts "lcm(30, 42, 72) => #{lcm(30, 42, 72)}"
実行結果
gcd2(30, 45) => 15
gcd(30, 72, 12) => 6
lcm2(30, 72) => 360
lcm(30, 42, 72) => 2520

二分法 編集

二分法を、若干 Ruby らしく書いてみました。

二分法
def bisection(low, high, &f)
  x = (low + high) / 2.0
  fx = f.call(x)
  return x  if (fx.abs < 1.0e-10)
  if (fx < 0.0) then low = x else high = x end
  return bisection(low, high, &f)
end

puts bisection(0, 3) { |x| x - 1 }
puts bisection(0, 3) { |x| x * x - 1 }
実行結果
0.9999999999417923
1.0000000000291038
旧課程(-2012年度)高等学校数学B/数値計算とコンピューター#2分法の例を Ruby に移植しました。

関連項目 編集

脚註 編集

  1. ^ インタープリターとは、あなたが書いたスクリプトを読んでそれを実行してくれるソフトウェアです。 [
  2. ^ インタープリターを ruby、スクリプティング言語を Ruby とかき分けます。
  3. ^ Ruby Maintenance Branches