Rubyの開発環境を2021年ぽくする for Windows

2021年なのでこれくらいは欲しい。

  • Ruby 2.7.4
  • VSCode
  • バイナリgemを確実にビルドできる
  • コードフォーマッタ
  • Lint
  • デバッガ
  • コード補完

それぞれは独立した機能なので全部入れなくてもいいと思います。(個人的には上から順に必須度が高い)

Ruby 2.7.4

Ruby3自体は安定しているがgem周りの挙動が若干安定していなかったのでこちらを採用した。 (RubyInstallerも2.7系をまだおすすめしていた。)

https://rubyinstaller.org/downloads/

rubyinstaller-devkit-2.7.4-1-x64.exeをダウンロードしてインストール。

Rubyのインストール終了後にmsysなどもインストールしてくるか聞いてくるので基本的には全てインストール。

バイナリgemのインストール

スタートメニューに「Start Command Prompt with Ruby」が作られるのでそこからgem installする。

f:id:tuto0621:20210807102945p:plain

(ビルドにかなり色々必要な) popplerもちゃんとインストールできて感動した。

コードフォーマッタ

コードフォーマッタにはrufoを使うことにした。 rubocopと比べてかなり高速に動作するのがよい。 VSCodeで編集中は定期的にShift+Alt+Fする派なのですぐに整形できる方がありがたい。prettierと違ってnodeを必要としないのもよい。

> gem install -N rufo

f:id:tuto0621:20210807103030g:plain

※ 整形したコードは有名なprettierのあれ

Lint

Toolboxで調べるとかなり勢いのあるstandardを採用。 面倒な設定無しですぐに使えるのがありがたい。

> gem install -N standard

適当なRubyプロジェクトの下に移動して、以下のコマンドを実行すればいい感じでコードを修正してくれる。

$ cd /path/to/project
$ standardrb --fix 

手持ちのmrubyプロジェクトのコードも問題なくコード修正できた。

ifのtrue節とfalse節で同じ変数に代入する場合に式の戻り値で代入するように変更してくれてなかなかすごい。(というかRubyのifが文じゃなくて式なことも知らなかった。こういうのも勝手に教えてくれるのがLintのいいところだと思う)

f:id:tuto0621:20210807103441p:plain

設定すればVSCodeからも問題のあるコードを教えてくれる。

f:id:tuto0621:20210807145448p:plain

デバッガ

これは色々なところでおすすめされていたgemをそのまま使った。

> gem install -N debase ruby-debug-ide

f:id:tuto0621:20210807145604g:plain

デバッガをF5で起動するには.vscode/launch.jsonの設定が必要。(VSCodeGUI上で自動生成してくれるし、手で書いてもよい)

f:id:tuto0621:20210807145718p:plain

VSCodeの設定

ここまでインストールしたgemをVSCodeでも使えるようにする。

いわゆるRubyプラグインをインストールして、以下の設定を加える。

https://github.com/testdouble/standard/wiki/IDE:-vscode

  • Language Serverを有効にする
    • ブロックのfold, unfoldなどが有効になる
  • インテリセンスにrubyLocate
    • F12で定義ジャンプができるようになる
  • Linterはstandard
  • Formatterはrufo
  • Debuggerは特に設定不要

settings.jsonは以下のような感じ。

{
    "ruby.lint": {
        "standard": true,
    },
    "ruby.format": "rufo",
    "ruby.useLanguageServer": true,
    "[ruby]": {
        "editor.tabSize": 2
    },
    "ruby.languageServer": {
        "logLevel": "info"
    },
    "ruby.intellisense": "rubyLocate",
}

コード補完

ここまででも十分に便利だが、さらにコード補完にも対応するならsolargraph gemを入れるとよい。

> gem install -N solargraph 

solargraphには専用のVSCodeプラグインが用意されている。"Ruby Solargraph"をインストール。

https://github.com/castwide/vscode-solargraph

補完だけじゃなくメソッドのドキュメントがその場で見れるのも便利。

f:id:tuto0621:20210807150126p:plain

まとめ

コード整形、Lint、デバッガ、コード補完とコーディングに必要な機能が一通り使えるようになり大分便利になった。

この辺りのコーディング支援機能がgolangやRustのような後発の言語と違って標準で用意されていない(もしくは選択肢が多すぎてどれを使ってよいか分からない)ため、どのgemを入れればよいかを検証するのにそこそこ時間がかかった(探せば何かしらあるであろうことは分かっていたのだが)。

irbも最近はコード補完が強力になってかなり使いやすくなったため、例えばコード整形機能だけでも標準で用意されているとすごく印象がすごくよくなりそうだなぁと思った。

Rubyは成熟した言語なのでこの辺りの周辺機能の充実がより重要なのかもしれない(https://github.com/ruby/debug などの開発が進んでいるのはとても楽しみです)。

Rustのライフタイムについて調べている

The Rust Programming Languageを読んでいる。GC無しでどうやって参照を安全に管理しているのかを知りたかったのだが、10章ライフタイムまで来てようやくぼんやりと分かってきた。

Rustの全ての参照には寿命が設定されている。書かなくていい場合もあるがそれは暗黙で設定されている。参照は当然何らかの実体を指しており(nullは無い)、実体の寿命より参照の寿命が長い場合はエラーになる。C++でこれをやった場合はいわゆるダングリングポインタになる。

ここまでは何となく分かっていたのだが、問題は関数の引数に渡した参照を戻り値で返すような場合だ。関数コールはいくらでも深くできるので正確にどの実体を指しているか把握しようとすると難しい。

例えば fn longest(x: str&, y: str&) -> str& のような、文字列参照を2つ受け取って長い方を返す関数を考えてみる。寿命にしても文字列長にしてもx, yどちらが長いかは呼び出し箇所によって異なる。どのように参照安全を確保すればよいのだろうか?Rustではこの問題を解決するためにライフタイムを明示させる。(実際のところ前述の書き方ではRustはコンパイルエラーになる)

fn longest<'a>(x: str&'a, y: str&'a) -> str&'a

'aがライフタイムで、この場合はx, yと同じ寿命の文字列参照を返す、という意味になる。

呼び出し側はx, yどちらの参照が返ってくるか分からないので「longest()の結果の参照は引数の短い方の寿命だと仮定してその後のコードを処理する」ことになる(ここが賢いところ)。確かによく考えたらコンパイラが実際の寿命よりも仮定すればコードは安全になる。

メンバ変数の参照にもライフタイムが設定されており、自分よりも早く実体が消えるものの参照はメンバ変数に代入できない。基本的な考え方は同じということだ。

まとめると

  • 寿命が自分よりも短い実体の参照は保持できない
  • 関数呼び出しで複数の候補から参照を返すような場合は、その中で最も短いものが返って来ると仮定して静的に解析する

となる。寿命のワーストケースを仮定しながら解決していけば静的に参照安全を保証できるのか。

Windowsの親指シフト入力用のソフトをDvorakJからやまぶきRに変更した

ずっとDvorakJを愛用していたのだが、勝間さんがやまぶきRを使っているという情報を聞いてやまぶきRを試してみることにした。

ここからダウンロード。インストールすればすぐに親指シフトが使えるようになる。

設定はほとんどデフォルトのままだが左親指シフトキーは「無変換」に変更する。(Thinkpadの日本語キーボードはスペースキーが小さいので無変換でもいける)

インストール後の話、やまぶきRだと入力のレスポンスが向上した気がする。https://kamosawa.hatenablog.com/entry/2019/12/21/232303 辺りが理由らしい。

さらに、DvorakJを有効にしているとコマンドプロンプトでの入力がもたつくという不具合があったのだが(英語入力のときも発生する、左シフト+右シフトで一時的にOFFにしてしのいでいた)、やまぶきRだとこれが発生しない!これが私的にはかなり嬉しい。

残念な点としてはエクスプローラーのクイックアクセスへの入力がなぜかローマ字入力のままになるようだ。雰囲気的にこれは他のアプリでも発生するかもしれない。

さておきメリットが大きいので一旦やまぶきRを使っていくことにする。

最後に、何年も自分の入力環境になくてはならない存在だったDvorakJには最大級の感謝を送りたい。

最近作っているClipScript

https://github.com/ongaeshi/clipscript

短い動画を簡単に作成するためのスクリプト言語です。

f:id:tuto0621:20210618235722g:plain

require 'clip'

App.window_size(400, 225)

font_s = Font.new(40)
font = Font.new(50)
smile = Texture.new(Emoji.new("😀"))

script do |root|
  Drawer.background "white"

  (0..10).each do |x|
    (0..10).each do |y|
      if (x + y) % 2 == 0
        root.rect(x * 40, y * 40, 40, 40, color: "gray")
        root.wait 0.02
      end
    end
  end
end  

script do |root|
  t = root.text(font, 200, 100, color: "black", text: "Hello, World!", length: 0, center: true)
  root.wait 0.2

  1.upto(t.text.length) do
    t.length += 1
    root.wait 0.1
  end

  root.until_time 3

  x = root.texture(smile, 180, 150)
  x.scale(0.4, 0.4)
end

App.run

タイムラインUI

記述したスクリプトは好きな場所から再生したり逆再生することができます。

f:id:tuto0621:20210619000458g:plain

gifアニメを再利用した動画の作成

gifアニメの再生機能に力を入れており、動画ファイルの編集無しで以下のようなことができます。

  • テロップの表示
  • 再生レートの変更
  • サイズの調整

f:id:tuto0621:20210619004049g:plain

これは直前に紹介したgifファイルを再利用して作成した動画です。追加で書いたのはこのスクリプトのみです。

インストール

最新版をGitHub Actionでビルドしたものがあるので興味がある人は触ってみてください。

  1. https://github.com/ongaeshi/ClipScript/actions から(成功した)最新のActionを開いてbuild-resultをダウンロード
  2. .rbファイルを.exeにドラッグ&ドロップすると動きます

使用ライブラリ

  • OpenSiv3D
  • murby

OpenSiv3dはgifアニメの再生が簡単なのがよいです。(次の0.6ではmp4の再生もできるようになるそうなのて大変楽しみです。)

mrubyは自作のongaeshi/mruby-packerを使ってソースコード丸ごとレポジトリに入れてあります。(ので、ソースコードを対応するプラットフォームのOpenSiv3DにコピーすればMacLinuxでも動くはず)

自分のホームページをリニューアルした

dev.toのBuilding a Kickass Portfolio - DEV Communityに触発されて、 しばらく消えていた https://ongaeshi.me を復活させた。

f:id:tuto0621:20210216224945p:plain

TwitterやBlogへのツールバーを作ったのでホームページ経由ですぐにアクセスできるのが便利。 自分がここ最近何をやっているのかも大分把握できた。 ドキュメントページをちゃんと整備するのはやはり重要。

HISTORYを眺めていてふと思ったのは、 FireLinkみたいに(Firefoxのバージョンがあがったことで)すでに使えなくなってしまったソフトウェアでも、 ちゃんとドキュメントのページを残しておくとそれがどんなツールで何ができるのかは他の人が見てもなんとなく分かる。 ドキュメントの寿命はソフトウェア本体よりも長いことが大半なのかもしれない。

WindowsでWSL2を使ってRuby3.0.0-preview2を動かす

動きました。

f:id:tuto0621:20201216010609p:plain

WSL2のインストール

https://docs.microsoft.com/ja-jp/windows/wsl/install-win10#manual-installation-steps

プレビュー版のWindows10を使って簡単にやる方法と、現状のWindows10に手動インストールする方法が用意されているが、今回は手動インストールの方で進めた。とはいえ手動インストールでも十分に簡単。

を入れた。

Windows ターミナルをインストール

https://docs.microsoft.com/ja-jp/windows/wsl/install-win10#install-windows-terminal-optional

普段DvorakJを使って親指シフト入力をしているのだが、DOSプロンプトとの相性が悪く入力がもたつくバグがある。デフォルトのWSLのシェルはDOSプロンプトのため同じ問題があるのがずっと不満だった。(そのときだけDvorakJを無効にしてしのいでいた) Windowsターミナルだとそれが起きない!

それ以外でもきびきびと動作してとても印象がよい。

aptを最新に更新

$ sudo apt update

rbenvをインストール

https://qiita.com/ma2shita/items/5c41aa8a4908c919ba78

途中までは同じで最後に3.0.0-preview2を選択する。

$ rbenv install 3.0.0-preview2
$ rbenv global 3.0.0-preview2

Ruby3で遊ぶ

https://qiita.com/jnchito/items/bf8c6c2e1dd6cff05f4e

と同じことが一通りできることを確認。

WSL2上でcode rubytest/とかやると自動でRemove - SSHがインストールされて開くことができる。VSCode Steepも動いているようだ。

注意: /mnt/c/Users/..のようなWindowsフォルダ上でVSCode Steepを使おうとすると動作がもたついたり挙動が怪しくなるので注意。~/ruby3-testとかに置いて試してみよう。

感想

小さなファイルだからかもしれないが補完はきびきびと動くし型エラーが発生したときにすぐに赤線がついてエラー箇所も分かる。

後はF12で定義ジャンプや一括リネームなどができるようになれば型を書こうという気持ちになるかもしれない。

RubyMineのような有料の優れたツールを使えば現在でも補完やリファクタリングツールが使えるのかもしれないが、無料でもある程度の補完ができるようになると裾野が広がってとてもよいと思いました。

f:id:tuto0621:20201216010704p:plain

fizz_buzzの戻り値に対してmapをかけてもちゃんとその引数がStringになることも追跡できている

○○という言葉を使うのをやめようという提案に対してどう振る舞うべきか

自分用にまとめておく。

基本方針

  • BLMに賛同する(悲しい事件であり二度と起こるべきではない)。
  • 過去と現代の文化や慣習の違いにより、言葉の中には現在のアクティブコンテンツで使用すると不穏な印象を与えるものが多数存在している。それらをより穏当な言い回しで置き換えていくことに賛成。
  • この作業に終わりはない。現在許容されている言葉の中にも将来的に必ず禁止になる言葉が出てくると考えており、そのためこの作業は長期的な視点で行っていく必要がある。

振る舞い

  • ○○という言葉を□□に置き換えましょう、という提案を受ける
  • (重要) 理由を聞く
    • (注意) 理由について自力で調べて対話を進めるのはおすすめしない、複数の理由があり人によって異なる可能性があるため
    • 対話している人物や団体がどのような理由でその言葉を置き換えるべきだと思っているのかがとても重要
  • 分岐1: 理由に納得できた場合
    • お礼を言ってできることをやっていく。
    • 賛同しているけどすぐにできないケースはある、仕方ない。
  • 分岐2: 理由に納得できない場合
    • (したければ) その理由がおかしい理由を述べて、置き換えるべきではないのではないか、という話をする
    • (注意) 反論が発散しないように気を付ける。例えば△△という起源なので使うのをやめるべき、という理由であれば、◎◎という起源という話もありますよという反論は有効だが、そうで無い場合は軋轢を生むだけでいいことが少ない。
    • 論破して相手の意見を変えてもらうのは大量のエネルギーを使うしそもそも無理だったりするので注意する。主張している人はその人なりの理由がありすでに自分のコミュニティの中で賛成者がたくさんいるようなバックグラウンドに所属している可能性もある。しっくりこなければしっくりこないでよいけど、そんな簡単に変わる訳ない(お互いに)。
    • 名指しで作業を要求されているのでなければそこからすっと離れてもいいのかもしれない。(反対なのであればバズらせないほうがいいのかも)

Q&A

○○という言葉を□□に置き換えない人間は差別主義者だと言われたら?

  • 挑発に乗ってはいけません、あなたは差別主義者ではありません。
  • 今まで使っていた言葉を置き換えることのコストやプライオリティは人によって大きく異なります。1つ1つのトピックをすぐに実行できないだけでそのような攻撃的な言葉を使う人間の言うことを気にする必要はありません。
  • ただし、不穏な言葉を穏当な言葉に置き換えていく大きな流れ全体を否定するような言動や行為は差別に荷担していると(私は)考えています。

1つ受け入れたら、また1つ・・と全ての言葉を受け入れることになってしまうのではないか?

  • なりません。ブラックリストを置き換えることを決定しても、マスター/スレーブを置き換えることは決定しません
  • それぞれに個別の理由を聞いて、議論して、やるかやらないか決定する・・の繰り返しです。

まとめ

  • Twitterで誰かの主張がバズっていても別に強制ではない。
  • 自分のOSSプロジェクトにそのような提案が来たときは理由を聞く。
  • 理由に納得がいくものはやる、分からないものはひとまず保留する、いつやるかは他のIssueとの優先を見て考える。
  • 妥協点をさぐる。ソフトウェアの名前はすぐに変えられないかもしれないけど内部で使っているローカル変数やクラス名だったら比較的簡単なときもあるかもしれない。