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 を設定しようかな。

Polished Ruby Programming を読んでいる

ずっと興味のあった洋書の「Polished Ruby Programming」を Kindle で買った。英語の勉強も兼ねて少しずつ読んでいる。

Polished Ruby Programming: Build better software with more intuitive, maintainable, scalable, and high-performance Ruby code (English Edition)

自分の英語の読書スピードだと全てを読む前に飽きてしまいそうなので、目次を見て面白そうな順番で読むことにした。最初は「Chapter 4: Methods and Their Arguments」から。

以下面白そうなトピックの抜粋。

メソッドの引数は可能なら 0 にした方がよい

引数があるとパラメータの設定ミスが起こるので引数が不要なメソッドが一番分かりやすい。次点が1個で2つ以上になるととても難しくなるのでできるだけ引数の数は減らせるようにしよう。

実際に Ruby の Object も大半が 0 になっているのをコードを書いて確かめているのがよい。

h = Hash.new(0)
o = Object.new
o.methods.each do |m|
 h[o.method(m).arity] += 1
end
h
# => {0=>20, 1=>18, -1=>18, 2=>1}

Array, Hash, String も調べてみる。 -1 は可変長引数を受け付ける場合らしい。やはり 0 OR 1 がほとんどになっている。

def method_argument_count(t)
  h = Hash.new(0)
  o = t.new
  o.methods.each do |m|
   h[o.method(m).arity] += 1
  end
  h
end

method_argument_count(Array)
# => {0=>70, 1=>43, -1=>76, -2=>1, 2=>1}
method_argument_count(Hash)
# => {-1=>58, 0=>71, 1=>44, 2=>3}
method_argument_count(String)
# => {0=>67, -1=>71, 1=>41, -2=>2, 2=>8}

Ruby 引数の種類はたくさんある

Ruby の引数種類の詳しい説明は始めて見た。デフォルト引数前に置けるのね。

著者の Ruby を熟知した感じと好きな感じが端々から溢れていてとても楽しい。

callメソッドの糖衣構文

https://docs.ruby-lang.org/ja/latest/doc/spec=2fcall.html#call_method

Proc#call が実装済みなら以下で呼べるらしい。あんまり使われていないのは C++ みたいに.が省略できないからなんだろうなぁ。(筆者はそれもあって #[]をい使うことが多いとも書いてあった)

foo.(100)      # foo.call(100)と全く同じ意味
foo::(100)     # foo.call(100)と全く同じ意味

追記

ところで今なら日本語版の「研鑽Rubyプログラミング」が発売したばかりなのでそっちを買うのもおすすめです。

※ 実は自分もβ版買ってありました(すっかり忘れてた・・)

blogsync の使い方メモ

こんなルーティーンでやっている。セットアップは過去記事を参考に。Windows でも動く。

1. 下書きを書く

下書きはモバイルアプリやブラウザで作っておく。ちゃんと書くときは PC で書いた方が早いのでタイトルとざっくり内容だけ。

2. 下書きを手元に持ってくる。

$ blogsync pull
    200 <--- https://blog.hatena.ne.jp/tuto0621/ongaeshi.hatenablog.com/atom/entry?page=1203221981
    fresh remote=2023-04-10 23:52:22 +0900 JST > local=0001-01-01 00:00:00 +0000 UTC
  store C:\blog\ongaeshi.hatenablog.com\entry\2023\04\10\235222.md

3. 記事を編集して投稿

$ blogsync push ongaeshi.hatenablog.com\entry\2023\04\10\235222.md

4. git にも同期

投稿したら git レポジトリにもバックアップしておく。

$ git commit

メモ: アプリやブラウザから下書きを更新するとファイル名が別になってしまう

画像を張り付けるなど、ブラウザから下書きを更新してから blogsync pull すると別のファイルとしてファイルが降ってきてしまう。後で検索するときに複数の記事がひっかかってしまうと嫌なので古い下書きは削除している。一度投稿した記事だとそのようなことは起きない。