1 of 76

OpenAPI 3.1 が書きたくて

& RuboCop を白バイに乗せてみた

2026/07/13

フサギコ fusagiko

2 of 76

self.introduction

  • 名前:� フサギコ fusagiko
  • 仕事:� 主にバックエンド方面のエンジニア� (Rails, AWS, TypeScript, etc...)
  • 趣味:� DJ / VJ
  • 好き:� THE IDOLM@STER(全シリーズ)
  • SNSなど:
    • Twitter: fusagiko
    • GitHub: takayamaki
    • Mastodon: fusagiko@imastodon.net
    • Bluesky: fusagiko.jp
    • Mixi2: fusagiko

↑

RubyMusicMixin 2024でDJしたとき

3 of 76

RubyKaigi 2026

楽しかったですね!

4 of 76

函館山登って夜景見たり

5 of 76

五稜郭行ったり

6 of 76

明治初期の和洋折衷の街並みを観光したり

7 of 76

Day3のスポンサードイベントで発表したり

8 of 76

Day3のスポンサードイベントで発表したり

9 of 76

RubyKaigiは

毎回楽しい

(行ったことない土地行けるし)

10 of 76

しかし今回

11 of 76

いつもと違って

印象に残ったことがある

12 of 76

Matzキーノート

13 of 76

去年までは

コミュニティの方向性を

示すのが主だった

14 of 76

今年は実体として

ソフトウェアを作った話が出た

https://github.com/matz/spinel

15 of 76

LLM、coding agentの進化

16 of 76

OSSにAI出力コードを

使うことの是非は

立場が分かれうるが…

17 of 76

そうは言っても

猫の手も借りたい

ところもある

18 of 76

OpenAPI

19 of 76

皆さんOpenAPIってご存じですか

20 of 76

jsonスキーマをベースに

API仕様を定義する

マシンリーダブルなスキーマ記述規格

21 of 76

RubyでOpenAPIを扱うgem

22 of 76

committee

  • rackミドルウェアやrspecのmatcherとして、�OpenAPI定義に沿っているかを検証できるgem
  • レスポンスがOpenAPI定義に沿っているか機械的に確認できるのでとても便利
  • RubyKaigi 2019で講演されてたりもした

23 of 76

しかしこのcommittee

24 of 76

OpenAPI 3.0までの対応

25 of 76

OpenAPI 3.1書きたい!

26 of 76

OpenAPI 3.1書けると何が嬉しいか

27 of 76

type: nullが書ける

28 of 76

OpenAPI3.0におけるnullableの書き方

name: nullable_attr

type: string

nullable: true

​

29 of 76

OpenAPI3.1におけるnullableの書き方

name: nullable_attr

oneOf:

- type: string

- type: null

30 of 76

これだとOpenAPI3.0のほうが

よさそうに見える?

31 of 76

と思うじゃないですか

32 of 76

object OR nullなkeyでは

nullableが使えない

33 of 76

OpenAPI3.0でobject OR nullを書く方法(1)

name: null_or_object_attr

nullable: true

oneOf:

- type: object

properties: (略)

34 of 76

OpenAPI3.0でobject OR nullを書く方法(1)

name: null_or_object_attr

nullable: true

oneOf:

- type: object

properties: (略)

1種しかないのに

nullableのためだけに

挟まる謎のoneOf

35 of 76

OpenAPI3.0でobject OR nullを書く方法(2)

name: null_or_object_attr

oneOf:

- type: string

nullable: true

enum:

- null

- type: object

properties: (略)

36 of 76

OpenAPI3.0でobject OR nullを書く方法(2)

name: null_or_object_attr

oneOf:

- type: string

nullable: true

enum:

- null

- type: object

properties: (略)

nullを表現するための

謎のworkaround

37 of 76

OpenAPI3.1でのobject OR nullの書き方

name: null_or_object_attr

oneOf:

- type: null

- type: object

properties: (略)

38 of 76

OpenAPI3.1でのobject OR nullの書き方

name: null_or_object_attr

oneOf:

- type: null

- type: object

properties: (略)

書き方が1つに収束

迷わない!

39 of 76

しかしcommitteeは

OpenAPI 3.0まで

40 of 76

issueも開きっぱなし (上: committee, 下: openapi_parser)

41 of 76

issueも開きっぱなし (上: committee, 下: openapi_parser)

42 of 76

正直メンテが活発ではない

待ってても期待できない

43 of 76

でもやっぱり、

OpenAPI 3.1書きたい!!!

44 of 76

というわけで

45 of 76

名乗りを上げて、大方針の同意をもらって

46 of 76

順次、ルールをcontribute中

47 of 76

あと12個くらいPR要るけど

地道にやっていきます

48 of 76

もう一つ

49 of 76

こっちは個人的、技術的興味として

50 of 76

RuboCop

51 of 76

RuboCopは

皆さんご存じですよね

52 of 76

きっと皆さん使ってらっしゃる

偉大なるlinter

53 of 76

RuboCopのルールって、

コールバックベースで書かれている

54 of 76

on_block: ブロックが出るたび呼ばれる

on_send: メソッド呼び出しのたび呼ばれる

55 of 76

それらコールバックの中で

条件に該当したらadd_offense

56 of 76

つまり1ファイルにつき何回も

rubyメソッド呼び出しがされる

対象ファイル数 x 該当箇所数 x ルール数

57 of 76

しかしRuboCopのルールって

長期間変わっていないものもある

58 of 76

Rubyのparserは最近prismが主となり

prismはrustバインディングもある

rubydexとかが使ってる

59 of 76

しかもRuboCopも最近

prism ASTベースに移行した

(2025年3月 RuboCop-ast v1.43.0)

60 of 76

じゃあprismのAST直接横取りして

rustで解析させたら

爆速になるのでは?

61 of 76

作ってみました

62 of 76

63 of 76

shirobai

  • RuboCopに追加するだけで速くなる状態を目指す
  • 動作はRuboCop完全互換を目指す
  • RuboCopに取って代わろうとしない
    • あくまで主人はRuboCop

64 of 76

shirobaiのcopのruby側

65 of 76

shirobaiのcopのruby側

​

  • on_new_investigationという�1ファイル1回発火するハンドラ

66 of 76

shirobaiのcopのruby側

​

  • on_new_investigationという�1ファイル1回発火するハンドラ
  • そのファイルに対して有効な�rust製cop全てが1回のAST走査を�共有して全てのoffenseを計算

67 of 76

shirobaiのcopのruby側

​

  • on_new_investigationという�1ファイル1回発火するハンドラ
  • そのファイルに対して有効な�rust製cop全てが1回のAST走査を�共有して全てのoffenseを計算
  • 各ルールは呼び出されたときに�計算済みoffenseをaddするだけ

68 of 76

shirobaiのcopのruby側

​

  • on_new_investigationという�1ファイル1回発火するハンドラ
  • そのファイルに対して有効な�rust製cop全てが1回のAST走査を�共有して全てのoffenseを計算
  • 各ルールは呼び出されたときに�計算済みoffenseをaddするだけ
  • RuboCop:disableなどはRuboCop�本体がやってくれる!

69 of 76

shirobaiのcopのrust側

​

rust側

なんもわからん

70 of 76

与えたのは制約と定量指標だけ

(RuboCopと完全互換、実行時間短縮)

71 of 76

遅いルールのプロファイリング

チューニング、AST走査の1pass化まで

僕自身は指示をし続けただけ

72 of 76

しかしてその成果は…?

73 of 76

25~40%程度の短縮!

74 of 76

25~40%程度の短縮!

コード規模によっては

遅くなるかも

75 of 76

既知の制約

  • TargetRubyVersionには未対応
    • prismのrustバインディングがバージョン指定できないため
        • マージ済みだが未リリース
  • RuboCopとRuboCop pluginのバージョン組み合わせは完全固定
  • rustコンパイラが必要かも
    • prebuiltバイナリも提供しようとしてはいる
  • 全てのルールを移植したわけではない
    • rubyで十分に速く、rustにするとむしろ遅くなる場合も
    • Ruby-Rust分界点でのオーバーヘッド

76 of 76

まとめ

  • OpenAPI3.1書きた過ぎてopenapi_parser gemにcontribute
  • RuboCopがどれくらい速くなるのか気になりすぎて�ドロップイン高速化gem shirobaiを作った
  • coding agentを使ってのOSS貢献が悪いわけではない
  • ほかの人に迷惑をかけない
    • ちゃんと段取りするか
    • 自分だけの個人プロジェクトにするか
  • coding agent時代になっても、むしろなったからこそ、�自分が何を作りたいか、という意志が重要
  • やっていきましょう