RubyとPythonの基本構文の違いをまとめ

業務でPythonを使っていますが、ひょんなことからRubyを学ぶ機会が出来たのでPythonとの基本的な構文の違いをまとめています。
Rubyは初心者なので、変なことを書いていたらご指摘ください。
似ている所も多いので、業務と趣味で使っていたら混乱しそうだ...

# RubyとPythonの違うところ
## RubyとPythonで三項演算子の記法が異なる
以下のように、記法が異なります。
Ruby: `変数 = 条件式 ? 条件式がTrueの時の値 : 条件式がFalseの時の値`
Python: `変数 = 条件式がTrueの時の値 if 条件式 else 条件式がFalseの時の値`

サンプルコードを見ていきましょう。

__Ruby__

```ruby:sankouenzanshi.rb
size = 185
result = size > 180 ? 'Big size' : 'Small size'
p result # -> Big size
```

__Python__

```python:sankouenzanshi.py
size = 185
result = "Big size" if size > 180 else "Small size"
print(result)  # -> Big size
```

## メソッド呼び出し
メソッド呼び出し時、Rubyでは以下の呼び出し方法が可能です。

__Ruby__
- オブジェクト.メソッド(引数,引数,引数)
- オブジェクト.メソッド 引数,引数,引数
- 引数が無い場合：　オブジェクト.メソッド

コードをPythonと比べてみましょう。

__Ruby__

```ruby:hello.rb
def func_1(a, b)
    puts(a + b)
end

text_1 = 'Hello '
text_2 = 'Ruby'
func_1(text_1, text_2) # -> Hello Ruby
func_1 text_1, text_2 # -> Hello Ruby

def func_2()
    puts('Hello Ruby')
end

func_2() # -> Hello Ruby
func_2 # -> Hello Ruby
```

__Python__

```python:hello.py
def func_1(a, b):
    print(a, b)

text_1 = 'Hello '
text_2 = 'Python'
func_1(text_1, text_2) # -> Hello Python
func_1 text_1, text_2 # -> Syntax Error

def func_2():
    print('Hello Python')

func_2() # -> Hello Python
func_2 # -> なにも起きない（オブジェクトが呼ばれただけ）
```

## Ruby: ハッシュ, Python： dict
RubyではPythonのdict型のような型をハッシュと呼ぶ。
JavaだとHashMapとかもあるので、ハッシュという名前に違和感は感じない。

__Ruby__

```ruby:hello.rb
user = {
    "name" => "やまもと ルビ子",
    "phone" => "080-0000-0000",
    "address" => "埼玉県草加市"
}
puts(user) # -> {"name"=>"やまもと ルビ子", "phone"=>"080-0000-0000", "address"=>"埼玉県草加市"}
```

__Python__

```python:hello.py
user = {
    "name": "やまもと ルビ子",
    "phone": "080-0000-0000",
    "address": "埼玉県草加市"
}
print(user)
```

## Rubyではダブルクォートの文字列なら式展開を利用できる
Rubyではダブルクォートで囲み、`"#{1+1}"` のように#{式}で表すと、文字列の中に式の値を入れることが出来ます。
Pythonではfstringを使う必要があります。`f'{1+1}'`のように。

__Ruby__

```ruby:hello.rb
item = 'おにぎり'
message = "#{item}をお買い上げですね。ありがとうございます。"

puts(message) # -> おにぎりをお買い上げですね。ありがとうございます。
```

__Python__

```python:hello.py
item = "おにぎり"
message = f"{item}をお買い上げですね。ありがとうございます。"

print(message) # -> おにぎりをお買い上げですね。ありがとうございます。
```

## Rubyではfalseになる値が少ない
Pythonでは以下のような値がFalse判定される。
- 数値の0
- 空の配列やdictなどのコレクション
- 空文字
- None

Rubyでは以下の値がFalse判定される。
- nil
- false

Pythonとの違いというより、RubyはFalse判定されるものが極端に少ない。他言語で慣れている場合、実装時はこの違いを忘れないようにしなくてはならない。

__Ruby__

```ruby:hello.rb
puts('0 is true') if 0
puts('{} is true') if {}
puts('[] is true') if []
puts('nil is true') if nil
puts('false is true') if false

# -> 
# 0 is true
# {} is true
# [] is true
```

__Python__

```python:hello.py
print(bool(0)) # -> False
print(bool({})) # -> False
print(bool([])) # -> False
print(bool(None)) # -> False
print(bool(False)) # -> False
```

## Rubyではif文が戻り値を返す
Rubyではif文が戻り値を返すため、そのまま変数に詰めることが出来ます。

__Ruby__

```ruby:hello.rb
time = 'noon'
eat = 
    if time == 'morning'
        'break fast'
    elsif time == 'noon'
        'runch'
    elsif time == 'night'
        'dinner'
    else
        'snack'
    end

puts(eat)
```

## Rubyではメソッドの戻り値にreturnを使う必要がない
Rubyでは最後の式がメソッドの戻り値になるため、returnを使う必要がありません。また、returnを使わない方が好ましいとされているようです。
returnを使うのは、メソッドの途中で結果を戻したいときに明示的に使う用です。

returnを使わない場合のRubyとPythonのメソッドと実行結果を見てみましょう。


__Ruby__

```ruby:hello.rb
def greeting_morning()
    return 'good morning!'
end

def greeting_noon()
    'hello'
end

def greeting_night
    'good night'
end

puts greeting_morning # -> "good morning!"
puts greeting_night # -> "hello"
puts greeting_noon # -> "good night"
```

__Python__

```python:hello.py
def greeting_morning():
    return 'good morning!'


def greeting_noon():
    'hello'


def greeting_night():
    'good night'


print(greeting_morning())  # -> "good morning!"
print(greeting_night())  # -> None
print(greeting_noon())  # -> None

```

## Rubyではifの逆の意味を持つunless文が存在する
unless文はifと逆で、条件式がfalseの時に内部の処理を実行します。
以下、サンプルコードです。

__Ruby__

```ruby:unless.rb
hp = 500
status = 'poison'

if status == 'poison'
    hp -= 10
end
p hp # -> 490

status = 'healing'
unless status == 'poison'
    hp += 20
end
p hp # -> 510
```

## Rubyではcase文がある
Pythonでcase文、switch文のようなことをすることは出来ず、elseifであらわす必要があります。
Rubyにはcase文があります。

```ruby:case.rb
month = 10
season = 
    case month
    when 12, 1, 2
        'winter'
    when 3, 4, 5
        'spring'
    when 6, 7, 8
        'summer'
    when 9, 10, 11
        'autumn'
    end

p season # -> autumn
```

## Rubyではモジュールをインポートする際、モジュール名を文字列にしなければいけない
Rubyではライブラリをインポートするとき、`require 'Date'`のように、ライブラリ名を文字列とする必要があります。
Pythonでは`import datetime`のようにインポート可能です。

__Ruby__

```ruby:import.rb
require 'Date'
p Date.today
```

__Python__

```python:import.py
import datetime

print(datetime.datetime.now())
```


# RubyとPythonの同じところ
## すべてがオブジェクト
RubyもPythonもオブジェクト指向言語なので、すべてがオブジェクトです。

## インクリメント、デクリメントの演算子が無い
num++やnum--が使えません。
代わりに、num+=1, num-=1を使います。
__サンプルコード__

```ruby:hello.rb
num_1 = 10
num_1 += 100
puts(num_1) # -> 110

num_2 = 10
num_2 -= 100
puts(num_2) # -> 90
```

## 数値と文字列の暗黙的な変換は行われない
`1 + "1" = 2` 
`1 + "1" = 11` 
みたいなことは行われません。
__サンプルコード__

```ruby:hello.rb
puts(1 + "1") # -> `+': String can't be coerced into Integer (TypeError)
```

## AND条件やOR条件の戻り値は式の評価が終わったタイミング
こちらはRuby, Pythonのみの話ではなく、一般的にこの動作です。
式の評価が終わるタイミングは、AND条件とOR条件で大きく異なります。

AND条件：　左から評価していき、最初にFalseが評価されたタイミング または 最後まで値がTrueで最後の値を評価したタイミング
OR条件：　左から評価していき、最初にTrueが評価されたタイミング または 最後まで値がFalseで最後の値を評価したタイミング

AND条件では1つの値がFalseな時点で、式全体がFalseになります。
OR条件では1つの値がTrueな時点で、式全体がTrueになります。

それでは、サンプルコードを見ていきましょう。

__Ruby__

```ruby:sample.rb
# AND条件 最初にFalse or 最後の値
p 1 && 2 && 3 # -> 3
p 1 && nil && 3 # -> nil
p nil && 2 && 3 # -> nil
p 1 && false && 3 # -> false

# OR条件 最初にTrue or 最後の値
p 1 || 2 || 3 # -> 1
p 1 || nil || 3 # -> 1
p nil || 2 || 3 # -> 2
p false || false || 3 # -> 3
p false || false || nil # -> nil
```

__Python__

```python:sample.py
# AND条件 最初にFalse or 最後の値
print(1 and 2 and 3)  # -> 3
print(0 and 1)  # -> 1
print(1 and False and 20)  # -> False

# OR条件 最初にTrue or 最後の値
print(1 or 5)  # -> 1
print(0 or False or [] or 20)  # -> 20
```

## メソッドの引数の数が違うとエラーになる
メソッドの数が違うとエラーになるため、引数を柔軟にするためには可変長引数やデフォルト引数を使う必要があります。

```ruby:sample.rb
def method(a, b)
    p a
    p b
end

method('A', 'B')
method('A', 'B', 'C') # -> wrong number of arguments
method('A') # -> wrong number of arguments
```

__Python__

```python:sample.py
def method(a, b):
    print(a)
    print(b)


method('A', 'B')
method('A', 'B', 'C')  # -> method() takes 2 positional arguments but 3 were given
method('A')  # -> method() missing 1 required positional argument: 'b'

```