Ruby備忘録、Rubyの特に分かりにくかったところ、メソッド呼び出しのカッコ省略等

# この記事について

ruby学習中のため、その備忘録です。railsの話はほぼ出てきません。
rubyを学習していて特に分かりにくかったところなどを中心に書いています。

# 他言語からRubyへ

PHPやPython等他言語を使ってる人に対しては、Ruby公式サイトにそれぞれの言語とRubyの違いについて書かれたページがあります。

[他言語からのRuby入門
](https://www.ruby-lang.org/ja/documentation/ruby-from-other-languages/)

# メソッド呼び出しのカッコ省略、return省略

## 引数無しのメソッド呼び出しのカッコ省略

rubyではメソッド呼び出しの際カッコを省略することができます。

```ruby
def hello
  puts 'hello!'
end

hello() # hello!
hello   # hello!
```

## 引数ありのメソッド呼び出しのカッコ省略

引数がある時もカッコの省略ができます。
引数が複数ある場合は`,`で繋ぎます。

```ruby
def hello_name(name)
  puts "hello #{name}!"
end

hello_name('suzuki') # hello suzuki!
hello_name 'suzuki'  # hello suzuki!

def hello_name2(name1, name2)
  puts "hello #{name1}, #{name2}!"
end

hello_name2('suzuki', 'sato') # hello suzuki, sato!
hello_name2 'suzuki', 'sato'  # hello suzuki, sato!
```

## returnの省略

また、メソッド内の最終行で戻り値を返す場合は`return`を省略できます。

```ruby
def plus10(n)
  n + 10 # return n + 10
end

def double(n)
  n * 2
end

puts plus10 3        # 13
puts double plus10 3 # 26 ← puts double( plus10(3) )
```

## メソッド定義のカッコ省略

メソッド定義でもカッコが省略できます。
引数無しの場合だけでなく、引数ありの場合でも省略できるみたいです。
ただ、実際に引数ありのメソッド定義でカッコを省略して書いている人は少ないように感じました。

```ruby
def bye_name name
  puts "bye #{name}!!"
end

def bye_name2 name1, name2
  puts "bye #{name1}, #{name2}!!"
end

bye_name 'suzuki'          # bye suzuki!!
bye_name2 'suzuki', 'sato' # bye suzuki, sato!!
```

## メソッドの別名

メソッドの別名を付ける際は`alias`や`alias_method`を使用します。
`alias_method`は`class`の外では使えません。

```ruby
def method1
  puts 'method!'
end

# これはメソッドの別名を付けてる訳ではなく、戻り値を代入している
not_method = method1 # method!

method1 # method!
not_method # 何も出力されない
puts not_method # nil ← putsの戻り地はnil

alias :method2 :method1
method2 # method!
```

# メソッドのオプション引数、ハッシュの波カッコ省略

## オプション引数

引数にデフォルト値を設定してオプション引数とすることで、メソッド呼び出し時に省略できるようになります。

```ruby
def pow(n, m=2)
  n ** m # nのm乗
end

puts pow 3    #  9
puts pow 3, 4 # 81
```

## ハッシュの波カッコ省略

引数の最後がハッシュの場合は`{}`を省略できる

```ruby
def filter_high_persons(min, persons)
  persons.filter {|k,v| v > min}
end

puts filter_high_persons(170, {suzuki: 175, sato: 165, tanaka: 180}) # {:suzuki=>175, :tanaka=>180}
puts filter_high_persons 170, suzuki: 175, sato: 165, tanaka: 180    # {:suzuki=>175, :tanaka=>180}

```

railsでも基本`()`や`{}`を省略して書かれることが多いです。
例えばルーティングのところは省略せずに書くと以下のようになります。

```ruby
get 'test1', to: 'tests#test1', as: 'test_action1'
get('test1', {to: 'tests#test1', as: 'test_action1'})
```

# その他

## 命名

識別子に`!`や`?`を使えます。

慣習的に戻り値が真偽値のメソッドには名前の最後に`?`を付けることが多く、`is`や`can`等はあまり使いません。
例えば`is_success`ではなく、`success?`と命名します。

慣習的に破壊的メソッドには名前の最後に`!`を付けることが多いです。
例えば`Array`の`sort`メソッドは非破壊的ソートを行い、`sort!`メソッドは破壊的ソートを行います。
メソッド名に`!`が付いていなければ絶対に破壊的メソッドではない、という訳ではありません。


また、処理失敗時に`false`等を返すメソッドには`!`を付けず、処理失敗時に例外を発生させるメソッドには`!`を付けるといった命名もされています。
例えば`Rails`の`save`は成功したかどうか真偽値を返しますが、`save!`メソッドは失敗時に例外を発生させます。

## 標準出力

標準出力するメソッドに`puts`, `print`, `p`があり、それぞれ出力の仕方が少しずつ異なっています。
主に改行の入り方が違うようです。

|メソッド|引数毎の改行|配列の要素間の改行|nil|補足|
|-----|------|-------|----|---|
|puts |入る   |入る   |空行を出力|配列の`[]`の表示なし|
|p    |入る   |入らない|`nil`と出力||
|print|入らない|入らない|何も出力されない|スペースも入らない|


```ruby
puts 'suzuki', 'sato'        # suzuki(改行)sato(改行)
puts ['suzuki', 'sato']      # suzuki(改行)sato(改行)
puts name: 'suzuki', age: 20 # {:name=>"suzuki", :age=>20}(改行)
puts nil                     # (空行)

p 'suzuki', 'sato'        # "suzuki"(改行)"sato"(改行)
p ['suzuki', 'sato']      # ["suzuki", "sato"](改行)
p name: 'suzuki', age: 20 # {:name=>"suzuki", :age=>20}(改行)
p nil                     # nil

print 'suzuki', 'sato'        # suzukisato
print ['suzuki', 'sato']      # ["suzuki", "sato"]
print name: 'suzuki', age: 20 # {:name=>"suzuki", :age=>20}
print nil                     # 何も出力されない
```

## 式と文に違いはない

式と文に違いはなく、全ては値をもつ。

```ruby
x = 10
res = if 0 <= x
        '0以上'
      else
        '0未満'
      end
puts res # 0以上
```

## シンボル

シンボルは単なる軽量文字列ではない。
シンボルはオブジェクトの実体を指すもので、同じシンボルであればメモリ上の同じ場所を参照する。

```ruby
puts :test.object_id == :test.object_id   # true  ← メモリ上の全く同じ場所にある
puts 'test'.object_id == 'test'.object_id # false ← 値が同じだけでメモリ上の別々の場所にある
```

## 型、インスタンスの調べ方

型・クラスは`class`メソッドで調べられます。
インスタンスが特定のクラスのものか調べる際は`kind_of?`や`instance_of`メソッドを用います。
`kind_of?`はそのクラスの直接のインスタンスか、そのクラスを継承しているクラスのインスタンスであれば`true`となります。
`instance_of?`はそのクラスの直接のインスタンスの時のみ`true`となります。

```ruby
puts Time.class  # Class
puts Time.kind_of?(Class) # true
puts Time.kind_of?(Time)  # false

time = Time.now

puts time.class  # Time
puts time.kind_of?(Class) # false
puts time.kind_of?(Time)  # true

class MyTime < Time
end
my_time = MyTime.now

puts MyTime.class  # Class
puts my_time.class # MyTime
puts my_time.kind_of?(Time)       # true   ← MyTimeはTimeを継承しているため
puts my_time.kind_of?(MyTime)     # true
puts my_time.instance_of?(Time)   # false  ← MyTimeのインスタンスであってTimeのインスタンスではない
puts my_time.instance_of?(MyTime) # true
```

## nil (null)


### `&.`演算子

`nil`に対して`&.`演算子を用いると`undefined method`エラーを回避できます。
`nil`が入る可能性がある変数のメソッドを直接呼び出す書き方をしていると`nil`になった時にエラーが出てしまう為、そういった場合に`&.`演算子を使うことがあります。

```ruby
class Test
  def hello
    'hello!'
  end
end

test = Test.new
p test.hello  # "hello!"

test = nil
# p test.hello # undefined method `hello' for nil:NilClass

if test # nilはfalse扱い
  p test.hello # ここは通らないのでエラーとならない
else
  p 'bye!' # bye!
end

# `&.`演算子や`||`演算子を使えば条件分岐を減らすことができる時もある
p test&.hello           # nil ← エラーとならずにnilが返される
p test&.hello || 'bye!' # "bye!"
```

`&.`演算子を使用しても、nilではないものに対して存在しないメソッドを呼び出した場合はエラーとなる

```ruby
now = Time.now
# p now&.hello # undefined method `hello' for ~:Time
```

### `try`メソッド

railsの`try`メソッドを用いると、nilではないものに対して存在しないメソッドを呼び出した場合でもエラーとなりません。

```ruby
# rails上でしか動きません
now = Time.now
p now.try(:hello)
```

### 変数が定義されているか調べる方法

変数が定義されているか確認する際は`defined?`メソッドを用います、未定義であれば`nil`を返します。

```ruby
a = 10
p defined?(a) # local-variable
p defined?(b) # nil
```

## 可変長引数、展開

### 可変長引数

引数名の前に`*`を付けることで引数の個数を可変にすることができます。
渡された引数は配列となって可変長引数に渡されます。

```ruby
def variable_arg(*args)
  p args.class # Array
  p args       # [1, 2, 3]
end

variable_arg 1, 2, 3
```

```ruby
def sum(*nums)
  nums.sum
end

puts sum 1, 2    # 3
puts sum 1, 2, 3 # 6
```

通常の引数と可変長引数を組み合わせることもできます。

```ruby
def name_sum(name, *points)
  "#{name}さんの合計点は#{points.sum}点です"
end

puts name_sum 'suzuki', 10, 20, 30 # suzukiさんの合計点は60点です
```

### 展開

逆にメソッド呼び出し時の引数名の前に`*`を付けると配列を展開してメソッドに渡すことができます。

```ruby
def five_avg(a, b, c, d, e)
  (a + b + c + d + e) / 5
end

def avg(*nums)
  nums.sum / nums.length
end

points = [10, 20, 30, 40, 55]
puts five_avg *points # 31
puts avg *points      # 31
```

# 参考

+ ドキュメント・リファレンスマニュアル
  + [Ruby公式ドキュメント](https://www.ruby-lang.org/ja/documentation/) ([他言語からのRuby入門
  ](https://www.ruby-lang.org/ja/documentation/ruby-from-other-languages/))
  + [Ruby リファレンスマニュアル](https://docs.ruby-lang.org/ja/latest/doc/) ([Arrayクラス](https://docs.ruby-lang.org/ja/latest/class/Array.htm))
  + [Railsガイド](https://railsguides.jp/) ([Active Recordの基礎 > 6 バリデーション（検証）](https://railsguides.jp/active_record_basics.html#%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%EF%BC%88%E6%A4%9C%E8%A8%BC%EF%BC%89))
+ 参考にさせて頂いたQiitaの記事
  + [Rubyの引数(オプション引数とブロック引数)について](https://qiita.com/yui-knk/items/f7ce1c3138ef44872d3b)
  + [Rubyのメソッドの引数受け渡しまとめ](https://qiita.com/raccy/items/1168c7e8849dedf70fa4)
  + [Ruby 命名規則まとめ](https://qiita.com/TakeshiFukushima/items/647a652439b55525945f)