るりまの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経由で動作が確認できるようになった、べんり

gist.github.com

RDファイルをJSONに変換する

るりまでは RDCompiler を利用してRDファイルをHTMLに変換している。 RDCompilerではパースとHTMLの出力を同時に行っている。 HTMLを出力せずにJSONに変換するため、以下のようなステップで書き換えを行った。

  1. 出力を行う部分を分離する
  2. 出力を行う部分をJSONへの出力で置き換える
  3. GraphQL経由でJSONへの出力を利用可能にする

結果

今日時点での最新コミットだとDocEntryのRDファイルをパースした結果がJSONで取れるようになった🎉

github.com

以下のようなクエリを投げると

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へ変換する試みをしている最中にリスト処理のバグを見つけたので報告した。

github.com

こっちのバグも直しておきたい。(なお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冬

ラップトップにミルクティーを飲ませたら起動しなくなってしまった、つらい

デスクで飲み物を飲まないとか、水ではないものを飲まないとか、蓋のついたコップを常に使うとかは無理(それを遂行できないことが今回確認できた)なので別の対策をする。

飲み物をこぼしてラップトップが飲んじゃうのは、ラップトップより液体の位置が高いのが原因なので、ラップトップをディスプレイあたりの位置にマウントしてやれば絶対飲めないだろうと思う。

対策としてラップトップの頭を高くしてラップにおかないラップトップにして使う。

マウント探しします。

ThinkPad X260がサスペンドやハイバーネートから復帰しなくなったので直した

軽い気持ちで私用のラップトップのDebianのバージョンを上げたらなんだか電源ボタン押しても戻ってこなくなった。

ThinkWikiを参考に/etc/pm/config.d/thinkpad_acpi に以下を追記したら戻ってくるようになった。

SUSPEND_MODULES="thinkpad_acpi"

と思ったがやっぱり戻ってこない

Arch LinuxWikiを参考にgrubの設定を変更して起動オプション設定したらなおった

GRUB_CMDLINE_LINUX_DEFAULT="quiet i915.enable_psr=0"

wiki.archlinux.jp

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を買うイベントが発生して面白みがある。

ファンはブンブンいっていて膝の上に置くと暑い感じがするが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だけ使うならありかもしれない。

残り

鍵関係をいい感じに整えたら使えるかな、という感じ

  • SSH鍵づくり(YubiKeyでよい?)
  • SSH鍵をGitHubに登録
  • SSH鍵を仕事用の各種🐟に登録
  • GPG副鍵づくり
  • GPG副鍵をGitHubに登録
  • GPG副鍵をGitで使う設定

仕事の環境はだいたいdocker-composeで整っているものの、VSCodeで動かすツール(ESLintとか)周りはまだローカルでのインストールが必要なのでRemote Containerを育てて完全にローカルなしでVSCodeだけ入れればOKぐらいに育てたほうが便利かもしれない。

所感

久しぶりのラップトップで嬉しい。お外で仕事環境整ったらいろいろ捗るかもしれないなあ。

ワクチン2回目おわって緊急事態宣言あけたら近所のコワーキングスペースあたりで作業してみたい。当面無理そうだが。