Javaエンジニアが今さらRubyの基礎文法を覚えるために対比した その2(クラス、メソッド編)

# はじめに
2回目はクラスとかメソッドです。

# 環境
[paiza.io](https://paiza.io/)でこういう時は実行すると楽です

これを作った時のバージョンは以下です。バージョンは[ヘルプ](https://paiza.io/help?locale=ja-jp)から確認できます。

Ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]
Java openjdk version "12" 2019-03-19

# スコープの話
JavaもRubyもpublic,protected,privateが存在していますが、概念が違うので、項を分けました。

publicは同じで制限無しなのですが、protectedとprivateは違います。

詳しくは[こちら](https://qiita.com/tbpgr/items/6f1c0c7b77218f74c63e)を参考にさせていただきつつJavaエンジニア的な解釈で書いています。

なお、package privateの概念はRubyにはないようです。

## クラススコープ
public(記述しない)とprivateが存在します。
インナークラスじゃないクラスをprivateにして使うみたいなシチュエーションはWebやってると使う機会がなさそうなので(今のところの感想)、見なかったことにします。
必要に応じてどういうスコープになるのか追加で学習します。

Javaでインナークラスも最近使ってないなーって感じなので、今回の記事ではスコープまでは扱いません。ご了承ください。

## メソッドスコープ
public(記述しない)、protected、privateが存在してます。

publicは同じと捉えて良さそうなので、違う2つについて記述していきます。

### private
違いが検証しやすかった方からのせます。
まずは下記のサンプルコードをご覧ください。

``` Ruby
class A
    private def print
       p "a"
    end
end

class B < A
    def print2
        print
    end
end

b = B.new
b.print2
```

Javaと違ってクラス以外から使用してもRubyのprivateは動きます。
参考にさせていただいた記事を見ると`private に設定されたメソッドは関数形式でしか呼び出せません`という記述になっているので、関数形式で呼び出せるサブクラスからも呼べてます。
きちんと動いていますが、Javaエンジニア的には少し気持ち悪いので注意が必要。

たぶん、他のケースでもアクセス出来ないと思ったら出来ちゃったがありそうです。

### protected
色々調べたけど、良く分からないことが多いのと、生みの親であるMatzさんも今なら組み込まないと言われているというツイートを見かけたので見なかったことにします。

どうしても覚えなきゃいけないシーンに立ち会うまで初心者の方は見なかったことにしても良いかなと思います。

# クラス
ここらへんは特に問題ありませんね。
使う側は`クラス名.new`という形で生成して使用します。

```Java
public class A {
}
```

``` Ruby
class A
end
```

ただし、Rubyは以下のような形でclassの拡張が行えるので、やろうと思えばなんでもありで出来ます。

``` Ruby
class A
    def print
       p "a"
    end
end

class A
    def print2
        p "b"
    end
end

a = A.new
a.print
a.print2
```

生成したインスタンスに対しての拡張も行えるので、本当になんでもありな世界を作ることが出来ます。
こちらは生成したインスタンスに限定出来るので、使い道がないとは言えないかもしれません。

``` Ruby
class A
    def print
       p "a"
    end
end

a = A.new

# 特異クラスとして宣言する
class << a
    def print2
        p "b"
    end
end

a.print
a.print2
```

## 継承
JavaもRubyも継承は単一継承です。

ただしJavaはinterfaceなら複数個いけるので、ちょっと無理矢理なことも出来なくはないです(特にJava8以降)。

Rubyは言語的に抽象クラスや抽象メソッド、interfaceをサポートしていないようなので、完全に継承といったら単一のクラスの継承となります。
mixinとかdelegation(ライブラリを使用する必要あり)がありますが、そちらについては全く別の概念となっているようで、継承とは別と考えた方が良さそうです。(本記事では扱いません、moduleもいったん対象外とします)

``` Java
public class A extends B {
}
```

``` Ruby
class A < B
end
```

# メソッド
メソッドは引数無しと有りで分けます。

## 引数無し
Rubyは`()`を省略することが可能となっています。
Rubyは特に戻り値の宣言が必要ないため、Docs書くなりしないと分かりづらいので注意が必要です。
Rubyの戻り値はreturnを記述するか、最後に評価された式の結果が返却されます。
Javaはreturnを明確に記述しないといけません。

``` Java
public void method() {
    System.out.println("a");
}
```
``` Ruby
def method
    print "a"
end
```

呼び出し時もRubyは省略可能となっています。
びっくりするから、無しの場合にどのような記述とするかはルールとして定めた方が良いと思います。

``` Java
method()
```

``` Ruby
method
```

## 引数有り
引数有りでもRubyは`()`を省略可能となっています。
呼び出し側も同様です。

``` Java
public void method(String a, String b) {
    System.out.print(a);
    System.out.print(b);
}
```
``` Ruby
def method a, b
    print a
    print b
end
```

# メソッドのネスト
Javaでは出来ませんが、Rubyはメソッド内にメソッドが宣言出来ます。
使用についてはネストして宣言した後から使用出来、前からは使用出来ません。

``` Ruby
def method
    print "a"
    
    def methtod2
        print "b"
    end

    methtod2
end
```

# クラスメソッド
Rubyはクラスにメソッドを属することが出来ます。
Java的にはstaticメソッドと同様の使い方(考え方は違うと思います)が出来る感じです。



``` Java
public class A {
    public static void main() {
        System.out.print("a");
    }
}
```

``` Ruby
class A
    def self.method
        print "a"
    end
end

A::method
```

特異メソッドで宣言すればその中全てをクラスメソッドにすることも可能となっています。
複数のメソッドを定義する際に向いているとリファレンスには書いているため、分かりやすく分けてあげたほうが良いようです。

``` Ruby
class A
    def print
       p "a"
    end
end

class << A
    def print2
        p "b"
    end
end

a = A.new
a.print
A::print2
```

単一でさらっとやりたい場合にはわざわざクラスから宣言せずともクラスメソッドを生成することも可能です。

``` Ruby
def A.print2
    p "b"
end
```

# おわりに
とりあえずばーっと書き出しましたが、混沌の原因を作りやすくなっているのでしっかりとチームルールを作って運用すべきだなと感じました。
そしてまだ書けてないことがありますが、とりあえず初心者がスタートするには過不足なさそうな感じがしたので、ここで止めておきます。

Javaがかっちりしているので、Rubyの自由さは混乱しちゃいますね。