はてなブログの方で色々記事を書いては来たんだけど、もっと気軽に書きたいものを書けるようにしたかったので専用のブログを作った。
また個人的な課題感としてActivityPub対応の小規模実装が欲しかったのもあり、ActivityPub対応のブログとして運用している。
今後はこちらで雑に文を綴りたいと思うので、こちらを見ていただければと思う。
はてなブログの方で色々記事を書いては来たんだけど、もっと気軽に書きたいものを書けるようにしたかったので専用のブログを作った。
また個人的な課題感としてActivityPub対応の小規模実装が欲しかったのもあり、ActivityPub対応のブログとして運用している。
今後はこちらで雑に文を綴りたいと思うので、こちらを見ていただければと思う。
今年はあまりRuby関係のイベントに登壇はできなかった印象の一年だった。 特にプロポーザルに力を入れていたRubyWorld Conference 2025に関してはかなり悔しさが残っていて、2026年のどこかのイベントで供養したい。
登壇自体は東京Ruby会議12の前夜祭イベントくらいで、それ以外は登壇はなかった。
ゲームの方とかは相変わらずHaloをやりつつ、それ以外のゲームをプレイするといういつもの感じになっていた。 特に印象に残っているのは都市伝説解体センターかサイレントヒルfかな。 あとはLies of PのDLCも非常に良かったので個人的には豊作な一年だった印象
それ以外だと家族全員で観に行った大長編タローマン万博大爆発が個人的には一番印象に残っている。 人生初の応援上映もタローマンだったし、タローマン経由で岡本太郎さんの作品を調べたり、本を読み漁ったりとでかなり影響を受けていた気がする。
この記事は、僕が最近自作しているエディタであるMui(無為)でRubyの型定義ファイルである.rbsへ遷移できるようにした際の備忘録をまとめたものです。
実装時の詳細な情報などは個人的に利用しているesaにまとめてあるのですが、ちょうど最近技術ネタの記事をあまり書いていなかったのもあり、記事にしてみました。
ちなみに自作しているエディタのMui(無為)はヘイシャのブログで紹介しているのでそちらをご覧ください。
以下のように、自作のエディタ上で動いているTypeProfのLSP経由で、型定義ファイル(.rbs)へ直接遷移できるようにしています。
まずは自作のエディタ用のLSPプラグインには型定義ファイルへ遷移するためのコードを追加しました。
def type_definition(file_path:, line:, character:) # Only send to servers that support typeDefinitionProvider text_syncs = text_syncs_for(file_path).select do |ts| ts.client.server_capabilities["typeDefinitionProvider"] end if text_syncs.empty? # Fallback message: check if any server is running but doesn't support typeDefinition any_text_sync = text_syncs_for(file_path).first @editor.message = if any_text_sync "LSP: no server supports typeDefinition for this file" else server_unavailable_message(file_path) end return end uri = TextDocumentSync.path_to_uri(file_path) handler = Handlers::TypeDefinition.new(editor: @editor, client: text_syncs.first.client) # Collect results from all clients results_mutex = Mutex.new pending_count = text_syncs.size all_results = [] text_syncs.each do |text_sync| text_sync.client.type_definition(uri: uri, line: line, character: character) do |result, _error| results_mutex.synchronize do all_results << result if result pending_count -= 1 if pending_count.zero? merged = merge_locations(all_results) handler.handle(merged, nil) end end end end end
ただ、手元の環境でTypeProfを使ってクラスの型定義ファイルへ遷移しようとすると、何故かクラスの定義位置へのみ遷移する挙動をしていました。
エディタ上での動きからして「そもそも型定義ファイルへの遷移は、まだ実装されていないのでは?」と考え、以下のようにRubyのソースコードだった場合は型定義ファイルへ遷移するように変更しました。
def jump_to_type_file(file_path:, line: nil, character: nil) # For Ruby/RBS files, use custom toggle behavior if file_path&.end_with?(".rb", ".rbs") jump_to_ruby_type_file(file_path) else # For other languages, use LSP typeDefinition type_definition(file_path: file_path, line: line, character: character) end end
Rubyのコードだけ特別扱いする形になるので実装としては筋がいいものではありませんが、一旦型情報を参照できるようにしたかったのでこれで妥協することにしました。
ただ、この実装で終わるのも面白くなかったので今回の実装で得た知見を活かして、TypeProf本体にもパッチを投げてみました。
このパッチで以下のことができるようになりました。
foo = Foo.newのようにインスタンスを受け取っている変数からも型定義ファイルへ遷移できるようになった実際の動作としては以下の動画のようになっています。
動作確認としてはVSCodeとMui(無為)それぞれで確認しています。
なので、このパッチがマージされれば他のエディタ上でも型定義ファイルへの遷移ができるようになると思います。
今回の対応で.rbsへの遷移ができるようになりましたが、まだ型情報のホバー表示などには対応できていない状況です。
なので、今後はそのあたりを対応しつつ他の言語のLSPとの連携(たとえばTypeScriptの型情報への遷移とか)を試しつつ、開発を続けていきたいですね。
RubyWorld Conference 2025があったり、地域の人からの依頼で中学生向けに「ITエンジニアの仕事ってどんなもの?」というのを話してきたりとでイベント多めの月だった。 特に中学生向けのITエンジニアの仕事の話はかなり話す内容に迷ってて、どういう話の持って生き方にするのがいいのだろうかと悩んだ。 最終的に「伝えたいこと」を凝縮して話し、それなりに反響もあったのでまああれでよかったのかなとなっている。
たまにHalo2 Legendaryキャンペーン周回をやったりという感じでそんなに遊んではいなかった感じ。
UFOエンドを見たので三週目を進めていた。 ただ、OSS周りであれこれ作っていたのがあり、あまりプレイ出来なかった印象。
基本的にはKanayago(金屋子)とIgata(鋳型)の実装をしたりしていた。
KanayagoにはLSPモードを追加したりしたので、各種エディタ向けにリアルタイムにシンタックスエラーを検知できるプラグインとかも書いたりしてた。
大長編タローマン万博大爆発の三回目を観に行ったりしていた。地味に人生初の応援上映(タローマンの場合は「応援しない応援上映」だけど)で楽しめるか若干不安だったけど、かなり楽しかった思い出。
特に子供が声出して映画を楽しめているようでなによりだった。
引き続き、Halo2 Legendaryキャンペーン周回をやっていた。
徐々にクリアタイムの短縮もできているので、引き続き精進したい。
ただサイレントヒルfにかまけていて、あまり時間を割けていないので11月はガッツリやりたい。
地味に初サイレントヒルだった。
システム的には見切りがあるので、アクションに慣れてる人間からすると戦闘難易度はそこまで難しくないかも?
といっても五里霧中ではまだクリアしていないので、難易度が上がった時どれくらいは応えがあるのかが楽しみ。
「読書って自由で楽しいものなんだな」と再認識する一冊だった。
というか山月記のくだりが面白すぎて笑いがこらえられなかった。あれはだいぶずるいでしょうよ。
タローマン経由で読み始めた岡本太郎関連の本の一冊。
太陽の塔と70年万博と国立民俗博物館との関係性とかも説明があって面白い一冊だった。
日本のあちこちの土地に根差した祭りを岡本太郎がどういう視点で視ていたのかというのが分かる一冊。
オシラサマや御柱祭とかは知っていたけど、知らない祭りとかも出ていて面白い。
特に岡本太郎が気になった祭りの場面の写真もかなりあって良かった。
岡本太郎は民族学の人としての顔もあって、その部分にフォーカスした内容の一冊。
著者は民俗学者の赤坂憲雄さんで、柳田國男と岡本太郎との対比も挟みつつ「岡本太郎が日本をどう見ていたのか」が言及されていくという内容で非常に面白かった。
家族三人で三回目の大長編タローマン万博大爆発を観てきた。しかも「応援しない応援上映」で。
公式のパンフレットにも三回目まで観た日付が書かれているのでここまでは普通のファンのムーブに違いないと若干錯乱していたのかもしれない。
三回目かつ「多量の原液の岡本太郎成分を本で摂取した」上で観たというのもあり、かなり冷静に観つつ「ああ、これはあの話が元ネタだったのか」という気づきがあり良かった。
あと個人的に今年観た映画の中ではジークアクスのビギニングを差し置いて、大長編タローマン万博大爆発が不動の一位になっているので、会う人に「タローマンはいいぞ」という人になってしまった。
ハロウィンといえばこれだよね。ということで毎年恒例のカウボーイビバップ天国の扉を観ていた。
やっぱりいつ観ても良い。
BrakemanをRubyのmasterで動かしているとエラーになるか所があったのでパッチを書いたりしていた。
あとは粛々と作っていたKanayago(金屋子)がライブラリとして動くようにASTノードをサポートしきったり
「せっかくKanayagoが一通り動くようになったのでKanayagoを使ったものを作るか」となり、テスト生成ツールを作ったりしていた。
昨年登壇した福岡Rubyist会議04では、「Ruby本体のparse.yをサードパーティライブラリとして使えるようにする」という試みについて発表しました。
またその時に作ったライブラリのKanayago(金屋子)はこちらです。
当時はまだ一部のASTノードしか対応しておらず、実際にライブラリとして利用するのは難しい状況でした。登壇後も細々と実装を続け、つい先日ようやく全てのASTノードに対応しました。
「これでRubyのコードがパースしていじれる」ようになったので「せっかくだし何かKanayagoを使ったツールを作りたいな」と思い、Igata(鋳型)というツールを作ってみました。
Rubyのコードを渡すことでMinitestまたはRSpecのテストコードの雛型を作ってくれるツールになります。
テストの雛型作成ツールを作ろうと思ったきっかけとしては、後述する omochi の存在と、「実務でも使えるツールの方がドッグフーディングとして良さそうだ」と考えたからです。
利用シーンとしては
などを考えています
主な利用シーンとしては、既存のコードベースにテストを追加する場面を想定しています。
また実装の着想としてはRubyKaigi 2024のLTで紹介されていた omochi から得ました。 僕自身もLTで登壇しており、ちょうど前の枠が omochi の発表だったこともあり印象に残っています。
「テストコードを生成する」という点では omochi と同じ方向性のツールですが、Igataでは「複数のテストフレームワークに対応したい」「テストを書く際に面倒な構造を自動生成したい」「RubyのASTノードを直接扱いたい」といった意図を持って実装しています。
基本的にはCLIツールとして利用します。
# デフォルトではMinitestの雛型が生成される bundle exec igata lib/user.rb > test/test_user.rb # -f rspecでRSpecの雛型が生成される bundle exec igata lib/user.rb -f rspec > spec/user_spec.rb
例えば以下のようなコードを渡すと
class User def initialize(name, age) @name = name @age = age end def adult? @age >= 18 end end
以下のようなMinitestの雛型を生成したり
# frozen_string_literal: true require "test_helper" class UserTest < Minitest::Test def test_initialize skip "Not implemented yet" end def test_adult? # Comparisons: >= (@age >= 18) skip "Not implemented yet" end end
このようなRSpecの雛型を生成することができます。
# frozen_string_literal: true require "spec_helper" RSpec.describe User do describe "#initialize" do it "works correctly" do pending "Not implemented yet" end end describe "#adult?" do # Comparisons: >= (@age >= 18) it "works correctly" do pending "Not implemented yet" end end end
Kanayago経由でメソッド内の条件分岐などの情報が取得できるので Comparisons: >= (@age >= 18)のようなコメントも追加で出力するようにしています。
こうしたコメントを自動で出力することで、テスト設計時に条件分岐の意図を素早く把握できますし、将来的にはLLMを活用してテストケースを自動生成する際の補助情報としても活かせるのではと思ってこうしています。
一旦は個人的に作っているライブラリなどで試しつつ、Railsのrequest specやmodel specなども対応していきたいと思います。 またKanayago自体の改善やparse.yに投げているキーワードの位置情報を追加対応なども進められれば、より便利なテストの雛型を生成できるようになると考えています。