Open9

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"

https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md#screaming-snake-case

④変数名の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
# 幼児

https://www.sejuku.net/blog/11835

🦓🦓

オブジェクト

オブジェクトは、変数と、オブジェクトにアクセスして実行できる関数(メソッド)で構成されています。
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)はクラスと似たような機能を持つ構造ですが、インスタンスを作成することはできません。モジュールは主に以下の目的で使用されます。

  1. 名前空間(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 メソッドが定義されています。しかし、それぞれのネームスペース内では独立して存在しており、名前の衝突が回避されています。

ネームスペースは、コードの可読性、保守性、拡張性を向上させるために使用されます。特に大規模なプロジェクトや複数の開発者が協力して開発を行う場合には、ネームスペースをうまく活用することが重要です。

  1. 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." と出力される

モジュールは単体でインスタンスを作成することができないため、継承関係を持ちません。そのため、モジュールの中でインスタンス変数を定義することはできませんが、モジュール内で定義されたメソッドは他のクラスやモジュールから利用することができます。