Humanity

Edit the world by your favorite way

ふとテキストを HTML エスケープしたい時に使えるブックマークレット

いつも必要になった時にこんな感じのコードを DevTools のコンソール上で実行してるので雑にブックマークレット化してみた。 ダイアログが出るのでそれにテキストを入力すると alert() でエスケープしたテキストを表示するので手動コピーする。

javascript:(function(s){s.innerText=prompt('Input text containing special character(s)');alert(s.innerHTML)})(document.createElement('span'))

ちなみに Vimmer の方は operator-html-escape.vim というプラグインを利用すると HTML エスケープができます。 Vim から出たくない方はぜひ。*1

*1:自分はそもそも Vim を使えない職場で働いているので…

SVG の <circle> を <path> で描く

ふと仕事で SVG の <circle> タグの代わりに <path> を使って円を描く必要があったので調べたところ、色んな書き方 (描き方) があるらしいことが分かった。 自分が見つけたのは

  1. 2本の円弧で描画
  2. 4本の3次ベジェ曲線で描画
  3. 8本の2次ベジェ曲線で描画

の3通り。1番目が簡単な上に誤差が無いため通常は1番目を使うはず。 *1

詳しくは以下のページにまとめたのでそちらを参照してください。

SVG の <circle> を <path> で描く

何も考えずに ES6 を使って書いたら最新版の ChromeFirefox で動いてしまったので ES5 で書き直すモチベーションが失われてしまいました。 すみませんが、うまく表示されなかった場合は Chrome 58.0.3029.110 以上 または Firefox 53.0.3 以上 を使ってください。あしからず。

ちなみに今回 Vue.js を使ってみた。 Angular 1 に似てて使いやすかった。 Angular 1 はこういうちょっとした動きをつけたい時には大仰すぎるし、 Angular や React は環境構築から始めないといけないので CDN 上の .js ファイルを読み込めばすぐ使えるとかじゃないので面倒だし、 その点 Vue.js はコンポーネントルーターも使わない (vue.min.js のみ) ような今回のケースにもぴったりだった。 プログレッシブに大きなアプリを作る時じゃなくても気軽に使えるので良い。

*1:だけど実際のコードではアレコレの制限でそれも使えなかった…

Vim script に ECMAScript の Observable がほしい

タイトルは前記事からの流用。

最近 Vim script で Java 8 の Stream API を実装する、ということをしている。

tyru.hatenablog.com

github.com

Vim 8 でも lambda が入ったので、メソッドチェインでどんどん処理を繋げるスタイルの書き方ができると嬉しいとつくづく思っていたからだ(例:JS の Promise)。 ちなみにこの Vital.Stream モジュールを使うと以下のように書けるようになる(適当な乱数を10個生成するコード)。

というわけで開発の方も段々落ち着いてドキュメントを整備したりしているので、 ふと前から作りたかった ECMAScript の Observable を Vim script で実装するということについて考えてみた。

  • 非同期インターフェースを強制することになるので、Vim 8 の +timer 必須になるからおそらく Vim 8 以降限定のライブラリになるはず *1
  • あと async / await なんてものは Vim script に絶対入ることはないので、意地でもメソッドチェインで処理しないといけない

とつらつらと考えた所で、 Stream と Observable の相互変換ってできるんだろうか?という疑問がふと浮かび上がった。 filter や map でメソッドチェインする辺り似たようなインターフェースなのでできれば協調させたい… と考えた所やはりそれは無理という結論に至った。

Java の Stream は filter や map などの中間処理(intermediate operation)は非同期に実行されうるが、Stream から値を取り出す終端処理(terminal operation)は同期的なインターフェースである。 しかし Promise 型や Observable 型の値は持ち回った結果受け取るのも非同期である必要がある。 その点 Stream は出口が同期的なので、既存コードへの導入も楽だろう。 しかし本質的に非同期でないと処理できない類の問題がある。イベント処理だ。

Stream から要素を取ってくるために終端処理を実行するという一連の動作は能動的なものだが、プログラムのユーザーがクリックするなどのイベントをプログラムが事前に知ることは不可能だ。 どうしてもイベント駆動にならざるを得ない。 そもそも Promise や Observable はそのために導入されたものだ。 async / await で同期処理の様に書ける、と言ってもそれはトランスパイラやブラウザが読み替えているだけであって、非同期であることを意識して扱う必要があることに変わりはない。 この様に async / await は単なる糖衣構文であることを念頭に置く必要がある。


と、いうように当たり前だけど Observable と Stream は別物である。 RxJava に限らず各言語の Rxほげ なライブラリの Observable はなんだかリスト処理とかもできちゃったりするらしい(どうやら同期的な処理用のメソッドもある?)ので勘違いしそうになるので、ここでは ECMAScript の Observable のことを考えた方が良さそうだ。

ただ今考えるだけでも Vim script だと困る部分が色々ある。 例えば Vim でイベントって言ったら auto command だけど autocmd コマンドだと受け取ったコマンドを「文字列的に」実行するので、ローカル変数のキャプチャができない。 Vim script にはこのように副作用を強制するインターフェースがあちこちにある。 これを回避するにはスクリプトローカル変数や、グローバル変数、とにかくローカル変数以外のスコープの変数に代入する必要がある。 これはとても醜いのでできれば Vital.Observable.Autocmd みたいなモジュールで吸収できるものなら吸収したい。 そして listen(event) みたいな関数をポーンと提供したい。 しかし本当に実現可能だろうか。 恐らく追加で呼び出し元がどいつかを関数の引数として与えてやらなければいけない気がする。 できればそれは避けたいけど。


そういえばりんだんさん(id:rhysd)に「(Vital.Stream モジュールに)from_channel メソッドが欲しいです」って言われてて今回は量多くなるので見送ったのだけど、Vim の channel はソケット通信のためのオブジェクトで、非同期なので、Vital.Stream モジュールでは扱えませんというのが正しそう。

どうしても扱いたい場合は終端処理を実行した時点までに来た要素なら受け取れるけど、非同期で受け取った要素をバッファに持っておく必要があって逐次的に処理ができないため余計なメモリを食うし、そもそも途中までの要素がほしいってあんまり意味がない気がする。*2 なのでそういうのは Vital.Observable みたいな非同期用インターフェースで解決するのが筋じゃないだろうか。


と、記事を書いてから無限ストリームにイベントを流して take_while で中断するという用途はありそうだと思った。 ただ要素を取得中はブロッキングしてしまうのでやっぱり非同期で受け取りたいところ。

*1:それ以前の Vim では任意の処理を非同期にする方法は中々難しかった。この記事ではあまり関係ないので割愛

*2:りんだんさんもおそらくそういうつもりで言ったんじゃなさそう