Ruby基礎
命名について
①1語の変数名は全て小文字で書く
num
②2語の変数名は、アンダーバーで繋げて全て小文字で書く
この書き方を『スネークケース』といいます。
user_list
③定数を記載する場合は1文字目だけでなく、すべて大文字で記載する
定数では、プログラム中で変わらない固定の値を宣言します。
しかし他の言語と異なり、Rubyの定数は後から変えることができるため、
定数の値が変更されないよう、freezeメソッドを使用すると良いです。
# freezeを使用しない例
irb(main):001:0> STRING = "test"
=> "test"
irb(main):002:0> STRING.upcase!
=> "TEST"
irb(main):003:0> STRING
=> "TEST"
# freezeを使用する例
irb(main):001:0> STRING = "test".freeze
=> "test"
irb(main):002:0> STRING.upcase!
Traceback (most recent call last):
5: from /Users/yuya/.rbenv/versions/2.6.4/bin/irb:23:in `<main>'
4: from /Users/yuya/.rbenv/versions/2.6.4/bin/irb:23:in `load'
3: from /Users/yuya/.rbenv/versions/2.6.4/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
2: from (irb):2
1: from (irb):2:in `upcase!'
FrozenError (can't modify frozen String)
# freezeを使用したので変数の値自体を変更する`upcase!`のようなメソッドは実行できなくなっている。
irb(main):003:0> STRING
=> "test"
ただしfreezeを使用しても再代入はできます。
※ 定数を使っている場合は警告が表示されます。
irb(main):001:0> STRING = "test".freeze
=> "test"
irb(main):002:0> STRING = "change"
(irb):2: warning: already initialized constant STRING
(irb):1: warning: previous definition of STRING was here
=> "change"
irb(main):003:0> STRING
=> "change"
④変数名の1文字目に数字は使用できない
1user = 'test user'
Traceback (most recent call last):
3: from /Users/yuya/.rbenv/versions/2.6.4/bin/irb:23:in `<main>'
2: from /Users/yuya/.rbenv/versions/2.6.4/bin/irb:23:in `load'
1: from /Users/yuya/.rbenv/versions/2.6.4/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
SyntaxError ((irb):4: syntax error, unexpected tIDENTIFIER, expecting end-of-input)
1user = 'test user'
^~~~
条件分岐、繰り返し処理
if else文で複数の条件を処理する
if num <= 4
num += 2
else
num -= 2
end
上記コードは以下のように書き換えられるように見えますが、例えばnumに3が入ってた場合、
1つ目のif文でnumは5となるため、2つ目のif文にも入ってしまいます。
num += 2 if num <= 4
num -= 2 if num > 4
元々のコードはifまたはelseに該当するどちらかの処理しか行われません。
後置ifで記載したコードでは、条件の判定がそれぞれ別に行われるため、どちらの処理も実行される場合があります。
ifの条件式においてnilはfalseとして扱われる
つまり、nilの場合は条件式が偽と評価されます。
array = [1, 2, nil, 4, 5]
array.each do |element|
if element
puts "Element: #{element}"
else
puts "Element is nil"
end
end
unlessを使い「〜では無い場合」の条件を処理する
num = 3
unless num == 3
puts "3ではありません"
else
puts "3です"
end
# 3です
$var = false
print "3です" unless $var
# 3です
繰り返し処理
以下のコードを実行すると、xは7, yは2となる。
3.timesは2回、合計6回実行されます。
x = 0
y = 0
2.times do
3.times do
x = x + 1
end
y = y + 1
end
x = x + 1
case文
$age = 5
case $age
when 0 .. 2
puts "赤ちゃん"
when 3 .. 6
puts "幼児"
when 7 .. 12
puts "子供"
when 13 .. 18
puts "青年"
else
puts "大人"
end
# 幼児
オブジェクト
オブジェクトは、変数と、オブジェクトにアクセスして実行できる関数(メソッド)で構成されています。
Rubyでは、ほとんどのものがオブジェクトとして表現されます。文字列、数値、配列、ハッシュなどのデータ型は、すべてオブジェクトです。
オブジェクトは、クラスのインスタンスであり、そのクラスが持つ属性(インスタンス変数)とメソッド(インスタンスメソッド)にアクセスすることができます。
インスタンスは、クラスから new メソッドで生成されます。
# 文字列オブジェクトの作成
str = "Hello, Ruby!"
# 文字列の長さを取得
length = str.length
puts length # 出力: 12
# 文字列を大文字に変換
upcase_str = str.upcase
puts upcase_str # 出力: HELLO, RUBY!
文字列オブジェクトはStringクラスのインスタンスであり、文字列に関連する属性やメソッドにアクセスできます。
上記の例では、文字列オブジェクトを作成し、lengthメソッドを使って文字列の長さを取得し、upcaseメソッドを使って文字列を大文字に変換しています。
クラス
クラスは、オブジェクト指向プログラミングにおいて、オブジェクトを作成するための設計図やテンプレートです。クラスは属性とメソッドを持ち、それらの共通の特性を表現します。
Rubyでは、classキーワードを使用して新しいクラスを定義します。クラス名は大文字で始める慣習があります。
class BankAccount
def initialize ()
end
def test_method
puts "テストメソッド"
end
end
# accountオブジェクトを作成する
# クラスに属するオブジェクトは、そのクラスの「インスタンス」である
account = BankAccount.new
account.test_method
テストメソッド
配列
要素の追加
array = [1, 2, 3]
array << 4
array.push(5)
puts array # [1, 2, 3, 4, 5] を出力
array = [2, 3, 4, 5]
array.unshift(1)
puts array.inspect # 出力: [1, 2, 3, 4, 5]
要素の削除
array = [1, 2, 3, 4, 5]
array.pop
puts array # [1, 2, 3, 4] を出力
array.delete_at(1)
puts array # [1, 3, 4] を出力
array = [1, 2, 3, 4, 5]
shifted_element = array.shift
puts shifted_element # 出力: 1
puts array.inspect # 出力: [2, 3, 4, 5]
配列の長さの取得
array = [1, 2, 3, 4, 5]
puts array.length # 5 を出力
puts array.size # 5 を出力
配列の反復処理
array = [1, 2, 3, 4, 5]
array.each do |element|
puts element
end
# 1
# 2
# 3
# 4
# 5
new_array = array.map do |element|
element * 2
end
puts new_array # [2, 4, 6, 8, 10] を出力
配列から最大値を見つける
def find_max(array)
max = array[0]
array.each do |element|
max = element if element > max
end
return max
end
array = [3, 8, 2, 5, 1]
puts find_max(array) # 8 を出力
配列の要素を逆順に並び替える
def reverse_array(array)
reversed_array = []
i = array.length - 1
while i >= 0
reversed_array << array[i]
i -= 1
end
return reversed_array
end
array = [1, 2, 3, 4, 5]
puts reverse_array(array) # [5, 4, 3, 2, 1] を出力
break
array = [1, 2, 3, 4, 5]
array.each do |element|
break if element == 3
puts element
end
# 1
# 2
next
array = [1, 2, 3, 4, 5]
array.each do |element|
next if element == 3
puts element
end
# 1
# 2
# 3
# 4
配列の差分
array1 = [1, 2, 3, 4, 5]
array2 = [3, 4, 5, 6, 7]
result = array1 - array2
puts result # [1, 2] を出力
# array1には含まれているがarray2には含まれていない要素が残る
class Array
def difference(other)
self.reject { |element| other.include?(element) }
end
end
array1 = [1, 2, 3, 4, 5]
array2 = [3, 4, 5, 6, 7]
result = array1.difference(array2)
puts result # [1, 2] を出力
「!」が付くメソッド
Rubyでは、メソッド名の末尾に「!」を追加することで、そのメソッドが破壊的な操作を行うことを示します。破壊的な操作とは、元のオブジェクトを変更する操作のことです。
array = [3, 1, 2]
sorted_array = array.sort
puts sorted_array.inspect # 出力: [1, 2, 3]
puts array.inspect # 出力: [3, 1, 2](元の配列は変更されていません)
array.sort!
puts array.inspect # 出力: [1, 2, 3](元の配列がソートされました)
ハッシュ
ハッシュ(Hash)はキーと値のペアを格納するデータ構造です。キーと値の組み合わせを保持し、キーを使用して値を取得したり、新しいキーと値を追加したりすることができます。
hash = { key: value }
hash = { "key1" => "value1", "key2" => "value2" }
puts hash["key1"] # 出力: value1
puts hash["key2"] # 出力: value2
hash["key3"] = "value3" # ハッシュに新しいキーと値を追加
hash["key2"] = "new value" # 既存のキーの値を更新
puts hash.length # 出力: 3
puts hash.size # 出力: 3
# 反復処理
hash.each do |key, value|
puts "#{key}: #{value}"
end
# 削除:
hash.delete("key2") # キー "key2" とその値を削除
merge
マージによって、複数のハッシュのキーと値を組み合わせて1つのハッシュにまとめることができます。
hash1 = { name: "John", age: 30 }
hash2 = { city: "New York", country: "USA" }
merged_hash = hash1.merge(hash2)
puts merged_hash.inspect
# 出力: { name: "John", age: 30, city: "New York", country: "USA" }
hash1 = { name: "John", age: 30 }
hash2 = { name: "Alice", city: "New York" }
merged_hash = hash1.merge(hash2)
puts merged_hash.inspect
# 出力: { name: "Alice", age: 30, city: "New York" }
# hash2 の "name" キーの値 "Alice" が hash1 の "name" キーの値 "John" を上書き
複数のハッシュをマージする際、同じキーが存在する場合には、マージされるハッシュの値が優先されます。
メソッド
メソッド(Method)は処理のまとまりを再利用可能な形で定義するための機能です。メソッドを使用することで、同じ処理を繰り返し実行することなく、コードの再利用性と保守性を高めることができます。
def say_hello
puts "Hello, world!"
end
say_hello # Hello, world!
puts say_hello # Hello, world!
# 引数を渡す
def greet(name)
puts "Hello, #{name}!"
end
greet("Alice") # 出力: Hello, Alice!
greet("Bob") # 出力: Hello, Bob!
def add_numbers(a, b)
sum = a + b
return sum
end
result = add_numbers(3, 4)
puts result # 出力: 7
def add_numbers(a, b)
sum = a + b
return sum # メソッドの戻り値の指定
end
result = add_numbers(3, 4)
puts result # 出力: 7
returnでメソッドの早期終了
def check_even(num)
return false if num % 2 != 0
puts "#{num} is an even number."
true
end
check_even(3) # 出力: false
check_even(4) # 出力: 4 is an even number. # 出力: true
デフォルト値(Default Values)
デフォルト値は、メソッドの引数に予め値を設定することを意味します。メソッドを呼び出す際に引数の値が指定されなかった場合、デフォルト値がその引数に適用されます。
引数にデフォルト値を設定すると、メソッドの呼び出し時に引数を省略できます。
def greet(name = "Guest")
puts "Hello, #{name}!"
end
greet("Alice") # 出力: Hello, Alice!
greet # 出力: Hello, Guest!
キーワード引数(Keyword Arguments)
キーワード引数は、メソッドの呼び出し時に引数をキーワードと値のペアとして指定する機能です。通常の引数の位置に依存せず、キーワードに基づいて引数を指定することができます。
** Positional arguments require that the order in which we pass arguments when calling the method must match the order in which the parameters are set in the method definition. If we were to pass arguments in the method call in an order which did not match the parameter order in the method definition, we would get an 'undefined method' error. It could get difficult to keep track of the order if the number of parameters grows bigger.
** Keyword arguments are an alternative to positional arguments and resemble hash syntax.
def create_user(name:, age:)
puts "User name: #{name}, Age: #{age}"
end
create_user(name: "Alice", age: 25)
# 出力: User name: Alice, Age: 25
キーワード引数は引数の順序に依存せず、可読性を向上させるために使用されます。また、キーワード引数にはデフォルト値を設定することもできます。
def create_user(name:, age: 18)
puts "User name: #{name}, Age: #{age}"
end
create_user(name: "Bob")
# 出力: User name: Bob, Age: 18
スコープ
ローカルスコープ(Local Scope):
ローカルスコープは、メソッドやブロック内で定義された変数やブロック引数が有効な範囲です。ローカルスコープ内で定義された変数は、そのスコープ内でのみアクセス可能です。
def example_method
x = 10 # ローカル変数 x を定義
puts x # ローカル変数 x の値を出力
end
example_method # 出力: 10
puts x # エラー: undefined local variable or method `x' for main:Object
上記の例では、example_method
メソッド内で変数 x
を定義しています。この変数はメソッド内でのみアクセス可能であり、メソッドの外部で参照しようとするとエラーが発生します。
インスタンススコープ(Instance Scope):
インスタンススコープは、インスタンスメソッド内で使用されるインスタンス変数の範囲です。インスタンス変数は、そのインスタンス自体に固有の属性を表すために使用されます。
class ExampleClass
def initialize
@x = 10 # インスタンス変数 @x を定義
end
def example_method
puts @x # インスタンス変数 @x の値を出力
end
end
example = ExampleClass.new
example.example_method # 出力: 10
puts example.x # エラー: undefined method `x' for #<ExampleClass:0x00007fbef51a04f0>
上記の例では、ExampleClass
クラス内でインスタンス変数 @x
を定義しています。この変数はインスタンスメソッド内でのみアクセス可能であり、インスタンス自体からアクセスする場合は @
をつけて参照します。
クラススコープ(Class Scope):
クラススコープは、クラス定義内で使用されるクラス変数やクラスメソッドの範囲です。クラス変数はクラス全体で共有される変数であり、クラスメソッドはクラス自体に関連付けられたメソッドです。
class ExampleClass
@@count = 0 # クラス変数 @@count を定義
def initialize
@@count += 1 # クラス変数 @@count の値をインクリメント
end
def
self.get_count
@@count # クラス変数 @@count の値を返す
end
end
example1 = ExampleClass.new
example2 = ExampleClass.new
puts ExampleClass.get_count # 出力: 2
上記の例では、ExampleClass
クラス内でクラス変数 @@count
を定義し、インスタンスが生成される度にその値をインクリメントしています。クラスメソッド get_count
からはクラス変数にアクセスできます。
グローバルスコープ(Global Scope):
グローバルスコープは、プログラム全体で有効な範囲です。グローバル変数やトップレベルのメソッドは、どこからでもアクセス可能です。
$global_var = 10 # グローバル変数 $global_var を定義
def global_method
puts $global_var # グローバル変数 $global_var の値を出力
end
global_method # 出力: 10
puts $global_var # 出力: 10
上記の例では、グローバル変数 $global_var
を定義し、それを参照するメソッドを定義しています。グローバル変数はどこからでもアクセス可能であり、変更もできます。
モジュール
Rubyでは、モジュール(Module)はクラスと似たような機能を持つ構造ですが、インスタンスを作成することはできません。モジュールは主に以下の目的で使用されます。
- 名前空間(Namespace)の作成: モジュールを使用することで、クラスやメソッドの名前が衝突するのを防ぐことができます。例えば、複数のライブラリやGemが同じ名前のクラスを持っていた場合、モジュールを使用することでそれらを区別することができます。
モジュール内に定義されたクラスやメソッドは、そのモジュール名を接頭辞として持ち、同じ名前のクラスやメソッドでも異なるモジュール内では独立して存在できます。
module NamespaceA
class MyClass
def my_method
puts "Hello from NamespaceA"
end
end
end
module NamespaceB
class MyClass
def my_method
puts "Hello from NamespaceB"
end
end
end
a = NamespaceA::MyClass.new
a.my_method # 出力: "Hello from NamespaceA"
b = NamespaceB::MyClass.new
b.my_method # 出力: "Hello from NamespaceB"
上記の例では、NamespaceA
モジュールと NamespaceB
モジュール内に同名の MyClass
クラスと my_method
メソッドが定義されています。しかし、それぞれのネームスペース内では独立して存在しており、名前の衝突が回避されています。
ネームスペースは、コードの可読性、保守性、拡張性を向上させるために使用されます。特に大規模なプロジェクトや複数の開発者が協力して開発を行う場合には、ネームスペースをうまく活用することが重要です。
- Mixin: モジュールは他のクラスにミックスイン(混ぜ込む)することができます。これにより、同じ機能を複数のクラスで共有することができます。モジュールのメソッドはインスタンスメソッドとして使われることはなく、クラスメソッドや特異メソッドとして利用されます。
module MyModule
def my_method
puts "This is a module method."
end
end
class MyClass
include MyModule
end
obj = MyClass.new
obj.my_method # "This is a module method." と出力される
モジュールは単体でインスタンスを作成することができないため、継承関係を持ちません。そのため、モジュールの中でインスタンス変数を定義することはできませんが、モジュール内で定義されたメソッドは他のクラスやモジュールから利用することができます。