Progate +α メモず 【Ruby】

# はじめに
Progate楽しいマンです。
[最近学んだことリスト【主にCSS】](https://qiita.com/kohki_takatama/items/f3a516bece97ea407435)に続き、Rubyをやりました。
今回は1つの記事にまとまった！あと、少し見やすく書けました。(^^)
相変わらずなっがいので、気になった見出しがあれば見てみてください。
# メモず
### Rubyの`"`と`'`は区別なし
言語によっては区別あるので……Rubyは緩い方。
### コメントは`#`
シンプルですこ (^^)
### 余り計算は`%`でOK
`` `mod` ``も好きだけどね
### Rubyの`puts`の挙動一覧
```rb
puts "str " int # 間違った構文
puts "str ", int # "str"<br>int
puts "str #{int}" # str int テンプレート記法
puts 'str #{int}' # str #{int} シングルクォーテーション（'）だとテンプレート記法と認識しない。
```
テンプレート記法は`"`の中に`#{}`で書くことができる。
文字列と同じ書き方でできる、最高です(^^)
Javascriptでは`` ` ``の中に`${}`なので混同しないように注意。
### Rubyの変数は`varname =`で特定の宣言文はない
### 変数名はキャメルケースではなくスネークケース
俺のキャメルケースが……
### `+=`は可能
### `else if`ではなく`elsif`
ちょっとキモい……
### 倫理演算子は ` ==`, `!=`, `&&`, `||`
` ===`じゃなくていい！素晴らしい！
`or`は`||`なので、二個にするの忘れないように。
全部２個だと見た目がそろうのでいいね！素晴らしい設計。
### each / for of 文：`arr.each do |e|`
### 連想配列は`{"key"=>value, ...}`or`{:key=>value}`or`{key:value}
JSと違い、`key`を`"`で囲わなきゃいけない。`key`を文字列にしなかった場合は、変数として扱われる（まじかよ）
```rb
key = "name"
hash = {key => "John Doe"}
```
> この場合、`hash` のキーは `"name"` の文字列となります

Ruby1.9以降では、以下の構文が導入
```rb
hash = {key: value} #キーは:keyシンボル
```
#### シンボル`:key`と文字列`"key"`の違いって？
##### シンボルと文字列の違い

1. **イミュータビリティ（変更不可能性）**:
    
    - **文字列**: 文字列は変更可能です。例えば、`str = "hello"` とした後で `str[0] = "H"` により `str` を `"Hello"` に変更できます。
    - **シンボル**: シンボルはイミュータブル（変更不可能）です。一度作成されると、その値は変更できません。
2. **オブジェクトID**:
    
    - **文字列**: 同じ内容の文字列でも、それぞれが異なるオブジェクトとして作成されます。つまり、毎回新しいメモリが割り当てられます。
    - **シンボル**: 同じ内容のシンボルはアプリケーション全体で同じオブジェクトを参照します。これにより、メモリ使用効率が良くなります。
3. **パフォーマンス**:
    
    - **文字列**: 文字列の比較は内容を1文字ずつチェックするため、比較に時間がかかることがあります。
    - **シンボル**: シンボルの比較はオブジェクトIDの比較になるため、高速です。

##### 混同した場合の影響

- **ハッシュのキーとしての使用**: Rubyではハッシュのキーとして文字列とシンボルのどちらも使用できますが、これらは異なるキーとして扱われます。たとえば、`{ :key => "value1" }` と `{ "key" => "value2" }` は異なるキーを持つハッシュです。これらを混同すると、意図しない挙動を引き起こす可能性があります。
    
- **メモリ使用**: 文字列を頻繁に作成すると、同じ内容でも異なるオブジェクトがメモリ上に作成されるため、メモリ使用量が増加します。一方、シンボルは同じ内容であれば同じオブジェクトを再利用するため、メモリ効率が良いです。
    
- **変更可能性**: 文字列は変更可能なので、アプリケーションの状態を変更する可能性があります。シンボルは変更不可能なので、このような副作用はありません。
### Rubyでは`nil` と `false` 以外のすべての値は真と評価される
つまり、`undefined`が存在しない。
例えば、連想配列の存在しないキーにアクセスした場合、JSだと`undefined`を返すが、Rubyだと`nil`を返す。
豆知識：JSの`null`、Rubyの`nil`は`falsy`と呼び、`false`ではないが`false`として扱われることがある。
### `&.`演算子
  
Rubyの場合、ハッシュに存在しないキーにアクセスしたときは `nil` が返されるので、一般的には安全です。ただし、その後に `nil` に対してメソッドやさらなるキーへのアクセスを試みるとエラーが発生します。したがって、`element[:values]` が `nil` でないことを確認することは重要ですが、より簡潔に書く方法もあります。

例えば、以下のように `&.` 演算子（セーフナビゲーション演算子）を使用すると、`element[:values]` が `nil` の場合には、それに続くメソッド呼び出しが無視されます：

```rb
array = [{values: {a: "v", b: "v2"}}, ...]

array.each do |element|
  puts element[:values]&.[](:b) 
  #[](:key)は[:key]のもともとの形。ここではメソッド呼び出しをしている。
end

```


この場合、`element[:values]` が `nil` であれば、`[:b]` の呼び出しは無視され、`nil` が返されます。これにより、`element[:values]` が存在しない場合にエラーを防ぐことができます。また、`element[:values]` が存在していても、それがハッシュであり `:b` キーが存在しない場合には、やはり `nil` が返されます。

この方法は、Ruby 2.3 以降で利用可能です。それ以前のバージョンでは、条件分岐を使用してキーの存在を確認する必要があります。
### `hash[:key]`は`hash.[](:key)`の糖衣構文
そうなん！！いわれてみれば確かに🦀
#### `[](:b)` と `[:b]` の違い

`element[:values]&.[](:b)` と `element[:values]&.[:b]` は実質的に同じ動作をします。ただし、`&.` 演算子を使用してメソッド呼び出しを行う場合、`[](:b)` の形式を使用することで、`element[:values]` が `nil` であった場合にメソッド呼び出しを無視することができます。一方で、`element[:values]&.[:b]` は文法的に不正です。

`element[:values]&.[:b]` ではなく `element[:values]&.[](:b)` を使用する理由は、セーフナビゲーション演算子 `&.` がメソッド呼び出しにのみ適用されるためです。`[:b]` はハッシュのキーへのアクセスを示すブラケット構文ですが、これを直接 `&.` と組み合わせることはできません。そのため、メソッド呼び出しの形式 `[](:b)` を使用します。
### Rubyには`function`という概念がない！！
すべてメソッドと呼ばれる。
### 命名規則：真偽値を返すメソッドは末尾に`?`をつける
`negative?`など
### キーワード引数※超便利！！全オブジェクト指向言語に導入すべき
それに対して、普通のを`位置引数`と呼ぶ。
キーワード引数は
```rb
def method(arg1:, arg2:)
	puts "#{arg1}, #{arg2}"
end

method(arg2:"hoge", arg1:"ruby")
method("ruby", "hoge") #error. キーワード引数は位置引数として呼び出せない。
```
これで機能する。すごい。
あと、発展形として
```rb
def method(arg1, arg2:"arg2!!")
	puts "#{arg1}, #{arg2}"
end

method("ruby", arg2:"hoge") # ruby, hoge
method("ruby") # ruby, arg2!! ※初期値arg2!!が設定されているため
method(arg2:"hoge", "ruby") #error. キーワード引数は位置引数の後。
```
初期値の設定、キーワード引数と位置引数の混合も可能。
どっちも便利だなあ……
毎回呼び出さない、いわばアディショナルになる引数はキーワードで初期値を設定しておいて、それ以外は位置引数で毎回渡す、ってことが可能
例
```rb
#今日の日付を取得
today = Date.today
#日記を保存する
def diary(title, content, date:today)
	#日記を作成。日付がdate, タイトルがtitle, 内容がcontent
end

#今日の日記
diary("rubyを学んだ", "キーワード引数とか、おもしろいことがいっぱいあった") 
#書き忘れた昨日の日記
diary("CSSを学んだ", "デザインって、やっぱ楽しいなと思った", date:"2024-01-12") 
```

なお、初期値の設定はJSでもできるようになってたっぽい（ES6）
知らなかった……
```js
function greet(name, greeting = "Hello") {
  return `${greeting}, ${name}!`;
}

console.log(greet("Alice"));          // "Hello, Alice!"
console.log(greet("Alice", "Hi"));    // "Hi, Alice!"
```
### 命名規則：クラスは大文字で始める
`class Menu`てきな

### ﾎﾞｸが苦手な「クラス」という概念
#### `@`：インスタンス変数
オブジェクトごとに存在する変数
#### `initialize`：コンストラクタ
`new`したときに実行されるメソッド。rubyでは`def initialize`
例
```rb
class Person
  def initialize(name, age)
    @name = name  # インスタンス変数の設定
    @age = age    # インスタンス変数の設定
  end

  def greet
    "Hello, my name is #{@name} and I am #{@age} years old."
  end
end

# クラスからオブジェクトを生成
alice = Person.new("Alice", 30)

# オブジェクトのメソッドを呼び出す
puts alice.greet  # => "Hello, my name is Alice and I am 30 years old."
```
なお、`@name = name`と`self.name = name`どちらでも機能するが、大きな違いがある。
##### `@name = name`
- `@name = name` は、インスタンス変数 `@name` にローカル変数 `name` の値を直接割り当てます。
- この表現は、Rubyのインスタンス変数に直接アクセスし、値を設定する最も基本的な方法です。
##### `self.name = name`
- `self.name = name` は、`name=` という名前のセッターメソッドを呼び出し、そのメソッドを通じて `@name` インスタンス変数に値を設定します。
- この方法は、`attr_accessor` または `attr_writer` によって自動的に生成されたセッターメソッドを利用します。
- セッターメソッドを通じて値を設定することで、追加の検証や処理を行うことができます。
##### どちらを使用するべきか
- **直接割り当て (`@name = name`)**: 値を直接設定するだけの場合、または特別な検証や処理が不要な場合に適しています。
- **セッターメソッド経由 (`self.name = name`)**: セッターメソッドに特別なロジック（例えば、検証、変換、ロギングなど）が含まれている場合に適しています。また、将来的にセッターメソッドの挙動を変更する可能性がある場合にも有用です。
#### `attr_accessor`：ゲッターとセッターを設定
**アトリビュート**（属性・プロパティ）への**アクセサ**を設定する。
具体的には以下の２つ
- **ゲッターメソッド**: インスタンス変数の値を取得するメソッド
- **セッターメソッド**: インスタンス変数に値を設定するメソッド
例
```rb
class Person
  attr_accessor :name, :age

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

person = Person.new("Alice", 30)
puts person.name  # => Alice #ゲッターメソッド
person.name = "Bob" #セッターメソッド
puts person.name  # => Bob 
```
類似メソッドとして、以下のものがある
- `attr_reader`: ゲッターメソッドのみを生成
- `attr_writer`: セッターメソッドのみを生成
  なんでわざわざ`attr_accessor`と記述しないと記述しないとアクセスできないの？
  不便じゃない？と思ったｷﾐ！
  **危険なのだ！不必要なアクセスはバグの温床なのだ！**
#### インスタンスメソッド
`new`でインスタンスを作った後に使われるメソッド
インスタンスから呼び出す。当然クラスからは呼び出せない。
例
```rb
class Person
  def initialize(name)
    @name = name
  end

  def greet #インスタンスメソッド
    "Hello, my name is #{@name}"
  end
end

alice = Person.new("Alice")
puts alice.greet  # => "Hello, my name is Alice"
```
なお、`initialize`もインスタンスメソッドに属する。ただし直接呼び出すことはできない。
#### クラスメソッド
クラス自体に属するメソッド。インスタンスからは呼び出せない。
`def self.method_name`や`class名`を用いて定義される。
例
```rb
class Person
  def self.describe #Person.describeでも同じ。ただ、selfの方がクラス名の変更に対応できる。
    "This is a Person class"
  end
end

puts Person.describe # => "This is a Person class"

me = Person.new
puts me.describe  # これはエラーになります
```
クラシックな例
```rb
class MyClass
  @class_instance_var = "初期値"

  # クラスインスタンス変数へのアクセス用のクラスメソッド
  def self.class_instance_var
    @class_instance_var
  end

  # クラスインスタンス変数を設定するためのクラスメソッド
  def self.class_instance_var=(value)
    @class_instance_var = value
  end
end

# クラスメソッドを通じてクラスインスタンス変数を取得
puts MyClass.class_instance_var  # => "初期値"

# クラスメソッドを通じてクラスインスタンス変数を設定
MyClass.class_instance_var = "新しい値"
puts MyClass.class_instance_var  # => "新しい値"
```
#### クラスの継承`<`
`class Food < Menu`など
#### オーバーライド＆`super`
親クラスのメソッドを子クラスで「上書き」すること
```rb
class Person
  def initialize(name, age)
    @name = name
    @age = age
  end

  def info
    "Name: #{@name}, Age: #{@age}"
  end
end

class Employee < Person
  def initialize(name, age, job)
    super(name, age)  # 親クラスのinitializeメソッドを呼び出し
    @job = job  # 従業員固有の属性
  end

  def info
    "#{super}, Job: #{@job}"
  end
end

employee = Employee.new("Alice", 30, "Developer")
puts employee.info  # => "Name: Alice, Age: 30, Job: Developer"
```
```rb
#キーワード引数の場合
def initialize(name:, price:, calorie:)
	super(name: name, price: price) #(parent_keyword_arg: child_arg)
	self.calorie = calorie
end
```
### `require`：インポート文
`require "./parts`など。`.rb`拡張子は省略するのが通例。
> Rubyの `require` メソッドはデフォルトで `.rb` または `.so`（またはプラットフォームに応じた適切なバイナリファイルの拡張子）を探します。他の種類のファイルを読み込む場合、特に `.js` や `.json` などの非Rubyファイルを読み込む場合は、明示的に拡張子を指定する必要があります。
### `gets.chomp`：コンソールからの入力を取得
`gets`：コンソールを入力待機状態にする
`chomp`：文字列の末尾にある改行文字（`\n` や `\r\n`）を取り除く。主に「がぶりとかじる」や「むしゃむしゃ食べる」といった意味で使われる動詞
`gets.chomp`取得された文字列には、ユーザーがEnterキーを押した際に生成される改行文字（`\n`）が含まれているため、`chomp`と併せて使用される。
### `.to_i`
おもろい。確かにこの命名でいいよなあ、ってなる。
他
`.to_f`：`float`
`.to_s`：`string`
`.to_sym`：`symbol` ←初めて見た。文字列に対して使うっぽい。
`.to_h`：`hash`←すごい。
```rb
[["key1", "value1"], ["key2", "value2"]].to_h
# => {"key1" => "value1", "key2" => "value2"}`
```
## 追記：`extend`と`include`
モジュールの読み込み方
`extend`はクラスメソッドとして
`include`はインスタンスメソッドとして読み込む

# 終わりに
久しぶりにコードかけて気持ち良かった……
CSSも楽しかったけど、やっぱ動くのがいいですね。
次はRails！SNSを作れるとのことで、非常に楽しみ。SNSのレイアウトを使って実装したいアイデアもあるので、モチベ高めです。明日から。