本書は、Rubyのチュートリアルです。
Rubyは、比較的習得が容易なオブジェクト指向スクリプティング言語です。
まつもとゆきひろによって開発されました。
Ruby on Railsの記述言語として選ばれたことで有名になりましたが、ウェブアプリケーション以外にもシステム管理やネットワークアプリケーションなどさまざまな用途に用いられます。
__TOC__
Rubyには、強力で多用途な言語とするための多くの特徴があります。その特徴とは以下の通りです：
オブジェクト指向のプログラミング
Rubyは完全なオブジェクト指向言語であり、Rubyのすべてがオブジェクトであることを意味します。このため、複雑なプログラムを簡単に作成することができ、メンテナンスも容易です。
動的な型付け
Rubyは動的型付け言語であり、コンパイル時に変数の型がチェックされることはありません。このため、プログラムを再コンパイルすることなく、変数の型を簡単に変更することができます。
インタプリタ型言語
Rubyはインタープリタ型言語であり、機械語にコンパイルされるのではなく、コードが1行ずつ実行されます。そのため、Rubyのプログラムの開発やデバッグが容易に行えます。
簡潔な構文
Rubyには簡潔な構文があり、コードを書くのが簡単です。そのため、初心者から経験豊富なプログラマーまで、幅広く利用することができます。
大規模なコミュニティ
Rubyには、言語やライブラリに貢献する開発者たちの大規模で活発なコミュニティがあります。そのため、Rubyプログラミングのヘルプやサポートを簡単に見つけることができます。
Rubyは強力で汎用性の高い言語であり、さまざまなタスクに適しています。Rubyの学習と使用は簡単で、開発者の大規模で活発なコミュニティがあります。強力で汎用性が高く、習得が容易な言語をお探しなら、Rubyは良い選択です。
Rubyを利用するためには、公式ウェブサイトからインストーラーをダウンロードしてインストールします。
以下は、主要なプラットフォームへのインストール手順の概要です：
Windows:
RubyInstaller（ https://rubyinstaller.org/ ） のページからインストーラーをダウンロードします。
ダウンロードしたインストーラーを実行し、指示に従ってインストールを進めます。
macOS:
macOSにはデフォルトでRubyがインストールされていますが、最新バージョンを利用する場合はRVM(Ruby Version Manager https://rvm.io/ ) や [https://github.com/rbenv/rbenv rbenv]を使用することをお勧めします。
Linux:
sudo apt-get update
sudo apt-get install ruby
RubyでのHello Worldプログラムは非常に簡単です。以下は、コンソールに"Hello, World!"と出力するプログラムです：
hello.rb:
puts "Hello, World!"
これをhello.rbという名前で保存し、ターミナルでruby hello.rbと実行すると、"Hello, World!"が表示されます。
$ ruby  hello.rb
Hello, World!
$ 
Rubyでは、様々なデータ型が利用できます。文字列、数値、配列、ハッシュなどがその代表的なものです。動的型付け言語であるRubyでは、変数の型宣言が不要です。以下に、主要なデータ型と変数の宣言と代入について詳細を示します。
数値 (Numeric)
数値には、整数 (Integer) や浮動小数点数 (Float) が含まれます。整数は例えば42のように表され、浮動小数点数は例えば3.14のように表されます。
文字列 (String)
文字列は、ダブルクォーテーション (") またはシングルクォーテーション (') で囲まれた文字の並びです。例えば、"Hello"や'Ruby'などが文字列です。
配列 (Array)
配列は、複数の要素を順序付けして格納するデータ構造です。要素は角かっこ [ ] で囲まれ、コンマで区切ります。例えば、[1, 2, 3]や['a', 'b', 'c']などが配列です。
ハッシュ (Hash)
ハッシュは、キーと値のペアを格納するデータ構造です。波かっこ { } で囲まれ、キーと値はコロン : で区切ります。例えば、{'name' => 'Alice', 'age' => 30}などがハッシュです。
変数は代入演算子 = を使用して宣言および初期化されます。変数名はアルファベットまたはアンダースコア _ で始まり、その後にはアルファベット、数字、アンダースコアを組み合わせることができます。型宣言は不要であり、変数は動的に型が決まります。
以下は、変数の宣言と代入の例です。
name = "Alice"   # 文字列型の変数
age = 30         # 整数型の変数
scores = [85, 90, 75, 100]  # 配列型の変数
person = {'name' => 'Bob', 'age' => 25}  # ハッシュ型の変数
これらの例では、それぞれの変数に適切なデータ型の値が代入されています。
Rubyには様々な制御構造が用意されており、以下のようなものがあります。
条件分岐
ループ
例外処理
その他
Rubyの制御構造はPerlやBashなどとよく似ていますが、独自の構文も存在します。
また、Rubyはブロックの概念があり、それを活用した制御構造があるのが特徴です。
制御構造の一例:
name = 'Alice'
if name == 'Alice'
  puts 'こんにちは、Aliceさん'
elsif name == 'Bob'
  puts 'こんにちは、Bobさん'
else
  puts "あなたの名前は#{name}ですね"
end
puts if name == 'Alice'
       'こんにちは、Aliceさん'
     elsif name == 'Bob'
       'こんにちは、Bobさん'
     else
       "あなたの名前は#{name}ですね"
     end
file_exists = false
puts 'ファイルが存在しません' unless file_exists
age = 25
case age
when 0...18
  puts '未成年者です'
when 18...65
  puts '働き盛りの年齢ですね'
else
  puts 'シニア世代かもしれません'
end
puts case [2, 3, 5]
     in 0, 1, 2
       '最初の整数'
     in 0, 2, 4
       '最初の偶数'
     in 1, 3, 5
       '最初の奇数'
     in 2, 3, 5 => n
       "最初の素数、三番目は#{n}"
     else
       'どの数列でもない'
     end
i = 0
while i < 5
  puts "i = #{i}"
  i += 1
end
j = 0
until j > 5
  puts "j = #{j}"
  j += 1
end
array = [10, 20, 30, 40]
for item in array
  puts "要素は#{item}"
end
count = 1
loop do
  puts "回数は#{count}"
  count += 1
  break if count > 5
end
numbers = [1, 2, 3, 4, 5]
numbers.each do |n|
  next if n.even?
  puts "奇数は#{n}"
  break if n == 5
end
begin
  result = 10 / 0
rescue ZeroDivisionError => e
  puts "0で割ろうとしました: #{e.message}"
else
  puts "結果は#{result}"
ensure
  puts '計算処理が完了しました'
end
[2, 3, 5, 7, 11].each { |i| puts i }
5.times { puts 'Hello' }
1.upto(5) { |i| puts "uptoの値は#{i}" }
5.downto(1) { |i| puts "downtoの値は#{i}" }
string = 'Hello'
result = string.tap { |s| puts "tap内: #{s}" }
puts "tapの結果: #{result}"
def greet
  yield('Morning')
  yield('Evening')
end
greet { |time| puts "Good #{time}!" }
Rubyには条件実行を簡潔に記述するためのいくつかのイディオムがあります。
条件式 ? 真の場合の値 : 偽の場合の値
三項演算子を使うと、if...elseを1行で記述できます。
allowed = user.admin? ? "Full access" : "Read only"
値が nil または false の場合のみ右辺の値が代入されます。
name = params[:name] || "Guest"
値が真の場合のみ右辺の値が評価され、代入されます。
obj &&= obj.method
レシーバがnilの場合にメソッドが呼ばれず、nilを返します。
name = params.dig(:user, :name)&.strip
これらのイディオムを適切に使うことで、条件実行を簡潔で読みやすく記述できます。
Rubyには反復実行を簡潔に記述するためのいくつかのイディオムがあります。
[1, 2, 3].each do |n|
  puts n
end
(1..5).map { |n| n**2 } # => [1, 4, 9, 16, 25]
[1, 2, 3].select(&:even?) # => [2]
5.times { puts "Ruby!" } # "Ruby!"が5回出力される
loop do
  cmd = gets.chomp
  break if cmd == "exit"
  # 処理
end
[1, 2, 3].each { |n| puts n }
for n in [1, 2, 3] do
  puts n
end
each はループ変数がメソッドに閉じている。
などの理由で好まれます。
ary = [1, 2, 3]
i = 0
while i < ary.length
  puts ary[i]
  i += 1
end
["a", "b", "c"].each_with_index { |item, index| puts "#{index}: #{item}"}
["a", "b", "c"].with_index { |item, index| puts "#{index}: #{item}"}
Rubyの反復構文はループだけでなく、ブロックやイテレータによる関数型のスタイルの記述も可能です。状況に応じて適切な方法を選ぶことで、簡潔でわかりやすいコードを書くことができます。
条件分岐は、プログラムの中で特定の条件が満たされた場合に異なる処理を実行するための制御構造です。
Rubyには、if-elsif-else-end 構文、case-when-else-end 構文があります。
if、elsif、elseキーワードを使用して条件分岐を記述します。以下はその基本的な構文です：
if 条件式
  # 条件が真の場合の処理
elsif 別の条件式
  # 条件が真の場合の処理
else
  # どの条件も満たされない場合の処理
end
例えば、次のように使用します：
age = 20
if age >= 20
  puts "You are an adult."
else
  puts "You are not an adult yet."
end
この場合、ageが20以上の場合は"You are an adult."が出力され、それ以外の場合は"You are not an adult yet."が出力されます。
Rubyのcase-when-else-end文は、条件に応じて異なる処理を行うための制御構造です。
以下に、基本的な構文と使い方を解説します。
 
case 式
when 条件１
  # 式が条件１に合致したときに実行されるコード
when 条件２, 条件３
  # 式が条件２または条件３に合致したときに実行されるコード
else
  # どの条件にも合致しない場合に実行されるコード
end
caseの後に評価したい式を置きます。その式の評価結果と、when節の各条件を比較し、合致する場合に対応するブロックが実行されます。else節は、どの条件にも合致しない場合のデフォルトの処理を提供します。
例えば、以下はcase-when-else-end文の使用例です。
 
grade = 'B'
puts case grade
     when 'A' then 'Excellent!'
     when 'B' then 'Good job!'
     when 'C' then 'You passed, but you could do better.'
     else 'Sorry, you failed.'
     end
     #=> Good job!
この例では、変数gradeの値に応じて異なるメッセージが出力されます。gradeが'A'の場合は"Excellent!"が出力され、'B'の場合は"Good job!"が出力されます。gradeが'C'の場合は"You passed, but you could do better."が出力され、どの条件にも一致しない場合は"Sorry, you failed."が出力されます。
case-when-else-end文は、複数の条件をテストする必要がある場合や、条件に基づいてさまざまな処理を行う必要がある場合に便利です。
パターンマッチングは、プログラムの中で特定のパターンに処理を実行するための制御構造です。
Rubyには、case-in-else-end 構文と=>演算子とin演算子があります。
Rubyのパターンマッチング（Pattern Matching）は、構造化された値の深いマッチングを可能にする機能です。これにより、構造をチェックし、一致した部分をローカル変数にバインドすることができます。
Rubyのパターンマッチングは、case/in式を使用して実装されています。
以下に、その基本的な構文と使い方を示します。
 
case 式
in パターン１
  # 式がパターン１に合致したときに実行されるコード
in パターン２
  # 式がパターン２に合致したときに実行されるコード
else
  # どのパターンにも合致しない場合に実行されるコード
end
case式の中のinブロックは、パターンと一致するかどうかをチェックし、マッチした場合に対応するコードを実行します。else節は、どのパターンにも一致しない場合のデフォルトの処理を提供します。
以下は、パターンマッチングの使用例です。
 
puts case [2, 3, 5]
     in 0, 1, 2
       '最初の整数'
     in 0, 2, 4
       '最初の偶数'
     in 1, 3, 5
       '最初の奇数'
     in 2, 3, 5 => n
       "最初の素数、三番目は#{n}"
     else
       'どの数列でもない'
     end
このコードは、パターンマッチングを利用して、与えられた配列の最初の要素に応じて異なる処理を行います。与えられた配列 [2, 3, 5] の最初の要素が特定のパターンに一致するかどうかをテストし、一致する場合に対応するメッセージを出力します。
具体的には、与えられた配列 [2, 3, 5] の最初の要素が各条件に一致するかどうかをテストします。
[2, 3, 5] は 0, 1, 2 に一致せず、次の条件へ進みます。
[2, 3, 5] は 0, 2, 4 に一致せず、次の条件へ進みます。
[2, 3, 5] は 1, 3, 5 に一致せず、次の条件へ進みます。
[2, 3, 5] は 2, 3, 5 => n に一致し、n に 7 が割り当てられます。
最終的に "最初の素数、三番目は7" というメッセージが出力されます。
else 節は、どの条件にも一致しない場合に実行されますが、この場合、どの数列でもないことを示すメッセージが出力されることになります。
=>演算子とin演算子 は、パターンマッチングを簡潔に行う方法の1つです。通常、パターンマッチングは複数の行にわたるケース式や条件分岐を使用しますが、=>演算子とin演算子 は1行の式でパターンをマッチングする手法です。
具体的には、次のような形式で表現されます:
式 => パターン
あるいは
式 in パターン
 
この形式では、式 の値が パターン にマッチするかどうかを評価します。
=>演算子とin演算子 でパターンマッチングに失敗すると、NoMatchingPatternKeyError例外が raise されます。
{a: 1, b: 2, c: 3} => { b: n }
puts n # 2
{a: 1, b: 2, c: 3} => { x: n }
パターンマッチングにはさまざまなパターンがあります：
これらのパターンを組み合わせて、複雑なデータ構造をマッチングできます。また、パターンマッチングではマッチした部分をローカル変数にバインドすることもできます。
Rubyにおける反復（ループ）は、いくつかの方法で行うことができます。主な方法は以下の通りです。
配列やハッシュなどのコレクションに対して使われる最も一般的な反復方法です。以下はその例です。
array = [1, 2, 3, 4, 5]
array.each do |item|
  puts item
end
for文も使用できますが、Rubyではあまり一般的ではありません。
for i in 1..5
  puts i
end
while文を使って条件が満たされている間、ブロック内のコードを実行します。
x = 0
while x < 5 do
  puts x
  x += 1
end
until文は条件が満たされるまでループします。
x = 0
until x == 5 do
  puts x
  x += 1
end
固定回数のループを行う場合に便利です。
5.times do |i|
  puts i
end
これらの方法を組み合わせて、さまざまな反復のニーズに対応できます。
ただし、Rubyではeachメソッドが最も一般的で、他の方法よりも好まれることが多いです。
メソッドは、Rubyプログラムで特定の処理を実行するための手段を提供します。メソッドは、関数や手続きと同様の機能を持ち、再利用可能なコードブロックを定義します。Rubyでは、メソッドはオブジェクト指向プログラミングの基本的な概念であり、ほとんどの処理がメソッドとして定義されます。
メソッドは以下のような形式で定義されます：
def メソッド名(引数1, 引数2, ...)
  # メソッドの処理
end
ここで、defキーワードを使ってメソッドを定義し、メソッド名を指定します。メソッドが引数を取る場合は、引数のリストを指定します。メソッドの本体は、endキーワードで終了します。
以下は、簡単なメソッドの例です：
def greet(name)
  puts "Hello, #{name}!"
end
greet("Alice")
この例では、greetという名前のメソッドが定義されています。このメソッドはnameという引数を取り、それを使用して挨拶を表示します。greet("Alice")という呼び出しでは、"Hello, Alice!"というメッセージが表示されます。
endキーワードを伴わず、代入に似た形式でも定義できます：
def メソッド名(引数1, 引数2, ...) = 式
ここで、defキーワードと=を使ってメソッドを定義し、メソッド名を指定します。メソッドが引数を取る場合は、引数のリストを指定します。
以下は、簡単なメソッドの例です：
def greet(name) = puts "Hello, #{name}!"
greet("Alice")
また、Rubyではメソッド内で最後に評価された式が自動的にメソッドの戻り値となります。明示的なreturn文は省略することができますが、必要に応じて使用することもできます。
さらに、メソッドはオプションのブロックを受け取ることができます。ブロックを受け取るメソッドは、yieldキーワードを使ってブロックを実行します。
def greet(name)
  puts "Hello, #{name}!"
  yield if block_given?
end
このメソッドでは、引数として受け取ったnameに対して挨拶を出力し、その後にyieldを使ってブロックを実行しています。block_given?メソッドは、メソッドがブロックを受け取ったかどうかを判定します。
メソッドを呼び出す際には、通常の引数と一緒にブロックを渡すことができます。
 
greet("Alice") do
  puts "Nice to meet you!"
end
このコードは、以下を出力します。
 
Hello, Alice!
Nice to meet you!
配列は複数の要素を格納するためのデータ構造であり、それぞれの要素は順序付けされています。Rubyでは、配列は角かっこ [ ] で囲まれ、コンマで区切られた要素のリストとして表現されます。
fruits = ['apple', 'banana', 'orange']
fruits << 'grape'
fruits.push('kiwi')
fruits.delete_at(0)  # インデックス0の要素を削除
fruits.pop  # 末尾の要素を削除
puts fruits[0]  # => "banana"
ハッシュは、キーと値のペアを格納するデータ構造であり、各要素はキーを使用して参照されます。Rubyでは、波かっこ { } を使用してハッシュを定義します。
person = {'name' => 'Alice', 'age' => 30}
person['gender'] = 'female'
person.delete('age')
puts person['name']  # => "Alice"
クラスは、オブジェクトの設計図として機能し、それぞれのオブジェクトはそのクラスのインスタンスです。Rubyでは、classキーワードを使用してクラスを定義します。
class Person
  def initialize(name, age)
    @name = name
    @age = age
  end
  def introduce
    puts "My name is #{@name} and I'm #{@age} years old."
  end
end
この例では、Personという名前のクラスが定義されています。initializeメソッドは、新しいインスタンスが作成されるときに呼び出され、インスタンス変数 @name と @age に値を設定します。introduceメソッドは、そのインスタンスの情報を出力します。
alice = Person.new("Alice", 30)
bob = Person.new("Bob", 25)
これにより、Personクラスの新しいインスタンス alice と bob が作成されます。それぞれのインスタンスは、initializeメソッドによって設定された名前と年齢を持ちます。
alice.introduce  # => "My name is Alice and I'm 30 years old."
bob.introduce    # => "My name is Bob and I'm 25 years old."
各インスタンスは、クラス内で定義されたメソッドを呼び出すことができます。
オブジェクト指向プログラミング（OOP）は、プログラムをオブジェクトとそれらの相互作用に基づいて構造化する方法です。OOPには、次のような重要な概念があります：
カプセル化: データとそれに関連するメソッドを1つのユニットにまとめ、外部からのアクセスを制限します。
継承: 既存のクラスから新しいクラスを作成し、既存の機能を再利用します。
ポリモーフィズム: 同じ名前のメソッドが異なるクラスで異なる振る舞いをすることを許容します。
これらの概念を使用することで、コードをより柔軟で保守しやすくすることができます。
例外処理は、予期しないエラーが発生した場合にプログラムの実行を中断せずに制御を継続するための仕組みです。Rubyでは、begin、rescue、endキーワードを使用して例外処理を実装します。
begin
  # 例外が発生する可能性のあるコード
  result = 10 / 0
rescue ZeroDivisionError => e
  # 例外が発生した場合の処理
  puts "Error occurred: #{e.message}"
end
上記の例では、beginブロック内でゼロ除算エラーが発生する可能性があります。rescueブロックでは、特定の例外（ここではZeroDivisionError）が発生した場合の処理を指定します。例外が発生した場合、その例外オブジェクトがrescueブロックの変数eに割り当てられ、messageメソッドを使ってエラーメッセージを取得します。
ファイルの読み書きは、プログラムでよく行われる操作の1つです。Rubyでは、Fileクラスを使用してファイルの読み書きを行います。
File.open("example.txt", "w") do |file|
  file.write("Hello, World!")
end
File.open("example.txt", "r") do |file|
  content = file.read
  puts content  # => "Hello, World!"
end
ファイルポインタを移動して、ファイル内の特定の位置から読み書きを行うこともできます。
File.open("example.txt", "r") do |file|
  # ファイルポインタの移動
  file.seek(7)
  # 指定位置からの読み込み
  content = file.read
  puts content  # => "World!"
}
モジュールは、関連するメソッドや定数をまとめるための仕組みであり、クラスにインクルードすることでその機能を利用することができます。
module Greeting
  def say_hello
    puts "Hello!"
  end
end
class MyClass
  include Greeting
end
obj = MyClass.new
obj.say_hello  # => "Hello!"
上記の例では、Greetingモジュールを定義し、MyClassクラスにインクルードしています。その結果、MyClassのインスタンスであるobjからsay_helloメソッドが利用できるようになります。
Mix-inは、複数のクラスに同じメソッドや振る舞いを提供するためのデザインパターンです。モジュールを使ってMix-inを実現することができます。
module Debug
  def debug_info
    puts "#{self.class} - #{self.inspect}"
  end
end
class MyClass
  include Debug
end
obj = MyClass.new
obj.debug_info  # => "MyClass - #"
Debugモジュールは、debug_infoメソッドを提供し、このメソッドを含むクラスにMix-inします。これにより、クラスのインスタンスがデバッグ情報を表示するメソッドを利用できるようになります。
Minitestは、Rubyプログラミング言語用の軽量なテストフレームワークです。Minitestは、Rubyの標準ライブラリに含まれており、Rubyのバージョン1.9以降で利用可能です。Minitestは、テスト駆動開発（Test-Driven Development、TDD）や振る舞い駆動開発（Behavior-Driven Development、BDD）などのソフトウェア開発手法を支援するために使用されます。
Minitestは、単体テストや統合テストなど、さまざまな種類のテストをサポートしています。また、アサーションを用いて期待される振る舞いを確認するための豊富な機能も提供しています。Minitestの特徴は、シンプルで使いやすいインターフェース、高速な実行速度、そしてRubyの標準ライブラリに含まれているため、追加の依存関係を導入せずに利用できることです。
開発者がMinitestを使用することで、安定性や品質を向上させることができます。また、テストコードの記述や実行が容易であるため、素早く効果的なテストを作成することができます。
----
実際のコードを観てみましょう。
下記は、逆ポーランド記法の式を評価する機能を配列を継承して実装した例で、コメントを合わせても30行のコードですが、各演算子の実装の確認など基礎的なテストケースを書くだけで、数倍のコード量になります。
[https://paiza.io/projects/VltRK6tlhKoiWqIxn2dOaw?language=ruby Minitestの例]
RPNクラスは逆ポーランド記法（Reverse Polish Notation）の式を評価するためのクラスです。
スタック構造を使用して式を解析し、結果を計算します。
Rubyでは、Arrayクラスがpop,pushなどのスタックとしてのメソッドが完備されているので継承しました。
class RPN < Array
  # 与えられた逆ポーランド記法の式を評価し、結果を返します。
  # @param expression [String] 評価する式
  # @return [Numeric] 式の評価結果
  def eval(expression)
    expression.split.each do |token|
      case token
      when /\A-?\d+\z/, # 十進数
           /\A[+-]?0[Bb][01]+\z/, # 2進数
           /\A[+-]?0[Oo][0-7]+\z/, # 8進数
           /\A[+-]?0[Xx][0-9A-Fa-f]+\z/ # 10進数
        push Integer(token)
      when /\A-?\d+(\.\d+)?([eE][-+]?\d+)?\z/ # 浮動小数点数
        push(token.to_f)
      when *%w[+ - * / % ** & | ^ << >>] # 二項演算子
        left, right = pop(2)
        push left.send(token.to_sym, right)
      else
        raise RuntimeError, "Invalid operator: #{token}"
      end
    end
    # 最終的な結果はスタックの一番上に残る
    peek
  end
  # スタックの一番上の値を返しますが、スタックから削除しません。
  # @return [Numeric, nil] スタックの一番上の値。スタックが空の場合はnilを返します。
  alias peek last
end
require 'minitest/autorun'
class TestRPN < Minitest::Test
  def setup
    @rpn = RPN.new
  end
  
  def test_eval_with_single_operand
    assert_equal 5, @rpn.eval('5')
    assert_equal 5, @rpn.eval('0b101')
    assert_equal -5, @rpn.eval('-0b101')
    assert_equal 5, @rpn.eval('+0b101')
    assert_equal 127, @rpn.eval('0o177')
    assert_equal -127, @rpn.eval('-0o177')
    assert_equal 127, @rpn.eval('+0O177')
    assert_equal 195935983, @rpn.eval('0xbadbeef')
    assert_equal -195935983, @rpn.eval('-0xbadbeef')
    assert_equal 1.5, @rpn.eval('1.5')
    assert_equal 1e234, @rpn.eval('1e+234')
  end
  
  def test_eval_with_addition
    assert_equal 8, @rpn.eval('3 5 +')
    assert_equal 10, @rpn.eval('2 +')
  end
  
  def test_eval_with_subtraction
    assert_equal 7, @rpn.eval('10 3 -')
  end
  
  def test_eval_with_multiplication
    assert_equal 24, @rpn.eval('4 6 *')
  end
  
  def test_eval_with_division
    assert_equal 5, @rpn.eval('15 3 /')
  end
  
  def test_eval_with_remain
    assert_equal 2, @rpn.eval('11 3 %')
  end
  
  def test_eval_with_exponentiation
    assert_equal 8, @rpn.eval('2 3 **')
    assert_equal 1.4142135623730951, @rpn.eval('2 0.5 **')
    assert_equal 633825300114114700748351602688, @rpn.eval('2 99 **')
  end
  
  def test_eval_with_bitwidth_and
    assert_equal 8, @rpn.eval('12 10 &')
    assert_raises(NoMethodError) { @rpn.eval('12.0 10 &') }
    assert_raises(TypeError) { @rpn.eval('12 10.0 &') }
  end
  
  def test_eval_with_bitwidth_or
    assert_equal 14, @rpn.eval('12 10 |')
    assert_raises(NoMethodError) { @rpn.eval('12.0 10 |') }
    assert_raises(TypeError) { @rpn.eval('12 10.0 |') }
  end
  
  def test_eval_with_bitwidth_exclusive_or
    assert_equal 6, @rpn.eval('12 10 ^')
    assert_raises(NoMethodError) { @rpn.eval('12.0 10 ^') }
    assert_raises(TypeError) { @rpn.eval('12 10.0 ^') }
  end
  
  def test_eval_with_shift_left
    assert_equal 12288, @rpn.eval('12 10 <<')
    assert_raises(NoMethodError) { @rpn.eval('12.0 10 <<') }
    assert_equal 12288, @rpn.eval('12 10.1 <<')
  end
  
  def test_eval_with_shift_right
    assert_equal 15, @rpn.eval('123 3 >>')
    assert_raises(NoMethodError) { @rpn.eval('123.0 3 >>') }
    assert_equal 15, @rpn.eval('123 3.9 >>')
  end
  
  def test_eval_with_invalid_expression
    assert_raises(TypeError) { @rpn.eval('2 +') }
  end
  
  def test_peek_returns_top_element
    @rpn.eval('1 2 3 + +')
    assert_equal 6, @rpn.peek
  end
  
  def test_nan_or_zero_division
    @rpn.eval('0.0 0 /')
    assert @rpn.peek.nan?
    @rpn.eval('0 0.0 /')
    assert @rpn.peek.nan?
    @rpn.eval('-0.0 0 /')
    assert @rpn.peek.nan?
    assert_raises(ZeroDivisionError) { @rpn.eval('0 0 /') }
  end
  
  def test_inf_or_zero_division
    @rpn.eval('1.0 0 /')
    assert_equal Float::INFINITY, @rpn.peek
    @rpn.eval('-1 0.0 /')
    assert_equal -Float::INFINITY, @rpn.peek
    @rpn.eval('1 -0.0 /')
    assert_equal -Float::INFINITY, @rpn.peek
    @rpn.eval('-1 -0.0 /')
    assert_equal Float::INFINITY, @rpn.peek
    assert_raises(ZeroDivisionError) { @rpn.eval('110 0 /') }
  end
  
  def test_peek_returns_nil_for_empty_stack
    assert_nil @rpn.peek
  end
end
このコードは、逆ポーランド記法（Reverse Polish Notation）の式を評価するためのRPN（Reverse Polish Notation）クラスを定義しています。このクラスは、与えられた式をスタックを使用して解析し、計算します。以下に、このコードの機能と構造についての解説を行います。
RPNクラス
# frozen_string_literal: true: この行は、ファイル内の文字列リテラルが変更されないことを確認するためのリテラルです。
RPNクラスはArrayクラスを継承しており、スタックとしての機能を使用します。
evalメソッドは与えられた逆ポーランド記法の式を評価し、結果を返します。
peekメソッドは、スタックの一番上の値を返しますが、スタックから削除しません。
テストケース
TestRPNクラスはMinitest::Testを継承しており、RPNクラスのテストを定義します。
setupメソッドは各テストメソッドの前に実行され、テストで使用するRPNオブジェクトをセットアップします。
テストメソッド
test_eval_with_single_operandからtest_eval_with_invalid_expressionまでのメソッドは、evalメソッドが正しく動作することを確認するためのテストです。
test_peek_returns_top_elementはpeekメソッドがスタックの一番上の値を返すことを確認するテストです。
test_nan_or_zero_divisionとtest_inf_or_zero_divisionは、NaNやInfinityの扱い、ゼロ除算の例外処理をテストします。
これらのテストは、RPNクラスの各機能が正しく動作することを保証します。
このコードは、逆ポーランド記法の式の評価に関する機能を提供し、テストによってその正確性が検証されています。
RSpecは、Rubyでのテストを行うためのフレームワークの1つです。RSpecを使用すると、テストをより明確に記述し、テスト結果を見やすく出力することができます。
Gemfile:
source 'https://rubygems.org'
gem 'rspec'
導入:
bundle install
ユニットテストは、個々のコンポーネント（クラスやメソッドなど）が正しく機能するかをテストするものです。一方、統合テストは複数のコンポーネントが互いに連携して正しく動作するかをテストします。
spec/my_class_spec.rb:
require 'my_class'
RSpec.describe MyClass do
  describe '#method_name' do
    it 'returns something' do
      obj = MyClass.new
      expect(obj.method_name).to eq(something)
    end
  end
end
spec/integration_spec.rb:
require 'app'
RSpec.describe 'Integration Test' do
  it 'checks something' do
    # 統合テストの実装
  end
end
RSpecを使ってユニットテストと統合テストを書くことで、コードの品質を向上させ、予期せぬバグを見つけるのに役立ちます。
継承は、既存のクラスから新しいクラスを作成し、そのクラスが親クラスのすべての特性を引き継ぐことができる機能です。ポリモーフィズムは、同じ名前のメソッドが異なるクラスで異なる振る舞いをすることを指します。カプセル化は、データやメソッドをオブジェクト内部に隠蔽し、外部からのアクセスを制限することです。これらの概念を活用することで、より柔軟で効率的なコードを書くことができます。
class Animal
  def speak
    raise NotImplementedError, "Subclasses must implement the 'speak' method."
  end
end
class Dog < Animal
  def speak
    "Woof!"
  end
end
class Cat < Animal
  def speak
    "Meow!"
  end
end
dog = Dog.new
puts dog.speak  # => "Woof!"
cat = Cat.new
puts cat.speak  # => "Meow!"
上記の例では、Animalクラスが親クラスとして定義され、speakメソッドが定義されています。DogクラスとCatクラスはそれぞれAnimalクラスを継承し、speakメソッドをオーバーライドしています。これにより、DogクラスとCatクラスは同じ名前のメソッドを持ちつつも、それぞれ異なる振る舞いをします。
オブジェクト指向デザインパターンは、再利用可能なソフトウェア設計のガイドラインです。これらのパターンは、特定の問題に対する解決策を提供し、コードの再利用性、拡張性、保守性を向上させます。代表的なデザインパターンには、Singleton、Factory、Observer、Decoratorなどがあります。
require 'singleton'
class SingletonClass
  include Singleton
  def initialize
    @counter = 0
  end
  def increment_counter
    @counter += 1
  end
  def get_counter
    @counter
  end
end
instance1 = SingletonClass.instance
instance1.increment_counter
puts instance1.get_counter  # => 1
instance2 = SingletonClass.instance
puts instance2.get_counter  # => 1
上記の例では、Singletonパターンを使用して、特定のクラスのインスタンスが常に1つしか存在しないことを保証しています。Singletonモジュールをインクルードすることで、インスタンスが複数作成されることを防ぎます。
Rubyにおける並行プログラミングは、スレッドとプロセスを使用して実現されます。スレッドはプロセス内で動作し、複数のスレッドが同時に実行されることで並行処理が可能になります。一方、プロセスは独立した実行単位であり、それぞれが独自のメモリ空間を持ちます。
以下では、Rubyにおけるスレッドとプロセスの管理について解説し、コード例を示します。
RubyではThreadクラスを使用してスレッドを作成し、Thread.newメソッドを使って新しいスレッドを生成します。生成されたスレッドは並行して実行され、メインスレッドと同時に動作します。スレッドの制御にはjoinメソッドを使用して、メインスレッドがスレッドの終了を待機することができます。
 
threads = []
threads << Thread.new do
  3.times do
    sleep 1
    puts "Thread 1 executing"
  end
end
threads << Thread.new do
  3.times do
    sleep 2
    puts "Thread 2 executing"
  end
end
threads.each(&:join)
puts "All threads finished"
上記の例では、2つのスレッドを生成し、それぞれが一定間隔でメッセージを出力しています。joinメソッドにより、メインスレッドが全てのスレッドの終了を待機します。
Rubyでは、forkメソッドを使用して新しいプロセスをフォークし、子プロセス内で処理を実行することができます。プロセスの終了を待機するにはProcess.waitメソッドを使用します。
 
child_pid = fork do
  puts "Child process executing"
  sleep 3
  puts "Child process finished"
end
puts "Parent process waiting for child to finish"
Process.wait(child_pid)
puts "Parent process finished waiting"
上記の例では、親プロセスが子プロセスをフォークし、子プロセスが一定時間待機した後に終了します。親プロセスはProcess.waitメソッドで子プロセスの終了を待機します。
Rubyのスレッドとプロセスを使った並行プログラミングには、他にも多くの機能や制御方法がありますが、基本的な部分はこのようになります。
Rubyには、スレッドとプロセス以外にも並行プログラミングを行うためのさまざまな手段があります。以下にいくつかの方法を紹介します。
Fiberは、イテレータと似たコンテキストを持つ軽量なスレッドのようなものです。複数のFiberを作成し、それらを切り替えながら処理を行うことで、非同期の並行処理を実現することができます。
fiber1 = Fiber.new do
  puts "Fiber 1 executing"
  Fiber.yield
  puts "Fiber 1 resumed"
end
fiber2 = Fiber.new do
  puts "Fiber 2 executing"
  Fiber.yield
  puts "Fiber 2 resumed"
end
fiber1.resume
fiber2.resume
fiber1.resume
fiber2.resume
Concurrent Ruby gemは、並行プログラミングを行うための機能を提供するGemです。ThreadPoolやFuture、Promise、Actorなどの機能を使って、複雑な並行処理を実現することができます。
require 'concurrent'
pool = Concurrent::FixedThreadPool.new(5)
future = Concurrent::Future.execute(executor: pool) do
  # 並行処理を実行するコード
  sleep 1
  "Future result"
end
puts "Waiting for future to complete..."
puts future.value
Celluloid gemは、アクターモデルをベースにした並行プログラミングを行うためのGemです。アクターモデルでは、個々のアクターがメッセージを送受信しながら処理を実行します。
require 'celluloid'
class MyActor
  include Celluloid
  def initialize
    puts "Actor initialized"
  end
  def process_message(message)
    puts "Received message: #{message}"
  end
end
actor = MyActor.new
actor.async.process_message("Hello from main thread!")
これらの手法を使うことで、Rubyでより効果的な並行プログラミングを実現することができます。選択肢はプロジェクトの要件や好みに応じて異なりますが、Rubyの並行処理に関する柔軟性と機能性は広範囲にわたっています。
並行プログラミングでは、競合状態やデッドロックなどの問題が発生する可能性があります。競合状態は、複数のスレッドが同時に共有されたリソースにアクセスしようとすることで起こります。デッドロックは、複数のスレッドがお互いにリソースを解放するのを待ち合わせることで発生します。
これらの問題を回避するための解決策として、適切なロックの使用、スレッドセーフなデータ構造の選択、並行処理の慎重な設計などがあります。
並行処理の問題点と解決策について、コード例を示して説明します。
競合状態は、複数のスレッドが同時に共有されたリソースにアクセスしようとすることで発生します。
以下は、競合状態が発生する可能性のあるコード例です。
 
counter = 0
threads = 10.times.map do
  Thread.new do
    1000.times { counter += 1 }
  end
end
threads.each(&:join)
puts "Counter: #{counter}"
このコードでは、複数のスレッドがcounter変数にアクセスしています。しかし、counter += 1の操作は複数のスレッドで同時に実行される可能性があり、結果として期待通りにカウンターが増加しない可能性があります。
競合状態を回避するために、ロックを使用して複数のスレッドが同時に共有されたリソースにアクセスできないようにします。Rubyでは、Mutexクラスを使用してスレッドセーフなロックを実装できます。
 
counter = 0
mutex = Mutex.new
threads = 10.times.map do
  Thread.new do
    1000.times do
      mutex.synchronize { counter += 1 }
    end
  end
end
threads.each(&:join)
puts "Counter: #{counter}"
このコードでは、Mutexを使用してcounter変数へのアクセスを同期化しています。
これにより、複数のスレッドが同時にcounter変数にアクセスすることができず、競合状態が回避されます。
デッドロックは、複数のスレッドがお互いにリソースを解放するのを待ち合わせることで発生します。
以下は、デッドロックが発生する可能性のあるコード例です。
 
mutex1 = Mutex.new
mutex2 = Mutex.new
thread1 = Thread.new do
  mutex1.lock
  sleep 1
  mutex2.lock
  mutex1.unlock
  mutex2.unlock
end
thread2 = Thread.new do
  mutex2.lock
  sleep 1
  mutex1.lock
  mutex2.unlock
  mutex1.unlock
end
thread1.join
thread2.join
このコードでは、thread1がmutex1をロックし、同時にthread2がmutex2をロックする可能性があります。その後、各スレッドは相手のロックを解放するのを待ち合わせることになり、デッドロックが発生します。
デッドロックを回避するために、ロックを取得する順序を一貫させることが重要です。
この方法により、複数のスレッドが同じ順序でロックを取得しようとしても、デッドロックを引き起こすことがありません。
 
mutex1 = Mutex.new
mutex2 = Mutex.new
thread1 = Thread.new do
  mutex1.lock
  sleep 1
  mutex2.lock
  mutex1.unlock
  mutex2.unlock
end
thread2 = Thread.new do
  mutex1.lock # ロックの順序を変更
  sleep 1
  mutex2.lock
  mutex1.unlock
  mutex2.unlock
end
thread1.join
thread2.join
この修正では、thread2がmutex1を先にロックするように変更されており、ロックの順序が一致しています。これにより、デッドロックが発生する可能性が低くなります。
以上が、並行処理の問題点とその解決策をコード例を交えて説明したものです。競合状態やデッドロックは並行プログラミングにおける一般的な問題であり、適切な対処が必要です。
Ruby on Railsは、RubyでのWebアプリケーション開発を支援する人気のあるフレームワークです。Railsを使用することで、MVC（Model-View-Controller）アーキテクチャをベースにした効率的なWebアプリケーションを開発することができます。
rails new myapp
rails generate model User name:string email:string
rails db:migrate
rails generate controller UsersController
config/routes.rb:
Rails.application.routes.draw do
  resources :users
end
Railsでは、コマンドラインツールを使用してモデルやコントローラを簡単に生成し、ルーティングを設定することができます。これにより、短期間で効率的なWebアプリケーションを構築することができます。
MVC（Model-View-Controller）アーキテクチャは、アプリケーションの設計を3つの主要なコンポーネントに分割するアーキテクチャパターンです。
モデル (Model):
データやビジネスロジックを担当します。
アプリケーションの状態やデータを管理し、ビューに表示されるデータを提供します。
モデルは通常、データベースや外部サービスとのやり取りも担当します。
ビュー (View):
ユーザーインターフェース（UI）の表示を担当します。
ユーザーにデータを視覚的に提示し、ユーザーからの入力を受け付けます。
ビューは通常、モデルからデータを受け取り、それをユーザーに見やすい形で表示します。
コントローラ (Controller):
ユーザーからの入力を受け付け、それに基づいてモデルやビューの操作を制御します。
ユーザーの操作に応じてモデルの状態を変更し、ビューの更新をトリガーします。
コントローラはユーザーとアプリケーションの主要な仲介者であり、ビジネスロジックを含む場合があります。
相互関係:
ユーザーがビューで何かしらの操作を行うと、それに対するイベントがコントローラに送信されます。
コントローラはそのイベントを受け取り、必要に応じてモデルを更新したり、新しいデータをビューに送ったりします。
モデルが変更されると、モデルはその変更をビューに通知します。
ビューは通知を受け取り、表示を更新します。
このように、MVCアーキテクチャは各コンポーネントが疎結合であり、変更が発生した際に一部のコンポーネントを変更しても他のコンポーネントに影響を与えにくい特徴があります。これにより、柔軟性が向上し、保守性が高まります。
RoR（Ruby on Rails）は、MVC（Model-View-Controller）アーキテクチャの理念に基づいて設計されたWebアプリケーションフレームワークです。RoRにおけるMVCの役割と機能を説明します。
モデル (Model)
RoRのモデルは、アプリケーションのデータベースとのやり取りを担当します。
モデルはActive Recordとして実装されており、データベースのテーブルと対応するオブジェクトを表現します。
モデルはビジネスロジックを含み、データの検証や処理を行います。
class User < ApplicationRecord
  validates :name, presence: true
end
ビュー (View)
RoRのビューは、ユーザーにデータを表示するためのテンプレートを提供します。
HTMLやERB（Embedded Ruby）などのテンプレートエンジンを使用して、動的なコンテンツを生成します。
ビューは主にユーザーインターフェースの生成に使用されます。
<% @users.each do |user| %>
  <%= user.name %>
<% end %>
コントローラ (Controller)
RoRのコントローラは、ユーザーからのリクエストを受け取り、それに応じて適切な処理を行います。
リクエストの解析やデータの操作など、ビジネスロジックの一部もコントローラで処理されます。
ビューの表示を制御し、モデルへのデータの渡し方もコントローラで決定されます。
class UsersController < ApplicationController
  def index
    @users = User.all
  end
end
ルーティング (Routing)
RoRでは、URLとコントローラアクションの対応をルーティングで定義します。
ルーティングはconfig/routes.rbファイルに記述され、特定のURLパスへのリクエストを特定のコントローラアクションにマップします。
Rails.application.routes.draw do
  resources :users, only: [:index]
end
MVCの相互関係
ユーザーからのリクエストはルーティングで適切なコントローラアクションに送信されます。
コントローラは必要に応じてモデルからデータを取得し、適切なビューをレンダリングしてユーザーに表示します。
ビューはユーザーにデータを表示し、必要に応じてユーザーの入力を受け付けます。
ユーザーの入力やアクションによっては、再びコントローラへリクエストが送信され、その処理が繰り返されます。
Ruby on RailsはMVCアーキテクチャにより、アプリケーションの各コンポーネントが明確に分離され、保守性が向上し、柔軟性が高まります。
Railsでは、アクティブレコードと呼ばれるオブジェクト関係マッピング（ORM）ツールを使用して、データベースとのやり取りを簡単に行うことができます。アクティブレコードを使用することで、SQLクエリを直接記述せずに、Rubyオブジェクトとしてデータベースのテーブルを操作することができます。
users = User.all
user = User.new(name: "Alice", email: "alice@example.com")
user.save
Railsでは、データベースへの接続設定を行うことで、アプリケーション内でアクティブレコードを使用してデータベースとやり取りすることができます。
ORMは、オブジェクトとリレーショナルデータベースとの間のマッピングを行うためのツールです。ORMを使用することで、データベースのテーブルをオブジェクトとして操作することができ、SQLクエリの記述を最小限に抑えることができます。これにより、コードの可読性や保守性が向上します。
メモリ管理とコードの最適化は、Rubyプログラミングにおいて重要な要素です。効率的なメモリ管理を行うことで、アプリケーションのメモリ使用量を最小限に抑え、パフォーマンスを向上させることができます。また、コードの最適化により、処理速度を高速化し、リソースの効率的な利用を実現することができます。
メモリ管理のベストプラクティス:
不要なオブジェクトの解放: 不要なオブジェクトを定期的に解放することで、メモリリークを防止しましょう。
大量のデータの処理: 大規模なデータ処理が必要な場合は、メモリを過剰に消費することがあります。代わりに、イテレータやジェネレータを使用してデータを効率的に処理しましょう。
メモリフラグメンテーション: メモリフラグメンテーションが発生すると、メモリが不連続に配置されるため、効率的なメモリ使用が妨げられます。適切なメモリ管理を行い、フラグメンテーションを最小限に抑えましょう。
コードの最適化のベストプラクティス:
効率的なアルゴリズムの選択: 適切なアルゴリズムを選択することで、処理速度を向上させることができます。時間計算量や空間計算量を考慮して、最適なアルゴリズムを選択しましょう。
不要なループの削減: 不要なループや再帰呼び出しを削減することで、処理速度を向上させることができます。ループのネストを最小限に抑え、効率的なコードを作成しましょう。
遅延読み込み: 大きなデータセットを扱う場合は、遅延読み込みを活用して、必要な時点でデータを取得するようにしましょう。これにより、不要なデータの読み込みを回避し、メモリ使用量を最小限に抑えることができます。
プロファイリングツールは、アプリケーションのパフォーマンスを詳細に分析し、ボトルネックを特定するための有用なツールです。プロファイリングツールを使用することで、どの部分が最もリソースを消費しているかや、どの部分が最も遅いかなどを把握することができます。
代表的なプロファイリングツール:
RubyProf: Rubyのプロファイリングツールの1つであり、メソッドごとの実行時間や呼び出し回数などを詳細に分析することができます。
StackProf: スレッドごとのスタックトレースを収集し、アプリケーションのホットスポットを特定することができるプロファイリングツールです。
DTrace: オペレーティングシステムレベルでのパフォーマンス分析を行うための強力なツールであり、Rubyアプリケーションのボトルネックを特定するのに役立ちます。
これらのプロファイリングツールを使用して、アプリケーションのパフォーマンスを詳細に分析し、効率的な最適化を行いましょう。
プロファイリング手法と注意点:
アプリケーション全体のプロファイリング: アプリケーション全体のプロファイリングを行うことで、全体のパフォーマンスを把握し、最も時間がかかる部分を特定します。この情報をもとに、重点的に最適化を行いましょう。
繰り返し実行による平均化: プロファイリングを行う際には、複数回の実行を行い、結果を平均化することが重要です。これにより、ランダムな外部要因の影響を排除し、より正確なプロファイリング結果を得ることができます。
プロファイリングの結果の解釈: プロファイリング結果を解釈する際には、アプリケーションのコードや処理の特性を理解することが重要です。高負荷がかかっている部分やボトルネックを正確に特定し、効果的な最適化を行いましょう。
プロファイリングの定期的な実施: アプリケーションのコードや処理が変更されるたびに、プロファイリングを定期的に実施することで、パフォーマンスの変化や問題点を早期に検出し、適切な対策を講じることができます。
セキュリティとプライバシー: プロファイリングツールを使用する際には、セキュリティとプライバシーに配慮しましょう。機密情報や個人情報が含まれる可能性がある場合は、適切な対策を講じて情報漏洩を防止しましょう。
総括
メモリ管理、コードの最適化、およびプロファイリングツールの使用は、Rubyプログラミングにおいてアプリケーションのパフォーマンスを向上させるために重要なスキルです。効率的なメモリ管理とコードの最適化により、リソースの効率的な利用を実現し、プロファイリングツールを使用してボトルネックを特定し、効果的な最適化を行うことで、より高速で効率的なアプリケーションを開発することができます。
上級レベルでは、オブジェクト指向デザインパターンの理解と実装に焦点を当てましたが、実際のアプリケーション開発では、これらのパターンを活用して柔軟で効率的なコードを書くことが重要です。より実践的な例や、実際の問題に対する解決策を学ぶことで、より高度な開発スキルを身につけることができます。
プロの開発者になるためには、セキュリティとエラーハンドリングの重要性を理解し、適切な対策を講じることが不可欠です。セキュリティホールや悪意のある攻撃からアプリケーションを保護し、エラーが発生した際にユーザーやシステムに影響を与えないようにするための方法を学びましょう。
テスト駆動開発（Test-Driven Development, TDD）は、コードを書く前にテストを書き、そのテストをパスするようなコードを実装する開発手法です。TDDを実践することで、より品質の高いコードを生産し、バグの早期発見やリファクタリングの容易化が可能となります。
コード品質は、プロの開発者にとって非常に重要な要素です。コードを読みやすく、保守しやすく、拡張しやすくするためのリファクタリングのテクニックやベストプラクティスを学び、コードベースを常に改善していきましょう。
これらのトピックを網羅的に学ぶことで、より高度なRubyプログラミングスキルを身につけることができます。プロの開発者としてのキャリアを築くために、着実にスキルを向上させていきましょう。
Rubyの変数は、オブジェクトに名前をつけるために使われます。
Rubyでは、変数は宣言する必要はありません。
オブジェクトを変数に代入するには
変数名 = オブジェクト
の様に代入演算子 = を使います。
[https://paiza.io/projects/x1_UlCeb1PtW8pG8Xi-i-g?language=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]
bはaと同じ配列を参照しているため、bの変更がaにも反映されます。
{{コラム|puts メソッドと p メソッド|2=
putsメソッドはオブジェクトにto_sメソッドで適用した結果を表示します。
これに対し、pメソッドはオブジェクトにinspectメソッドで適用した結果を表示します。
[https://paiza.io/projects/uZV53RJGbr3FKbscJc8tiw?language=ruby 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
このコードでは、$global_variableというグローバル変数が定義されています。そして、print_globalメソッド内でその値が参照されて表示されます。グローバル変数はプログラム中のどこからでも参照可能であるため、異なるメソッド間でデータを共有する場合に使用されます。しかし、グローバル変数の使用は避けるべきであり、できるだけローカル変数やインスタンス変数を使用することが推奨されます。
特殊変数は、Rubyがあらかじめ定義している変数で、プログラム中で直接代入することができません。これらの変数は、プログラムの実行中に自動的に設定され、Rubyの様々な機能で使用されます。
puts "This program's name is #{$0}"
puts "The Ruby version is #{RUBY_VERSION}"
puts "The current line number is #{$.}"
Rubyは完全なオブジェクト指向言語であり、すべてがオブジェクトです。オブジェクトは、データとそれに対する操作をカプセル化したものであり、オブジェクトを操作するためにメソッドを使用します。
以下は、オブジェクトについての基本的な説明です。
オブジェクトは、Rubyの世界で唯一の存在であり、それぞれが固有の状態と振る舞いを持っています。
オブジェクトは、何らかのデータ（文字列、数値、配列、ハッシュ、ファイルなど）を表します。例えば、整数、浮動小数点数、有理数や複素数などの数値を表すオブジェクトがあり、文字列オブジェクトはテキストを表します。
オブジェクトは、そのデータを操作するためのメソッドを提供します。メソッドは、オブジェクトの状態を変更することができます。例えば、数値オブジェクトには、加算や減算などの算術演算を行うためのメソッドがあります（演算子もメソッドです）。文字列オブジェクトには、文字列の結合や部分文字列の取得などのメソッドがあります。
オブジェクトは、クラスと呼ばれるテンプレートから作成されます。クラスは、オブジェクトのデータやメソッドを定義するための設計図です。オブジェクトは、クラスのインスタンスとして作成されます。
オブジェクトは、他のオブジェクトとやり取りすることができます。オブジェクトは、別のオブジェクトをメソッドの引数として受け取ることができ、戻り値としても返すことができます。
これらのオブジェクトのクラスを知ることは、そのオブジェクトがどのような振る舞いをするかを理解するために非常に重要です。
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 
Rubyにおける式と演算子について説明します。
Rubyにおける式とは、ある値を評価するためのコードのことを指します。例えば、以下のような式があります。
 
1 + 2
この式は、1と2を足した結果を評価するための式です。この式を実行すると、3という値が返されます。
演算子は、式を組み合わせたり、値を変更するために使用されます。Rubyにはさまざまな種類の演算子があります。以下はいくつかの例です。
数値演算子には、加算、減算、乗算、除算、剰余演算子などがあります。
以下はいくつかの例です。
[https://paiza.io/projects/z2HDB6CbEbLClzWILhmpmA?language=python3 operators.rb]:
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 (-2)**0.5 # (0.0+1.4142135623730951i)
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では、これらの演算子がオーバーロードされることがあります。
数値演算子の使用は、さまざまなデータ型に対して行われます。整数、文字列、配列、有理数、複素数など、Rubyは様々なデータ型をサポートしており、それぞれのデータ型に対して適切な演算が行われます。
例えば、文字列の場合、加算演算子は文字列の連結を行います。同様に、整数や有理数の場合は数値演算が行われますが、複素数の場合は複素数の演算が行われます。
また、Rubyでは四則演算子や剰余演算子などの演算子がオーバーロードされることがあります。これにより、ユーザー定義のクラスやオブジェクトに対して独自の演算を定義することができます。オブジェクト指向の特性を活かした柔軟な演算の定義が可能です。
数値演算子の適切な使用は、プログラムの正確性や効率性に直結します。Rubyの数値演算子を適切に理解し、適切に活用することで、より効率的で読みやすいコードを書くことができます。
比較演算子とComparableモジュールは、Rubyにおいてオブジェクトの比較を可能にする重要な機能です。
比較演算子には以下のようなものがあります：
以下はいくつかの例です。
a = 1
b = 2
puts a == b # 等しい
puts a != b # 等しくない
puts a > b  # より大きい
puts a < b  # より小さい
puts a >= b # 以上
puts a <= b # 以下
これらの演算子を使って、オブジェクト同士を比較することができます。例えば、整数同士や文字列同士の比較などが挙げられます。
Comparableモジュールは、比較可能なオブジェクトを定義するためのモジュールです。このモジュールをクラスにincludeすることで、そのクラスのインスタンス同士を比較可能にすることができます。
Comparableモジュールでは、<=>演算子（スペース船演算子）を実装する必要があります。この演算子は、二つのオブジェクトを比較して以下のような値を返します：
Comparableモジュールを使用することで、クラス内で<=>演算子を定義するだけで、そのクラスのインスタンス同士を比較することができます。これにより、コードの可読性を高め、一貫した比較処理を実現することができます。
例えば、数値や文字列など、大小関係を持つオブジェクトを扱う場合に便利です。また、minやmaxなどのメソッドを利用して、比較可能なオブジェクトの最小値や最大値を簡単に取得することもできます。
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) を表現するための真理値表を示します。
上記の表で、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です"
このコードでは、name が nil でないかつ文字列の長さが0より大きいかを同時にチェックしています。
具体的には、条件式 name && name.length > 0 によってチェックしています。
この条件式では、短絡評価 (short-circuit evaluation) が利用されています。短絡評価とは、条件式の全ての部分を評価せずに、最初に結果が確定した部分で評価を終了するという評価方法です。
具体的には、この場合はnameがnilである場合、name.length > 0 の評価は行われず、条件式全体がfalseと判定されます。
このような短絡評価の利用により、コードのパフォーマンスを向上させることができます。また、name が nil の場合に name.length を呼び出すことがなくなるため、エラーを避けることができます。
しかし、短絡評価を乱用すると、プログラムの可読性が低下したり、バグを引き起こしたりすることがあります。適切な場面でのみ利用するようにしましょう。
論理演算子（AND, OR）は演算子の姿をしていますが、内実は制御構造です。そのため論理演算子は演算子オーバーロード出来ません。
「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では、クラスやモジュールで演算子に対応するメソッドを定義することができます。このようにして定義された演算子メソッドをオーバーロードと呼びます。
以下は、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 によって、x と y のインスタンス変数に対する getter/setter メソッドが定義されています。これによって、外部から v1.x のようにしてインスタンス変数にアクセスしたり、v1.x = 10 のようにしてインスタンス変数に値を代入したりできます。
次に、initialize メソッドが定義されています。これは、new メソッドが呼ばれた時に、引数として渡された x と y をインスタンス変数 @x と @y に代入するためのコンストラクタです。
+ メソッドは、引数として与えられた other という別の Vector2 オブジェクトを足し合わせ、新しい Vector2 オブジェクトを作成して返します。これによって、v1 + v2 のようにして2つのベクトルを足し合わせることができます。
最後に、to_s メソッドが定義されています。これは、オブジェクトを文字列に変換するためのメソッドで、ベクトルの座標を [x, y] のような形式の文字列に変換して返します。
実際に、v1 と v2 を足し合わせた結果を v3 に代入し、puts v3 で v3 を表示しています。v3 の値は [4, 6] となります。
このように演算子メソッドをオーバーロードすることで、プログラムの読みやすさや柔軟性を高めることができます。ただし、意図しない挙動を招くこともあるため、注意して使いましょう。
Rubyでは、演算子をオーバーロードすることが出来ます。
オーバーロード可能な演算子には、組み込みクラスの演算子も含まれます。
class String
  def /(s) = split(s)
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の演算子の優先順位と結合方向の表です。
優先順位が高い演算子から順に、結合方向の左右を記載しています。
表中の "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
%w(one two three) : ["one", "two", "three"]
--------------------
Rubyには、if-else-elsif-end、unless-else-end、case-when-else-end、case-in-else-end、while文、until文、for文、そしてbegin-rescue-else-ensure-endのような例外処理構文など、様々な制御構造があります。
これらの制御構造を使うことで、プログラムの実行を条件に応じたループや分岐によって制御することができます。
制御構造を正しく理解し、適切に使用することで、効率的で洗練されたプログラムを書くことができます。
また広義の制御構造にはブロックを伴う each や loop などのメソッドも含まれ、ここではそれらについても解説します。
書式概観:
if 条件式1 then
  処理1
elsif 条件式2 then
  処理2
else
  処理3
end
式 if 条件式
unless 条件式 then
  処理1
else
  処理2
end
式 unless 条件式
case 対象のオブジェクト
when 条件式1 then
  処理1
when 条件式2 then
  処理2
when 条件式3 then
  処理3
else
  処理4
end
while 条件式 do
  処理
end
式 while 条件式
until 条件式 do
  処理
end
式 until 条件式
for 変数 in 範囲 do
  処理
end
loop do
  処理
end
コレクション.each do |変数|
  処理
end
回数.times do |変数|
  処理
end
Rubyの条件分岐には、if-elsif-else-end、unless-else-end、そしてcase-when-else-endがあります。
また、if, unless には修飾子構文もあります。
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 条件式
例えば、ある数値変数numが0未満なら「negative」と表示するプログラムは以下のように書けます。
num = -3
puts "negative" if num < 0
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修飾子は、if修飾子に似ていますが、条件式が否定されたときに式を評価する構文です。
式 unless 条件式
例えば、ある数値変数numが0以上でなければ「negative」と表示するプログラムは以下のように書けます。
num = -3
puts "negative" unless num >= 0
case-when-else-endは、複数の値に応じて処理を分岐するための構文です。if-elsif-else-endと比較して、１つのオブジェクトに対して複数の条件式を一度に評価できるという利点があります。
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
Rubyの case 文では、比較に用いるオブジェクトの型に応じて条件分岐することができます。具体的には、case 文の式の型が以下のいずれかである場合に、対応する条件分岐が行われます。
以下に、それぞれの場合の例を示します。
整数型の場合
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は式|2=Rubyの if、unless、case は、制御フロー構文としての使い方に加えて、式としても使うことができます。
例えば、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のパターンマッチングは、バージョン2.7で導入された新機能であり、構造化された値に対してパターンをマッチングすることができます。これにより、より複雑なデータ構造を柔軟に操作できるようになります。
以下に、Rubyのパターンマッチングの基本的な構文と機能について説明します。
case 式
in パターン1
  # パターン1にマッチする場合の処理
in パターン2
  # パターン2にマッチする場合の処理
else
  # どのパターンにもマッチしない場合の処理
end
パターンは以下のようなものがあります：
パターンマッチングによって、マッチした部分をローカル変数にバインドすることができます。
 
case [1, 2]
in Integer => a, Integer
  puts "マッチしました: #{a}"
else
  puts "マッチしませんでした"
end
ifを使用して、パターンがマッチした場合に追加の条件を指定することができます。
case [1, 2]
in a, b if b == a * 2
  puts "マッチしました"
else
  puts "マッチしませんでした"
end
複数のパターンを組み合わせてマッチングを行うこともできます。
 
case [1, 2]
in [1, Integer]
  puts "マッチしました"
else
  puts "マッチしませんでした"
end
パターンマッチングが失敗した場合には、例外が発生します。これは、NoMatchingPatternErrorとして知られています。
カスタムクラスに対してパターンマッチングを行う場合、deconstructやdeconstruct_keysメソッドを実装することでマッチングを行うことができます。
より読みやすいコードを書くことができます。
より安全なコードを書くことができます。
より柔軟なデータ操作が可能になります。
以上が、Rubyのパターンマッチングについての基本的な説明です。この機能は、プログラミングのパラダイムをより関数型プログラミング寄りのスタイルに変えることができます。
Rubyの反復構文は、特定の条件が満たされるまでコードのブロックを繰り返すことができる文のセットです。最も一般的な反復文は、while、until、for、loop です。
while文は、ある条件が真である限り、コードのブロックを実行します。
until文は、ある条件が偽である限り、コードのブロックを実行します。
for文は、要素のコレクションを繰り返し処理し、各要素に対してコードのブロックを実行します。
また、while, until には修飾子構文もあります。
これらの基本的な反復処理文に加えて、Ruby には break、next、redo、lazy などの反復処理文があります。これらの文により、コードの実行の流れを制御することができます。
例:
このコードでは、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修飾子は、if修飾子に似ていますが、条件式が肯定されている間は式を評価し続ける構文です。
式 while 条件式
例えば、ある数値変数numが0未満の間、num に 2 を足し続けるプログラムは以下のように書けます。
num = -3
num += 2 while num < 0
例:
このコードでは、10から1までの数字を表示します。
i = 10 
until i <= 1 do
  puts i
  i -= 1 
end
until文の構文は以下の通り：
構文:
until 条件 do
  # 処理
end
条件とは、ループの実行を継続するためにfalseと評価されなければならないブール値の式です。
処理の部分は、条件が偽である限って実行されるコードのブロックです。
まえの例では、条件はi <= 1である。これは、iの値が1以上である限り、ループが実行され続けることを意味します。
処理の部分は、puts i行です。この行はiの値をコンソールに出力します。
until文は、特定の条件が満たされない限り、コードのブロックを繰り返すために使用できる強力なツールです。
until修飾子は、while修飾子に似ていますが、条件式が否定されている間は式を評価し続ける構文です。
式 until 条件式
例えば、ある数値変数numが0以上でない間、num に 2 を足し続けるプログラムは以下のように書けます。
num = -3
num += 2 until num >= 0
例:
このコードでは、配列の要素を順に表示します。
array = [2, 3, 5, 7, 11] 
for element in array
  puts element 
end
puts element #=> 11 ## forループを抜けてもスコープは終わらない
for文の構文は以下の通り：
構文:
for ループ変数 in コレクション
  # ループ変数にまつわる処理
end
ループ変数は、コレクション内の現在の要素のプレースホルダーです。
コレクションは、配列、範囲、その他の反復可能なオブジェクトのいずれでもかまいません。
ループ変数にまつわる処理の部分は、コレクション内の各要素に対して実行されるコードのブロックです。
この例では、コレクションは配列[2, 3, 5, 7, 11]です。ループ変数はelementです。
ループ変数にまつわる処理の部分は、puts element行です。この行は、elementの値をコンソールに表示します。
for文は、要素のコレクションを繰り返し処理するために使用できる強力なツールです。
Rubyには、反復制御を行う文が5つあります。
break : break文は、現在のループを終了させる。
next : 現在のループの繰り返しをスキップする。
redo : 現在のループの繰り返しを再び実行する。
retry: 例外処理をリトライする。
return : メソッドを終了します。現在のループの繰り返しも終了します。
反復制御文は、Rubyのコードをより効率的に、より読みやすくするために使用できる強力なツールです。
break文は、現在のループを終了させます。
例:
(1..).step(12) do |i|
  break if i >= 50
  puts i
end
このコードは、1から始まり、12ずつ増加する無限の数列を生成し、その数列の各要素をdo..endブロック内で処理しています。各要素は変数iに割り当てられ、puts文を使って出力されます。
しかし、break if i >= 50の部分によって、iが50以上になった場合、ループが終了します。つまり、ループは50未満の値のときだけ実行されます。
このコードは、1, 13, 25, 37, 49といった50未満の数列を出力します。そして、iが50以上の値になった時点でループが終了します。
next文は、ループの現在の反復をスキップさせます。
例:
1.upto(10) do |i|
  next if i == 5
  puts i
end
このコードは、1から10までの数列を生成し、その数列の各要素をdo..endブロック内で処理しています。各要素は変数iに割り当てられ、puts文を使って出力されます。
next if i == 5の部分によって、iが5の場合、それ以降の処理をスキップして次の要素の処理に進みます。つまり、5は出力されません。
したがって、このコードは1, 2, 3, 4, 6, 7, 8, 9, 10という数列を出力します。5がスキップされ、それ以外の値が出力されます。
redo文は、現在のループの繰り返しを再度実行します。
例:
count = 0
(1..10).each do |i|
  count += 1
  redo if i == 5 and count < 20
  puts "#{count}: #{i}"
end
例外が発生した場合に、その処理をやり直します。
begin
  # 何らかの処理
rescue SomeException
  retry
end
メソッド内でループを含む場合、returnを使ってループからも抜けることができます。以下はその例です。
 
def example_method
  (1..10).each do |i|
    return if i == 5
    puts i
  end
end
example_method
この場合、returnが呼び出されると、example_method自体が終了し、その場でループも終了します。
これらのキーワードやメソッドを使うことで、ループの挙動を制御することができます。
Rubyでは、反復処理を用いて演算を行うメソッドを反復処理メソッドと呼びます。
反復処理とは、コードのブロックを指定された回数だけ、あるいは特定の条件が満たされるまで繰り返す処理のことです。
Rubyには、ArrayやHashなどのコレクションオブジェクトを簡単にイテレーションできる多数のメソッドがあります。以下はいくつかの例です：
例:
array = [1, 2, 3]
array.each { |x| puts x }
array = [1, 2, 3]
new_array = array.map { |x| x * 2 }
array = [1, 2, 3]
new_array = array.select { |x| x.even? }
array = [1, 2, 3]
sum = array.reduce(0) { |total, x| total + x }
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には、様々なメソッドやイテレータで使用される暗黙のブロック引数があります。これらは _1, _2 などの形式で表され、ブロック内で引数を明示的に書く必要がなくなります。代表的なものを以下に示します。暗黙のブロック引数はRuby 2.7からサポートされました。
numbers = [1, 2, 3, 4, 5]
numbers.each { |num| puts num } # 通常の引数を使用する場合
numbers.each { puts _1 } # `_1` を使用することで、暗黙の引数として要素を取得
hash = { a: 1, b: 2, c: 3 }
hash.each { |key, value| puts "#{key}: #{vale}" }
hash.each { puts "#{_1}: #{_2}" }
doubled = numbers.map { |num| num * 2 } # 通常の引数を使用する場合
doubled = numbers.map { _1 * 2 } # `_1` を使用することで、暗黙の引数として要素を取得して計算
 
このように、暗黙のブロック引数は通常の引数の代替として使われ、ブロック内でのコードをより簡潔にすることができます。ただし、可読性の観点から、コードが複雑になりすぎないよう注意が必要です。
Rubyには、数値を連続して扱うための便利なメソッドがあります。その中でもupto、downto、stepはよく使われるものです。これらのメソッドについて解説します。
例:
1.upto(5) do |i|
  puts i
end
5.downto(1) do |i|
  puts i
end
1.step(10, 2) do |i|
  puts i
end
上記の例では、以下のように動作しています。
uptoメソッド:整数オブジェクトから別の整数オブジェクトまで、1ずつ増加させながら、ブロック内の処理を繰り返します。この例では、1から5までの整数を順に出力しています。
downtoメソッド:整数オブジェクトから別の整数オブジェクトまで、1ずつ減少させながら、ブロック内の処理を繰り返します。この例では、5から1までの整数を順に出力しています。
stepメソッド:開始値から終了値まで、指定されたステップで数値を増加させながら、ブロック内の処理を繰り返します。この例では、1から10までの奇数を順に出力しています。stepメソッドで
は、第2引数に指定した数値が増加量として使用されます。この例では、2ずつ増加しているため、1, 3, 5, 7, 9という結果になっています。
過去の編集で、loopをloop文と紹介されていましたが、loopはKernelオブジェクトのメソッドで構文ではありません。
loopメソッドの使い方は以下の通り：
loop do
  # 処理
end
処理の部分は、無限に実行されるコードのブロックです。
例:
このコードは、永久に "This will print forever!" を表示します。
loop do 
 puts "This will print forever!" 
end
この例では、処理パートは puts "This will print forever!"です。
この行は、"This will print forever!"というメッセージをコンソールに無限に出力します。
loopとEnumrator:
enum = [1, 2, 3].each
puts enum.class  #=> Enumerator
loop do
  puts enum.next
end
    #=> 1
    #   2
    #   3
enumは[1, 2, 3].eachから生成されたEnumeratorです。Enumeratorは、eachメソッドをブロックなしで呼び出すことで生成され、配列内の各要素を反復処理することができます。
その後、loop構文が使われています。loop構文は、無限ループを作成するためのもので、ループ内のコードを繰り返し実行します。
ループ内では、enum.nextが呼び出されています。これにより、Enumeratorから次の要素が取得され、その要素がputsメソッドを使って出力されます。最初は1が出力され、次に2、そして3が出力されます。
しかし、3を出力した後、Enumeratorからはもう要素がないため、StopIteration例外が発生します。この例外がloop構文によって自動的に捕捉され、ループが終了します。
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
ブロック引数を指定する方法
array = [1, 2, 3]
array.each { puts _1 }
このように、イテレーションメソッドは、ブロックを引数に取り、ブロック内で要素に対する処理を実行するため、とても柔軟性が高く、コードの再利用性を高めることができます。
{{コラム|eachメソッドを使ったハック|2=
普段あまり使うことはありませんが、配列のeachメソッドは戻値を返します。
通常は配列自身ですが、breakでループを中断すると nil を返します。
この特徴を利用すると、ZigやPythonのループと結合したelseの様に「ループを完走したときだけ実行する処理」を記述できます。
[https://paiza.io/projects/Je9yc_1sAi0h-jMfCSln4g?language=ruby 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)から１つ素数(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
Rubyでは、制御構造の修飾子版も提供されています。これは一行で短く書くことができ、可読性を向上させる場合があります。
制御構造の修飾子版には、以下のものがあります：
puts "Hello" if flag
この場合、"Hello"はflagが真の場合にのみ出力されます。
puts "Hello" unless cond
この場合、"Hello"はcondが偽の場合にのみ出力されます。
x = 0
puts x += 1 while x < 5
この場合、ループが続行される条件が満たされている間、xの値がインクリメントされ、その値が出力されます。
x = 0
puts x += 1 until x == 5
この場合、ループが続行される条件が満たされるまで、xの値がインクリメントされ、その値が出力されます。
Rubyのrescue修飾子は、単一行の式での例外処理を行うために使用されます。通常のbegin..rescue..endブロックと異なり、修飾子版はコードを短く保ち、よりコンパクトに書くことができます。
rescue修飾子の構文は以下の通りです：
 
式1 rescue 式2
式1が例外を発生させた場合、rescue修飾子はその例外をキャッチし、代わりに式2を評価します。
以下はrescue修飾子を使用した例です：
 
result = risky_operation() rescue default_value
この例では、risky_operationというメソッドを呼び出しますが、もし例外が発生した場合には、デフォルト値を代入することでエラーハンドリングを行っています。
rescue修飾子は、例外が発生する可能性のある単一の式を簡潔に記述する場合に便利ですが、複雑な例外処理を行う場合や、複数の式に対する例外処理を行う場合には、通常のbegin..rescue..endブロックを使用する方が適しています。
これらの修飾子版は、単純な条件の場合や短いコードブロックの場合に便利です。
ただし、複雑な制御構造や複数の条件がある場合は、通常の制御構造を使用した方が可読性が高くなります。
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!" }
def greet_with_remainder(*names)
  names.each { |name| puts "Hello, #{name}!" }
end
greet_with_remainder("Alice", "Bob", "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.call
end
my_method do
  puts "Hello, World!"
end
上記の例では、my_methodメソッドにブロックを渡しています。my_methodメソッド内では、ブロックを扱うための引数として"█"を指定しており、ブロックを呼び出すために"block.call"を用いています。
yieldは、メソッドに渡されたブロックを実行するためのキーワードです。yieldを使用することで、メソッド内でブロックを実行することができます。
以下に例を示します。
def my_method
  yield
end
my_method do
  puts "Hello, World!"
end
上記の例では、my_methodメソッド内でyieldを用いてブロックを実行しています。my_methodメソッドが呼び出されると、引数として渡されたブロックが実行されます。
ブロック引数の呼び出しやyieldは引数を渡すこともできます。
def my_method(name, █)
  block.call(name)
end
my_method("John") do |name|
  puts "Hello, #{name}!"
end
上記の例では、my_methodメソッドにブロックを渡し、ブロック引数に"name"を指定しています。
ブロック内で引数を使用するために、block.callで"name"を渡しています。
ブロック内では、引数として渡された"name"を使用して文字列を出力しています。
Procクラスは[]をオーバーロードしており。
def my_method(name, █)
  block[name]
end
と書くことも出来ます。
def my_method(name)
  yield(name)
end
my_method("John") do |name|
  puts "Hello, #{name}!"
end
上記の例では、my_methodメソッドに引数として"name"を渡し、yieldに"name"を引数として渡しています。
ブロック内では、引数として渡された"name"を使用して文字列を出力しています。
再帰を行う場合、通常はブロック引数を使用する方が適切です。再帰的な関数では、ブロック引数を使用することで、再帰呼び出しのたびに異なるブロックを渡すことができます。これにより、再帰呼び出しのたびに異なる処理を行うことが可能になります。
例えば、再帰的なメソッドを定義する際には、ブロック引数を使用して次の再帰呼び出し時に実行される処理を指定します。
def recursive_method(n, █)
  if n > 0
    # ブロックを実行
    block[n]
    # 再帰呼び出し
    recursive_method(n - 1, █)
  end
end
recursive_method(5) { |num| puts num }
このように、ブロック引数を使うことで、再帰呼び出し時に実行される処理を柔軟に指定することができます。これにより、再帰メソッドがより汎用的で柔軟なものになります。
Rubyでは、メソッド内でブロックが渡されたかどうかを判定する方法があります。これを行うには、block_given?メソッドを使用します。このメソッドは、メソッド内でブロックが渡された場合にtrueを返し、それ以外の場合にfalseを返します。
以下は、block_given?メソッドを使用してブロックが渡されたかどうかを判定する例です。
 
def method_with_block
  if block_given?
    puts "ブロックが渡されました"
    # yield が使えます
  else
    puts "ブロックが渡されていません"
    # yield は使えません
  end
end
method_with_block { puts "Hello, block!" }  # => ブロックが渡されました
method_with_block  # => ブロックが渡されていません
このように、block_given?メソッドを使うことで、メソッド内でブロックが渡されたかどうかを簡単に判定することができます。
ブロック引数を受け取るメソッドの呼び出しで、ブロック引数を省略した場合の戻り値は、Enumeratorオブジェクトとする慣習があります。
例えば、配列をeachメソッドで呼び出した場合、ブロックが省略されるとEnumeratorオブジェクトが返ります。
 
array = [2, 3, 5, 7]
enum = array.each
puts enum.class # => Enumerator
begin
  puts enum.next while true
rescue StopIteration => e
  puts e.inspect
end
    # => 2
    #    3
    #    5
    #    7
    #    #
enum2 = 10.upto(15)
loop do
  puts enum2.next
end
    # => 10
    #    11
    #    12
    #    13
    #    14
    #    15
loop は StopIteration をキャッチすると静かに繰り返しを終了します。
このように、eachメソッドがブロック引数を省略された場合、戻り値はイテレータとして機能するEnumeratorオブジェクトとなります。このオブジェクトは、コレクションの各要素を順番に処理するために使用されます。
典型的なブロック引数処理
  def inorder_traversal(node = @root, █)
    return to_enum(__method__, node) unless block
    def core(node, █)
      return if node.nil?
      core(node.left, █)
      yield node.value
      core(node.right, █)
    end
    core(node, █)
    self
  end
Rubyにおける「残余引数（rest argument）」とは、メソッド定義の中で最後の引数として指定され、そのメソッドに渡された全ての追加の引数を１つの配列として受け取る機能です。残余引数は、メソッドが可変長の引数を受け取ることを可能にします。
残余引数は、メソッド定義の引数の前にアスタリスク * を付けて指定されます。これにより、メソッドが受け取る引数の数を動的に決定することができます。
以下は、残余引数を使用する例です。
[https://paiza.io/projects/ieLAdVArMpdUwbnQ5z_oKQ?language=ruby rest-args.rb:]
def greet(greeting, *names)
  names.each { |name| puts "#{greeting}, #{name}!" }
end
greet("Hello", "Alice", "Bob", "Charlie")
この例では、greet メソッドは greeting という通常の引数と、*names という残余引数を持っています。greet メソッドは最初の引数を挨拶の文字列として受け取り、残りの引数を配列 names として受け取ります。その後、names 配列内の各要素に対して、挨拶と名前を組み合わせたメッセージを出力します。
残余引数を使用することで、メソッドが任意の数の引数を受け取る柔軟性が向上し、可読性の高いコードを記述することができます。
メソッド内で最後に評価される値が、そのメソッドの戻り値になります。例えば、次のようなメソッドを考えてみましょう。
def add(a, b)
  return a + b 
end
このメソッドは2つの引数を受け取り、それらの和を返します。return キーワードを使用して、明示的に戻り値を指定しています。このように return を使わずに値を返すと、メソッドの最後に評価された値が自動的に戻り値として返されます。
def add(a, b)
  a + b 
end
 
このように、明示的に return を書かなくても、メソッド内で最後に評価された値が自動的に戻り値となります。
さらに、１つの式からなる関数は = を使い end を伴わない構文で定義できます。
def add(a, b) = a + b 
メソッドを呼び出す際には、その戻り値を変数に代入したり、別のメソッドの引数として渡したりすることができます。
戻り値が必要な場合や、逆に必要ではない場合など、メソッドの設計時にはしっかりと考慮して実装する必要があります。
Rubyには4つのスコープがあります。以下にそれぞれのスコープとコード例を示します。
ローカルスコープ
変数が定義されたブロック内でしか使用できません。
def local_scope
  x = 10
  puts x # output: 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つのスコープです。
{{コラム|メソッドの引数リストを囲む括弧の省略|2=
メソッドの引数リストを囲む括弧 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_name、def 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クラスに swim、run、fly メソッドを定義しています。 swimメソッドは public、run メソッドは protected、fly メソッドは 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 という親クラスを作成し、 Dog と Cat という子クラスを作成しています。 Dog と Cat はそれぞれ speak メソッドを持っており、それぞれ異なる出力をします。
Dog と Cat は Animal クラスを継承しています。このため、 Dog と Cat も Animal クラスの 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!」という文字列が出力されます。
注目すべきは:
の２点です。
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の特異メソッドについてのチュートリアルです。オブジェクトに対して固有のメソッドを定義することで、便利なプログラミングをすることができます。
Go/メソッドとインターフェースの都市間の大圏距離を求めるメソッドを追加した例を、Rubyに移植しました。
[https://paiza.io/projects/Pr8BO96TMXQCuTybsTm3mg?language=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
なお、Rubyではダブルクォートで囲まれた文字列リテラル内でエスケープシーケンスが展開されますが、シングルクォートで囲まれた文字列リテラル内では展開されません。
Rubyにおける「文字リテラル」は、?を前置した1文字で表します。
p ?a         #==> "a"
p ?字        #==> "字"
p ?😈       #==> "😈"
p ?😈.class #==> String
Rubyに文字型はなく、文字リテラルは長さ１文字の文字列です。
Ruby では、文字列のエンコーディングを指定することができます。通常、UTF-8 エンコーディングが使われますが、別のエンコーディングを指定することもできます。
文字列のエンコーディングを指定するには、文字列の前に encoding: を付けて指定します。例えば、UTF-8 エンコーディングの文字列を扱う場合は以下のように書きます。
str = "こんにちは".encoding("UTF-8")
別のエンコーディングを指定する場合は、指定したいエンコーディング名を文字列で渡します。
str = "こんにちは".encoding("Shift_JIS")
上記のコードでは、文字列 "こんにちは" が Shift_JIS エンコーディングの文字列として扱われます。
文字列のエンコーディングを指定することで、文字列の変換時にエラーが発生することを防ぐことができます。
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の「シンボル(Symbol)」は、一度定義されたら変更できないイミュータブルなオブジェクトで、文字列に似たデータ型です。シンボルは、コロン(:)の後ろに名前を付けて表します。例えば、:appleや:bananaなどがシンボルの例です。
シンボルは、主にキーとして使われることが多く、文字列と比較して以下のようなメリットがあります。
シンボルは一度生成されたら変更できないため、ハッシュのキーとして使うときに、キーの値が変更される心配がありません。
同じ名前のシンボルは必ず同じオブジェクトIDを持つため、検索が高速になります。
文字列よりもメモリ消費量が少ないため、大量のデータを扱う場合や、ハッシュのキーとして多用する場合に有効です。
シンボルを使う場合、通常はコロン(:)をつけて定義しますが、:"apple"のようにダブルクォーテーション(")で囲って文字列から生成することもできます。また、文字列からシンボルを生成するには、to_symメソッドまたはinternメソッドを使います。
例えば、以下のようにハッシュのキーとしてシンボルを使うことができます。
 
fruits = { apple: 100, banana: 200, orange: 300 }
puts fruits[:banana]  # => 200
Rubyの配列（Array）は、複数の要素を順序付けて格納するためのデータ構造です。配列は、異なるデータ型の要素を混在させることができます。例えば、整数、文字列、オブジェクトなどを含めることができます。
Rubyの配列は、角かっこ [ ] で囲まれた要素のコンマ区切りのリストで表されます。以下は、Rubyの配列の例です。
numbers = [1, 2, 3, 4, 5]
fruits = ["apple", "banana", "orange"]
mixed_array = [1, "hello", true, 3.14]
配列内の要素は、0から始まるインデックスを使用してアクセスできます。例えば、numbers配列の最初の要素にアクセスするには、numbers[0]とします。
Rubyの配列は動的で、サイズを事前に宣言する必要はありません。要素を追加、削除、置換することができます。また、Rubyには多くの配列関連のメソッドが組み込まれており、配列を操作するための便利な機能が提供されています。
Rubyの配列には、さまざまな操作が可能です。以下にいくつかの一般的な操作を示します。
要素の追加と削除: <<演算子やpushメソッドを使用して要素を配列の末尾に追加できます。また、popメソッドを使用して末尾の要素を削除できます。他にも、unshiftメソッドを使って先頭に要素を追加したり、shiftメソッドを使って先頭の要素を削除したりすることもできます。
numbers << 6
fruits.push("grape")
numbers.pop
fruits.unshift("kiwi")
fruits.shift
要素の取得と変更: インデックスを使用して特定の要素にアクセスし、値を取得したり変更したりできます。
puts numbers[2] # 3を出力
fruits[1] = "pear"
配列の結合と分割: +演算子を使用して配列を結合したり、concatメソッドを使用したりして配列を結合できます。また、sliceメソッドを使用して配列を部分的に分割することもできます。
combined_array = numbers + fruits
part_of_fruits = fruits.slice(1, 2)
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メソッドで出力しています。
要素の検索とフィルタリング: include?メソッドを使用して特定の要素が配列に含まれているかどうかを確認したり、selectメソッドを使用して条件に一致する要素のみを抽出したりすることができます。
puts numbers.include?(3) # trueを出力
even_numbers = numbers.select { |num| num.even? }
配列操作メソッド: Rubyには、配列を操作するための便利なメソッドが豊富に用意されています。その中でも、map、filter、reduceは特によく使われるメソッドです。
numbers = [1, 2, 3, 4, 5]
doubled_numbers = numbers.map do |n|
  n * 2
end
p doubled_numbers #=> [2, 4, 6, 8, 10]
even_numbers = numbers.filter do |n|
  n.even?
end
p even_numbers #=> [2, 4]
sum = numbers.reduce do |result, n|
  result + n
end
puts sum #=> 15
ブロックの代わりにシンボルを使って、次のように書くこともできます。
puts numbers.reduce(&:+) #=> 15
これらはRubyの配列を操作するための基本的な操作の一部です。Rubyの配列にはさらに多くの機能がありますが、これらの基本操作から始めることができます。
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 
上の例ではパッターンを丸括弧()で囲みましたが、波括弧{}・角括弧[]で囲むことも出来、括弧でない文字（例えば!）で始めたら、同じ文字（この場合は!）で閉じることが出来ます。
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]
これらの例では、%記法の丸括弧 ()の部分を、波括弧 {}、角括弧 []、感嘆符 !、縦棒 | に置き換えています。%記法では、括弧以外にも様々な文字を使うことができますが、適切な文字を選んで使用することが重要です。
def print_subclasses(klass, indent = 0)
  subclasses = klass.subclasses
  return if subclasses.empty?
  subclasses.to_a.sort{|a,b| a.to_s <=> b.to_s}.each do |subclass|
    puts "#{"\t" * indent}#{subclass}"
    print_subclasses(subclass, indent + 1)
  end
end
print_subclasses(Object.superclass)
print_subclassesメソッドは、与えられたクラス（klass）のサブクラスを再帰的に表示します。indentはインデントレベルを表し、デフォルト値は0です。
subclassesメソッドは、指定されたクラスの直接のサブクラスを返します。
sortメソッドは、サブクラスをアルファベット順に並べ替えます。
eachメソッドは、サブクラスを1つずつ処理し、その名前を表示します。
print_subclassesメソッドを再帰的に呼び出すことで、サブクラスのサブクラスも同様に処理されます。
Object.superclassは、すべてのクラスの祖先であるObjectクラスから始まります。
最後に、print_subclasses(Object.superclass)を呼び出すことで、すべてのクラスの階層構造を表示します。
次は、Rubyの標準クラス階層を再帰的に表示するものです。各クラスはその直接のサブクラスとしてインデントされて表示されます。以下に各部分の解説を示します：
ObjectクラスはRubyのほとんどのクラスの祖先となる基本クラスです。
ARGF.class: コマンドライン引数やファイルからの入力を扱うクラスです。
Array: 配列を表すクラスです。
Binding: メソッド呼び出しのコンテキストを保持するオブジェクトを表すクラスです。
Complex::compatible: 複素数を表すクラスです。
DidYouMean以下のクラス群: ユーザーの入力ミスに対する修正候補を提案する機能を提供するモジュールです。
Dir: ディレクトリを扱うクラスです。
Encoding以下のクラス群: 文字エンコーディングを扱うクラスです。
Enumerator以下のクラス群: 列挙可能なオブジェクトを生成するためのクラスです。
ErrorHighlight以下のクラス群: エラーメッセージをハイライトする機能を提供するモジュールです。
Exception以下のクラス群: 例外を扱うためのクラスです。
FalseClass: 真でない値を表すクラスです。
Fiber: コルーチンを表すクラスです。
File::Stat: ファイルの状態を表すクラスです。
Gem以下のクラス群: RubyGemsを扱うためのクラスです。
Hash: ハッシュを表すクラスです。
IO以下のクラス群: 入出力を扱うクラスです。
MatchData: 正規表現のマッチング結果を表すクラスです。
Method: メソッドオブジェクトを表すクラスです。
Module以下のクラス群: モジュールを表すクラスです。
Monitor以下のクラス群: スレッドセーフな処理を実現するためのクラスです。
NameError::message: 名前エラーのメッセージを表すクラスです。
NilClass: nilを表すクラスです。
Numeric以下のクラス群: 数値を表すクラスです。
Integer整数を表すクラスです。
Complex複素数を表すクラスです。
Rational有理数を表すクラスです。
ObjectSpace::WeakMap: 弱参照を使ったハッシュマップを表すクラスです。
Proc: プロシージャやラムダを表すクラスです。
Process::Status: プロセスのステータスを表すクラスです。
Ractor以下のクラス群: Rubyの並行処理を実現するためのクラスです。
Random::Base以下のクラス群: 乱数生成を行うためのクラスです。
Range: 範囲を表すクラスです。
Regexp: 正規表現を表すクラスです。
RubyVM以下のクラス群: Rubyの仮想マシンを扱うクラスです。
String: 文字列を表すクラスです。
Struct: 構造体を表すクラスです。
Symbol: シンボルを表すクラスです。
Thread以下のクラス群: スレッドを扱うクラスです。
ThreadGroup: スレッドグループを表すクラスです。
Time以下のクラス群: 時刻を表すクラスです。
TracePoint: トレースポイントを表すクラスです。
TrueClass: 真の値を表すクラスです。
UnboundMethod: バインドされていないメソッドを表すクラスです。
Ractor::MovedObject: 移動されたオブジェクトを表すクラスです。
これはRubyの標準ライブラリで定義されたクラス階層を表しており、各クラスがどのような階層構造にあるかを示しています。
結果:
Object
	ARGF.class
	Array
	Binding
	Complex::compatible
	DidYouMean::ClassNameChecker
	DidYouMean::DeprecatedMapping
	DidYouMean::Formatter
	DidYouMean::KeyErrorChecker
	DidYouMean::MethodNameChecker
	DidYouMean::NullChecker
	DidYouMean::PatternKeyNameChecker
	DidYouMean::RequirePathChecker
	DidYouMean::SpellChecker
	DidYouMean::TreeSpellChecker
	DidYouMean::VariableNameChecker
	Dir
	Encoding
	Encoding::Converter
	Enumerator
		Enumerator::ArithmeticSequence
		Enumerator::Chain
		Enumerator::Lazy
	Enumerator::Generator
	Enumerator::Producer
	Enumerator::Yielder
	ErrorHighlight::DefaultFormatter
	ErrorHighlight::Spotter
	Exception
		ErrorHighlight::Spotter::NonAscii
		NoMemoryError
		ScriptError
			LoadError
				Gem::LoadError
					Gem::ConflictError
					Gem::MissingSpecError
						Gem::MissingSpecVersionError
			NotImplementedError
			SyntaxError
		SecurityError
		SignalException
			Interrupt
		StandardError
			ArgumentError
				Gem::Requirement::BadRequirementError
				UncaughtThrowError
			EncodingError
				Encoding::CompatibilityError
				Encoding::ConverterNotFoundError
				Encoding::InvalidByteSequenceError
				Encoding::UndefinedConversionError
			FiberError
			IOError
				EOFError
			IndexError
				KeyError
				StopIteration
					ClosedQueueError
					Ractor::ClosedError
			LocalJumpError
			Math::DomainError
			NameError
				NoMethodError
			NoMatchingPatternError
				NoMatchingPatternKeyError
			RangeError
				FloatDomainError
			RegexpError
			RuntimeError
				FrozenError
				Gem::Exception
					Gem::CommandLineError
					Gem::DependencyError
						Gem::DependencyResolutionError
						Gem::UnsatisfiableDependencyError
					Gem::DependencyRemovalException
					Gem::DocumentError
					Gem::EndOfYAMLException
					Gem::FilePermissionError
					Gem::FormatException
					Gem::GemNotFoundException
						Gem::SpecificGemNotFoundException
					Gem::GemNotInHomeException
					Gem::ImpossibleDependenciesError
					Gem::InstallError
						Gem::RuntimeRequirementNotMetError
					Gem::InvalidSpecificationException
					Gem::OperationNotSupportedError
					Gem::RemoteError
					Gem::RemoteInstallationCancelled
					Gem::RemoteInstallationSkipped
					Gem::RemoteSourceException
					Gem::RubyVersionMismatch
					Gem::UninstallError
					Gem::UnknownCommandError
					Gem::VerificationError
					Gem::WebauthnVerificationError
				IO::Buffer::AccessError
				IO::Buffer::AllocationError
				IO::Buffer::InvalidatedError
				IO::Buffer::LockedError
				Ractor::Error
					Ractor::IsolationError
					Ractor::MovedError
					Ractor::RemoteError
					Ractor::UnsafeError
			SystemCallError
				Errno::E2BIG
				Errno::EACCES
				Errno::EADDRINUSE
				Errno::EADDRNOTAVAIL
				Errno::EADV
				Errno::EAFNOSUPPORT
				Errno::EAGAIN
					IO::EAGAINWaitReadable
					IO::EAGAINWaitWritable
				Errno::EALREADY
				Errno::EBADE
				Errno::EBADF
				Errno::EBADFD
				Errno::EBADMSG
				Errno::EBADR
				Errno::EBADRQC
				Errno::EBADSLT
				Errno::EBFONT
				Errno::EBUSY
				Errno::ECANCELED
				Errno::ECHILD
				Errno::ECHRNG
				Errno::ECOMM
				Errno::ECONNABORTED
				Errno::ECONNREFUSED
				Errno::ECONNRESET
				Errno::EDEADLK
				Errno::EDESTADDRREQ
				Errno::EDOM
				Errno::EDOTDOT
				Errno::EDQUOT
				Errno::EEXIST
				Errno::EFAULT
				Errno::EFBIG
				Errno::EHOSTDOWN
				Errno::EHOSTUNREACH
				Errno::EHWPOISON
				Errno::EIDRM
				Errno::EILSEQ
				Errno::EINPROGRESS
					IO::EINPROGRESSWaitReadable
					IO::EINPROGRESSWaitWritable
				Errno::EINTR
				Errno::EINVAL
				Errno::EIO
				Errno::EISCONN
				Errno::EISDIR
				Errno::EISNAM
				Errno::EKEYEXPIRED
				Errno::EKEYREJECTED
				Errno::EKEYREVOKED
				Errno::EL2HLT
				Errno::EL2NSYNC
				Errno::EL3HLT
				Errno::EL3RST
				Errno::ELIBACC
				Errno::ELIBBAD
				Errno::ELIBEXEC
				Errno::ELIBMAX
				Errno::ELIBSCN
				Errno::ELNRNG
				Errno::ELOOP
				Errno::EMEDIUMTYPE
				Errno::EMFILE
				Errno::EMLINK
				Errno::EMSGSIZE
				Errno::EMULTIHOP
				Errno::ENAMETOOLONG
				Errno::ENAVAIL
				Errno::ENETDOWN
				Errno::ENETRESET
				Errno::ENETUNREACH
				Errno::ENFILE
				Errno::ENOANO
				Errno::ENOBUFS
				Errno::ENOCSI
				Errno::ENODATA
				Errno::ENODEV
				Errno::ENOENT
				Errno::ENOEXEC
				Errno::ENOKEY
				Errno::ENOLCK
				Errno::ENOLINK
				Errno::ENOMEDIUM
				Errno::ENOMEM
				Errno::ENOMSG
				Errno::ENONET
				Errno::ENOPKG
				Errno::ENOPROTOOPT
				Errno::ENOSPC
				Errno::ENOSR
				Errno::ENOSTR
				Errno::ENOSYS
				Errno::ENOTBLK
				Errno::ENOTCONN
				Errno::ENOTDIR
				Errno::ENOTEMPTY
				Errno::ENOTNAM
				Errno::ENOTRECOVERABLE
				Errno::ENOTSOCK
				Errno::ENOTSUP
				Errno::ENOTTY
				Errno::ENOTUNIQ
				Errno::ENXIO
				Errno::EOVERFLOW
				Errno::EOWNERDEAD
				Errno::EPERM
				Errno::EPFNOSUPPORT
				Errno::EPIPE
				Errno::EPROTO
				Errno::EPROTONOSUPPORT
				Errno::EPROTOTYPE
				Errno::ERANGE
				Errno::EREMCHG
				Errno::EREMOTE
				Errno::EREMOTEIO
				Errno::ERESTART
				Errno::ERFKILL
				Errno::EROFS
				Errno::ESHUTDOWN
				Errno::ESOCKTNOSUPPORT
				Errno::ESPIPE
				Errno::ESRCH
				Errno::ESRMNT
				Errno::ESTALE
				Errno::ESTRPIPE
				Errno::ETIME
				Errno::ETIMEDOUT
				Errno::ETOOMANYREFS
				Errno::ETXTBSY
				Errno::EUCLEAN
				Errno::EUNATCH
				Errno::EUSERS
				Errno::EXDEV
				Errno::EXFULL
				Errno::NOERROR
			ThreadError
			TypeError
			ZeroDivisionError
		SystemExit
			Gem::SystemExitException
		SystemStackError
		fatal
	FalseClass
	Fiber
	File::Stat
	Gem::BasicSpecification
		Gem::Specification
		Gem::StubSpecification
	Gem::Dependency
	Gem::ErrorReason
		Gem::PlatformMismatch
		Gem::SourceFetchProblem
	Gem::List
	Gem::PathSupport
	Gem::Platform
	Gem::Requirement
	Gem::StubSpecification::StubLine
	Gem::UnknownCommandSpellChecker
	Gem::Version
	Hash
	IO
		File
	IO::Buffer
	MatchData
	Method
	Module
		Class
		Refinement
	Monitor
	MonitorMixin::ConditionVariable
	NameError::message
	NilClass
	Numeric
		Complex
		Float
		Integer
		Rational
	ObjectSpace::WeakMap
	Proc
	Process::Status
	Ractor
	Random::Base
		Random
	Range
	Rational::compatible
	Regexp
	RubyVM
	RubyVM::AbstractSyntaxTree::Node
	RubyVM::InstructionSequence
	String
		DidYouMean::ClassNameChecker::ClassName
		Warning::buffer
	Struct
		#
		#
		Process::Tms
	Symbol
	Thread
		Process::Waiter
	Thread::Backtrace
	Thread::Backtrace::Location
	Thread::ConditionVariable
	Thread::Mutex
	Thread::Queue
		Thread::SizedQueue
	ThreadGroup
	Time
	Time::tm
	TracePoint
	TrueClass
	UnboundMethod
Ractor::MovedObject
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は、以下の形式のマークアップタグをサポートしています。
RDocの実行には、次のコマンドを使用します。
 
$ rdoc [options] [names...]
オプションには、ドキュメンテーションを生成するFormattersや、ドキュメント化するファイルの指定などが含まれます。namesには、ドキュメンテーションを生成するファイルまたはディレクトリを指定します。
以上が、RDocの構文解説です。
Ruby 3.3.0では、多くの重要な変更が導入されました。その中には、言語機能の改善、コアクラスの更新、標準ライブラリの更新、C APIの更新、実装の改善などが含まれます。
言語機能の変更：
匿名の可変長引数とキーワード可変長引数が引数として渡せるようになりました。
Procオブジェクトのdupとcloneメソッドが#initialize_dupおよび#initialize_cloneフックを呼び出すようになりました。
"Find pattern" が実験的ではなくなりました。
ブロック内での匿名パラメータの転送が制限されました。
匿名の可変長引数とキーワード可変長引数が引数として渡せるようになりました。
def example(*args, **kwargs)
  p args
  p kwargs
end
example(1, 2, 3, key1: 'value1', key2: 'value2')
Procオブジェクトのdupとcloneメソッドが#initialize_dupおよび#initialize_cloneフックを呼び出すようになりました。
proc_object = proc { |x| x * 2 }
cloned_proc = proc_object.clone
p cloned_proc.call(5)  # => 10
Range#overlap?メソッドが追加されました。
range1 = 1..5
range2 = 4..8
p range1.overlap?(range2)  # => true
Core classesの更新：
Array#packとString#unpackが未知のディレクティブに対してArgumentErrorを発生させるようになりました。
メソッドRange#overlap?が追加され、2つの範囲が重なっているかどうかを確認できるようになりました。
標準ライブラリの更新：
RubyGemsとBundlerが、必要なgemをGemfileやgemspecに追加せずにrequireした場合に警告を発生させるようになりました。
多くの標準ライブラリのバージョンが更新されました。
C APIの更新：
新しいAPIが導入されいくつかのAPUが廃止されました。
Postponed job APIが変更され、新しいAPIが追加されました。
実装の改善：
パーサーがBisonからLrama LALRパーサージェネレーターに置き換えられました。
GCとメモリ管理のパフォーマンスが大幅に向上しました。
YJITのパフォーマンスとメモリ使用量が改善されました。
MJITが削除され、代わりにRJITが導入されました。
これらの変更により、Ruby 3.3.0はより高速で効率的なバージョンになりました。
Ruby 3.2.0では、いくつかの重要な変更と新機能が導入されています。以下に概要を示します：
匿名の可変長引数とキーワード可変長引数が引数として渡せるようになりました。
単一の位置引数とキーワードを受け入れるProcは、自動的にスプラットしなくなりました。
明示的なオブジェクトに対する定数の割り当て評価順序が一貫性を持つようになりました。
"Find pattern" が実験的ではなくなりました。
restパラメータを持つメソッドが*argsを通じてキーワード引数を委譲する場合、ruby2_keywordsでマークする必要があります。
匿名の可変長引数とキーワード可変長引数が引数として渡せるようになりました。
def example(*args)
  p args
end
example(1, 2, 3)  # => [1, 2, 3]
単一の位置引数とキーワードを受け入れるProcは、自動的にスプラットしなくなりました。
proc_example = proc { |a, **kw| [a, kw] }
p proc_example.call(1, x: 2, y: 3)  # => [1, {:x=>2, :y=>3}]
明示的なオブジェクトに対する定数の割り当て評価順序が一貫性を持つようになりました。
class Foo; end
BAR = :baz
Foo::BAR = BAR
p Foo::BAR  # => :baz
"Find pattern" が実験的ではなくなりました。
restパラメータを持つメソッドが*argsを通じてキーワード引数を委譲する場合、ruby2_keywordsでマークする必要があります。
def target(**kw)
  p kw
end
ruby2_keywords def delegate(*args)
  target(*args)
end
delegate(a: 1, b: 2)  # => {:a=>1, :b=>2}
継承可能なファイバーストレージのためのFiber.[]とFiber.[]=が導入されました。
Thread、IO、Class、Data、Encoding、Enumerator、Exception、Hash、Integer、Kernel、MatchData、Module、Proc、Process、Regexp、Refinement、RubyVM::AbstractSyntaxTree、Set、String、Struct、Timeなどの新しいメソッドや機能が追加されました。
Bundler、CGI、Coverage、Date、ERB、FileUtils、IRB、Net::Protocol、Pathname、Socket、URIなどの更新と機能強化が行われました。
更新されたAPIや非推奨APIの除去、PRNGやスレッドの計装などのための新しいAPIが導入されました。
Kernel#autoloadにおける競合状態が解消されました。
Regexpマッチングのキャッシュベースの最適化が導入されました。
変数幅割り当てがデフォルトで有効化されました。
オブジェクトの形状を考慮した新しいインスタンス変数のキャッシングメカニズムが導入され、JITコードの生成が改善されました。
命令シーケンスのマーキングやメジャーコレクションの高速化が実装されました。
YJITが実験的な段階を抜け、複数のプラットフォーム（x86-64やarm64/aarch64など）をサポートするようになりました。
YJITはオブジェクトの形状を最適化するように改善され、物理メモリの遅延割り当てが導入されました。
MJITコンパイラがRubyで再実装され、フォークされたRubyプロセスで実行されるようになりました。
これらの変更と改善により、Rubyプログラミングのさまざまな側面でパフォーマンス、安定性、機能性が向上しました。ユーザーは、より良いエクスペリエンスと改善されたパフォーマンスのために、Ruby 3.2.0へのアップグレードを検討することが推奨されます。
Ruby 3.1.0の変更点は以下の通りです：
言語の変更点：
ブロック引数が、ブロックが別のメソッドに渡される場合は匿名であってもよくなりました。
ピン演算子は、式を受け取れるようになりました。
ピン演算子は、インスタンス、クラス、グローバル変数をサポートするようになりました。
1行のパターンマッチングが実験的ではなくなりました。
複数の代入の評価順序が単一の代入の評価順序と一貫性が持たされるようになりました。
ハッシュリテラルとキーワード引数では値を省略できるようになりました。
main-Ractor以外のRactorも、共有可能なオブジェクトを参照する場合はクラス/モジュールのインスタンス変数を取得できるようになりました。
無限メソッド定義でもコマンド構文が許可されるようになりました。
ブロック引数が、ブロックが別のメソッドに渡される場合は匿名であってもよくなりました。
def foo(&)
  bar(&)
end
ピン演算子は、式を受け取れるようになりました。
result = Prime.each_cons(2).lazy.find_all{_1 in [n, ^(n + 2)]}.take(3).to_a
ピン演算子は、インスタンス、クラス、グローバル変数をサポートするようになりました。
@n = 5
result = Prime.each_cons(2).lazy.find{_1 in [n, ^@n]}
1行のパターンマッチングが実験的ではなくなりました。
Parenthesesを省略できるようになりました。
[0, 1] => _, x
{y: 2} => y:
x #=> 1
y #=> 2
複数の代入の評価順序が単一の代入の評価順序と一貫性が持たされるようになりました。
foo[0], bar.baz = a, b
foo[0], bar.baz = a, b
ハッシュリテラルとキーワード引数では値を省略できるようになりました。
例: {x: x, y: y} を {x:, y:} と書けます。
コアクラスの更新：
Array、Class、Enumerable、Enumerator::Lazy、File、GC、Integer、Kernel、Marshal、MatchData、Method / UnboundMethod、Module、Process、Struct、String、Thread、Thread::Backtrace、Thread::Queue、Time、TracePointなどのクラスに変更が加えられました。
標準ライブラリの更新：
RubyGems、base64、benchmark、bigdecimal、bundler、cgi、csv、date、did_you_mean、digest、drb、erb、error_highlight、etc、fcntl、fiddle、fileutils、find、io-console、io-wait、ipaddr、irb、json、logger、net-http、net-protocol、nkf、open-uri、openssl、optparse、ostruct、pathname、pp、prettyprint、psych、racc、rdoc、readline、readline-ext、reline、resolv、rinda、ruby2_keywords、securerandom、set、stringio、strscan、tempfile、time、timeout、tmpdir、un、uri、yaml、zlibなどの更新があります。
C APIの更新、実装の改善、JIT（MJIT、YJIT）、静的解析、デバッガ、エラーハイライト、IRBの自動補完、その他の変更が含まれます。
Ruby 3.0.0には、多くの言語の変更点が含まれています。主な変更点を以下に示します：
キーワード引数と位置引数の分離： キーワード引数は位置引数と区別されるようになりました。これにより、Ruby 2.7で警告が発生していたコードは、ArgumentErrorが発生するか、異なる動作をするようになります。
Procの動作変更： 単一のrest引数とキーワードを受け入れるProcは、autosplattingの対象外となりました。これにより、単一のrest引数とキーワードを受け入れるProcの動作が統一されました。
Arguments forwardingの改善： Arguments forwarding（...）が前方の引数をサポートするようになりました。
パターンマッチングの改善： パターンマッチング（case/in）が実験的な段階から正式な機能に移行しました。また、一行のパターンマッチングも改良され、=>演算子が導入されました。
Endless method definitionの導入： Endless method definitionが導入され、メソッドをより簡潔に定義することができるようになりました。
文字列補間リテラルの変更： # frozen-string-literal: trueを使用している場合、文字列補間リテラルが凍結されなくなりました。
静的解析の導入： 静的解析の基盤が導入され、RBSというRubyプログラムのための型定義言語が導入されました。また、TypeProfというRubyプログラムのための型解析ツールも実験的な形で提供されます。
非推奨の警告の変更： 非推奨の警告はデフォルトで表示されなくなりました。
$SAFEと$KCODEの変更： $SAFEと$KCODEは通常のグローバル変数として振る舞い、関連するC-APIメソッドが削除されました。
yieldの変更： メソッド内のシングルトンクラス定義でのyieldは、警告ではなくSyntaxErrorとなりました。
クラス変数のアクセスの変更： 同じ定義でクラス変数が上書きされた場合、RuntimeErrorが発生するようになりました。
番号付きパラメータへの代入の変更： 番号付きパラメータへの代入は、警告ではなくSyntaxErrorとなりました。
def example(arg, kwarg:)
  puts arg
  puts kwarg
end
proc = ->(*rest, **kwargs) { [rest, kwargs] }
p proc.call(1, 2, a: 3, b: 4)
def forwarder(*args, **kwargs)
  receiver(*args, **kwargs)
end
def receiver(a, b:, c: nil)
  puts "a: #{a}, b: #{b}, c: #{c}"
end
forwarder(1, b: 2, c: 3) # => a: 1, b: 2, c: 3
case [1, 2]
in [1, x]
  puts x
end
def foo = puts "Hello"
foo # => Hello
foo = "foo #{Time.now}"
class MyClass
  @@var = 1
end
これらの変更点は、Ruby 3.0.0で導入された主な機能です。これにより、より安全で効率的なコーディングが可能になり、言語の進化が促進されました。
エラトステネスの篩を、若干 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)
def gcd(*ints) = ints.reduce(&method(:gcd2))
def lcm2(m, n) = m * n / gcd2(m, n)
def lcm(*ints) = ints.reduce(&method(:lcm2))
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 らしく書いてみました。
[https://paiza.io/projects/9R72T8PZ3vDlXJXq08FgeA?language=ruby 二分法]:
def bisection(low, high, &f)
  x = (low + high) / 2.0
  fx = f[x]
  return x if fx.abs < 1.0e-10
  case fx <=> 0
  when -1 then low = x
  when 1  then 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 に移植しました。