hotoolong's blog

プログラムのことやエンジニアリングに関することを記事にしています。

Ruby 3.0.0 preview1 の インストール

イントロ

Ruby 3.0.0 preview1がリリースされました。

www.ruby-lang.org

RBS、Ractorなど新しい機能が試してみたいところですね。

手順

ruby-build の アップグレード

まずruby-buildのバージョンアップをしましょう。

$ brew upgrade ruby-build

インストール時のメッセージにOpenSSLのバージョンに関して注釈があります。

ruby-build installs a non-Homebrew OpenSSL for each Ruby version installed and these are never upgraded.

To link Rubies to Homebrew's OpenSSL 1.1 (which is upgraded) add the following
to your ~/.config/fish/config.fish:
  export RUBY_CONFIGURE_OPTS="--with-openssl-dir=$(brew --prefix openssl@1.1)"

簡単に訳すと

ruby-build はインストールされた Ruby のバージョンごとに、Homebrew ではない OpenSSL をインストールしますが、これらは決してアップグレードされません。
RubyをHomebrewのOpenSSL 1.1(アップグレードされている)にリンクさせるには、次のように追加します。

あなたの設定ファイルに:
  export RUBY_CONFIGURE_OPTS="--with-openssl-dir=$(brew --prefix openssl@1.1)"

私の場合はシェルがfishなので
このexportは設定できないのでset -xでglobalに設定します。

set -x RUBY_CONFIGURE_OPTS --with-openssl-dir=(brew --prefix openssl@1.1)

ruby の インストール

install list を確認

rbenv install --list は stable のみが表示されるためまだ3.0は表示されません。

$ rbenv install --list
2.5.8
2.6.6
2.7.1
jruby-9.2.13.0
maglev-1.0.0
mruby-2.1.2
rbx-5.0
truffleruby-20.2.0
truffleruby+graalvm-20.2.0

Only latest stable releases for each Ruby implementation are shown.
Use 'rbenv install --list-all' to show all local versions.

--list-all ですべてが表示されるので3.0.0-preview1が追加されていることを確認しましょう。

ローカルのOpenSSLバージョン確認

ローカルのOpenSSLのバージョンを確認

$ openssl version
OpenSSL 1.1.1g  21 Apr 2020

同じバージョンなので設定したものをつかってもらうことにします。

rbenv install

普通にインストールすると

$ rbenv install 3.0.0-preview1
Downloading openssl-1.1.1g.tar.gz...
-> https://dqw8nmjcqpjn7.cloudfront.net/ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46
Installing openssl-1.1.1g...

このようにOpenSSLのインストールから開始されます。
先程の RUBY_CONFIGURE_OPTS のオプションを追加しておくと設定されたOpenSSLを使ってもらえます。

 $ rbenv install 3.0.0-preview1
Downloading ruby-3.0.0-preview1.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0-preview1.tar.bz2
Installing ruby-3.0.0-preview1...

上記のようにRUBY_CONFIGURE_OPTSを設定しているとrubyのインストールが始まります。 こうすることでインストール時間も節約できますね。

$ rbenv local 3.0.0-preview1
$ ruby -v
ruby 3.0.0preview1 (2020-09-25 master 0096d2b895) [x86_64-darwin19]

Enjoy Ruby life!

RSpec初心者向け勉強会の動画がとても良かった

イントロ

RSpecの初心者向け勉強会が紹介されていました。

blog.jnito.com

勉強会の内容を動画で公開してくれています。
最近RSpecをあまり書いておらずトレンドも追えてなかったのでとても為になる内容でした。

気になった内容

テストの書くべきところ

動画の12:25

システムとして重要な点を書くのは当然なんでしょうが、
System Testに重きをおいて書いていくのがいいという内容でした。

これはよくE2E(End to End)をいかに作っておくかがRailsバージョンアップする際にも鍵になる。
ような話を勉強会に参加したときによく話が盛り上がります。
E2Eを如何に作って置けるかがプロジェクトをうまくすすめる上でも効率がいいですね。

Capybaraの支援ツール

動画の8:10

github.com

を紹介していました。
これはChromeのExtensionでブラウザ操作をCapybaraのコードをジェネレートしてくれます。
これは便利そうですね。

github.com

は知っていたのですが、
それより以前に作らてていますし、
操作ごとに追加されているのを確認できるので使いたいところだけ使うこともできそうです。
これはいいですね。

まとめ

このような勉強会は有意義ですね。とても為になりました。
余談ですが、 最後の方に伊藤さんがイケメンだという話が出てたのがダンディな感じでイケメンですねw

Rubyの継承元のクラスの別メソッドをsuperで呼び出す

イントロ

Rubyの継承先で継承元のメソッドを単純に呼び出すにはsuperを使いますが、
継承元の別メソッドを呼び出したい場合にどうしていいのかわからなかったので調べてみました。

詳細

class A
  def test1(*args)
    puts "A#test1:args(#{args})"
  end

  def test2(*args)
    puts "A#test2:args(#{args})"
  end
end

class B < A
  def test1(*args)
    puts "B#test1:args(#{args})"
  end

  def test2(*args)
    method(:test1).super_method.call(*args)
    puts "B#test2:args(#{args})"
  end
end

B.new.test2('test')
# => A#test1:args(["test"])
# => B#test2:args(["test"])

Aを継承したBのtest2メソッドを呼び出しているのですが、
test2の処理でAクラスのtest1メソッドを呼び出したくなった場合に
以下の処理で呼び出しています。

method(:test1).super_method.call(*args)

method(:test1)でMethodオブジェクトを取り出して
super_methodで親のAクラスのtest1メソッドのMethodオブジェクトを呼びだせます。
これは便利ですね。

参考URL

親クラスの別のメソッドを呼ぶ - Qiita
class Method (Ruby 2.7.0 リファレンスマニュアル)

vimの置換で改行、タブを挿入する

イントロ

度々vimの置換処理で改行やタブを追加して置換するケースがあるのですが、 挿入するためのキーバインドを忘れてしまうのでもう少し調べてみたという内容です。

やり方

改行に置換したいケースで 私がよく利用するのはjsのコードで;の後に改行を無作為に入れたいケースです。

:%s/;/;^M/g

というようなコマンドを入力します。 ^Mはそのまま文字列で入力するのではなく制御文字として挿入します。 ^Mの入力方法はCtr-vとCtr-mで入力可能です。

これで目的は達成できました。

忘れっぽい

^M を入力するための Ctr-vとCtr-m なのですが、
頻繁に利用するわけではないので 脳内で\nを使って改行を挿入しようとするのですが、これだと出来ないんだったわ。
なんだっけ?
のような感じでググることを何度か繰り返していました。

そもそもCtr-vがよくわかってなくCtr-vとCtr-mがセットになっていてこれが何を意味してるのか分からないなという感じでした。
これ別々のコマンドなのかな?とおもい調べてるとhelpに書いていました。

helpを確認してみると

CTRL-V
Insert next non-digit literally.
Up to three digits form the decimal value of a single byte.
The non-digit and the three digits are not considered for mapping.
This works the same way as in Insert mode (see above, |i_CTRL-V|).

Note: Under Windows CTRL-V is often mapped to paste text.
Use CTRL-Q instead then.

Ctr-vの後に入力された文字を非数字文字にして挿入されるようです。 ですのでその後に入力されるCtr-mはEnterでも代替できました。

改行以外でTABを入力する場合もCtr-vとCtr-i Ctr-vとTABキーでも入力可能でした。

ちなみにWindowsではCtr-vはペーストに割り当てられていることがよくあるのでCtr-qで代用できるそうです。

これで結構スッキリはしました。なんとか記憶に定着されそうです。

参考

https://vim-jp.org/vimdoc-ja/cmdline.html#c_CTRL-V https://ja.wikipedia.org/wiki/%E5%88%B6%E5%BE%A1%E6%96%87%E5%AD%97 https://ja.wikipedia.org/wiki/ASCII#ASCII.E5.88.B6.E5.BE.A1.E6.96.87.E5.AD.97

asyncomplete-tabnine.vim を neovim に対応してみた

概要

tabnineはAIによる入力補完をサポートしてくれるツールです。
vimでも利用できるのですが、デフォルトで使うと同期処理されてレスポンスが遅く使い勝手が悪いです。
非同期用としてYouCompleteMeやCoC、Deopleteが対象となっていますが、私は普段asyncomplete.vimで補完をしているため対象になってませんでした。
asyncomplete-tabnine.vim とうプラグインを作ってくださった方がおり、インストールしてみたのですが、NeoVimではjob_start関数がないとエラーになっていました。
そこで自分用にneovimで動作させてみました。

リポジトリ

github.com

インストールする場合はREADMEを確認してください。

変更点

https://github.com/kitagry/asyncomplete-tabnine.vim/compare/master...hotoolong:master

上記の差分が修正点になります。興味のある方は確認してみてください。

vimのjob_startはneovimではjobstart関数(ハイフンがない)で似たように処理をしています。
引数で渡すコールバック関数の引数の数が違っていたりするので、
vimとneovim両者に対応する場合はどちらのコールバック関数も作成する必要がありそうです。冗長な状態ですね。

jobでIOを確立した後にchannelを制御するのも vimではch_sendrawを使っているのに対してneovimではchansendを使っています。
このあたりもまだ理解が追いついてないのですがhelpを見ながらなんとか動かしてみたという状態です。

まとめ

以前からneovimで動作しないvim pluginを見かけては使いたかったけど仕様が無い気持ちでいました。
これで少しは便利に使えそうです。

ただ、以下のように

と両者の違いが吸収されていくのか少し期待していたのですが、
Shougoさんから

とあったので
ますます乖離していきそうです。
もともとvimからneovimに完全に乗り換えていたのはvimの動作がもっさりしていたのがきっかけですが、
neovimは独自のエディタとして進んでいきそうです。

最近のVimのバージョンでは新しい機能も増えて速度も随分と改善されているように感じます。
neovimの開発がvimを踏襲したものになってはいないのでこのままneovimを使い続けるべきかとても心動かされる内容となりました。
しばらくは併用して考えるかもしれないです。

参考にした記事

scrapbox.io

Nvim documentation: job_control

Nvim documentation: channel

nanasi.jp

thinca.hatenablog.com

vim-plug で プラグインの遅延ロードを行う

イントロ

最近neovimの起動が もっさり してきました。
プラグインマネージャーにはvim-plugを使っていまます。
こちらの環境で起動時間を改善してみました。

計測

nvim --startuptime ./startup.log

こちらのコマンドで起動時の処理時間が計測できます。

times in msec
 clock   self+sourced   self:  sourced script
 clock   elapsed:              other lines

000.093  000.093: --- NVIM STARTING ---
002.755  002.662: locale set
:
: (途中省略)
:
952.261  000.003: --- NVIM STARTED ---

左端が累計の時間、2番目が実行されている処理の時間です。

:%!sort -r -n -k 2

処理時間別に並び替えて重い処理を抽出できます。

プラグインの遅延ロード

vim-plugでは遅延ロードの種類が限定されています。
onとforをつかって遅延ロードさせるのが常套なのですが、
数秒後に読み込みのような設定はまだないようです。

タイマーで呼び出す

qiita.com

こちらの記事で取り上げられていて試してみたらとても良かったです。

以下のサンプルとしてlspの読み込みを遅延させています。

call plug#begin('~/.vim/plugged')

" .. 省略

Plug 'prabirshrestha/vim-lsp', { 'on': [] }
Plug 'mattn/vim-lsp-settings', { 'on': [] }

" .. 省略

call plug#end()

function! s:load_plug(timer)
    call plug#load(
                \ 'vim-lsp',
                \ 'vim-lsp-settings',
                \ )
endfunction
call timer_start(500, function("s:load_plug"))

Plugにonでから配列を設定することで読み込まなくなります。
timer_startで500ms後にs:load_plug関数を呼び出すようにしています。

plug#loadで遅延させる対象のprefix部分の文字列を省いて登録しておくと呼び出せます。
はじめ間違ってPlugに設定している文字列をそのまま渡してしまいエラーになってしまいました。
気をつけて!

計測時に遅くなっているものとあとからロードしても問題なさそうなプラグインを設定して再度計測してみると

952.261ms → 455.829ms になりました。

これでしばらくは快適に過ごせそうです。

参考URL

vim-plug/plug.txt at master · junegunn/vim-plug · GitHub

【vim-plug】InsertEnterイベントで遅延読み込み - Qiita

vim/neovimの起動時間・プラグイン読込時間を調べる - Qiita

neovimでpython3のエラーに遭遇

概要

結果としてはpython3のバージョンを上げてしまったのでエラーがでてたので対応したというものです。

起動時のエラー内容

ERROR: Failed to run healthcheck for "denite" plugin. Exception:
  function health#check[21]..health#denite#check[3]..<SNR>211_check_required_python[7]..denite#init#_python_version_check, line 8
  Vim(python3):E319: No "python3" provider found. Run ":checkhealth provider"

上記のような内容のエラーが出ていました。

詳細確認

:checkhealthしてみたところ

## Python 3 provider (optional)
  - WARNING: No Python executable found that can `import neovim`. Using the first available executable for diagnostics.
  - ERROR: Python provider error:
    - ADVICE:
      - provider/pythonx: Could not load Python 3:
          /usr/local/bin/python3 does not have the "neovim" module. :help |provider-python|
          python3.9 not found in search path or not executable.
          /usr/local/bin/python3.8 does not have the "neovim" module. :help |provider-python|
          python3.7 not found in search path or not executable.
          python3.6 not found in search path or not executable.
          python3.5 not found in search path or not executable.
          python3.4 not found in search path or not executable.
          python3.3 not found in search path or not executable.
          /usr/bin/python is Python 2.7 and cannot provide Python 3.
  - INFO: Executable: Not found

というメッセージが出ていたので help provider-pythonして確認すると

To use Python plugins, you need the "pynvim" module. Run |:checkhealth| to see
if you already have it (some package managers install the module with Nvim
itself).

For Python 3 plugins:
1. Make sure Python 3.4+ is available in your $PATH.
2. Install the module (try "python" if "python3" is missing): >
   python3 -m pip install --user --upgrade pynvim

解決方法

python3 -m pip install --user --upgrade pynvim

を実行して解決しました。 めでたし。