るりまのRDファイルをJSONに変換する
前回
bitclust serverコマンドにオプションを追加し、GraphQLの口を作った
https://github.com/hanachin/bitclust/tree/graphql
こう --graphql オプションを渡すとGraphQLが生える
% bundle exec bitclust server --debug --port=4567 --auto --baseurl=http://localhost:4567/ --graphql
GraphiQL
前回のブランチではGraphQLの口を作った。以下のようなファイルを用意してGraphiQL経由で動作が確認できるようになった、べんり
RDファイルをJSONに変換する
るりまでは RDCompiler を利用してRDファイルをHTMLに変換している。
RDCompilerではパースとHTMLの出力を同時に行っている。
HTMLを出力せずにJSONに変換するため、以下のようなステップで書き換えを行った。
結果
今日時点での最新コミットだとDocEntryのRDファイルをパースした結果がJSONで取れるようになった🎉
以下のようなクエリを投げると
query { methodDatabase(version: "3.0.0") { doc(id: "index") { id, title, body } } }
以下のようなレスポンスが返ってくる
{ "data": { "methodDatabase": { "doc": { "id": "index", "title": "オブジェクト指向スクリプト言語 Ruby リファレンスマニュアル", "body": [ { "level": 1, "name": "ul", "children": [ { "level": 1, "name": "li", "children": [ "Ruby オフィシャルサイト ", { "name": "bracket_link", "type": "url", "arg": "https://www.ruby-lang.org/ja/" } ] }, { "level": 1, "name": "li", "children": [ "開発版対応リファレンス" ] }, { "level": 1, "name": "li", "children": [ "原著:まつもとゆきひろ" ] }, { "level": 1, "name": "li", "children": [ "最新版URL: ", { "name": "bracket_link", "type": "url", "arg": "https://www.ruby-lang.org/ja/documentation/" } ] } ] }, { "name": "headline", "label": "使用上の注意", "level": 2, "fragment": null }, { "name": "paragraph", "children": [ "組込みクラスのリファレンスはほぼ揃っています。標準添付ライブラリのリファレンスは一部未完成です。それ以外のドキュメントについては、まだまだ書き直しが必要です。\n" ] }, { "name": "headline", "label": "目次", "level": 2, "fragment": null }, { "level": 1, "name": "ul", "children": [ { "level": 1, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/intro" } ] }, { "level": 1, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/commands" } ] }, { "level": 1, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/rubycmd" } ] }, { "level": 1, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/envvars" } ] } ] }, { "name": "headline", "label": "Ruby 言語仕様", "level": 3, "fragment": null }, { "name": "paragraph", "children": [ "Ruby でのオブジェクト:\n" ] }, { "level": 2, "name": "ul", "children": [ { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/object" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/class" } ] } ] }, { "name": "paragraph", "children": [ "プロセスの実行:\n" ] }, { "level": 2, "name": "ul", "children": [ { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/eval" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/terminate" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/thread" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/safelevel" } ] } ] }, { "name": "paragraph", "children": [ "Ruby の文法:\n" ] }, { "level": 2, "name": "ul", "children": [ { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/lexical" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/program" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/variables" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/literal" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/operator" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/control" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/call" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/def" } ] } ] }, { "name": "paragraph", "children": [ "その他:\n" ] }, { "level": 2, "name": "ul", "children": [ { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/m17n" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/regexp" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "spec/lambda_proc" } ] } ] }, { "name": "headline", "label": "組み込みライブラリ", "level": 3, "fragment": null }, { "level": 2, "name": "ul", "children": [ { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "lib", "arg": "_builtin" } ] } ] }, { "name": "headline", "label": "標準添付ライブラリ", "level": 3, "fragment": null }, { "level": 2, "name": "ul", "children": [ { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "lib", "arg": "/" } ] } ] }, { "name": "headline", "label": "C API", "level": 3, "fragment": null }, { "level": 2, "name": "ul", "children": [ { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "f", "arg": "/" } ] } ] }, { "name": "headline", "label": "その他", "level": 3, "fragment": null }, { "level": 2, "name": "ul", "children": [ { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "news/index" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "pack_template" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "print_format" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "glossary" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "symref" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "marshal_format" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "license" } ] }, { "level": 2, "name": "li", "children": [ { "name": "bracket_link", "type": "d", "arg": "help" } ] } ] } ] } } } }
次試したいこと
ひとまず、ひき続きRDからJSONに変換できる対象を拡大していきたい。 組み込みクラスあたりまでJSONで出せるようになったらフロントエンドの実装をしてみる。
JSONへ変換する試みをしている最中にリスト処理のバグを見つけたので報告した。
こっちのバグも直しておきたい。(なおGraphQLお試しブランチでは直っている)
るりまのフロントエンドを分離したいなぁ
現状
bitclustのコマンドで静的なHTMLを生成している。 テンプレートがbitclustに内包されており、HTMLの構造についてある程度分離されているが一部のHTMLを生成する部分はRubyで書かれている。
こうしたい
bitclustにGraphQLのインターフェイスをおく。 GraphQL経由で取得した情報をもとに、フロントエンドのツールチェインを利用してHTMLを生成する。
フロントエンドを分離することで、フロントエンドのツールをより手軽に利用できるようにし、マニュアルの使い勝手を向上させる足がかりとしたい。あとフロントエンド得意な人のコントリビュートチャンスを増やしたい。
いま試していること
bitclust serverコマンドにオプションを追加し、GraphQLの口を作った
https://github.com/hanachin/bitclust/tree/graphql
こう --graphql オプションを渡すとGraphQLが生えるので
% bundle exec bitclust server --debug --port=4567 --auto --baseurl=http://localhost:4567/ --graphql
こういう感じで叩くと
% curl -s -X POST -H 'Content-Type: application/json' -d '{"query": "query ListDocs($version: ID!){ methodDatabase(version: $version){encoding,version,docs{id,title}}}","variables":{"version":"3.0.0"}}' http://localhost:4567/graphql
こんな感じで情報が取れる
{ "data": { "methodDatabase": { "encoding": "utf-8", "version": "3.0.0", "docs": [ { "id": "symref", "title": "Rubyで使われる記号の意味(正規表現の複雑な記号は除く)" }, { "id": "help", "title": "このマニュアルのヘルプ" }, { "id": "spec.thread", "title": "スレッド" }, { "id": "news.2_4_0", "title": "NEWS for Ruby 2.4.0" }, { "id": "platform.index", "title": "Ruby が動作するプラットフォーム" }, { "id": "news.1=2e8=2e4", "title": "ruby 1.8.4 feature" }, { "id": "ReFe", "title": "ReFe" }, { "id": "spec.def", "title": "クラス/メソッドの定義" }, { "id": "marshal_format", "title": "Marshal フォーマット" }, { "id": "platform.Win32=2dnative", "title": "Win32ネイティブ版" }, { "id": "spec.control", "title": "制御構造" }, { "id": "news.2_7_0", "title": "NEWS for Ruby 2.7.0" }, { "id": "spec.eval", "title": "Ruby プログラムの実行" }, { "id": "spec.terminate", "title": "終了処理" }, { "id": "platform.GNU", "title": "GNU" }, { "id": "platform.Win32", "title": "Win32" }, { "id": "glossary", "title": "Ruby用語集" }, { "id": "news.3_0_0", "title": "NEWS for Ruby 3.0.0" }, { "id": "news.2_5_0", "title": "NEWS for Ruby 2.5.0" }, { "id": "index", "title": "オブジェクト指向スクリプト言語 Ruby リファレンスマニュアル" }, { "id": "platform.Cygwin", "title": "Cygwin" }, { "id": "news.index", "title": "Ruby変更履歴" }, { "id": "spec.operator", "title": "演算子式" }, { "id": "spec.rubycmd", "title": "Rubyの起動" }, { "id": "spec.safelevel", "title": "セキュリティモデル" }, { "id": "platform.MinGW", "title": "MinGW" }, { "id": "platform.Unix", "title": "Unix" }, { "id": "news.1=2e8=2e1", "title": "ruby 1.8.1 feature" }, { "id": "spec.m17n", "title": "多言語化" }, { "id": "spec.regexp", "title": "正規表現" }, { "id": "platform.mingw32", "title": "mingw32" }, { "id": "platform.DOSISH=2dsupport", "title": "DOSISH 対応" }, { "id": "spec.commands", "title": "コマンド" }, { "id": "spec.variables", "title": "変数と定数" }, { "id": "pack_template", "title": "pack テンプレート文字列" }, { "id": "license", "title": "配布条件" }, { "id": "news.1=2e8=2e0", "title": "1.6.8から1.8.0への変更点(まとめ)" }, { "id": "platform.mswin32=2dcompat", "title": "Win32ネイティブ版Rubyの互換性問題" }, { "id": "news.2_0_0", "title": "NEWS for Ruby 2.0.0" }, { "id": "news.2_6_0", "title": "NEWS for Ruby 2.6.0" }, { "id": "spec.envvars", "title": "環境変数" }, { "id": "news.1_9_0", "title": "ruby 1.9 feature" }, { "id": "manual=2dpage", "title": "manual page" }, { "id": "spec.lambda_proc", "title": "手続きオブジェクトの挙動の詳細" }, { "id": "spec.lexical", "title": "字句構造" }, { "id": "platform.GNUHurd", "title": "GNU Hurd" }, { "id": "news.2_2_0", "title": "NEWS for Ruby 2.2.0" }, { "id": "news.1=2e6=2e0", "title": "ruby 1.6 feature" }, { "id": "news.2_1_0", "title": "NEWS for Ruby 2.1.0" }, { "id": "spec.literal", "title": "リテラル" }, { "id": "news.1=2e8=2e2", "title": "ruby 1.8.2 feature" }, { "id": "platform.MacOSX", "title": "Mac OS X" }, { "id": "news.2_3_0", "title": "NEWS for Ruby 2.3.0" }, { "id": "print_format", "title": "sprintf フォーマット" }, { "id": "platform.mswin32", "title": "mswin32" }, { "id": "news.1=2e8=2e5", "title": "ruby 1.8.5 feature" }, { "id": "spec.intro", "title": "はじめに" }, { "id": "news.1=2e8=2e3", "title": "ruby 1.8.3 feature" }, { "id": "spec.program", "title": "プログラム・文・式" }, { "id": "spec.class", "title": "クラス" }, { "id": "spec.object", "title": "オブジェクト" }, { "id": "spec.call", "title": "メソッド呼び出し(super・ブロック付き・yield)" } ] } } }
次ためすこと
一応口ができたので、現状のるりまが生成するHTMLを模してHTMLを生成できるかやってみる
もう二度とラップトップにミルクティーを飲ませない気持ち2021冬
ラップトップにミルクティーを飲ませたら起動しなくなってしまった、つらい
デスクで飲み物を飲まないとか、水ではないものを飲まないとか、蓋のついたコップを常に使うとかは無理(それを遂行できないことが今回確認できた)なので別の対策をする。
飲み物をこぼしてラップトップが飲んじゃうのは、ラップトップより液体の位置が高いのが原因なので、ラップトップをディスプレイあたりの位置にマウントしてやれば絶対飲めないだろうと思う。
対策としてラップトップの頭を高くしてラップにおかないラップトップにして使う。
マウント探しします。
Laptopに挿しているYubiKeyに誤タップしてOTPが入力されるのを防ぐ
外しておけばOK、使いたくなったらさしなおすかbindする
# echo $(find /sys/bus/usb/drivers/usb/*/manufacturer -type f -regextype posix-egrep -regex '.*/[0-9]+-[0-9]+/manufacturer$' | xargs -I {} sh -c '[ "Yubico" = "$(cat {})" ] && echo {}' | cut -d"/" -f 7) > /sys/bus/usb/drivers/usb/unbind
NixOSをつかいはじめた
社用のXPS 15が届いたので設定をしていた
若者が一人XPS 15を買ったのに続いて社用PCがないみんなが乗っかって同じXPS 15を買うイベントが発生して面白みがある。
XPS 15盃
— むろ.figma🍥 (@murokaco) August 6, 2021
ファンはブンブンいっていて膝の上に置くと暑い感じがするが8C16T、メモリ64GB、SSD 2TBだと思うとまあよし、という気持ち。 デスクトップマシンとコア数メモリ数並んでSSDに至っては負けたのでデスクトップマシンの方のコア数を増やしたい気がする
インストールメディアづくり
台風の影響がなく1週早く届いた同僚氏の情報によりGNOMEのインストールメディアでWi-Fiつながらないと聞いており、だるそうだったので、雑に最新カーネルでビルドしたISOを作ってそれを使った。
VM上にNix入れる→VM上のNixでISO作る→ISO持ってくる→ISO焼く→実マシンに入れる流れ。
1回入れる練習ができたのでよかった。Wi-Fiは最新カーネルだと無事つながった。
Mozcの日本語入力の切り替え
US配列のキーボードなのでMozcの日本語の切り替えをCtrl + \あたりにしようとトレイのメニューから設定開こうとしたらうまく動かなかった。 Qtないせいかも、と思ってQt入れても設定画面出なかったのでCLIで試したらうまくでた。
% /run/current-system/sw/lib/mozc/mozc_tool --mode=config_dialog
パーティション
Btrfs on LUKSでやっている。ひよってWindowsのパーティションは残したままだけど署名されたブートローダーがないのでWindowsを起動するためにはBIOS入ってSecure Bootを有効にするか、鍵か何か入力せんといかん。
今回はじめてLUKSの鍵YubiKey + PassphraseにしたがYubiKeyをなくすとセットアップやり直しになっちゃうので、支給YubiKeyのほか自前YubiKeyの空きスロットに同じ情報登録しておこうと思う(まだやってない)。
home-manager
もともとthoughtbotのrcmで設定ファイル雑に管理していたので今回は見送り。 NixOSだけ使うならありかもしれない。
残り
鍵関係をいい感じに整えたら使えるかな、という感じ
仕事の環境はだいたいdocker-composeで整っているものの、VSCodeで動かすツール(ESLintとか)周りはまだローカルでのインストールが必要なのでRemote Containerを育てて完全にローカルなしでVSCodeだけ入れればOKぐらいに育てたほうが便利かもしれない。
所感
久しぶりのラップトップで嬉しい。お外で仕事環境整ったらいろいろ捗るかもしれないなあ。
ワクチン2回目おわって緊急事態宣言あけたら近所のコワーキングスペースあたりで作業してみたい。当面無理そうだが。