何ぞや||=

# はじめに
gemなどで公開されているコードを読んでいて`` ||= ``を見かけます。
これってなんだろう？と思ったので、調べた内容をメモしておきます。

間違っているなどあると、指摘・ご教示頂けると嬉しいです！！
# ``||=``って何？
「||」演算子の自己代入演算子。
左辺が**偽**か**未定義**であった場合、右辺が代入されます。
##コンソール検証
どう言うことか、実際にコンソールを使って検証してみました。

**(2019/9/16 偽と未定義で紹介する内容変更)**
**①左辺が偽の場合編**
Rubyではfalseとnilが「偽」と定義されたオブジェクト(「[擬似変数](https://docs.ruby-lang.org/ja/2.6.0/doc/spec=2fvariables.html#pseudo)」と言うらしいです）です。
裏を返すとそれ以外は全て「真」と言うことです。
（詳しくは記事下の@scivolaさまからのコメント解説を！！！参考になります^^）←投げた!!!

それでは、「偽」オブジェクトである「false」と「nil」それぞれについて確認してみましょう。

**falseパターン**

```sample.console.rb
[1] pry(main)> flag   = false  # 「偽の代表オブジェクトである「false」を定義した変数を用意
=> false
[2] pry(main)> flag ||= true   # [1]に"||="を使って「真の代表オブジェクトである「true」を代入
=> true                        # 左辺がfalse(偽）なので値が代入された！
[3] pry(main)> flag ||= false  # true(真)が入った変数に"||="を使って「false(偽)」を代入
=> true                        # 左辺が真なので何も起こらない！
```

ほうほう。``true``に``true``代入しても動作する気はするけど、この方が意図が伝わりやすいですね（・ω・）

**nilパターン**

```sample.console.rb
[1] pry(main)> sample = nil         #「nil」を代入
=> nil
[2] pry(main)> sample               #「nil」が代入されてるね！
=> nil
[3] pry(main)> sample ||= 1         #「1」が自己代入されたね！
=> 1
[4] pry(main)> sample ||= nil       #状態が「真」に変わっているので、もう自己代入されないね！
=> 1
[5] pry(main)> sample = 0           #じゃあ「0」は？
=> 0
[6] pry(main)> sample ||= 1         #もちろん「偽」じゃないので、自己代入されません^^
=> 0
```

なるほど〜。
定義済みだった場合でも``nil``を代入すれば、「||=」による自己代入が可能になる訳ですね。

**②左辺が未定義の場合編**
そもそも未定義ってなんぞやって気もしますが、「未定義（undefined）」であることを確認した上で試してみました。

```sample.console.rb
[1] pry(main)> sample               # 「未定義（undefine）」であることを確認
NameError: undefined local variable or method `sample' for main:Object
from (pry):1:in `__pry__'
[2] pry(main)> sample ||= 1         # 未定義だった変数に左辺の値が代入された！
=> 1
[3] pry(main)> sample ||= 2         # 定義済みの変数には左辺の値が代入されない！
=> 1
```

すでに定義された値があれば、それを潰さずに済むのかぁ〜。
未定義の場合に限り、自己代入すると言うのは、かなり強力ですね（・ω・）!!!

## 具体的な使用例〜その①〜
**(2019/9/14 指摘による再確認により訂正と大幅加筆)**

Payjpで公開されているコードを使用例として抜粋します。

```payjp/lib/payjp.rb
module Payjp
  @api_base = 'https://api.pay.jp'
  @open_timeout = 30     #デフォルト値指定可能
  @read_timeout = 90     #デフォルト値指定可能
  @ssl_ca_file = nil
  @ssl_ca_path = nil
  @ssl_cert_store = nil

  class << self
    attr_accessor :api_key, :api_base, :api_version, :connect_base, :uploads_base,:open_timeout, :read_timeout, :ssl_ca_file, :ssl_ca_path, :ssl_cert_store
  end

 #　省略 #
  def self.request(method, url, api_key, params = {}, headers = {}, api_base_url = nil, open_timeout = nil, read_timeout = nil, ssl_ca_file = nil, ssl_ca_path = nil, ssl_cert_store = nil)
    api_base_url ||= @api_base
    open_timeout ||= @open_timeout  # nilが保証された状態なので確実にdefault値／指定値のどちらかを代入される
    read_timeout ||= @read_timeout  # nilが保証された状態なので確実にdefault値／指定値のどちらかを代入される
    ssl_ca_file ||= @ssl_ca_file
    ssl_ca_path ||= @ssl_ca_path
    ssl_cert_store ||= @ssl_cert_store
 # 省略 #
  end
end
```
出典：[Payjp/lib/payjp.rb](https://github.com/payjp/payjp-ruby)

**【①仮引数でnil初期化→インスタンス変数を自己代入(Payjpでの使われ方)】**
「open_timeout」と「read_timeout」は、利用者側で指定が可能な変数です。
指定するにはWebAPIを呼び出す前に``Payjp.open_timeout = 40``等と定義しておくだけです。

呼び出されたWebAPI側は``@open_timeout``に指定された"40"の値を保持しています。
また、WebAPI側では、仮引数として``open_timeout``を定義し``nil``が代入されるようになっています。（=``nil``が入っていることを保証している状態）

この状態で``open_timeout ||= @open_timeout``を行うことで、指定した値がちゃんと入る訳ですね。

**【②引数で値指定し真の状態に→default値の上書きを防ぐ】**
payjpのreadmeを見る限り、引数指定でのopen_timeoutの値指定は記載されていません。
ただ、引数でdeafult値と指定値を切り分けること自体は可能だとは思います。
こんな感じ↓

　実引数の指定がある　→　実引数で仮引数が初期化される
　実引数の指定がない　→　仮引数のデフォルト値（nil)で初期化される

この状態で``open_timeout ||= @open_timeout``を行うことで、指定した値とすることが可能！！（な、はず・・・）
私なりには、この使い方の方が成る程感がありました^^;

###補足検証
私の分かりにくい説明で、腑に落ちる人が一体どの程度存在するか・・・否(笑)
と言うことで、payjpのメソッドの超劣化抜粋版のsampleメソッド作ってコンソールから、試してみました。

**検証用のサンプルコード**
とりあえず、見てくれはこれで似せれたはず。（ホントか

```app/controllers/concerns/sample_service.rb
module SampleService
  extend ActiveSupport::Concern
  @default_param = 30 # インスタンス変数。デフォルト値は30

  class << self
    attr_accessor :default_param #インスタンス値にアクセスするためのメソッド
  end

  def self.sample_service(num,options={},default_param = nil) #nilを代入して偽であることを保証する
    binding.pry
    default_param ||= @default_param # インスタンス変数をローカル変数に代入して処理
  end
end
```
**①サンプルコードの検証結果**
Payjpぽく使うなら、こんな感じだと思います。
configとかの設定って、こう言う風にやってるのかな（?_?）

```sample.console.rb
# まずは呼び出し前にインスタンス変数の中身を確認
[1] pry(main)> include SampleService              #まずは対象をインクルード
 => Object
[2] pry(main)> SampleService.default_param        #インスタンス変数の中身を確認。初期値に設定した値が入ってるね！
 => 30
[3] pry(main)> SampleService.default_param = 100  #インスタンス変数に「100」を代入。成功！
 => 100
[4] pry(main)> SampleService.sample_service(3)    #そいじゃ適当にサービスを呼び出そう！

 # binding.pry　されたね !
    12: def self.sample_service(num,default_param = nil)
 => 13:   binding.pry
    14:   default_param ||= @default_param

[1] pry(SampleService)> @default_param           #さっきの設定が生きているかインスタンス変数を確認。OK！大丈夫！
=> 100
[2] pry(SampleService)> default_param            #仮引数はnil初期化・・・OK!されてるね！
=> nil
[3] pry(SampleService)> default_param ||= @default_param  #面倒だ！ここで自己代入かけちゃう！おっし成功！
=> 100
[4] pry(SampleService)> default_param            #うん、大丈夫、大丈夫！
=> 100
```

**②サンプルコードの検証結果**
可変長引数が邪魔な感じはあるけど、何となく行けそうな感じ。

```sample.console.rb
[1] pry(main)> include SampleService                     #default値を確認する
=> 30
[2] pry(main)> SampleService.sample_service(3,{},40)        #第3引数を指定してメソッド呼び出し

    12: def self.sample_service(num,options={},default_param = nil)
 => 13:   binding.pry                                     #こちらもbinding.pryされたね！
    14:   default_param ||= @default_param
    15: 

[1] pry(SampleService)> default_param                     #nilじゃなくて、引数で指定した値になってる！
=> 40
[2] pry(SampleService)> @default_param                    #インスタンス変数はdefault(30)のままだね!
=> 30
[3] pry(SampleService)> default_param ||= @default_param  #インスタンス変数の値に更新されなかった！ヨシ!
=> 40

```
とりあえず、こんな感じで行けるのではと(^^;
他の使い方も見つけたら、載せていこうと思います〜。よろしくお願いしますmm


# 【補足】「||」演算子について
そもそも「||」演算子ってなんぞや？と思いませんか？
条件式書くときによく見る、条件と条件をORで繋げる記述じゃないの？くらいな理解ですよ。
それに=がついて自己代入になったからって、何故この仕様なのか(？_？)

と、理解の足りていなかった私のために、追加で整理。
##「||」演算子
「||」の左辺、右辺のどちらかの条件が真であれば**真**を返す。と言う演算子です。
この演算子でも「||」演算子の自己代入と同一の処理を実現可能です。

下記を実行すると**基本的に**同じ結果が返ってきます。

```sample.rb
a ||= b         #||演算子の自己代入
a ||  (a = b)   #||演算子
```

##コンソールで検証
実際に||演算子を使って検証してみるのが理解への近道。
と言うことで、コンソールで確認。

**①aがnil、bが2の場合**

```sample.console.rb
[1] pry(main)> a = nil           # aに「nil」を代入
=> nil
[2] pry(main)> b = 2             # bに「1」を代入
=> 2
[3] pry(main)> a || ( a = b )    # 結果として「1」が返ってくる！
=> 2
```

**②aが1、bが2の場合**

```sample.console.rb
[1] pry(main)> a = 1             # aに「1」を代入
=> 1
[2] pry(main)> b = 2             # bに「2」を代入
=> 2
[3] pry(main)> a || ( a = b )    # 結果として「1」が返ってくる！
=> 1
[4] pry
```
ここまで来ると「あ〜なるほど〜」と納得できました。

説明には「||の左辺、右辺のどちらかの条件が真であれば真を返す」とあるけど、左から順番に検証を行って、真を見つけたら、そこでリターンしているってことか。

なので、流れのイメージはこんな感じかと？

```
# ①のパターン
 1. 左辺を評価
 　　↓
 2. aは「nil(偽)」だ！次いこいこ！！
 　　↓
 3. 右辺を評価
    ↓
 4. (a=b)の結果は「2(真)」だ！！評価完了〜!

　結果：2

# ②のパターン
 1. 左辺を評価
 　 ↓
 2. aは「1(真)」だ！次見る必要なし！撤収撤収〜！！

  結果：1
```
結論「||」演算子は、式全体を評価するわけではないエコ仕様。

**2019/9/14 指摘による加筆**
「||」演算子の説明で``a||=b``と``a || (a = b)``が「基本的に」と強調したところ。
下で@scivolaさまから頂いた指摘の説明の方が分かりやすいのですが、一旦こちらにも加筆しておきます。

**＜同一の結果とならないパターン＞**
「||=」は、左辺が未定義であっても、右辺が真を返すなら真が返ってきます。
ですが「||」では、左辺が未定義の場合、NameErrorになります。

検証例をのせておきます。

```sample.console.rb
# 「||=」で左辺が未定義の場合（すでに、結果はご存知ですね・・・）
[1] pry(main)> b = 1
=> 1
[2] pry(main)> a ||= ( a = b )
=> 1

# 「||」で左辺が未定義の場合（こちらが問題のパターンです）
[1] pry(main)> b = 1          # aは定義せず、bのみに１を代入する
=> 1
[2] pry(main)> a || (a+b)     # aが未定義であるとエラーが出てしまい正常終了せず
NameError: undefined local variable or method `a' for main:Object
from (pry):2:in `__pry__'
```
# まとめ
``||=``は積極的に使っていって良さそう。
論理演算こんがらがりがち。もう少しスッキリイメージできるようにどこかで整理しないと。。

ちゃんと実機確認しながら理解する！！猛省！！！

# 参考
[Ruby2.6.0リファレンス：Rubyで使われる記号の意味（正規表現の複雑な記号は除く）](https://docs.ruby-lang.org/ja/latest/doc/symref.html)
[ Let'sプログラミング：Ruby入門:演算子](https://www.javadrive.jp/ruby/if/index4.html)
[とほほのWWW入門：Ruby入門：演算子](http://www.tohoho-web.com/ruby/operators.html)