JavaエンジニアのためのRuby入門

[ディップ Advent Calendar](http://qiita.com/advent-calendar/2016/dip-dev) の17日目です:)
# はじめに
## どんな記事？
JavaエンジニアがRubyを書くようになり、
「**これJavaの◯◯みたいなことだったのか！**」と思ったことを共有する記事です。

今回は`コーディング`について書きます…！

## 目次
[クラス](#クラス)
[インスタンス化](#インスタンス化)
[メソッド](#メソッド)
[インスタンス化（引数あり）](#インスタンス化（引数あり）)
[配列/リスト](#配列リスト)
[Map/ハッシュ](#mapハッシュ)
[知っておくと役立ったこと](#知っておくと役立ったこと)
[おわりに](#おわりに)

# クラス
## Java
```java:Father.java
// デフォルトパッケージ
public class Father {
}

```
## Ruby
```rb:father.rb
class Father
end
```
# インスタンス化
## Java
```java:Main.java
// デフォルトパッケージ
public class Main {

    public static void main(String[] args) {
        Father father = new Father(); 
    }

}
```
## Ruby
```rb:main.rb
require './father.rb' # ./father.rbを読み込む。javaでいうimportに似ています。

father = Father.new
```

# メソッド
## Java
### 宣言
```java:Father.java
public class Father {

    // staticなメソッド
    public static void hello() {
        System.out.println("Hello...");
    }

    // 非staticなメソッド（インスタンスメソッド）
    public void tellTheTruth() {
        System.out.println("I am your father.");
    }

    // 非staticなメソッド（インスタンスメソッド）:引数あり
    public void fuga(String words) {
        System.out.println(words);
    }

}
```
### 呼び出し
```java:Main.java
public class Main {

    public static void main(String[] args) {
        Father.hello(); // Hello...
        Father father = new Father(); 
        father.tellTheTruth(); // I am your father.
        father.fuga("Nooo!!"); // Nooo!!
    }

}
```
## Ruby
### 宣言
```rb:father.rb
class Father
  # クラスメソッド
  def self.hello
    puts 'Hello...'
  end

  # インスタンスメソッド（引数なし）
  # snake_case記法
  def tell_the_truth
    puts 'I am your father.'
  end

  # インスタンスメソッド（引数あり）
  def fuga(words)
    puts words
  end
end
```

### 呼び出し
```rb:main.rb
require './father.rb'

Father.hello # hoge

father = Father.new

father.tell_the_truth() # I am your father.
father.tell_the_truth   # I am your father. ()は省略可能。メンバの呼び出しに見えますが、メソッドの呼び出しです。

father.fuga('nooooo!!') # nooooo!!
father.fuga 'nooooo!!'  # nooooo!! ()は省略可能。よく使用されますが、メソッドの右辺などでは分かりづらくなるので避けた方が良いでしょう。
```

# インスタンス化（引数あり）
前述のインスタンス化では引数なしのコンストラクタでしたが、今回は引数を持つコンストラクタでよりオブジェクト感を出していきます。
## Java
```java:Father.java
public class Father {

    private String name;

    public Father(String name) {
        this.name = name;
    }

    public void tellTheTruth() {
        System.out.println("I am " + name + "...");
    }

}
```
## Ruby
```rb:father.rb
class Father
  attr_accessor :name

  def initialize(name)
    @name = name
  end

  def tell_the_truth
    puts "I am #{name}..."
  end
end
```
`initialize`がいわゆるコンストラクタです。
また、`@hoge`はインスタンス変数を表します。
Javaではよく、`フィールド`とか`メンバ変数`とか呼ばれるものですね。

### 文字列について
* 文字列はシングルクォーテーション`'`で囲みましょう。  
  * ダブルクオーテーション`"`は式展開時に使用します。
  * 文字列はStringクラスのインスタンスです。

### attr_accessor / アクセサについて
`attr_accessor `はアクセサ（いわゆるgetter/setter）を定義するものです。
実際は、以下のコードを記述しているのと同じです。

```rb
def name
  @name 
end

def name=(val)
  @name = val
end
```

Javaの以下と同じです。

```java
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}
```

# 配列/リスト
## Java
```java:Main.java
package com.company;

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("pen", "pineapple", "apple", "pen");

        // java5-7
        for (String word : words) {
            System.out.println(word);
        }
        // java8以降
        words.forEach(System.out::println);
    }
}
```
## Ruby
```rb:ppap.rb
words = ['pen', 'pineapple', 'apple', 'pen']

puts words[0] # pen

words.each do |word|
  # 以下の処理をループ実行する。
  # wordにはループされたオブジェクトが格納されている。
  # よって、最初のループは'pen'がコンソールに表示される。
  puts word
end
```
配列はArrayクラスで表現されます。
[Array - Rubyリファレンス](http://ref.xaio.jp/ruby/classes/array)

配列の繰り返しは`#each`がしばしば使用されます。
for文もありますが、まずは`#each`を覚えておけば大概のループは大丈夫でしょう。

`do`から`end`で表される`ブロック`については、以下の記事が非常にわかりやすいです。

[[Ruby] ブロックやProcの使いどころを理解する](http://qiita.com/kidach1/items/15cfee9ec66804c3afd2)
（混乱する可能性があるので、ストックして後で読む方が良いかもしれません。）


また、文字列の配列は以下の書き方で生成されることも頭の片隅に置いておくと、
他の人が書いたコードを読んでドキドキする可能性が低くなるでしょう。

```rb
# 文字列の配列を生成する
words = %w(pen pineapple apple pen)
```
このあたりは、[Rubyで%記法（パーセント記法）を使う](http://qiita.com/mogulla3/items/46bb876391be07921743)が非常に参考になります。
（ストック推奨）

# Map/ハッシュ
## Java
```java:Main.java
import java.util.HashMap;
import java.util.Map;

public class Main {

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();

        map.put("name", "ディップ");
        map.put("service", "ナースではたらこ");

        System.out.println(map.get("name")); // ディップ
        System.out.println(map.get("service")); // ナースではたらこ
    }

}
```
## Ruby
Rubyにおけるハッシュはいくつか書き方が用意されています。

```rb:main.rb
# 1 文字列をキーとする
dip = {'name' => 'ディップ', 'service' => 'ナースではたらこ'}

puts dip['name'] # ディップ
puts dip['service'] # ナースではたらこ

# 2 シンボルをキーとする。
dip = {name: 'ディップ', service: 'ナースではたらこ'}

puts dip[:name] # ディップ
puts dip[:service] # ナースではたらこ
```

書き方は上記だけではなく、また、バージョンによってもサポートが異なります。
以下の記事が非常にわかりやすいので目を通すと良いでしょう。
[Rubyのhash宣言方法いろいろ](http://qiita.com/yukimura1227/items/8c972efb27667dfac5cd)

# 知っておくと役立ったこと

## 名前空間について（Foo::Bar.newについて）
以下の書き方を見て戸惑うことがあるかもしれません。

```rb
Foo::Bar.new
```

こちらは、実際には以下のクラスをインスタンス化している処理です。

```rb
module Foo
  class Bar
  end
end
```

moduleの役割の一つに**名前空間の提供**があります。（他にはメソッドの提供などの機能を持ちます。）
Javaでいうパッケージに近い概念ですね。

```java:Bar.java
package foo;

public class Bar {
}
```

```java:Fuga.java
package hoge;

import foo.Bar;

public class Fuga {
    Bar bar = new Bar();
}

```

上記と似ています。

## NullPointerExceptionではなく、NoMethodErrorが発生する
Rubyの`nil`はJavaでいう`null`に似ていますが、多少異なります。

> nil は NilClass クラスの唯一のインスタンスです。 nil は false オブジェクトとともに偽を表し、 その他の全てのオブジェクトは真です。
[class NilClass (Ruby 2.3.0)](https://docs.ruby-lang.org/ja/latest/class/NilClass.html)

よって、nilクラスに存在しないメソッドを呼び出した際は、
`NullPointerException`というような例外ではなく、`NoMethodError`という例外が発生します。

```rb:main.rb
# 定義していないメソッドを呼び出す。
nil.special_method 
```

```
# NilClassにはspecial_methodとうメソッドはないので、以下のエラーが出力される。
undefined method `special_method' for nil:NilClass (NoMethodError)
```

# おわりに
Rubyは文法が美しい上、組み込みクラスが便利で、使えば使うほど手に馴染む言語だと個人的に思います。
Javaから入ると「**型宣言がないと何か不安！！**」みたいになるかもしれませんが、すぐに慣れると思います。（3日で慣れました。）
他言語を始めると元の言語への見方も変わるので、是非始めてみるのはいかがでしょうか。