トップ 追記

2019-11-03 [長年日記]

_ 富山Ruby会議01に参加してきた

富山Ruby会議01

Ruby会議に参加するのは Final 以来なので、実に8年ぶりなのです。

The Final RubyKaigi は Kanazawa.rb をやろうと思った大きなきっかけの一つになった「アンチぼっちランチ」のあったイベントです*1

あの頃はずっと悩んでいた。あれから8年、懇親会で、進行から外れてゆっくりあちこちのテーブルを楽しむ @kakutani さんと「いつぶりでしたっけ?」「Finalです」「えー? いつ? 10年前?」みたいな話ができたのは富山Ruby会議01のおかげです。ありがとう。

今回はほとんど地元みたいな富山で、喋る側になって参加したので、前回と感じることはずいぶん変わっていました。

若い子が増えた

自分が歳をとったのだからある意味当たり前なのだけど、いや、それって Ruby コミュニティがまだ代謝してるってことだからね? これはやはり大きいですよ。金沢ではなかなか感じることができないんだけど、まだ Ruby コミュニティはちゃんと代謝していました。すごい。*2

地域エンジニアコミュニティの「広がり」の難しさ

今回、01 ということで、Ruby はそんなにあぶなっかしくも怖くないし、Rubyist はあたたかく迎え入れてくれるよというメッセージが(特に前半は)多かったのですが、これは裏を返すとまだまだ地方ではそういうメッセージが必要なのかな? という風に受け取ることもできます。まーそらそうかもしんない。もう自分にとっては当たり前になって久しいことも丁寧に説明されている様子を見て、こういう基礎的な部分も定期的に必要なのかもしれないなーと思うことができました。

懇親会では 02 どうしよう、今後どうしていきたいか悩んでいるという話の流れの中で「実は Hokuriku.rb ってあったんだよ」という話もできました。「規模を追わずにコンパクトにしつつ、裾野を広げるために、何より自分たちが楽しむために内容は絞らない」という Kanazawa.rb の選択は、kanazawa.js や Hokuriku.rb という先輩がいたから導出できたものなのです。これを伝えることができて本当によかった。Hokuriku.rb も富山生まれなんだぜ。

ハードコア部隊はやはりよいね

Final RubyKaigi の時、理解できるか分からないけど飛び込んだセッションを思い出しました。

  • RubyVM の話
  • Ruby AST の話
  • mruby parser/generator の話

こういう楽しみ方もいいよねー。

ライブコーディングは鬼門だけど(笑)

*1 改めて8年前の日記読むとヒジョーにエモい。ちょっと泣けてくる。

*2 Kanazawa.rb を見つけて近づいてきてくれる学生さんは優秀なので都会に旅立ったりしがちなのです。


2019-10-25 [長年日記]

_ chokidar-cliとパイプを使って本当に変更のあったファイルだけ何かしたい

kimmobrunfeldt/chokidar-cli: Fast cross-platform cli utility to watch file system changes

chokidar <files> -c '<command> <files>' 方式は無駄が多いかも

chokidar を使った処理でよく見るのは以下のような方法だと思う。

chokidar '**/*.js' -c '<command> **/*.js'

この方法だと監視対象のいずれかのファイルに何らかのイベントが発生した場合に、対象ファイル群すべてに対してコマンドを実行してしまう。すべてを対象にトランスパイルして bundle ファイルを生成するような処理なら仕方ないが、一つ一つの処理が独立していてお互いに関係せず、かつそこそこ負荷が高い場合には別々に実行したい。

chokidarはコマンド実行だけはなくイベントのstream outputもできる

chokidar は対象ファイル群を watch し始めたら、検知したイベントとファイル名を

イベント:ファイル名

の形で stdout に出力する機能を持っている。

この出力を受け取って何らかの処理をするコマンドを作れば、上のような無駄を防げる。

ただし、注意が必要

愚直にパイプで繋いで

chokidar <files> | <command>

ってやってしまうと、以下のような無駄な出力も受け取ってしまう

  1. yarn run コマンドの出力 ( yarn run <version> )
  2. chokidar コマンドを起動した文字列そのまま
  3. unlink したファイル

1 と 2 は単純に chokidar の出力が始まる前のものなので、そもそも必要な情報が入っていない。unlink イベントは chokidar の反応なのだが、unlink されているファイルに対して何らかの処理をするコマンドを叩いてもエラーにしかならないので、これも除外する必要がある。

本当に欲しかったもの

総合すると必要なものは

chokidar <files> | <filter> | <command>

のような形。

実装例

実際やったのは PlantUML の render で、以下のような感じ。

chokidar "**/*.plantuml" | awk -F : "
  !/unlink|run|\*/ {
    print \$0
    system(\"plantuml -headless -tsvg \" \$2)
  }
"

これで処理対象の PlantUML のファイルが増えても最小のコストで re-render できる。

chokidar なんか名前が好きじゃなくて敬遠してたんだけど、この機能はよい。とてもよいぞ。好きになった(簡単)。


2019-10-24 [長年日記]

_ PlantUML始めました

最近いろいろ新しいものを試せているのは Emacs の環境が新しくなってパッケージ管理と設定に悩まなくなったからだなぁ。というわけで前々から VS Code では書けたけど Emacs で書けるようになったのでおさらい。

基本

シンプルなテキストファイルで UML が書ける、オープンソースのツール

PlantUML は UML をテキストで書くための文法であり処理系の名前でもある。UML については割愛。

ねらい

  • 画像エディタと画像ファイルと共同管理の組み合わせで発生する種々様々な課題を避けたい

必要なもの

PlantUML の処理系は以下に依存している

Java の話はまた後日。

VS Codeで

以下の extension を入れる。

PlantUML - Visual Studio Marketplace

動作確認しているのは 2.12.2

以前は plantuml.com のサーバにデータを投げる仕様だったのかな? 最新版では plantuml.server の設定はデフォルトではなくなったよ、と書かれている。

  • 文法のパーサを持っている
  • plantuml.jar が同梱されている

ので、あとは Java と Graphviz だけ。PATH の通っている場所に java or jar コマンドと dot コマンドがあればたぶん何も設定しなくても動く。

Preview ペインを持っていて、一度これを開いておくとファイルの保存を待たずに適当なタイミングで rerender が走るのでカジュアルに始めるのにオススメ。ただ、どうも内部で一回一回コマンドを叩いてゼロから JVM が起動しているようで、preview と言う割にそこそこ重くて逆に気になるかもしれない。

Emacsで

plantuml-mode - MELPA

これも構成としては VS Code の場合と一緒。ただし、plantuml-mode は plantuml.jar を同梱していないのでその設定から行う必要がある。

plantuml-mode は 20191019.1309 の時点でデフォルトで plantuml.com のサーバに繋ぎにいくので注意が必要。

また、一度その動作をしないと M-x customize で設定項目が出てこない。この現象は以下のバージョンで確認済み。

  • Emacs 26.2
  • 20191019.1309

一度、何も内容のない UML で preview を叩いてみると plantuml.com に繋ぎに行くので、そこでキャンセルして

M-x customize

と叩くと設定できるようになっている。ここで

Plantuml Default Exec Mode

jar

にしておくとサーバに繋ぎに行かなくなる。あとは Java の設定やら Jar の設定やら必要かもしれないので頑張る。

plantuml を brew などなんらかのパッケージ管理ツールで入れている場合はその辺の設定の参考になると思う。

コマンドで

Homebrew を利用している場合は brew install plantuml すると plantuml コマンドというか sh script ができるのでこれを利用する。

この中身を見ると

  • 同じく brew で入れた dot
  • brew で入れた plantuml.jar

のパスが直書きされているのが分かる。

Emacs の plantuml-mode の設定の際にこれが必要になるかも。逆に plantuml-mode の設定を見ていると plantuml -help では分からない設定があって、それが

-headless

オプション。これがないと一瞬 Dock に Duke が現れて今使いたいアプリからフォーカスを奪って逃げていく。すごく腹がたつので絶対に設定しておきたい。

出力形式とビュワー

  • デフォルトは PNG を生成するので適当な画像ビュワーで開ける
  • 書き込みが細かくなってくるとベクター画像が欲しくなってくるが、そうなるといろいろ挙動があやしい。とりあえずでやってみたら PDF は生成できなかった。EPS と SVG はイケた。
    • ベクター画像が欲しければ SVG を生成してブラウザで開く、くらいがお手軽かも

本当は dot ファイルそのものが出力できるといいんじゃないかと思ったんだけど、どうやら PlantUML にそういう出力オプションを作るのは難しいらしい。(request はちょくちょく上がっている模様。)

SVG はブラウザが対応してるので各種 Web サービスに上がっていてもそのまま表示できるわけで、まぁまぁよさげ。ちょっと確認したところ OmniGraffle も draw.io も対応してるし、なんかいろいろ大丈夫じゃないかな。

Tags: UML

2019-10-22 [長年日記]

_ Sinon.JSにもう少し詳しくなったのでちょっとまとめ

Sinon.JS - Standalone test fakes, spies, stubs and mocks for JavaScript. Works with any unit testing framework.

対象バージョン

Sinon 7.5.0

背景

  • これを書いている人はテスティングフレームワーク組み込みの double より独立しているものの方が好み
    • その方が寿命が長い傾向にあるため
  • これを書いている人はもともと Ruby で RR をよく使っている
  • Ruby の場合は property はそもそも private
  • public なのはすべて method
  • ただし Ruby の method は定義時も呼び出し時も () を付ける必要がなく、引数がない場合は property アクセスと同じように見える

Sinonの基本

  • Sinon の double はもともと存在している property に対してしか書けない
    • TypeError: Cannot stub non-existent own property <name> エラー
    • RR では存在していようがいまいが関係ない
  • Sinon の double は一回一回ちゃんと restore しないといけない
    • 同名のdouble に対して double をもう一度定義できない
    • TypeError: Attempted to wrap <name> which is already wrapped エラー
  • Sinon のドキュメントでは生成した double の object をレシーバにして restore しているが、sinon.restore() でもよい

Sinonのdoubleはmethodに対して機能する

Ruby と RR の組み合わせに慣れているとちょっと「あれ?」と思ってしまうが、以下の書き方を見ると納得。ここでは stub を例に挙げる。

sinon.stub(obj, <method>).returns(<val>)
sinon.stub(obj, <method>).callsFake(<func>)

ここでうっかり property を対象に stub を書いてしまっても定義はできるが property アクセスした際の値には影響しないし、method として call しようとすると not a function で TypeError になる。

では property を諦めて全部 method にしないといけないかというと、そうではなくて、これは getter method なのだと見做すとよい。正解はこう。

sinon.stub(obj, <method>).get(() => <val>)

何らかの値を return する function を get に与えてやればよい。

上に書いたように Ruby は property のように見えるものも method だし、method は式なので、RR の場合は return するか call するかのような区別は必要ない。これらの Ruby の API が DSL を作る際に非常に有利に働いていることがよく分かる。

stub().get()はなぜか多重定義できる

上に書いた原則に反するし、これを知っていても別に得しないが、

sinon.stub(obj, <method>).get(() => <val>)

に関しては restore なしに複数回実行できる。

callback, Promise地獄のJSでは純粋な関数とSpy重要

Promise は書いた順番通りに実行されないし、debugger でも完全に自由に break できるわけでもない。そこで

spyObj = sinon.spy(obj, <method>)
..
assert(spyObj.called)

のようにしておくと、どのメソッドが呼ばれたか ≒ どのルートを通っているかなどの確認ができるし、これが可能なように細かく純粋な関数を増やしておくと非常にテストしやすくなるのでオススメ。*1

*1 純粋な関数がよいのは sinon とか double とかに限らない普遍的なテクニック