ryotatake blog

Webエンジニア

Rubyのnilガードは未定義の変数にも使うことができた

Ruby(ver. 2.7.2)で次のように未定義な変数に対してnilガードを書いたらNameErrorだと思っていたのですが、普通に動きました。

# hogeは未定義な変数
hoge ||= "hogehoge"
hoge # => "hogehoge"

nilガードは未定義な変数についても使えるんですね。リファレンスにも書いてありました。

a ||= 1 # a が偽か未定義ならば1を代入。初期化時のイディオムの一種。

演算子式 - 自己代入 (Ruby 2.7.0 リファレンスマニュアル)

調べて分かったこと

私が未定義な変数にnilガードが使えないと勘違いしていたのは、hoge ||= "hogehoge" == hoge = hoge || "hogehoge"で、この式の右辺を評価する際にNameErrorが起きるかな、と思っていたためです。

# 右辺だけを評価したらエラー
hoge || "hogehoge" # => NameError (undefined local variable or method `hoge' for main:Object)

調べていたら、ここで二つの勘違いをしていたことが分かりました。

1. hoge = hoge || "hogehoge"はエラーにならない

そもそも hoge = hoge || "hogehoge"は、代入が挟まると最初に変数の初期化が行われるようでエラーになりません。

hoge = hoge || "hogehoge" # => "hogehoge"

2. hoge ||= "hogehoge"hoge = hoge || "hogehoge"ではなくて hoge || (hoge = "hogehoge")

基本的には自己代入式1 op= 式2式1 = 式1 op 式2のように評価されます。
しかし、&&||に限っては式1 op (式1 = 式2)と評価されるようです。これもリファレンスに記載されていました。

ちなみに、次のコードはエラーになります。

hoge || (hoge = "hogehoge") # => NameError (undefined local variable or method `hoge' for main:Object)

じゃあ hoge ||= "hogehoge"もエラーになるのでは、と思うのですが、||=を使った場合は特別に変数の初期化をしてくれているためエラーにならないようでした。

||=は変数の初期化に関しては1つのトークンとして機能し、未定義により参照に失敗すると、直ちに値の付与に移行します。

マネーフォワード社内PRに見られるRubyの書き方について – (4) 真理値 | Money Forward Engineers' Blog

fishシェルでvimのキーバインドを設定するときは`--no-erase`オプションをつける

fishシェルでvimキーバインドを設定するときは、fish_vi_key_bindingsfish_user_key_bindings関数の中に記述します。

このとき、基本的に--no-eraseオプションは付けた方が良いかと思います。

~/.config/fish/functions/fish_user_key_bindings.fish

function fish_user_key_bindings
  fish_vi_key_bindings --no-erase
end

--no-eraseオプションがないとき、fish_vi_key_bindingsが実行されるタイミングでそれより前に設定されていたキーバインドが全てリセットされます(実装されているコード)。

他のプラグインで自動的にキーバインドが設定されている場合、--no-eraseを付けないとそれらも全てリセットされてしまうのでご注意ください。

本日このせいで一部のキーバインドが効かなくなり、少し困りました。

fishシェルのvimキーバインドでEsc以外でインサートモードからノーマルモードに変更する

~/.config/fish/functions/fish_user_key_bindings.fishfish_user_key_bindingsに以下のように追記すればOKです。

function fish_user_key_bindings
  ...

  fish_vi_key_bindings --no-erase
  bind -M insert -m default jk force-repaint # 追記  jkでノーマルモードへ
end

やっていること

  • bindコマンドでキーバインドを設定
    • -Mオプションでキーバインドを追加するモードを指定
    • -mオプションでキーが実行された後に変更するモードを指定
    • force-repaintでプロンプトを再描画

今回設定したもので、インサートモードでjkが押されたらノーマルモード(defaultモード)に変更して、プロンプトの再描画を行う、ということになります。プロンプトの再描画を行わないと、プロンプトに現在のモードを表示している場合に表示されているモードが書き変わりません。

詳細はman bindもしくはfish-shellのbindのドキュメントをご確認ください。

ちなみにドキュメントにも書かれていますが~/.config/fish/config.fishの方にカスタムキーバインドの設定を直接書いても動かないのでご注意ください。

Macに公開鍵認証でssh接続できない時はまずログを確認する

仮想マシンからMacに対して公開鍵認証でssh接続をしようとしたのですが、上手くいかずハマりました。

結局ログを確認することで原因が分かり解決したので、ログの確認方法などを残しておきます。

Macに対するsshに限らず、ssh接続が上手くいかない場合はまずクライアントとサーバーそれぞれのログを確認すると確実な解決に繋がりそうです。

続きを読む

neosnippet.vimで次のマーカーにジャンプできない

neosnippet.vimを使ってsnippetを登録して使おうとしたのですが、次のマーカーへのジャンプができませんでした。

とりあえず解決したので、同じような問題に出会う人用に記録を残しておきます。

さいしょに結論

907th/vim-auto-saveというプラグインInsertLeaveイベントにフックしてオートセーブしているとうまく次のマーカーにジャンプしない。

907th/vim-auto-saveを使っている場合は、READMEを参考にしてg:auto_save_eventsInsertLeave以外のイベントを指定するか、vim-auto-saveを使わずに、autocmdを使って自分でInsertLeave時に保存する設定を定義する。

augroup vimrc-auto-save
  autocmd!
  autocmd InsertLeave * w
augroup END
続きを読む

GASでTimeTreeの今日の予定をLINEに通知する

先日TimeTree(タイムツリー)でAPIを使って予定の取得ができるようになりました。

カレンダーシェアアプリ「TimeTree」の予定取得API公開、Alexaに対応:CodeZine(コードジン)

私は普段TimeTreeを使っているので、Google Apps Scriptを使ってTimeTreeの今日の予定をLINEに送るようにしてみました。

続きを読む

Rubyで意図せず変数の値が書き換わってしまうことについて調べてみる

引数に文字列や配列を渡す場合、メソッドの中での処理のされ方によって元の変数の値が変わってしまうことがあります。

元の変数の値が変わってしまうことについて手を動かしながら確認してみました。

続きを読む