第２回　Ruby勉強会

「[第１回　Ruby勉強会](http://qiita.com/CyberMergina/items/a0d8997ec6e7cbc4a14a)」の続き

# クラスとメソッド

## クラス定義とメソッド
* クラス名は半角英数字（先頭は大文字の英字）
* メソッド名は半角英数字で定義する。（先頭は半角英字）

**クラスの定義**

```class.rb
# そのクラスで一貫した処理が行える場合
class クラス名
end

# ベースとなるクラスがあり、拡張としてクラスを作成する場合
class クラス名 < 親クラス名
end
```

**メソッド定義**

```method.rb
# 引数を持たせない場合
def メソッド名
end

# 引数を持たせる場合
def メソッド名(引数)
end
```

DateTimeFormatという日付フォーマットを行うメソッド群をまとめるクラスのサンプルです。

```test10.rb
class DateTimeFormat
  require 'date'

  def default(date)
    # 文字列⇒日付オブジェクトに変換
    date = Date.strptime(date, '%Y-%m-%d')
    # フォーマットして返す
    return date.strftime('%Y/%m/%d')
  end

  def defaultJp(date)
    # 文字列⇒日付オブジェクトに変換
    date = Date.strptime(date, '%Y-%m-%d')
    # フォーマットして返す
    return date.strftime('%Y年%m月%d日')
  end

end

# クラスの初期化
dateTimeFormat = DateTimeFormat.new()
sampleDate = '2015-01-03'

# DateTimeFormatクラスのメソッドを使用する
puts dateTimeFormat.default(sampleDate) # 2015/01/03
puts dateTimeFormat.defaultJp(sampleDate)

```


### initialize関数

上の例では、クラスのメソッド内では全てはじめに「文字列⇒日付オブジェクトに変換」をしています。
ここを、クラスを初期化した時のみ行うような書き方にすると以下のようになります。

```test11.rb
class DateTimeFormat2
  require 'date'

  # クラスを初期化した時点で通過するinitialize関数
  def initialize(date)
    @date = Date.strptime(date, '%Y-%m-%d')
  end

  def default()
    return @date.strftime('%Y/%m/%d')
  end

  def defaultJp()
    return @date.strftime('%Y年%m月%d日')
  end

end

# 初期化をする際に値を持たせている
dateTimeFormat = DateTimeFormat2.new('2015-01-03');

# DateTimeFormatクラスのメソッドを使用する
puts dateTimeFormat.default(); # 2015/01/03
puts dateTimeFormat.defaultJp(); # 2015年01月03日

```

## 継承とメソッドのオーバーライド

### 継承（class Main < Base）
　MainはBaseを親とするという記述。このことを継承と言います。
　継承すると、クラスの拡張が出来る。
　親のクラスに手を加えずに、メソッドの処理書き換えや追加ができる。

### オーバーライド
　親のクラスにあるメソッドと同名のメソッドを自身のクラスに
　作成することで、メソッドの処理書き換えをすることが出来る。
　もちろん、親の処理を呼び出すことは可能。

BaseとMainという二つのクラスを用意しました。

```test13.rb
class Base
  # (num=0) 引数が無かった場合は0が入るように指定
  def test(num=0)
    puts "num = #{num}"
  end

  def test2
    puts 'hoge!!!'
  end
end

class Main < Base
  # Baseのtestメソッドをオーバーライドしている。
  def test(num)
    super(5) # 5　Base.test()に引数にセットした「5」が渡っている
    super() # 0　Base.test()に何も渡していないため、デフォルトの0が入っている
    puts "num = #{num}" # 2　渡された数値をそのまま表示している
    super(5 + num) # 5 + 2 (result:7)　渡された数値と「5」がプラスされた数値がをBase.test()に渡っている
  end
end

main = Main.new()
main.test(2)
main.test2() # hoge!!!

base = Base.new()
base.test(3) # 3
```

・super()
　オーバーライドしているメソッドでこの関数を使用すると
　親の同名メソッドにアクセスできます。



# モジュールについて

## クラスとモジュールの違い
- 継承が無い
- クラスメソッドが無い
- インスタンスを作成しない
- インクルードして使用する形

## 使用シーン
　たとえば、機能全体として「日時計算の複数の機能」「ページングに使う複数の機能」
　これらをそれぞれ塊にして用意しないといけない場合。
　クラスにして継承して使用する形だとそれらを一つのクラスで管理するか、*親>子>孫*といった形で
　深く謎い継承しなくてはいけなくなる。
　（１つのクラスに対して１つのクラスしか継承できないので階層が深く不思議な構成になってしまう。）

```
  # どんな親子関係だよって突っ込みたくなりますね。
　# UserMasterClass > DateTimeCalculationClass > PagingClass
　class PagingClass
   # ページング処理
　end

　class DateTimeCalculationClass > PagingClass # ⇐ここに何でページング？ってなるわけです。
　 # 日時計算の処理
  emd

  class UserMasterClass > DateTimeCalculationClass
　 # 主な処理
　end
```

　それぞれをモジュールにしてしまえば、読み込むモジュールの数に制限は無いので
　うまくソースの切り分けが出来る。　

```test14.rb
# モジュール定義１
module DateTimeCalculation
  # 日時計算
  def test
    return true
  end
end

# モジュール定義２
module Paging
  # ページング処理
  def getCurrentPosition
    return 1
  end

  # よく使用する関数は、通常の関数と同じように扱いたければ、
  # 以下の指定を入れれば可能になる
  module_function :getCurrentPosition
end

class UserMaster
  # モジュール１を読み込み
  # モジュール２は module_function の指定を入れたので getCurrentPosition を使う分には読み込まなくてもOK
  include DateTimeCalculation

  def sample
    if test # モジュール１は関数名だけで使用可能
      return Paging.getCurrentPosition # モジュール２は モジュール名.関数名 で使用可能
    else
      return nil
    end
  end
end

user = UserMaster.new()
puts user.sample # 1
```

# 変数の種類

```test12.rb
class Sample

  @@classVar = 'd' # クラス変数

  def initialize
    localVar = 'a' # ローカル変数
    @instanceVar = 'b' # インスタンス変数
  end

  def test01
    # puts "localVar = #{localVar}" # エラー
    @instanceVar = 'bbb'
    $globalVar = 'ccc'
    @@classVar = 'ddd'
  end

  def echo
#     puts "localVar = #{localVar}" # エラー
    puts "instanceVar = #{@instanceVar}" # bbb
    puts "globalVar = #{$globalVar}" # ccc
    puts "classVar = #{@@classVar}" # ddd
  end
end

$globalVar = 'c' # グローバル変数

sample = Sample.new()
sample.test01()
sample.echo()
puts "globalVar2 = #{$globalVar}" # ccc

sample2 = Sample.new()
sample2.echo()
```
ここで挙げたのは「ローカル変数、クラス変数、インスタンス変数、グローバル変数」です。
他の言語と同じようにそれぞれスコープが異なるので使い分けが必要です。
（基本的にはローカル変数とインスタンス変数でしょうね。）

## ローカル変数
　他の３種と比べ、スコープが一番狭いです。
　例題でいうと、始めに定義したinitializeでのみ使用できます。
　test01やクラス外では存在しないとエラーが返されます。
　変数名の先頭は小文字かアンダースコア(_)。

## クラス変数
　クラス内で使用する変数。
　複数のメソッドで使用でき、インスタンス間で共有することが出来る。

## インスタンス変数
　クラス内で使用する変数。
　だが、[アクセスメソッド](http://www.rubylife.jp/ini/class/index6.html)を使用すると「参照と変更」が可能になる。
　複数のメソッドで使用できるが、インスタンス間での共有はできない。　

## グローバル変数
　どこからでも参照、変更が可能な変数。


# 参考サイト

[Ruby Steady 1 変数と代入](http://qiita.com/kyohei8/items/5941477037df9b6cde98)
[Rubyにおけるスコープのおなはし](http://melborne.github.io/2013/09/24/rubys-scope/)
[Ruby入門](http://www.rubylife.jp/ini/)