[Ruby]とりあえずsuperって書いてない？super・super()・super(*)・super(**)は違うんだよ

親クラスのメソッドを呼び出す際に使用される`super`には、`super`、`super()`、`super(*)`、`super(**)`など、いくつかの異なる呼び方があります。
この記事では、それぞれの呼び方の違いと具体的な使用例について説明します。

これで僕みたいにとりあえず`super`って書いておけば良いんでしょって人が減ると嬉しいですね。

## super
`super`は、現在のメソッドに渡された引数をそのまま親クラスのメソッドに渡します。
```ruby
class Person
    def initialize(name, age)
        @name = name
        @age = age
    end
end

class Yuusha < Person
    def initialize(name, age)
        super
    end
end

yuusha = Yuusha.new('tarou', 28)
```

親クラスのメソッドが、現在のメソッドと同じ引数を必要とする場合に使用します。コードがシンプルで読みやすくなるため、最も一般的な使用方法です。

ただし、親クラスと子クラスで引数の数が違うとエラーが発生します。
```ruby
class Person
    def initialize(name, age)
        @name = name
        @age = age
    end
end

class Yuusha < Person
    def initialize(name, age, hp)
        super
    end
end

yuusha = Yuusha.new('tarou', 28, 60)

# => index.rb:2:in `initialize': wrong number of arguments (given 3, expected 2) (ArgumentError)
```

## super()
`super()`は、引数なしで親クラスのメソッドを呼び出します。

```ruby
class Person
    def initialize
        puts 'Personの初期化'
    end
end

class Yuusha < Person
    def initialize(name, age)
        @name = name
        @age = age
        super()
    end
end

yuusha = Yuusha.new('tarou', 28)
# => Personの初期化
```
親クラスのメソッドが引数を必要としない場合に使用します。現在のメソッドが引数を受け取っていても、親クラスのメソッドには渡したくない場合に便利です。

## super(*)
`super(*)`は、スプラット演算子（*）を使用して引数を展開することで、親クラスのメソッドに全ての引数を配列として渡します。

```ruby
class Person
    def initialize(*args)
        puts "この人の装備は#{args.join('、')}"
    end
end

class Yuusha < Person
    def initialize(*args)
        super(*args)
    end
end

yuusha = Yuusha.new('天空のつるぎ', '天空の鎧', '天空の兜')
yuusha = Yuusha.new('天空のつるぎ', '天空の鎧', '天空の兜', '天空の盾')

# => この人の装備は天空のつるぎ、天空の鎧、天空の兜
# => この人の装備は天空のつるぎ、天空の鎧、天空の兜、天空の盾
```
現在のメソッドが可変長引数を受け取り、それを親クラスのメソッドへそのまま渡す場合に使用します。引数の数や内容が動的に決まる場合に有効です。

## super(**)
`super(*)`は、スプラット演算子（**）を使用して引数を展開することで、親クラスのメソッドに全ての引数をハッシュオブジェクトとして渡します。

```ruby
class Person
    def initialize(**args)
        args.each do |key, value|
            instance_variable_set("@#{key}", value)
        end
    end
end

class Yuusha < Person
    def initialize(**args)
        super(**args)
    end
end

yuusha = Yuusha.new(name: 'tarou', age: 28, hp: 100)
puts yuusha.instance_variable_get('@name')
puts yuusha.instance_variable_get('@age')
puts yuusha.instance_variable_get('@hp')

# => tarou
# => 28
# => 100

yuusha2 = Yuusha.new(name: 'zirou', age: 25, hp: 100, mp: 200)
puts yuusha2.instance_variable_get('@name')
puts yuusha2.instance_variable_get('@age')
puts yuusha2.instance_variable_get('@hp')
puts yuusha2.instance_variable_get('@mp')

# => zirou
# => 25
# => 100
# => 200
```

spuer(*)と同様、引数の数や内容が動的に決まる場合に有効です。例のように、キーと値の形でインスタンス変数を動的に設定することも可能です。



## super(arg1, arg2, ...)
`super`を使うときに、具体的な引数を直接渡すこともできます。

```ruby
class Person
    def initialize(name ,age)
        @name = name
        @age = age
    end
end

class Yuusha < Person
    def initialize(name, age, hp)
        @hp = hp
        super(name.upcase, age)
    end
end

yuusha = Yuusha.new('tarou', 28, 100)
puts yuusha.instance_variable_get('@name')
puts yuusha.instance_variable_get('@age')
puts yuusha.instance_variable_get('@hp')

# => TAROU
# => 28
# => 100
```
現在のメソッドが受け取った引数と異なる引数を親クラスのメソッドに渡したい場合に使用します。引数を加工してから渡す場合に便利です。

## まとめ
- super: 引数をそのまま親クラスに渡す
- super(): 引数なしで親クラスのメソッドを呼び出す
- super(*): 可変長引数をフラットに展開して親クラスに配列として渡す
- super(**): 可変長引数をフラットに展開して親クラスにハッシュオブジェクトとして渡す
- 直接引数を指定: 特定の引数を親クラスに渡す
- 
これらの方法を使い分けることで、Rubyのメソッド継承をより柔軟にコントロールできます。ぜひ`super`を使う時はどれを使うと一番効率よく継承をコントロールできるのか考えてみてください。