Hello, FemtoRuby in Corne v4 Cherry
結構前に買ったキーボード corne v4 cherry を prk_firmware でうごかそうとして1年くらい放置してた。 そしたらいつのまにか deprecated になって picoruby-keyboard を利用することに なっていました。
Corne V4
prk_firmware をしばらく Corne V3 でつかってたのですが、 動いてる以上替える意味もなかったので替えていなかった。 いろいろと変更された Corne V4 になったときに変更をしようとしています。 この変更も Corne V4 自体がキー配線方式がマトリクス方式から ダイレクトピン方式に変更されてるためという事情もあります。
まずは prk_firmware で V4 を動かそうとします。 まあうごかないんですよ。理由は上記にあるダイレクトピン方式になったためですね。 でいろいろと試したんですが、左右通信が上手くいかず断念。 ということで1年ほど放置。
picoruby-keyboard
そしたら rubykaigi 2026 で prk_firmware 作者の @hasumikin にもうやってない。と告げられてそのかわり picoruby-keyboard でやってるという話になったのでそちらを利用することを決意。
まず picoruby-keyboard を picoruby のリリースページ からダウンロードしてきます。 ここでダウンロードのパッケージとして R2P2-FEMTORUBY と R2P2-PICORUBY の UF2 ファイルがあります。 R2P2 の説明はリンクにあります。 FEMTORUBY と PICORUBY の違いなのですが、Femto Ruby は mruby/c の VM 版だそうです。
どちらを利用するといい?という話になりますよね? これは picoruby-keyboard が利用できればどちらでもよいのですが、 今回の Corne V4 は RP2040 を搭載しています。 そのため対応する R2P2-FEMTORUBY-PICO を利用します。
ただ使っているモジュールが異なるので単純な比較はできないのですが、 picoruby 4.0.5 でのファイルサイズはそれぞれ FemtoRuby 版は 約1.4MB 、 PicoRuby 版は 約4.4MB となっています。 github にある Corne V4 Cherry の公式基板データ(基板上の表記はv4.1.0)を読むと、 128Mbit(16MiB)の外付けFLASHが搭載されているようです。 さらに実際に使用できる領域はファームウェアの構成によって異なります。
まずは Corne V4 にダウンロードしたファイルをインストールしましょう。 インストール自体は問題はなく、完了。 インストールがおわったら次に picoruby が動いてるかどうか確認しましょう。 PicoRuby Web Terminal を開いて R2P2 が動いてることを確認します。 確認できたらつぎはキー配列をキーボードへ送り込みます。 送り込むときは、 Open local file でキー配列を定義したrubyファイルを選択します。 選択したら Plain と Compile があるので Compile をクリックし、Upload でコンパイルされたキー配列 mrb ファイルを送り込みます。

trouble!!!
ここからが本題。 なにが問題だったかというと結局、この Femto Ruby にしても問題は変ってなく、 左右の通信が上手くいかなかったんですよ。 ということでここからは Codex を利用してトラブルシューティング。
HUMAN SIDE KANSO
まず今回の問題というか諦めかけてた問題は、左側をマスターとしたとき右側との通信が 上手くいっていないという問題でした。 といったけどこの時点ではそもそも通信できていないのか、片側が死んでいるのか判断は できていないです。なぜできないのかということを探ります。
まず、 そもそも app.mrb のキー配置が間違えていないかを疑ってみます。 そもそも V3 では Adafruit KB2040 を使っていたのでピン配列部分の移植に ミスがないかを確認。 また、上記で述べたとおり、配線方式が マトリクス方式 から ダイレクトピン方式 に変っているためそこも疑います。 がどうもそこらへんではないようです。
埒があかないので、 QMK Firmware から Corne V4 がどう使っているかの定義を Codex に見てもらうことに。 そしたら、いきなり Codex が「6個押せるようにPatchあてました」と言いだして なにか picoruby-keyboard のバグを修正してくれましたね。 バグがあったとは報告はきいたものの、この時点ではまだダウンロード版の FemtoRuby を利用してます。
このとき 6個同時押しのパッチを適用するため自前ビルドすることにしました。 自前でビルドした picoruby でいったん デバッグ 用ログを仕込むようにしてくれました。 出力されたログを見てわかったのは送ってはいるが受け取れてなさそうということ。 これにはボーレート(baud rate)が怪しそうという助言をもらったので変更。 状況はかわらず。関係はないことがわかる。
ここでハードウェア自体の故障疑惑が出てくるが、Codex はほぼないとのこと。 またうまくいかず。次に送っているデータの配列をログ化。 こわれてることは確認できたがよくわからないこわれかた。 とここでもういちど picoruby 側の実装を見てた Codex から 「内蔵 RP2040 の PIO クロックを止めてる」との報告が。 UART 通信を実現するために PIO を利用しているため、これが止まるとまずそう。 ということで picoruby 側を修正して、ようやく左右の通信を確認。 一件落着と。
AI SIDE KANSO
最初に確認する必要があったのは、「右側のキーが入力できない」という症状が、 どこで発生しているかでした。 キーの読み取り、左右間の通信、左側でのキー処理、USBへの出力と、 入力が届くまでにはいくつかの段階があります。 この時点では、右側が動いていないのか、通信だけが失敗しているのかは 判断できていませんでした。
まず QMK Firmware の定義を確認し、Corne V4.1 の各キーに対応する GPIOと、左右間の通信に使用するピンを調べました。 V3 のマトリクス方式とは異なり、V4.1 はダイレクトピン方式なので、 キーの読み取りもそれに合わせる必要があります。 また、左右の判定と、右側のキー位置を左側のキーマップへ対応させる処理も確認しました。
途中で追加した「6個のキーを同時押しできるパッチ」は、 左右間通信とは別の修正です。 今回使用した FemtoRuby のUSB HIDバインディングでは、 複数のキーコードをまとめて送るための変更が必要でした。 これは既存のパッチを見つけて適用したものではなく、 今回の作業で作成した変更でした。
左右間の通信については、右側の送信数と、左側の受信数、 さらに正常なパケットとして解釈できた数をログへ出しました。 右側ではキーを押すと状態が変わり、送信処理も進んでいました。 一方、左側ではデータを受信しても、正常なパケットとして扱えるものが ほとんどありませんでした。
ただし、送信数が増えているだけでは、正しい信号がピンから出ているとは限りません。 ボーレートを下げても改善しなかったため、速度だけでは説明できない状態でした。 ハードウェア故障も、この段階では完全には除外できませんでした。
そこで、同じ基板内で送信したデータを受信するループバックテストを行いました。 左右をつなぐケーブルを介さずに確認しても失敗したため、 まず PIO の送受信処理や、ファームウェア側を調べることにしました。
そこで見つかったのが、RP2040 の待機時のクロック設定でした。 今回の左右間通信は PIO で UART を実装していますが、 待機中にPIOのクロックが止まる設定になっていました。 そのため、CPUが待機に入ると、通信のタイミングも崩れてしまいます。
PIOのクロックを待機中も動かすよう修正すると、 ループバックテストで送信した8バイトが正しく受信できるようになりました。 その後、実際の左右間通信でも正常なパケットとキー状態の変化を確認し、 右側からの入力が通りました。 最終的には、ボーレート 9600 でも動作を確認できました。
yey yey vibe coding!!!
Corne V4 のファームウェアを picoruby に変えてみたのですが、 いろいろと大変でした。とはいえ何とかうごいたのでおわり
それとdiff https://github.com/katsyoshi/picoruby/commit/4aecb0d5338699748893234245fcf68636b7b6cc
Ruby::Box Hacking Guide
Ruby::Box と戦っているので Ruby::Box を Codex に Ruby::Box Hacking Guide としてまとめてもらいました。
ここから本文
1. Ruby::Box とは何か
Ruby::Box は、同じ Ruby VM の中で、box ごとのロード状態や class / module に紐づく内部状態の一部を切り分けるための仕組みです。Ruby::Box.new で新しい box を作ると、$LOAD_PATH、$LOADED_FEATURES、global variable table、class / module に紐づく一部の内部状態が box ごとに分かれます。
Ruby::Box の目的は、同じ VM の中で box ごとの状態分離を実現することです。そのためには、どの状態を共有し、どの状態を box ごとに保持し、どこで解放するのかという ownership を正しく管理する必要があります。
2. まず読むファイル
Ruby::Box を追うときは、次の順で読むと流れを掴みやすいです。
box.cclass.cinternal/class.htest/ruby/test_box.rb
まず box.c で Ruby 側 API と box の lifecycle を見て、次に class.c と internal/class.h で class / module 周りの内部状態の扱いを追います。最後に test/ruby/test_box.rb を読むと、外部からどのような振る舞いが期待されているかと、既存のテストの流儀をまとめて確認できます。
3. 各ファイルの責務
Ruby::Box を追うときは、まず「どのファイルが何を担当しているか」を押さえた方が読みやすくなります。
box.c は Ruby 側 API と box 自体の lifecycle を担当します。Ruby::Box.new、Ruby::Box.current、Ruby::Box#require、Ruby::Box#eval といった入口に加えて、box-local な load path、loaded features、global variable table、local extension cleanup もここで扱います。
class.c は class / module に紐づく Ruby::Box の内部実装の中心です。rb_class_duplicate_classext、class_duplicate_iclass_classext、rb_class_classext_free など、box ごとの class/module 状態を複製・管理・解放する処理があります。
internal/class.h は rb_classext_t の定義と、その読み書きを行う macro / helper を持ちます。box ごとの classext lookup がどのように切り替わるかを見るにはここが基準になります。
test/ruby/test_box.rb は Ruby::Box に期待されている外部挙動を確認する場所です。API の使い方だけでなく、どのような regressions が既に認識されているかを把握するうえでも重要です。
4. rb_classext_t と box ごとの状態
Ruby::Box を理解するうえで重要なのは、class object 自体を box ごとに丸ごと複製しているわけではない、という点です。実際に box ごとの差分を支えているのは rb_classext_t です。
概念的には、次のような構造をイメージすると分かりやすいです。
+----------------------+
| class / module obj |
| (shared) |
+----------------------+
|
+----------------+----------------+
| |
v v
+----------------------+ +----------------------+
| prime classext | | box classext |
+----------------------+ +----------------------+
| m_tbl | | m_tbl |
| const_tbl | | const_tbl |
| cvc_tbl | | cvc_tbl |
| subclasses / caches | | subclasses / caches |
+----------------------+ +----------------------+
Ruby::Box の class/module 周りの挙動は、「どの class object を見るか」ではなく「どの box 用 classext を使うか」で切り替わります。したがって、method table、constant table、class variable cache table、subclass 関連の情報、一部の cache 類が、shared のままよいのか、box ごとに持つべきかを常に意識する必要があります。
include が絡むと ICLASS 用の classext も登場しますが、それは基本構造の上に乗る特殊ケースです。まずは「shared な class/module object に対して、box ごとに classext がぶら下がる」という見方を固めるのが先です。
5. Box の基本操作はどう実装されているか
Ruby 側から見える操作の大半は box.c にあります。Ruby::Box.new は root box の状態を土台にして、新しい box-local 状態を初期化します。Ruby::Box.current、Ruby::Box.root、Ruby::Box.main は、現在どの box 文脈で実行しているかを表す入口です。
Ruby::Box#require、Ruby::Box#load、Ruby::Box#require_relative は、box ごとの load path と loaded features を使って feature を解決します。現状の実装では、新しい box は root 側の $LOAD_PATH や $LOADED_FEATURES を初期値として複製し、その後は独立して変化します。そのため、box 作成後に main 側で行った path の変更や gem activation は box 側に自動では反映されず、require の解決結果が一致しないことがあります。
Ruby::Box#eval は、指定した box の文脈でコードを評価する入口です。再現コードの切り分けや、box ごとの定数・メソッド解決を確認するときに重要です。
また、Ruby::Box は Ruby-level API だけで完結していません。class/module 周りの状態は class.c と internal/class.h が支えており、必要な classext は読むタイミングや書くタイミングで作られます。新しい box を作った瞬間に全てが eager に複製されるわけではありません。
6. Box 拡張時の設計上の論点
以下は、現状の Ruby::Box 実装から読み取れる範囲で、box ごとの状態分離を考えるうえで整理が必要になる点をまとめたものである。
新しい機能や内部状態を Box 対応させるときは、まず次の 4 点を整理する必要があります。
- その状態は shared でよいのか
- box-local にするならどこに持つのか
- いつ複製するのか
- どこで解放するのか
box-local な load path や loaded features のように rb_box_t にぶら下がっているものもあれば、class/module に紐づくので rb_classext_t に置かれているものもあります。新しい state を追加するときは、まずその所有単位が box なのか class/module なのかを見定める必要があります。
次に必要なのは duplication の方針です。eager に複製するのか、最初の write や最初の lookup まで遅延させるのかで実装が変わります。Ruby::Box は copy-on-write に寄せた構造が多いので、複製の入口と invalidation の入口を分けて考えた方が追いやすくなります。
最後に、mark、write barrier、free の対応も確認対象になります。Ruby object への参照が増えるなら GC の mark/update が必要になりますし、table entry を heap 上に積むなら cleanup 側で誰が free するのかを決める必要があります。Ruby::Box の拡張では、機能追加そのものより ownership と lifecycle の整合性が問題になりやすいです。
7. テストの書き方
Ruby::Box のテスト入口は test/ruby/test_box.rb です。ここには enabled?、current、root、main、require、load、nested box、ICLASS 周りの回帰テストがまとまっています。
通常の機能追加なら、まず既存のテストと同じ粒度で setup_box を使ったテストを書けば十分です。一方で、exit 時 crash や process-global な副作用が絡むなら subprocess 系 assertion を使います。
assert_separatelyassert_ruby_statusassert_in_out_err
exit status だけ見たいなら assert_ruby_status が軽く、標準出力や標準エラーも検証したいなら assert_in_out_err を使います。Box 内部の regression test では、可能な限り pure Ruby の再現に寄せ、stdlib native extension 依存は避ける方が無難です。
8. Box 拡張時の実装確認項目
実装を入れた後は、少なくとも次を確認した方がよいです。
- root / main / user box で見え方が変わるか
require/load/evalをまたいで状態が期待通りに見えるか- class/module に紐づく状態なら classext duplication と cleanup が対応しているか
- GC mark/update と write barrier が不足していないか
- process 終了時や box teardown 時にだけ壊れないか
特に class/module に紐づく state は、「作る場所」と「free する場所」をセットで確認した方がよいです。複製側だけを見ていると shallow copy の見落としをしやすく、cleanup 側だけを見ていると shared state を壊しやすくなります。
9. Appendix: 壊れやすい箇所
Ruby::Box の不具合は、表面的には NameError、LoadError、stale cache、終了時 crash のように見えても、内部では ownership mismatch に収束することが多いです。特に class/module 系では、次の 3 点を一本の線で追うと整理しやすくなります。
- box 作成時に何が複製されるか
- 何が shared のまま残るか
- 終了時に何が free されるか
特に class/module 系では、次の関数から読むと追いやすいです。
rb_class_duplicate_classextclass_duplicate_iclass_classextrb_class_classext_free
class variable 系なら variable.c の rb_cvar_set が rb_cvar_class_tbl_entry を作り、vm_insnhelper.c がそれを cache として使います。allocation と free が本当に 1 対 1 になっているかを見ると、exit 時 crash の切り分けがしやすくなります。
10. Appendix: build / run の落とし穴
Ruby::Box の調査では、VM の問題と build/run 環境の問題が混ざりやすいです。
- source tree Ruby に別 install の native extension を混ぜると ABI mismatch で壊れる
- 新しい box は root 側の
$LOAD_PATHや$LOADED_FEATURESを初期値として複製し、その後は独立して変化する extconf.rbを変な場所で叩くと top-levelMakefileを壊すことがある
再現コードを削るときは、まず unpatched build だけで確実に落ちるケースを作り、その後で patched build に切り替えて差分を見る方がよいです。最初から両方を並行で追うと、再現条件が曖昧なまま比較してしまいやすくなります。
Ruby::Boxを使っただけなのに
ruby-4.0 出ましたね。
待望の新機能、 Ruby::Box を使っていますか?
個人プロジェクトで利用しているのでその利用方法について書いていきますよ。
Testで安全にFFI(fiddle)を使いたい!!!!
Ruby::Box はかつて Namespace と呼ばれていたものです。ということは コンパイラー 書いてる人にとってテストが安全にできるじゃないですか。
コンパイラーで生成したバイナリを安全に分離できるじゃないですか。
テスト 向けのロード用ファイルを作ります。
require "fiddle/import"
module Fibonacci
extend Fiddle::Importer
dlload "./libhoge.so"
extern "int fibo(int)"
end
テスト側では以下のようにしますね。
require "test/unit"
class TestFibo < Test::Unit::TestCase
def test_load_fiddle
omit('"Ruby::Box" needs RUBY_BOX=1') unless ENV["RUBY_BOX"] == "1"
box = Ruby::Box.new
box.require "./load_so"
assert_equal(box::Fibonacci.fibo(10), 55)
end
end
では実行してみましょう
$ RUBY_BOX=1 ruby test_fibo.rb
ruby: warning: Ruby::Box is experimental, and the behavior may change in the future!
See https://docs.ruby-lang.org/en/4.0/Ruby/Box.html for known issues, etc.
Loaded suite test_fibo
Started
Finished in 0.007523671 seconds.
-----------------------------------------------------------------------------------------------
1 tests, 1 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
-----------------------------------------------------------------------------------------------
132.91 tests/s, 132.91 assertions/s
テスト通りましたね!やった!!便利!!!
Ruby::Box つかうには RUBY_BOX=1 が必要ですね。なので無い場合のガードとして omit... を入れています。
この確認もしますかね。
$ ruby test_fibo.rb
Loaded suite test_fibo
Started
O
===============================================================================================
Omission: "Ruby::Box" needs RUBY_BOX=1 [test_load_fiddle(TestFibo)]
test_fibo.rb:5:in 'TestFibo#test_load_fiddle'
===============================================================================================
Finished in 0.000660511 seconds.
-----------------------------------------------------------------------------------------------
1 tests, 0 assertions, 0 failures, 0 errors, 0 pendings, 1 omissions, 0 notifications
0% passed
-----------------------------------------------------------------------------------------------
1513.98 tests/s, 0.00 assertions/s
そうしたら omit しないようにしますかね
$ ruby test_fibo.rb
Loaded suite test_fibo
Started
E
===============================================================================================
Error: test_load_fiddle(TestFibo): RuntimeError: Ruby Box is disabled. Set RUBY_BOX=1 environment variable to use Ruby::Box.
test_fibo.rb:5:in 'Ruby::Box#initialize'
test_fibo.rb:5:in 'Class#new'
test_fibo.rb:5:in 'TestFibo#test_load_fiddle'
2:
3: class TestFibo < Test::Unit::TestCase
4: def test_load_fiddle
=> 5: box = Ruby::Box.new
6: box.require "./load_so"
7: assert_equal 55, box::Fibonacci.fibo(10)
8: end
===============================================================================================
Finished in 0.000693731 seconds.
-----------------------------------------------------------------------------------------------
1 tests, 0 assertions, 0 failures, 1 errors, 0 pendings, 0 omissions, 0 notifications
0% passed
-----------------------------------------------------------------------------------------------
1441.48 tests/s, 0.00 assertions/s
とこのようになりますね。omit 入れることで error にならなくなりますね。便利!!!!
ということで Ruby::Box の便利な面をみてきました。こうやって安全に利用できるようになりましたね。
Ruby::Boxでネームスペースを区切ろう
コンパイラーつくってると生成したバイナリをロードして読み込みたいんですよ。
でもテストはプロセス1つじゃないですか?
libbinA.so と libbinB.so を同時に読みたいということはとくになく、
libbinA.so は一つで読みとりたい。
libbinB.so も libbinA.so とは別に読みとりたいことがあるじゃないですか。
このとき、 Ruby::Box でそれぞれ読めばいいとおもうじゃん?ということでやってみますね。
といってもいきなり分けてやるよりもどうせネームスペースがわかれるので同じファイルで実験してみましょう。
require "test/unit"
class TestFibo < Test::Unit::TestCase
def test_load_fiddle
omit('"Ruby::Box" needs RUBY_BOX=1') unless ENV["RUBY_BOX"] == "1"
box = Ruby::Box.new
box.require "./load_so"
assert_equal(box::Fibonacci.fibo(10), 55)
end
def test_load_fiddle_2
omit('"Ruby::Box" needs RUBY_BOX=1') unless ENV["RUBY_BOX"] == "1"
box = Ruby::Box.new
box.require "./load_so"
assert_equal(box::Fibonacci.fibo(10), 55)
end
end
実行〜〜
$ RUBY_BOX=1 ruby test_fibo.rb
ruby: warning: Ruby::Box is experimental, and the behavior may change in the future!
See https://docs.ruby-lang.org/en/4.0/Ruby/Box.html for known issues, etc.
Loaded suite test_fibo
Started
E
===============================================================================================
Error: test_load_fiddle_2(TestFibo)
===============================================================================================
Error: test_load_fiddle_2(TestFibo)Finished in 0.011718944 seconds.
-----------------------------------------------------------------------------------------------
1 tests, 1 assertions, 0 failures, 2 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
-----------------------------------------------------------------------------------------------
WTF 落ちるなんで!!!????よくみたら 2 errors なのに 100% passed ってなんぞ!?
そもそも表示も崩壊してんじゃねーか。
ということでエラー内容みますかね。
load_so.rb:1:in 'Kernel#require': cannot load such file -- fiddle/import (LoadError)
WTF 標準ライブラリーが見えねえってどういうことだよ!!!
これから真相を探るため Ruby::Box を探す旅がはじまります。
老害からのひとこと
やんちゃハウス Advent Calendar 2025 1日目の記事となります。
やんちゃハウスとは?
@yancya が主催する RubyKaigi/Regional RubyKaigi用泊り込み施設です。 RubyKaigi 2017からやんちゃハウスは開催されています。 今年のRubyWorld Conference開催時のやんちゃWorldハウス含み計15回開催(コロナ情勢により2つのイベントがキャンセル)されています。 うちやんちゃハウス6回(2018-2025)、やんちゃWorldハウス1回(2024)に参加しています。 やんちゃ首都圏メガロポリスハウス(2025)は参加申し込みはして料金も払ったけど体調不良で不参加でした。
よいてん
よい点として以下のような点があります。
- 宿を予約しなくていい
- わいわいできる
宿を予約しなくていい
あらかじめやんちゃさんが予約してくれているので私にとってはこの点は非常に大きい点です。 予約して時間通りに行くというのが嫌な人間としてはこの点は非常にいいですね。 それくらいか。
わいわいできる
同じ目的を持ったひとたちで集まるので、自然とわいわいできます。 とくに RubyKaigi の感想とかで深夜まで話こんだりしてしまいますね。 今年のハウスではRubik’s Cubeで盛り上がってたようです。
どちらともいえないてん
いいともわるいともいえない点としては以下のようなものがあります。
- 大人数での宿泊
- 場所
大人数での宿泊
どうしても大人数での宿泊となりますので、深夜までうるさくなりがちです。 私はそんな環境でも寝れるのでたいして問題にはなりませんが、気になる人は注意かも。
場所
毎回毎回近い場所で開催できるわけもなく、遠い回もあります。一番遠かったのは三重かな。 次回の函館は一番近いです。道中みんなでわいわいしながら行くという話もあるので そんなに大変かというとそこまでないです。
もっていくとよさそうなもの
とりあえずうるさくてもまぶしくてもあまり気にならない人間なのであるとよさそうなものを
安眠にあるとよさそうなもの
- アイマスク
- 耳栓
- ネックピロー
やんちゃハウス 2019 のときはリビングルームみたいなところで寝てたのでアイマスクや耳栓はあるとよいと思いますね。 そのときはまあそんなところだとはおもっていなかったけど、どこでも寝れるので問題なかったですね。 あと枕は気になるというひとは予めネックピローなんてものを買ってもっていくといいんじゃないかな。
みんなでわいわいするためのもの
- 酒、お土産
- ボードゲーム
- PC
わいわいするために酒やお土産を持っていってもいいとおもいますね。 ボードゲームで盛り上げるのもありだとおもいます。 やんちゃハウス 2025 ではやんちゃさんがいろいろ持ってきていました。 熱燗用のお酒や、Rubik’s Cubeを大量に持ってきてくれてました。 PCはRubyKaigiのセッション内容の復習とかであるといいとおもいますし、 復習時に動かしたりコード読んだりすることができるのであるといいですね。 みんな当然持ってきてるとおもうけどね。 やんちゃハウス開催期間中、二次会でいそがしく実はみんなで集る機会はすくないのですが……
まとめ
主催者以外で自称最多参加のおじさんからのやんちゃハウス参加への心得を書いてみました。 来年の函館やんちゃハウスも参加予定ですのでよろしくおねがいします。
身分証明書を引き出すための方法
去る 2025/08/03 14:00 ごろに財布を紛失したのでやったことをまとめます。
財布紛失
普段行かない原宿で買い物してたら、財布がないのに気付く。 とりあえず気付いた店で「財布落ちてなかったか?」と店員に聞きまわる。 そこではみつからなかったので、一旦立ち寄った店でも聞きまわり、ないということが分かった。 ないことが分かったので、近く警察に紛失した旨を申告、遺失物届けを提出。
カード類停止
原宿という場所柄、クレジットカードが利用されていないかスマートフォンで確認。 調べた時点では利用されていないので、帰宅後クレジットカード、キャッシュカードを止め、クレジットカードは再発行手続きを実施。 幸い買い物行く直前にカードから suica へ入金していたので got 事なき。 現金、カードが無いのでその日の夕食はスタ丼屋ヘ。 紛失した日は一旦これで終わり。
ブートストラップ身分証明書
次の日、仕事休んで身分証明書の発行へ。
まず現金が手元にないのでキャッシュカードの再発行手続きへ銀行に行く。 ここでキャッシュカードの再発行に必要なものとして病院の診察券などの本人確認書類の提示が求められた。 財布を紛失したことでそもそもそのような身分証明書類になるようなものを所持しておりません。 正直になにも所持していないことを銀行の窓口に伝える。これ以上は銀行ではできないことがわかりました。 キャッシュカードの再発行は後回しにして、身分証明書の再発行へ。
まずは、マイナカードの再発行。マイナカードの再発行に居住地区の役所へ、すると役所でのマイナカードの再発行手続きにはどうやら本人確認書類となる運転免許証が必要とわかった。
ということで運転免許証の再発行へ近くの警察署へ。警察署署員に聞くとここでは運転免許証の再発行は行なわれていないことを告げられる。 運転免許試験場で再発行が行なわれていることを署員さんに教えてもらったので運転免許試験場へ。 運転免許試験場へ着いて再発行手続きをすると本人確認書類として住民票の提出を求められました。 そんなものは持っていない状態なので一旦帰宅。
帰宅後、キャッシュカード再発行手続きで必要といわれた身分証明書類を探したが、みつからず。 住民税の通知書を発見したので手に再び役所へ。 役所では、身分証明書類を紛失した旨を伝え、住民票の発行手続きへ。 どうやら住民税支払い通知書だけではダメだったらしく1、本人しか知り得ない情報を捻り出してなんとか発行。 住民票を得たので、今度こそ運転免許証の発行へ最寄りの運転免許試験場に出発。 運転免許試験場の再発行手続きでは、とくになにも問題なくスムーズに再発行手続きがおわり、再発行できました。 運転免許証の再発行自体が完了したのは16:00すぎだったのでその他カード類の再発行は手続きは無理そうだったのでこの日は終了。
カード類復活
身分証明書のブートストラップは解決したので今度は止めてあるカード類の復活を行います。 まずは銀行のキャッシュカードです。住民票と運転免許証を所持しているのでなにも気にせず銀行へ。 銀行に到着したら怒られが発生。 銀行員に「今、ここでキャッシュカードの再発行は予約いっぱいでできないかもしれない。どうしてもやりたいなら予約が空くまでここで待機しておいてください」と。 朝ごはん食べていなかったので昼食をとりに行きたかったので、何時ごろ空くのか聞いてみたら突然予約が空いたらしくその日の午後に手続きができるようになった2。 午後、再訪問し再発行完了!!!
この勢いのままマイナカード再発行へ。今度は身分証明書をいろいろ所持しているので大丈夫やろ。 手続きに入って最終の再発行する際に発行手数料がかかりました。平気平気、この役所は電子マネー使えるから!と思ってたら、 役所の人に「あ、現金のみです」と告げられました。 キャッシュカード再発行できたとはいえ、電子マネー使えるので現金を降ろさずに来てます、なので当然現金なんて持っていないです。 ということで一旦現金降ろしにコンビニへ。
コンビニで現金を引き出そうとすると謎にエラーになります。当然です。カード類停止時にキャッシュカードロックを行なっています。 引き出せないです。どうしようもなくなったので3一旦その日の手続きは終わらして、後日やるということを窓口で伝えました。
帰宅後、キャッシュカードロックの解除を行なおうと銀行のサイトで操作してたら、秘密の質問とかいう謎のパスワードを聞かれた4。 案の定謎パスワードも揮発しているので繰り返し入力してたらそれもバンされて詰み。現金はこの日は引き出せないことが確定。 そんなことなので再設定をするには銀行に行く必要がでてきた。この日は銀行を予約しておわり。
予約した銀行
前日に予約したと思ってた銀行は実際には一週間先で失意で仕事へ。 昼食へ外出する際にポスト覗くとなにかお手紙が。このお手紙読むとなんと財布が発見されたようです。 仕事は中抜けして財布を回収へ。回収した財布はなにひとつ欠けることなく現金まで入ってました5。 ということで急いで現金の引き出しが性急にする必要はなくなったので、銀行の予約は一旦そのままにしておきます。
予約した銀行へ訪問し、キャッシュカードロックを解除させるためにアプリのパスワードリセットします。 といっても銀行の人がリセットしてくれるので眺めておくだけで、こちらはパスワードと秘密のことばをその場で設定しておわりです。
このあと、発見された財布に入ってた旧運転免許証を破棄するために警察署6へ訪問して一連の作業は終了。 つかれた。
まとめ
財布を紛失した顛末を書いた。 財布は失くすといろいろと面倒というのはもともと理解してたつもりだったが、いざ失くなると何が必要とか焦ってしまって調べるとかできないこともわかった。
今回の一番面倒だなと思ったのがマイナンバーカードを紛失した際の手続き。 こいつ自体も強い本人確認証だしほぼすべての本人確認書類が集まっている。 申請自体は多分そこまでおかしい点はなさそうだが、一時的に利用できなくなる期間が1-2週間かかりそう。 今回は幸い盗まれたとかではなかったので再発行しなくてよかったけど。
身分証明書と本人確認書類という言葉が出てきますが、基本同じです。 本人確認書類は相手方(役所、銀行など)として審査、確認する際ときに使う意味として使っています。 身分証明書は自分が相手方に提出する書類としての意味として使っています。 区役所のウェブページで「本人確認書類」と掲示されていたため、意識的に分けています。
おまけ: いろいろなもの再発行フローチャート
Gentoo のバイナリ配布公式レポを発見したので対応してみたら大失敗した
[Gentoo Linux] でバイナリが公式配っていたのを発見したので、 退役したデスクトップをサーバー用途として利用してみます。
設定
設定自体は発見したブログを参考に設定することで問題はないです。
インストール
ではインストールをしてみましょう。 ブログを参考にリポジトリなどを設定後、以下のコマンドでインストールします。
emerge -uDN world
そして失敗へ……
インストールが終わり、動いているのを確認しましょう。 動いていますね。OK, OK では不要なパッケージを片づけましょうかね。
emerge --depclean
一部バイナリになって便利になりましたねー。便利ー。
Zellij のセッションが残っている間は問題が特にわからなかったです。
次の日あたり、クライアントから Samba がなぜか繋がらなくなっています。
原因を探るため、 ssh でログインしてみましょう。
これもログイン失敗します。しかたないのでユーザーを替えてログインしてみます。こいつはログインできます。
ログインしたアカウントから doas してみますが、 doas できる権限を与えていないので当然できません。
sudo は sudo 自体を削除しているのでできないですね。
また su も権限がないので別ユーザーへ変更できないです。
ということで何かまずいことが起きているのでログインできるようにサーバーの復旧を行ないます。
いつも通り OS インストールと同様にインストールディスクを起動して必要なディレクトリをマウントします。
そうするとなぜかいつも利用しているはずのコマンド eix 、 git や zsh が無いのです!!!
ということでインストールします。
emerge --sync # リポジトリを git で読むようにしているので失敗
emerge git # デフォルトリンカを mold にしているので失敗
# mold 使わないように修正
emerge git
emerge eix
eix-sync # ようやく成功
emerge zsh
というようなコマンドを実施してなんとか復旧。
おわり
バイナリの配布リポジトリを設定できるのは薄々知ってはいたのですが、
動いているのを変更するの面倒だったので今回替えてみました。
カーネルもバイナリでインストールできるようになったので便利になりました(たぶん)。
あとうかつに emerge --depclean はするもんじゃない。
RubyKaigi 2025 at Matz-yama
今年も RubyKaigi 2025 に行ってきました。
今年みたセッション一覧を日毎に。
Day 1
- Ruby Taught Me About Encoding Under the Hood
- Bringing Linux pidfd to Ruby
- The Evolution of the CRuby Build System
- Deoptimization: How YJIT Speeds Up Ruby by Slowing Down
- Ruby’s Line Breaks
- State of Namespace
- TRICK 2025: Episode I
初日のキーノートは、 @ima1zumi さんで文字コードの話してくれました。
つぎは @mensfeld の pidfd の話を聞きました。
これは server 動かしているとはまる問題、 pid の使い回しによるバグの対処方法として pidfd を Ruby に対応したという話でした。
オチは、そもそも overkill で不要だったねという。
午前の終りは @kateinoigakukun さんのビルドシステムの話でした。 Ruby のビルドシステムのリプレースを考えているようでした。
午後一発目はお馴染 Shopify の YJIT チームの @k0kubun さんの話。 YJIT を速くするために、如何に deoptimization するかという話で、速くするための方法を話していました。
パーサーギャング 一味のドン、@yi-knk さんの話で今年楽しみにしてた発表。
Namespace の話は @tagomoris さんがやってくれました。
今年のうちに入りそうな雰囲気を感じた。
いったん休憩して trick へ。
Day 2
- Performance Bugs and Low-level Ruby Observability APIs
- Dissecting and Reconstructing Ruby Syntactic Structures
- ZJIT: Building a Next Generation Ruby JIT
- Bazel for Ruby
- The Implementations of Advanced LR Parser Algorithm
- Lightning Talks
dd-trace-rb の作者 @ivoanjo の observability の話。
もう同じ目的をもった @osyoyu がスマートバンクブログで解説しているのでそちらを参照。
新米 Ruby Commiter の @ydah です。
lrama で Ruby の parse.y をどう読み込むのか、どう構造化するのかの話でした。
Shopify YJIT チームの親分、 maximecb の発表。
新しい JIT 、今年一番の衝撃 ZJIT の提案。詳細は Proposal to upstream ZJIT を見てくれ。
パーサーギャング 一味のトリ @junk0612 の発表。
lrama に IELR を適用してみる話。まあ遅かったりするようです。
最後に
Day 3
- Ruby Committers and the World
- Improving my own Ruby
- The Ruby One-Binary Tool, Enhanced with Kompo
- Toward Ractor local GC
- Modular Garbage Collectors in Ruby
- Matz Keynote
@sisshiki1969 さんで、rust の ruby 処理系を作ってる人で、速くした話でした。 @ahogappa さんが作ってる kompo というツールの話で、この kompo はバイナリー1つにまとめてくれる便利ツールです。 今回は Rails アプリが動くようになった話をしていました。 @peterzhu2118 さんが GC (Garbage Collection) をモジュール化して入れ替えれるような話をしてました。 さいごに @matz のキーノートで Ruby のこれからの話、AI の話などなど。
おわり
おそくなったけど、一旦聞いたセッションをまとめてみました。来年は函館で東京から電車一本で行けるので楽そうですね。 おわり。
Hello, ZOLA を失敗した話
HELLO, ZOLA World!!!!! としたかったけど、
移行が面倒すぎたので諦めた話。
以下は作業ログです。一応終りは見えたけど、
ELECTIONS
Jekyll でサイト作るの飽きてきたので、 新しい SSG(Static Site Generator) に変更することにした。
選定必須基準として、以下の条件を。
- markdown 形式1 で書けること
- Jekyll と同じ URL が生成されること
いまどき直接 HTML で書く人はあまりいないし、いままでの記事があるので markdown で書けることは当然ですね。 もうひとつの必須条件として、 Jekyll で設定した URL で記事が書けることとなります。 これは現在出している記事の URL を変更しないために必須です。
移行に苦労しないようにするために以下の条件をとることにした。
- Jekyll と同じ様に markdown の先頭に frontmatter でいろいろと設定できること
- Jekyll と同様にテーマが選択できること
- バイナリーで配ってること
frontmatter については移行を楽にするためで多少の書き替えはしかたがないとしています。 デザイン変更を楽にするためテーマが選択できる SSG だといいなあと思い。 バイナリーで配ってあると楽なんですよ2。
以上の条件を踏まえいくつか検討してみましたが、 zola にしました。
Jekyll to Zola
やったこと
まず、ファイル名が .markdown と混在してので .md へ統一。
つぎに markdown 先頭の frontmatter を YAML から TOML へ変換する。
これは大変な話ではなく、 frontmatter 部分を読み込んで変更するだけです。
でこの変更部分なのですが、大抵の部分は問題にならないです。
大抵の部分は……
URL の設定
URL の設定は、参考サイト の設定を利用して変換します。
ここで問題となるのが、Jekyll の設定で、 /blog/%Y/%m/%d/file-name となっていることです。
Zola では
(そもそも config.toml で設定する slugify に設定する方法があるようですが、イマイチ使えずslugify を勘違いしてた)。
ディレクトリを利用し設定する方法と frontmatter に path で設定する方法があります。
今回は frontmatter で path 指定して URL を設定することにしました。
変換はファイル名から取得すればよいので問題は特になく変換できました。
ただ、変換する際にこのままだと挿入するには注意が必要で、挿入する必要があります。
これは Array#insert を利用すれば 解決 ですね。
テーマ
テーマ はあるのですがプラグイン形式というわけではなく、 git clone or git submodule add して利用する点が慣れない。
気になる部分は template/ に修正ファイルを全部作る必要があり面倒でした。
Cargo でインストールできればいいのに……
ということでもっと面倒臭い自分のテーマを作ることでこの気になる点を解決。
作成方法は 公式ドキュメント を参考にすすめれば問題なく作成できます。
テーマというか、普通にテンプレート化するだけです。
テーマ化 も実際は簡単にでき、 theme.toml を書いておけば大丈夫なようです。
個人的に利用しているだけなのでテーマ化はしないですが。
FEED.XML
RSS Feed 自体はサポートされていますが、 URL のパスが /atom.xml か /rss.xml になってしまうため
旧来のパス /feed.xml は新規にテンプレートを作る必要があります。
これは追い追い考える。現状 Jekyll にあった feed.xml を作るのは大変すぎる。
こまかい修正
いくつか気になる部分があったがこまかいので手で修正
- 脚注の順番が脚注を書いた順に出力
- Syntax Highlighting のサポート言語
- 画像の変更
- rake task の整理
脚注は脚注で引用した順番ではなく、脚注を書いた順になっているので修正してます。 Syntax Highlighting ではサポートされていない書きかた(console)をやめてサポートされている言語(bash)へ修正。 画像の変更はとくに zola は関係なく、大きいファイルが多いので変更しています。 rake task では、いままでデプロイやら記事作成やらなんだかんだやっていたので整理を行いました。 今は一旦、記事作成だけにしております。そのうちデプロイを行なえるようになると思います
とここまで書いたけどデプロイやめた
というのが、 feed.xml の移行とスタイルの修正が思った以上に大変で中止。
この今 Jekyll のテーマのスタイルがあれば、そのうち変更するかもね。
KaigiOnRails 2024 に行ってきました
Kaigi on Rails 2024 にはじめて現地参加しました。
day 1
day 1 before
kaigiが始まるまえに場所が有明だったので朝寿司へ。 1年くらい前はよく朝寿司に行っていたので余裕だろうとおもい、朝9時集合に設定した。 普段行ってる店ではなく新規開拓ということで tabelog の評価が高い、寿司処 やまざき さんにしました。 食べたあと丁度いい時間に会場へ入れそうだったので歩いて向いました。
会議
聞いたセッションは以下のとおり
- rails-way-or-the-highway
- RailsのPull requestsのレビューの時に私が考えていること
- そのカラム追加、ちょっと待って!カラム追加で増えるActiveRecordのメモリサイズ、イメージできますか?
- モノリスでも使える!OpenTelemetryでRailsアプリのパフォーマンス分析を始めてみよう
- cXML という電子商取引のトランザクションを支えるプロトコルと向きあっている話
- リリース8年目のサービスの1800個のERBファイルをViewComponentに移行した方法とその結果
- [ActionCableなら簡単? 生成 AIの応答をタイピングアニメーションで表示。実装、コスト削減、テスト、運用まで。]
- 現実のRuby/Railsアップグレード
感想
キーノートの @palkan の話はすごくよくて、Rails Wayについて話をしてくれました。
@yahonda は、 Rails の The Committers の一員で Rails でレビューしている際に気を付けている部分について話してくれてました。
@asayamakk は DB にカラムを増やすとどれだけ ActiveRecord のオブジェクトが増え、メモリの消費量が増えるかの話でした。
@katty0324 は ViewComponent に移行するために自動化した話でした。この話は大変興味深く聞いてました。
ViewComponent に対応するために問題の整理、自動化するための準備など丁寧に仕事している印象でした。
@takeyuweb ではアップデートするためになにをしたのか、していくのかという話をしてくれていました。
day 1 after
この日はオフィシャルの懇親会があり、わいわいと話してました。このとき @tagomoris が Ruby でやっている Namespace のビルドが通ったらしく皆でお祝い。 懇親会後に @palkan や @yahonda たちと二次会で新橋へ。私は早々に帰ったのですが会は1:30ごろ解散だったようです。
day 2
day 2 before
この日の 10:00 のセッションに間に合うはずだったのですが、出る時間の予定が狂ってしまった。 出る直前に近所のおじさんが向っていることに気がついたので有楽町で落ちあい、タクシーで向かうことに。
Kaigi
- 作って理解する RDBMSのしくみ
- 入門『状態』
- Hotwire光の道とStimulus
- Data Migration on Rails
- Identifying User Identity
- WHOLENESS, REPAIRING, AND TO HAVE FUN: 全体性、修復、そして楽しむこと
Kansou
最初のセッションは前日いっしょに飲んでた @ydah で、RDBの中身の基本的な話をしてくれました。 その後はちょくちょくづつ聞く感じになりました。 @snoozer05 のキーノートはいい話でした。
day 2 after
会議後の懇親会は mov Drinkup と pixiv RubyMusicMixin へ。 この日は前日の疲れが取れていないので終ったあとすぐに帰宅。
おわり
たのしい二日間でした。ありがとうございました。
今日、私が学んだこと
ここ1年ほど Ruby のパーサーがもりあがっているので、 lrama の作者を講師にした 通称ドラゴンブックの「コンパイラ」読書会 に参加しています。
4.8.1 節の「競合解消のための優先順位と結合性」を読み感想を言い合う場で、 以下のような話になった。(細かいとろこは本を読んでくれ
- id + id * id
+は*より優先度が低いため shift
- id * id + id
*は*より優先度が高いため reduce
- id + id + id
+は左結合なので reduce
- id = id = id
=は右結合なので shift
ここでそういえば Ruby ではどう動くのだろうかとおもい、次の式をirbで書いてみた
0 - i = 1 + j = 2 * 3 #=> -7 とまあ普通(?)の答えが返ってきた。
でも上のパーサーの条件考えてみるとそもそもこのコードはほかのプログラミング言語で
パースできるのだろうかと思い、やってみた。
$ python -c '0 - j = 1 + j = 2 * 3'
File "<string>", line 1
0 - j = 1 + j = 2 * 3
^^^^^
SyntaxError: cannot assign to expression
$ perl -e '0 - j = 1 + j = 2 * 3'
Can't modify addition (+) in scalar assignment at -e line 1, at EOF
Execution of -e aborted due to compilation errors.
$ lua -e '0 - j = 1 + j = 2 * 3'
lua: (command line):1: unexpected symbol near '0'
$ crystal eval '0 - j = 1 + j = 2 * 3'
syntax error in eval:1
Error: unexpected token: "="
$ ruby -e '0 - j = 1 + j = 2 * 3'
$
:thinkingface:???とにかく Ruby は通るが他のプログラミング言語で通らないことがわかった。
さいごに Ruby の AST がどうなってるのかとりあずみてみた。
$ ruby -e 'pp RubyVM::AbstractSyntaxTree.parse "0 - j = 1 + j = 2 * 3"'
(SCOPE@1:0-1:21
tbl: [:j]
args: nil
body:
(OPCALL@1:0-1:21 (LIT@1:0-1:1 0) :-
(LIST@1:4-1:21
(LASGN@1:4-1:21 :j
(OPCALL@1:8-1:21 (LIT@1:8-1:9 1) :+
(LIST@1:12-1:21
(LASGN@1:12-1:21 :j (OPCALL@1:16-1:21 (LIT@1:16-1:17 2) :* (LIST@1:20-1:21 (LIT@1:20-1:21 3) nil)))
nil))) nil)))
まあわかるような木構造になってますね。 それはそうとパーサーどうなってるんですかねえという話でおわり。