Polished Ruby Programming を読んでいる(2)

前回から継続してコツコツ読んでいる。 Chapter4 から先に読んだので、そこから逆戻りして Chapter 1, 2, 3, 5 ... の順に進めている。アラカルトに気になったところをメモ。

Chapter3: 変数

  • 変数名の長さはスコープの広さと反比例させる
    • メソッドの場合は呼び出し回数と反比例させる
    • Ruby に限らずどの言語でも有用な法則
  • 定数の内部実装は変数
    • 値の変更も禁止されていない
    • 警告が出るだけ
  • クラス変数は使ってはいけない。
    • 親子関係のあるクラスやモジュール間で簡単に上書きできてしまうため
    • 代用方法1: 定数を使う(値を変更したときに警告が出るのには目をつぶる)
    • 代用方法2: クラスインスタンス変数を defined?再帰的にルックアップする方法
    • 代用方法3: クラスインスタンス変数を inherited で生成時にサブクラスにコピーする方法
    • クラス変数微妙に使いにくくていつ使うんだろう?と思っていたので「使わないほうがよい」と書いてあってすっきりした
    • 代用方法がたくさんあるのが Ruby のメタ的な柔軟性の勉強になって面白い
  • グローバル変数も使わない方がよい
    • 代用方法1: 定数+instance_eval
    • 代用方法2: シングルトンクラスで置き換えられる
    • メソッドコールのコストをどうしても払いたくない限は代用方法で書くのがよさそう
    • シングルトンクラスの方法しか知らなかったけど、instance_eval はなんか恰好よいのでどこかで使ってみたい

Chapter5: 例外

※ まだ途中

  • hash#[] のキーが見つからないとき Ruby だと nil を返して Python は例外を返す
  • それぞれ逆をするために fetch(Rubyで例外出す) と get(Pythonでデフォルト値返す) が用意されている
  • この辺り言語の特徴を表していて大変面白い

おわり

第1部までは頑張って原著で読んで、その後は研鑽Rubyプログラミングの pdf で読む予定。

ruremai gem を Ruby3 でも動くようにした

ruremai は irb から簡単に日本語リファレンスマニュアル(るりま)を開く便利ツール。

$ gem install ruremai

こんな感じで使う。

irb> require "ruremai"
irb> "".method(:concat).rurema!    # String#<< のリファレンスを開く
irb> [].mean?.join                 # Array#join のリファレンスを開く

Ruby3 で動かなかったので手元で修正して PR を出した。

https://github.com/ongaeshi/ruremai/tree/feature/support-ruby3

取り込まれれば本体 gem でも使えるようになる。 それまでは Gemfile に

gem 'ruremai', github: "ongaeshi/ruremai", branch: "feature/support-ruby3"

と書けば使える。

mermaid.js を使ったコードリーディング

mermaid.js を使ってコードリーディングをするときに便利な機能をまとめてみる。 標準でクラスダイアグラムも使えるが、色々試した結果、応用の効くグラフを使う方法に落ち着いた。

スタイル

注目させたい関数の色やアウトラインを変更できる。

graph LR
  foo --> bar --> baz

  style bar color:#000,fill:#ccc,stroke:#333,stroke-width:4px
graph LR
  foo --> bar --> baz
  style bar color:#000,fill:#ccc,stroke:#333,stroke-width:4px

サブグラフ

名前空間やファイル名を表すのに便利。

graph LR
  subgraph Foo
    f1 --> f2
  end

  f2 --> f3

  subgraph Bar
    f3 --> f4
  end
graph LR
  subgraph Foo
    f1 --> f2
  end

  f2 --> f3

  subgraph Bar
    f3 --> f4
  end

コメントアウト

%% でグラフの一部を無効にすることで1つのグラフを違う視点で表示することができる。
前述のスタイルと組み合わせるのもよい。

f1 に注目。

graph LR
  f1 --> f2
  f1 --> f3
  %% f3 --> f4 --> f5

  style f1 color:#000,fill:#ccc,stroke:#333,stroke-width:4px
  %% style f3 color:#000,fill:#ccc,stroke:#333,stroke-width:4px
graph LR
  f1 --> f2
  f1 --> f3
  %% f3 --> f4 --> f5

  style f1 color:#000,fill:#ccc,stroke:#333,stroke-width:4px
  %% style f3 color:#000,fill:#ccc,stroke:#333,stroke-width:4px

f3 に注目。

graph LR
  %% f1 --> f2
  f1 --> f3
  f3 --> f4 --> f5

  %% style f1 color:#000,fill:#ccc,stroke:#333,stroke-width:4px
  style f3 color:#000,fill:#ccc,stroke:#333,stroke-width:4px
graph LR
  %% f1 --> f2
  f1 --> f3
  f3 --> f4 --> f5

  %% style f1 color:#000,fill:#ccc,stroke:#333,stroke-width:4px
  style f3 color:#000,fill:#ccc,stroke:#333,stroke-width:4px

線にコメント

受け渡されるデータを記述できる。

graph LR
  user -- color --> makeTriangle -- graphic, pos --> drawGraphic
  makeTriangle -- graphic --> saveToPng
graph LR
  user -- color --> makeTriangle -- graphic, pos --> drawGraphic
  makeTriangle -- graphic --> saveToPng

開発環境

本家のライブプレビューを使えば大体のものは書ける。 URL に編集内容が保存されるので他の人に共有することも可能。

https://mermaid.live/

VSCode だと Markdown Preview Enhancedpng への保存もできるのでおすすめ。

実例

blogsync のコードを読むときに書いたグラフ。灰色になっているのが各コマンドに対応していてそこから各実装に分散している。設定ファイルの読み書き部分は全コマンド共通。

graph LR
  subgraph main.go
    main --> cli.NewApp --> cli.Run

    cli.Run --> commandPull
    cli.Run --> commandPush
    cli.Run --> commandPost
    cli.Run --> commandList

    commandPull --> loadConfiguration
    commandPush --> loadConfiguration
    commandPost --> loadConfiguration
    commandList --> loadConfiguration
    loadConfiguration --> loadConfigFiles --> loadSingleConfigFile    
  end

  commandPull --> newBroker --> FetchRemoteEntries --> LocalPath --> StoreFresh
  commandPush --> entryFromReader
  
  subgraph entry.go
    entryFromReader
  end

  subgraph broker.go
    newBroker
    FetchRemoteEntries
    LocalPath
    StoreFresh
  end

  style commandPull color:#000,fill:#ccc,stroke:#333,stroke-width:4px
  style commandPush color:#000,fill:#ccc,stroke:#333,stroke-width:4px
  style commandPost color:#000,fill:#ccc,stroke:#333,stroke-width:4px
  style commandList color:#000,fill:#ccc,stroke:#333,stroke-width:4px
graph LR
  subgraph main.go
    main --> cli.NewApp --> cli.Run

    cli.Run --> commandPull
    cli.Run --> commandPush
    cli.Run --> commandPost
    cli.Run --> commandList

    commandPull --> loadConfiguration
    commandPush --> loadConfiguration
    commandPost --> loadConfiguration
    commandList --> loadConfiguration
    loadConfiguration --> loadConfigFiles --> loadSingleConfigFile    
  end

  commandPull --> newBroker --> FetchRemoteEntries --> LocalPath --> StoreFresh
  commandPush --> entryFromReader
  
  subgraph entry.go
    entryFromReader
  end

  subgraph broker.go
    newBroker
    FetchRemoteEntries
    LocalPath
    StoreFresh
  end

  style commandPull color:#000,fill:#ccc,stroke:#333,stroke-width:4px
  style commandPush color:#000,fill:#ccc,stroke:#333,stroke-width:4px
  style commandPost color:#000,fill:#ccc,stroke:#333,stroke-width:4px
  style commandList color:#000,fill:#ccc,stroke:#333,stroke-width:4px

Obsidianのアウトライナープラグインを試す

普段のメモ書きに Obsidian を愛用しているが、アウトライナーは標準で用意されていない。
※ 見出しを一覧したり移動できる「アウトライン」というコアプラグインはある(これはこれで便利)。

評判のよいコミニティプラグインOutlinerZoom を試してみることにした。

インストール

コミニティプラグインから Outliner と Zoom を検索してそれぞれインストール。

ホットキー一覧

Outliner

  • Ctrl+↑↓でリストの開閉
  • Ctrl+Shift+↑↓ でリストの移動

Zoom

  • ホットキー不要でズームしたいリストのバレットをクリックすればOK

使い方

こんな感じのリストを

こんな感じに操作できる。Ctrl+Shift+↑↓でリストを移動しながら整理。集中して考えたいときはクリックしてズーム。

blogsync で Windows でも標準入力を使えるようにした

github.com

entryFromReader()関数でエントリー時刻を取得する際にエラーが発生していた。 Windowsでは、"/dev/stdin "に対してos.Stat()を行うことができないのが原因。

Windowsで標準入力が渡されたときは、エントリーに現在時刻を設定することにして回避。

これで Windows から直接投稿できるようになった。

WSL の時間が Windows とずれている

WSL を自前でビルドして下書きも作れるようになった のだが、 今度は更新がうまくいかない問題が発生。

調べると Windows の時刻よりも 5 分位 WSL の時間が遅れていて新しい記事だと blogsync が認識できなくなっていた。

WSL2で時刻がずれる - Qiita

WSL を再起動することで解決した。(スリープとかしているとだんだんずれていくらしい・・)

> wsl --shutdown

WSL で blogsync をビルドして Windows からも標準入力が使えるようにする

Windows版だと標準出力が使えない という問題があり、 WSL 版バイナリだと別のエラーで動かないという問題があって標準出力経由で投稿や下書きを作ることができなかった。

標準入力が使いたくなってきたので WSL 版を手元でビルドすることにする。

まず golang をインストール。

$ sudo apt install golang-go

次に blogsync をビルド

$ git clone https://github.com/x-motemen/blogsync.git
$ cd blogsync
$ go build -o blogsync

バイナリをパスの通った場所にコピー。

$ cp blogsync ~/.local/bin/ 

これで準備OK。

$ blogsync post --draft --title=空投稿テスト ongaeshi.hatenablog.com
空投稿のテストですよ。^D
      POST ---> https://blog.hatena.ne.jp/tuto0621/ongaeshi.hatenablog.com/atom/entry
       201 <--- https://blog.hatena.ne.jp/tuto0621/ongaeshi.hatenablog.com/atom/entry
     store /home/ongaeshi/doc/blog/ongaeshi.hatenablog.com/entry/2023/04/15/230732.md

下書きが作れるようになった!これでさらに便利になる😀
次は push したら自動で投稿されるように GitHub Actions を設定しようかな。