クラスについて学んだことまとめ

# はじめに
クラスについて勉強したことをまとめました！

# 参考
プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで

# クラスの定義方法
class クラス名
end
で定義します。クラス名は、キャメルケースで書くのが一般的です。
```ruby:クラスの定義
class User

end
```
# オブジェクトの生成方法
クラス名.newで生成します。
```ruby:オブジェクトの生成方法
User.new
```
# initializeメソッド
newメソッドでがオブジェクト生成されると、initializeメソッドが自動的に呼び出されます。
初期化を行いたい場合は、initializeメソッド内に処理を記述します。

```ruby:initializeメソッドの例
class User
    def initialize
    puts "hello"
    end
end

#initializeメソッドが呼び出されるため、"hello"が出力される
User.new #=>hello
```
initializeメソッドは、外部から呼び出すことはできません。
```ruby:initializeメソッドは、外部から呼び出せない例
class User
    def initialize
    puts "hello"
    end
end

taro = User.new #=>hello
taro.initialize #=>NoMethodError
```
initializeメソッドに引数をつける際は、newメソッドにも引数を付与する必要があります。
```ruby:initializeメソッドに引数がある際のnewメソッド呼び出し
class User
    def initialize(name,age)
        puts "私は#{name}。#{age}歳"
    end
end

taro = User.new('太郎',15) #=>私は太郎。15歳
taro = User.new #=>ArgumentError
```

# インスタンスメソッド
クラス内で定義したメソッドのことをインスタンスメソッドといいます。
インスタンスメソッドは、オブジェクトから呼び出すことが可能です。
```ruby:インスタンスメソッドの例
class User
    #これがインスタンスメソッド
    def greeting
        puts "私は太郎。15歳"
    end
end

user = User.new
#インスタンスメソッドは、生成したオブジェクトから呼び出せる
user.greeting #=>私は太郎。15歳
```

# インスタンス変数
インスタンス変数とは、生成されたオブジェクト内で共有される変数のことです。
下記のように、変数名の＠を付けると、インスタンス変数になります。
```ruby:インスタンス変数の例
class User
    def initialize(name)
        #これがインスタンス変数
        @name = name
    end
    def greeting
        #インスタンス変数はインスタンスメソッドで使用できる
        puts "私は#{@name}"
    end
end

taro = User.new('太郎')
taro.greeting #=>私は太郎
```
## インスタンス変数をクラスの外から参照・変更する
attr_accessorメソッドを使用すると、クラスの外からインスタンス変数を参照したり、書き換えることができます。
```ruby:attr_accessorメソッド使用例
class User
    #@nameが自動的に外から読み書きできるようになる。
    attr_accessor :name

    def initialize(name)
        @name = name
    end
end

user = User.new('太郎')

#インスタンス変数を外から参照することができる
puts user.name #=> 太郎

#インスタンス変数を外から書き換えることができる
user.name = '佐藤'
puts user.name #=>　次郎
```
## インスタンス変数をクラスの外から参照のみ行う
インスタンス変数をクラスの外から参照のみ行う場合は、attr_readerメソッドを使用します。
```ruby:attr_readerメソッド使用例
class User
    #インスタンス変数の読み取りが可能になる
    attr_reader :name

    def initialize(name)
        @name = name
    end
end

user = User.new('太郎')

#インスタンス変数を外から参照することができる
puts user.name #=> 太郎

#インスタンス変数を外から書き換えはできない
user.name = '佐藤' #=>NoMethodError
```
## インスタンス変数をクラスの外から変更のみ行う
インスタンス変数をクラスの外から変更のみ行う場合は、attr_writerメソッドを使用します。
```ruby:attr_writerメソッド使用例
class User
    #　インスタンス変数の書き込みが可能になる
    attr_writer :name
    def initialize(name)
        @name = name
    end
end

user = User.new('太郎')

#インスタンス変数を外から書き換えは可能
user.name = '佐藤' 

#参照はできない
puts user.name #=>NoMethodError
```
# ローカル変数
クラスにて、メソッドやブロック内で生成される変数のことをローカル変数と呼びます。
ローカル変数は、そのメソッドやブロック内でのみ有効で、呼び出される度に作り直されます。
ローカル変数は、アルファベットの小文字、_で始めます。
```ruby:ローカル変数の使用例
class User
    def initialize(name)
        @name = name
    end
    def greeting
        #これがローカル変数
        age = 15
        #ローカル変数は、そのメソッドやブロック内で使用できる
        puts "私は#{@name}。#{age}歳"
    end
end

taro = User.new('太郎')
taro.greeting #=>私は太郎。15歳

# 外からは参照できない
taro.age #=>私は太郎。15歳
```
# クラスメソッドの定義
メソッド名の頭にself.を付けるとクラスメソッドを定義できます。

```ruby:クラスメソッドの定義
class User
    #メソッド名の頭にselfを付けるとクラスメソッドになる
    def self.クラスメソッド

    end

    #クラスメソッドが複数になる場合は、下記のようにも書ける
    class << self
        def クラスメソッド1
        end
        def クラスメソッド2
        end
    end
end
```
# 定数
クラス内には、定数も定義することが可能です。
定数は慣習的に、アルファベットの大文字で定義されます。
定数は、インスタンスメソッド・クラスメソッドともに参照可能です。
```ruby:クラス内で定数を使用した例
class Product
    #定数の生成
    DEFAULT_PRICE = 100

    def self.default_price
        #クラスメソッド内で定数を参照
        DEFAULT_PRICE   
    end

    def default_price
        #インスタンスメソッド内で定数を参照
        DEFAULT_PRICE   
    end
end
product = Product.new
# インスタンスメソッドから参照可能
puts product.default_price #=>100

# クラスメソッドから参照可能
puts Product.default_price #=>100
```

# self
selfとは、インスタンスそのものを表すキーワードです。
```ruby:selfの使用例
class User
    attr_reader :name
    def initialize(name)
      @name = name
    end
    #self無しでnameを呼び出す場合
    def hello
        puts "こんにちは！#{name}"
    end
    #selfありでnameを呼び出す場合
    def hi
        puts "こんにちは！#{self.name}"
    end
    #インスタンス変数を直接呼び出す場合
    def my_name
        puts "こんにちは！#{@name}"
    end
end

user = User.new('太郎')

user.hello #=>こんにちは！太郎
user.hi #=>こんにちは！太郎
user.my_name #=>こんにちは！太郎
```
## メソッド内でセッターメソッドを呼び出す際の注意点
下記のように、セッターメソッド経由でインスタンス変数を書き換える際、selfを付けないと、ローカル変数として認識され、意図しない動作を出力しますので、注意が必要です！

```ruby:selfを使用しないと意図しない出力をする例
class User
    # セッターメソッドnameを設定
    attr_accessor :name

    def initialize(name)
      @name = name
    end

    # セッターメソッドのnameを書き換えたい（正解）
    def rename1(name)
        self.name = name
    end

    # セッターメソッドのnameを書き換えたい（間違い）
    def rename2(name)
        name = name
    end

end

user = User.new('太郎')
# rename前のため、"太郎"が表示される
puts user.name #=>"太郎"

user.rename1('佐藤')
# インスタンス変数のnameが書き換わる
puts user.name #=>"佐藤"

# ローカル変数のnameに’田中’が代入されたため、user.nameは変わらない
user.rename2('田中')
puts user.name #=>"佐藤"
```
## クラス直下のself
クラスの直下やクラスメソッド内にselfを使用すると、クラスを返します。
```ruby:クラス直下・クラスメソッドのselfはクラスを返す例
class User
    # クラス直下のselfは、クラスになる
    puts self #=> User

    #クラスメソッドでselfを返す
    def self.return
        self
    end
    
    # インスタンスメソッドでselfを返す
    def return
        self  
    end
end

# selfはクラスになる
puts User.return #=>User

user = User.new
# selfはインスタンスになる
puts user.return #=>#<User:0x00007ffb591b2360>
```

# 承継
「aはbの一種である」という関係が成り立つものを承継といいます。
例:「家電は商品の一種である」といった具合。
この時、家電のことをサブクラス。商品をスーパークラスと呼びます。

# クラスを確認する方法
+ classメソッド
+ instance_of?メソッド
の二つがあります。
```ruby:クラスの確認方法
class User
end

user = User.new
puts user.class #=> User

#userはUserクラスであるためtrueを返す
puts user.instance_of?(User) #=> true

#userはUserクラスでないためfalseを返す
puts 'text'.instance_of?(User) #=> false
```
## 承継関係であるか調べる方法
is_a?メソッドを使用します。

```ruby:is_a?メソッドの使用例
class User
end

user = User.new

# 承継関係にあるためtrueを返す
puts user.is_a?(Object) #=> true
puts user.is_a?(BasicObject) #=> true

# 承継関係でないためfalseを返す
puts user.is_a?(String) #=> false
```
# 子で親クラスのメソッドを呼び出す方法
superメソッドを使います。
```ruby:親クラスのメソッドを呼び出す方法
class Product
    attr_accessor :name, :price
    def initialize(name,price)
      @name,price = name,price
    end
end

class DVD < Product
    def initialize(name,price,running_time)
        #superメソッドで、親クラスのメソッドを呼び出せる

        @running_time = running_time
    end
end

dvd = DVD.new('トイストーリー',2000,2)

#子で定義していないメソッドを呼び出せる
puts dvd.name #=> トイストーリー
```

# メソッドの公開レベル
メソッドがどこからどこまでの範囲で使用できるかについて、主に三種類あります。
## publicメソッド
クラスの外から使用できるメソッド
インスタンスメソッドはクラスの外からでも使用できるため、publicメソッドに相当します。
```ruby:publicメソッド
class User
    #インスタンスメソッドを定義
    def hello
        puts "hello"
    end
end

user = User.new
#クラスの外からでも呼び出せるため、publicメソッドに相当
user.hello
```

## privateメソッド
privateメソッドとは、クラス内で使用できるメソッドのこと。クラスの外からは呼び出すことができません。
privateキーワード以降に定義したメソッドは、privateメソッドになります。
```ruby:privateメソッドの例
class User

    private
        #privateキーワード以降にメソッドを定義
        def hello
            puts "hello"
        end
end

user = User.new
# privateメソッドを呼び出したため、エラーとなる
user.hello #=>  private method `hello' called for #<User:0x00007fb74413e400> (NoMethodError)
```
　スーパークラスで定義されたprivateメソッドですが、サブクラスで呼び出すことができるので注意が必要です。
```ruby:スーパークラスのprivateメソッドはサブクラスで呼び出せる例
class Product
    private
        def price
            1000
        end
end

class DVD < Product
    def tax_price
        # スーパークラスのprivateメソッドを呼び出す
        price * 1.1
    end
end

dvd = DVD.new
# サブクラスでスーパークラスのprivateメソッドを呼び出しても、エラーにならない
puts dvd.tax_price #=>1100.0 
```
また、クラスメソッドをprivateメソッドとしたい場合は,class << self構文を使用する必要があります。
```ruby:クラスメソッドをprivateメソッドにする
class Product
    private
        def self.price
            1000
        end
end

# 上記の記述では、プライベートメソッドにしたつもりのpriceが外から呼び出せてしまう
puts Product.price #=>1000

class Product
    # class << self構文
    class << self
    private
        #クラスを定義
        def price
            1000
        end
    end
end
#クラスメソッドが外から呼び出せない（privateメソッドとして機能している）
puts Product.price #=>　NoMethodError
```

# 定数
## 定数はメソッド内では定義できない
定数は、メソッド内では作成できず、クラス直下に定義する必要があります。
```ruby:定数はメソッド直下で作成できない
class Product
    def price
        # メソッド内で定数を作成すると構文エラーになる
        PRICE = 1000 
    end
end
product = Product.new
puts product.price

#=>dynamic constant assignment
```