mruby向けのURI構文解析ライブラリ、mruby-uriparserを開発しました。
RFC 3986準拠のCライブラリであるuriparserのバインディングとして実装し、高速・軽量かつ堅牢なURI処理をmruby環境で利用可能にしています。
既存ライブラリの調査
RubyでのURIの構文解析には先駆者がたくさんいます。
まずはmrubyから見ていきます。
mrubyのホームページのmruby Librariesを見ると、Asmod4n/mruby-uri-parserが挙がっています。
こちらのライブラリはZewoGraveyard/uri_parserをCライブラリとして採用しています。
このCライブラリはNode.jsのhttp-parserライブラリのソースから抜粋してモジュール化したものです。
ただし、その元のライブラリのリポジトリnodejs/http-parserは現在アーカイブされており、新しいプロジェクトではllhttpを検討するように推奨しています。
他にもmrubyにはzzak/mruby-uriがあり、純粋にRubyで実装されています。
次にCRubyですが、当然標準のuri gem(GitHubリポジトリ、日本語のAPI文書)があります。
また、uriparserライブラリを使うtlewin/ruby-uriparserも存在します。
説明を読むと標準のURIライブラリに比べておおよそ7.5倍速いと謳われているように、速度と低メモリ消費を重視しています。
深追いはしませんが、CRubyには他にも多数のライブラリが存在します(参照:「uri parser」での検索結果)。
uriparserの選択理由
uriparserはC言語で書かれたRFC 3986準拠のURIの構文解析ライブラリです。
クロスプラットフォームで高速・軽量、依存関係もないため、組み込み用途で実績のあるmrubyとの相性が良いと考えました。
多くのプロジェクトで採用実績があり、直近ではPHP 8.5のURI拡張モジュールに採用されています。
採用に至った経緯はPHP Foundationのブログ記事で紹介されており、この過程でuriparser側にも複数の新機能が追加されました。
CRubyでも既にこのライブラリを使ったgemが存在し、他の言語でも公式ページに掲載されている通り、様々なバインディングが開発されています。
機能紹介
ここまでの調査で、mruby用のuriparserバインディングはまだ存在しないことが確認できました。
活発に開発されているこのライブラリを活用することで、CRubyなど他言語の実装と同等の品質を実現できると考え、mruby-uriparserを開発しました。
mruby-uriparserには以下の機能が含まれます:
- URI文字列の構文解析(スキーム、ホスト、パスなどの構成要素を取得)
- 例外処理によるエラーハンドリング
- 正規化(不要な
.や..の除去など)等の変更操作
使用例は以下です。
str = "http://example.com:8000/some-path?some-query"
uri = URIParser.parse(str)
uri.scheme #=> "http"
uri.host #=> "example.com"
uri.port #=> "8000"
uri.query #=> "some-query"
関連リンクは以下の通り:
- GitHubのリポジトリ:gemmaro/mruby-uriparser
- API文書
開発で学んだこと
C言語の学習
mruby拡張の開発にはC言語の知識が不可欠でしたが、当初は充分な理解がありませんでした。
プログラミング言語C 第2版とBuild Your Own Lispを通じて、必要な知識を習得しました。
uriparser APIの理解
uriparserは同一機能に対して複数のバリエーションを提供しています。
例えば、API文書にはuriAddBaseUriA、uriAddBaseUriExA、uriAddBaseUriExMmAといった関数が並んでいます。
公式文書によれば、通常の用途ではA接尾辞の関数で充分です。
また、mrubyのC APIはchar *を使用するため、W接尾辞(ワイド文字用)のバリアントは不要です。
既存実装との互換性確保
CRubyの標準URIライブラリとの互換性を重視し、API文書に機能比較表を掲載しました。
一部の非推奨機能は実装を見送りましたが、実用上必要な機能は網羅しています。
不足機能の補完
例として、uriparserはパス構成要素を連結リストとして提供しますが、パス全体を文字列として取得する機能がありません。
この問題に対しては、UriRecompose.cのToStringEngine実装を参考に、mrblib/mrb_uriparser.rbでpathメソッドを実装しました。
ドキュメント生成
RDocやYARDはCRuby向けに設計されており、mrubyでの利用にはカスタマイズが必要でした1。
本プロジェクトの実装の大部分がC言語であることを考慮し、Doxygenを採用しました。
RubyのAPIについてもDoxygenで記述していますが、相互参照機能により実用上の問題はありません。
ビルド設定の最適化
外部ライブラリとの依存関係管理において、当初はbuild_config.rbでバージョン検出を行う動的な方式を検討しました。
しかし、この方法ではユーザー側で追加設定が必要となり、環境差異による問題も発生しやすくなります。
そこで、uriparserのバージョンを0.9.9以上に固定する方針に変更しました(関連コミット)。
この決定により、ユーザーは必要な環境を明確に把握でき、開発側も安定した動作保証が可能になりました。
mgem-listへの登録
mruby-uriparserを公式のmgem-listに登録しました。
これにより、ユーザーは以下のように依存関係を簡単に追加できます:
conf.gem mgem: 'mruby-uriparser'
登録には、リポジトリ情報を含むYAMLファイルをmgem-listに追加するプルリクエストを送信します。
プルリクエストを作成する際はCONTRIBUTING.mdも参照してください。
バージョン0.9.9への対応
開発当初はuriparser 0.9.8を使用していましたが、0.9.9で追加された以下の機能2が重要と判断し、対応を行いました:
- URIオブジェクトの複製機能
- 個別コンポーネントのセッター関数
また、開発環境で使用しているGNU Guixでも最新バージョンを利用できるよう、パッケージ定義の更新に貢献しました。
まとめ
uriparserライブラリにmrubyのバインディングを作りました。
既存のCライブラリを活用して、有用そうなライブラリができてよかったです!
今後は手入れもしつつ、これを使って何か面白いことができればいいなと思っています。
Copyright (c) 2025 gemmaro.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
The license is located at <https://www.gnu.org/licenses/fdl-1.3.html>.
-
YARDはmrubyのAPI文書で使われています。 ↩
-
これらの機能は前述したPHP 8.5のURI拡張開発で追加されたものです。 ↩