---
title: "ngx_mruby v3.0.0"
language: "ja"
documentation_version: "3.x"
channel: "development"
release_context: null
source_revision: "10297d1e28653321d6996609fc53718d3b7c8278"
working_tree_clean: true
source_path: "docs/releases/v3.0.0.ja.md"
source_sha256: "3d7782c7ec8340ccafe3df7bd116d057d69c748708f3832b65db04c420bfee28"
source_at_revision: true
source_url: "https://github.com/matsumotory/ngx_mruby/blob/10297d1e28653321d6996609fc53718d3b7c8278/docs/releases/v3.0.0.ja.md"
html_url: "https://ngx.mruby.org/ja/releases/v3.0.0/"
markdown_url: "https://ngx.mruby.org/markdown/ja/releases/v3.0.0.md"
last_updated: "2026-10-30"
---

# ngx_mruby v3.0.0

## アップグレードの前に読む挙動の変更

### 同梱のmrubyが3.3.0から4.0.0になる(#561)

- 変更前：ngx_mruby 2.xはmruby 3.3.0を同梱し、mruby 3.3.0の`full-core.gembox`が選ぶコアgemをビルドします。その中にmruby-printも入ります。
- 変更後：このリリースはmruby 4.0.0を同梱します。これはmrubyのタグ`4.0.0`で、コミットは`831da26b9021`、日付は2026-04-20です。既定の`build_config.rb`は、`NGX_MRUBY_CORE_GEMS`が名前で挙げるコアgemを取り込みます。この一覧は、mruby 3.3.0の`full-core.gembox`が選んでいた集合からmruby-printを除き、hal-posix-io、hal-posix-dir、hal-posix-socketを加えたものです。mruby-printは、mruby 3.4で削除されました。`Kernel#print`、`#puts`、`#p`は、mruby-ioが定義します。hal-posix-io、hal-posix-dir、hal-posix-socketは、4.0.0のmruby-io、mruby-dir、mruby-socketが使うPOSIXのバックエンドです。この3つは、クラスもメソッドも追加しません。一覧は、4.0.0の`full-core.gembox`が取り込むmruby-taskとそのバックエンドのhal-posix-task、mruby-encoding、`Time#strftime`を定義するmruby-strftime、`Benchmark`を定義するmruby-benchmarkを含みません。一方、4.0.0の`full-core.gembox`が含まないmruby-sleepは含みます。nginxが設定を読むときに`info`のレベルで出す行は、`(mruby/4.0.0) mechanism enabled`で終わります。以下の項目は、スクリプト、ログの監視、C拡張、ビルドから見える違いのうち、ngx_mrubyのために見つけて測ったものを挙げます。mruby 3.3.0から4.0.0までの変更をすべて挙げたものではありません。mrubyは、利用者から見える変更を[`doc/mruby3.4.md`](https://github.com/mruby/mruby/blob/4.0.0/doc/mruby3.4.md)と[`doc/mruby4.0.md`](https://github.com/mruby/mruby/blob/4.0.0/doc/mruby4.0.md)に挙げています。
- 影響の範囲：このモジュールのすべてのビルドと、モジュールが実行するすべてのRubyスクリプトです。
- 必要な対応：同梱のmrubyと一緒にモジュールをビルドし直してください。そのうえで以下の項目を確かめ、項目が扱わない変更をmrubyの2つの一覧で確かめてください。手順は[Migrating from ngx_mruby 2.x to 3.0.0](/ja/releases/migration/)にあります。同梱のmrubyを変える理由は次のとおりです。v3の計画は、安定性、性能、依存するソフトウェアの更新を、新しい機能より先にします。また、mrubyは3.xの保守のリリースを出していません。根拠は`docs/proposals/v3-plan.md`の3.3節と6節です。計画の7節の決定1は、v3の目標をmruby 4.1.0としています。オーナーは2026-10-04に、その前の段階として4.0.0を承認しました。4.1.0のタグが付いたら、`next`は4.1.0に移ります。

### 自前の`build_config.rb`は、mruby 4.0.0のコアgemの変更に合わせる必要がある(#561)

- 変更前：自前の`build_config.rb`は、mruby-printを名前で挙げることも、`full-core.gembox`を取り込んでmruby 3.3.0のコアgemを得ることもできました。そのコアgemにはmruby-sleepも入ります。
- 変更後：mruby 4.0.0にはmruby-printがありません。`build_config.rb`の`ngx_mruby_core_gems`は、同梱のmrubyに無い名前があるとビルドを止めます。4.0.0の`full-core.gembox`は、mruby-taskとmruby-encodingを取り込み、mruby-sleepを含みません。mruby-taskは`Kernel#sleep`を定義し直します。また、mrb_stateを開くすべてのプロセスでSIGALRMのインターバルタイマー(`setitimer`)を動かし、mrb_stateの数を最大8個(`MRB_TASK_MAX_VMS`)に制限します。mruby-encodingについては`String#valid_encoding?`の項目を参照してください。4.0.0のmruby-io、mruby-dir、mruby-socketはHALのバックエンドを必要とします。一覧にバックエンドが無いと、これらはhal-posix-io、hal-posix-dir、hal-posix-socketを自分で読み込みます。そのとき、「No HAL specified ... (explicit selection recommended)」という警告を出します。コンテナの`/s`に作業ディレクトリをマウントした4.0.0のビルドは、Windowsのバックエンドを自分で選び、`windows.h: No such file or directory`で止まりました。`mruby/lib/mruby/gem.rb`の`for_windows?`が、ルートにある1文字のディレクトリをWindowsのドライブとみなすためです。
- 影響の範囲：このリリースのものとは別の`build_config.rb`を使い、mruby-printを名前で挙げるか、`full-core.gembox`を取り込むビルドです。
- 必要な対応：このリリースの`build_config.rb`から始めるか、`NGX_MRUBY_CORE_GEMS`と同じようにコアgemを名前で選んでください。mruby-printを除き、hal-posix-io、hal-posix-dir、hal-posix-socketを加えてください。mruby-taskとmruby-encodingを使うかどうかは、[コアのgem](/ja/guides/install/#コアのgem)の説明に従って決めてください。

### サードパーティのmrbgemを`build_config.rb.lock`が記録するコミットでビルドする(#558)

- 変更前：`build_config.rb`は、サードパーティのmrbgemをコミットを指定せずに挙げます。`.gitignore`は、mrubyのrakeが書く`build_config.rb.lock`を挙げているので、ロックはリポジトリに入りません。新しいチェックアウトやソースのアーカイブからのビルドは、各gemのブランチの先頭を`git clone --depth 1`でクローンします。そのため、同じngx_mrubyのコミットを別の日にビルドすると、別のgemのコードが入ることがあります。
- 変更後：`build_config.rb.lock`はリポジトリに入っています。ロックは、既定のビルドに入るサードパーティのgemと、それらが依存するgemのコミットを記録します。依存するgemの例は、同梱のrack-based-apiが必要とするksss/mruby-stringioです。新しいチェックアウトやソースのアーカイブからのビルドは、これらのgemを履歴ごとクローンし、記録されたコミットをチェックアウトします。そのため、ngx_mrubyのあるコミットをビルドすると、いつも同じgemのコードが入ります。自前の`build_config.rb`が加えるgemは、ブランチの先頭でクローンされます。rakeはそのgemの項目を手元のツリーにあるロックに加えるので、`git status`はロックを変更ありと表示します。rakeは、既にあるクローンにはフェッチしません。そのため、ロックが変わった後に`mruby/build`を残したツリーでビルドすると、ビルドが`fatal: reference is not a tree`で止まることがあります。止まるのは、新しいコミットを持たないクローンがあるときです。matsumotory/mruby-vedisが自分でクローンするsymisc/vedisは固定されません。
- 変更の理由：
  - 背景：v3の計画は、すべてのサードパーティのgemをコミットで固定し、`build_config.rb.lock`をコミットします。同じタグから同じバイナリをビルドできるようにするためです。根拠は`docs/proposals/v3-plan.md`の4節のPillar Aです。
  - 前の挙動を残せなかった理由：固定が無いと、ビルドに入るgemのコードはビルドした日で決まります。gemのリポジトリのどれかが変わると、その変更は、リリースしたタグを後でビルドするたびに入ります。CIの実行にも毎回入ります。どちらも、ngx_mrubyに変更が無くても起きます。
  - ドキュメントが示していた挙動：2.xのドキュメントは、サードパーティのgemのコミットについて何も書いていません。[docs/install/README.md](https://github.com/matsumotory/ngx_mruby/blob/v2.7.0/docs/install/README.md#2-configuring-mrbgems)は、既定のmrbgemを名前だけで挙げています。
- 影響の範囲：サードパーティのgemを最新のコミットで取り込むことを前提にした、ソースからのビルドです。gemを加える自前の`build_config.rb`と、ロックが変わるときに`mruby/build`を残すツリーも当たります。
- 必要な対応：新しいチェックアウトとソースのアーカイブでは、何もしなくてかまいません。gemを別のコミットでビルドするには、[gemのコミットとbuild_config.rb.lock](/ja/guides/install/#gemのコミットとbuild_configrblock)の説明に従ってロックの項目を変えてください。pullで入る変更を含め、ロックが変わったら、次のビルドの前に`mruby/build`を削除してください。

### `Hash#inspect`と`Hash#to_s`の形式が変わる(#561)

- 変更前：`{"a"=>1}`と`{:a=>1}`です。
- 変更後：`{"a" => 1}`と`{a: 1}`です。mruby 3.4からこの形式です。これらのメソッドでHashを文字列にするものは、すべて同じように変わります。文字列の式展開(`"#{h}"`)、`sprintf("%s", h)`、`Array#inspect`がこれに当たります。
- 影響の範囲：Hashの`inspect`や`to_s`を、レスポンスのボディやヘッダに入れるスクリプトと、固定の文字列と比べるスクリプトです。ngx_mrubyのテストスイートでもこの変化が出ました。変化が出たのは`test/t/ngx_mruby.rb`の`/async_http_sub_request`です。
- 必要な対応：Hashの`inspect`や`to_s`を、レスポンスのボディやヘッダでデータの形式として使わないでください。文字列を自分で組み立てるか、`JSON.generate`を使ってください。

### `Exception#inspect`の形式が変わり、`error.log`の`mrb_run failed`の行も変わる(#561)

- 変更前：`boom (RuntimeError)`です。ngx_mrubyは、スクリプトの例外を`Exception#inspect`で文字列にして、`error.log`の`mrb_run failed`の行に書きます。この行のレベルは`error`です。ただし、nginxが設定を読む間に`mruby_stream_server_context_code`の例外が出す行のレベルは`emerg`です。その行は`mrb_run failed: ngx_mruby stream module configuration failed: error: ...`です。行の例は`mrb_run failed: return 500 HTTP status code to client: error: boom (RuntimeError)`です。
- 変更後：`#<RuntimeError: boom>`です。そのため、行は`error: #<RuntimeError: boom>`で終わります。`Exception#message`と`#to_s`は変わりません。
- 影響の範囲：古い形式に合わせたログのパーサーとアラートと、`Exception#inspect`を使うスクリプトです。ngx_mrubyのテストスイートでも`error.log`にこの変化が出ました。
- 必要な対応：古い形式に合わせたログのパーサーとアラートを直してください。

### nginxが設定を読む間のメッセージのレベルが`notice`から`info`になる(#565)

- 変更前：nginxが設定を読む間、ngx_mrubyは次のメッセージを`notice`のレベルで出します。`http {}`のブロックに対して1回出す`ngx_mruby/<version> (mruby/<version>) mechanism enabled`、Rubyのコードを持つディレクティブごとの`ngx_mruby NOTICE ...: compile info: ...`、`stream {}`の中のそうしたディレクティブごとの`ngx_mruby-stream-module NOTICE ...: compile info: ...`、`mruby_set`と`mruby_set_code`ごとの`ngx_mruby NOTICE ...: target variable=(...)`です。nginxは、設定を読む間に出すログを起動時のログに書きます。起動時のログのレベルは、`error_log`の設定にかかわらず`notice`です。そのため、nginxを起動するたびにこれらの行が書かれます。`error_log ... warn;`でも同じです。
- 変更後：同じメッセージを`info`のレベルで出します。本文の`NOTICE`は`INFO`になります。行は`ngx_mruby INFO ...`と`ngx_mruby-stream-module INFO ...`です。nginxを起動しても、これらの行は書かれません。`nginx -t`は、これらの行を起動時のログだけに`[info]`で書きます。nginxが起動時のログの行を端末にも出力するのは、`warn`以上のレベルの行だけです。そのため、`nginx -t`の出力にこれらの行は出ません。動いている設定で`error_log`のレベルが`info`か`debug`なら、reloadはその`error_log`にこれらの行を書きます。開けないスクリプトのファイルのような、設定を読む間のエラーは、これまでどおり`emerg`で出ます。
- 変更の理由：
  - 不具合：nginxを起動するたびにこれらの行が書かれ、`error_log`のレベルを`notice`より上にしても止まりませんでした(#320)。
  - 前の挙動を残せなかった理由：nginxは、設定を読む間のログを起動時のログに`notice`のレベルで書き、設定した`error_log`にはその後で切り替えます。そのため、`error_log`をどう設定しても、`notice`のメッセージは除けません。起動時にこれらの行を出さないためには、`notice`より下のレベルにするしかありません。
  - ドキュメントが示していた挙動：2.xのドキュメントは、これらのメッセージについて何も書いていません。
- 影響の範囲：nginxの起動時にこれらの行を探すログの監視とスクリプトです。例えば、モジュールが読み込まれたことを確かめるためにこれらの行を探すものです。
- 必要な対応：これらの行を見るには、`nginx -t -e stderr`を実行するか、`nginx -t`の後で起動時のログを読むか、`error_log`を`info`にしてreloadしてください。`nginx -t -e stderr`は、起動時のログを端末に書きます。起動時のログは、`-e`で与えたファイルです。`-e`が無いときは、nginxのビルドで決めたエラーログのパスです。既定のパスは、prefixの下の`logs/error.log`です。説明は[Messages logged while nginx reads the configuration](/ja/reference/directives/#messages-logged-while-nginx-reads-the-configuration)にあります。

### `NoMethodError`のメッセージがレシーバのクラスを示す(#561)

- 変更前：`undefined method 'foo'`です。
- 変更後：`undefined method 'foo' for NilClass`です。
- 影響の範囲：`NoMethodError`のメッセージにマッチさせるスクリプトとログの監視です。
- 必要な対応：メッセージでなく、例外のクラスで判定してください。

### `private`と`protected`の制限が効く(#561)

- 変更前：制限は効きません。`private`や`protected`の後で定義したメソッド、`initialize`、トップレベルで`def`で定義したメソッド、`Kernel`のメソッドを、明示したレシーバで呼べます。`Kernel`自身もレシーバにできます。例えば`Kernel.Integer("12")`は`12`です。`Module#instance_methods`とオブジェクトの`#methods`は、privateメソッドも挙げます。メソッド`pub`とprivateメソッド`priv`を持つクラスでは、`instance_methods(false)`は`[:priv, :pub]`です。
- 変更後：制限が効きます。mruby 3.4からです。これらのメソッドを`self`以外の明示したレシーバで呼ぶと、`NoMethodError`が出ます。メッセージは`private method '<name>' called for <class>`です。対象には、`raise`、`sprintf`、`puts`、`Integer`、`rand`のような`Kernel`のメソッドと、mruby 4.0.0がprivateとして定義する`initialize_copy`、`respond_to_missing?`、`method_missing`も入ります。`"a".initialize_copy("b")`も例外を出します。`Kernel`自身をレシーバにして今も動くのは、`Kernel.format`、`Kernel.sprintf`、`Kernel.raise`、`Kernel.sleep`、`Kernel.usleep`だけです。`Integer`、`Float`、`String`、`Array`、`Hash`、`eval`、`rand`、`puts`を含む`Kernel`の他のprivateメソッドは、`NoMethodError`を出します。`Kernel.Integer("12")`は`private method 'Integer' called for Module`を出します。`respond_to?`は、どちらのバージョンでもprivateメソッドに`true`を返します。例えば`Kernel.respond_to?(:Integer)`は`true`です。そのため、`respond_to?`では、そうした呼び出しが動くかどうかを判定できません。`Module#instance_methods`とオブジェクトの`#methods`は、privateメソッドを挙げません。上のクラスの`instance_methods(false)`は`[:pub]`です。privateメソッドは、`Module#private_instance_methods`と`#private_methods`が挙げます。ただし、ハンドラのコードのトップレベルで`def`で定義したメソッドはpublicのままで、明示したレシーバで呼べます。理由は[#502の提案](https://github.com/matsumotory/ngx_mruby/blob/next/docs/proposals/archive/handler-code-frame.md#14-what-handler-code-shares-today)の1.4節にあります。
- 影響の範囲：そうしたメソッドを明示したレシーバで呼ぶスクリプトです。`Kernel.Integer(x)`をはじめとする`Kernel`をレシーバにした呼び出しも入ります。`instance_methods`や`methods`の結果からprivateメソッドを探すスクリプトも当たります。
- 必要な対応：レシーバなしで呼ぶか、`send`で呼んでください。例えば、`Kernel.Integer(x)`の代わりに`Integer(x)`と書きます。`Kernel.send(:Integer, x)`はどちらのバージョンでも動きます。privateメソッドを挙げるには、`private_instance_methods`か`private_methods`を使ってください。

### `Module#remove_const`、`#private`、`#public`、`#protected`、`#module_function`とフックがprivateになる(#561)

- 変更前：publicです。`Foo.remove_const(:X)`、`M.included(Foo)`、`M.prepended(Foo)`、`obj.singleton_method_added(:m)`が動きます。フックは、`Module`と`Class`の`#included`、`#extended`、`#prepended`、`#inherited`、`#method_added`と、`BasicObject#singleton_method_added`です。
- 変更後：privateです。明示したレシーバで呼ぶと、`NoMethodError: private method ... called`が出ます。`send`では動きます。mrubyは今もフックを自分で呼びます。`prepend`は`prepended`を呼び、`def obj.m`は`singleton_method_added`を呼びます。
- 影響の範囲：これらのメソッドのどれかを明示したレシーバで呼ぶスクリプトです。
- 必要な対応：クラスやモジュールの本体の中でレシーバなしで呼ぶか、`send`で呼んでください。例えば`Foo.send(:remove_const, :X)`です。

### `append_features`、`prepend_features`、`extend_object`のオーバーライドが呼ばれなくなる(#561)

- 変更前：`include`、`prepend`、`extend`はこの3つのメソッドを呼ぶので、モジュールはこれらをオーバーライドできます。
- 変更後：3つのメソッドはありません。`Module.new.respond_to?(:append_features, true)`は`false`で、他の2つも同じです。`include`、`prepend`、`extend`は、これらを呼ばずにモジュールを加えます。そのため、オーバーライドしたメソッドは呼ばれず、エラーも出ません。フックの`included`、`prepended`、`extended`は今も呼ばれます。
- 影響の範囲：3つのメソッドのどれかをオーバーライドするモジュールです。
- 必要な対応：そのコードを`included`、`prepended`、`extended`に移してください。

### `allbits?`、`anybits?`、`nobits?`が`Integer`だけのメソッドになる(#561)

- 変更前：`Numeric`のメソッドなので、Floatでも動きます。`1.5.allbits?(1)`は`true`です。
- 変更後：`Integer`だけのメソッドです。Floatに呼ぶと`NoMethodError`が出ます。Integerではこれまでどおり動きます。例えば`6.allbits?(2)`は`true`です。
- 影響の範囲：Floatにこれらを呼ぶスクリプトです。
- 必要な対応：Floatを先に`to_i`で変換してください。

### `FileTest`がモジュールになる(#561)

- 変更前：`FileTest`はクラスです。
- 変更後：`FileTest`はモジュールです。`FileTest.exist?`などのメソッドは、これまでどおり呼べます。
- 影響の範囲：メソッドを呼ぶ以外の形で`FileTest`をクラスとして使うスクリプトです。
- 必要な対応：メソッドを呼ぶだけなら、何もしなくてかまいません。

### メソッドの本体で定数に代入すると`SyntaxError`になる(#561)

- 変更前：許されます。例は`def m; X = 1; end`です。
- 変更後：スクリプトをコンパイルするときに`SyntaxError: dynamic constant assignment`が出ます。
- 影響の範囲：メソッドの本体で定数に代入するスクリプトです。ngx_mrubyのRack風の`Kernel#run`は、`Kernel.const_set`で`Server`を設定します。
- 必要な対応：`Object.const_set(:X, 1)`か`Kernel.const_set`を使ってください。

### Floatの値にビット演算が無くなる(#561)

- 変更前：`~`、`&`、`|`、`^`は整数部に対して動きます。`1.5 & 1`は`1`、`~1.5`は`-2`です。シフトの回数をnとします。nが1以上のとき、`<<`はFloatに2のn乗を掛けて切り捨てます。`1.5 << 1`は`3`、`-1.5 << 1`は`-3`、`1.5 << 40`は`1649267441664`です。結果がIntegerの範囲を超えると、Floatを返します。例えば`1.5 << 70`は`1.77088743107612e+21`です。nが1から32のとき、`>>`は正のFloatを2のn乗で割って切り捨てます。`8.0 >> 1`は`4`、`1.5 >> 1`は`0`です。nが1から32のとき、`>>`は負のFloatには`-1`を返します。例えば`-8.0 >> 1`は`-1`です。nが32を超えると、`>>`は正のFloatに`0`を、負のFloatに`-1`を返します。`1e20 >> 32`は`23283064365`、`1e20 >> 33`は`0`です。nが0のときは、Floatをそのまま返します。例えば`-1.5 >> 0`は`-1.5`です。nが負なら、逆の向きにシフトします。例えば`1.5 >> -1`は`3`です。
- 変更後：`~`、`&`、`|`、`^`、`>>`、`<<`は、Floatに対して`NoMethodError`を出します。mruby 3.4が6つすべてを削除しました。
- 影響の範囲：6つの演算子のどれかをFloatに使うスクリプトです。
- 必要な対応：`~`、`&`、`|`、`^`では、先に`to_i`で変換してください。`<<`と`>>`では、先に`to_i`で変換すると別の数になることがあります。`1.5.to_i << 1`は`2`、`-8.0.to_i >> 1`は`-4`です。前の数が必要なら、シフトの回数をnとして次のようにしてください。`<<`でnが1以上なら、Floatに2のn乗を掛けて`to_i`を呼びます。`>>`でnが1から32なら、正のFloatを2のn乗で割って`to_i`を呼び、負のFloatには`-1`を使います。`>>`でnが32を超えるなら、正のFloatには`0`を、負のFloatには`-1`を使います。この場合に割り算をすると、別の数になります。例えば`(1e20 / 2**40).to_i`は`90949470`ですが、`1e20 >> 40`は`0`でした。nが0なら、Floatをそのまま使います。

### `String#valid_encoding?`が既定のビルドに無くなる(#561)

- 変更前：mruby-string-extが定義します。ngx_mruby 2.xは、既定の`build_config.rb`ではmrubyを`MRB_UTF8_STRING`なしでビルドします。そのため、このメソッドはすべての文字列に`true`を返し、`"\xfe"`にも`true`を返します。`build_config.rb`で`MRB_UTF8_STRING`を定義したビルドでは、UTF-8として正しくない文字列に`false`を返します。
- 変更後：mruby 3.4からは、このメソッドを定義するのはmruby-encodingだけです。既定のビルドはそのgemを含まないので、呼ぶと`NoMethodError`が出ます。メッセージは`undefined method 'valid_encoding?' for String`です。このメソッドを呼ぶハンドラは、500を返します。
- 影響の範囲：`String#valid_encoding?`を呼ぶスクリプトです。
- 必要な対応：2.xの既定の`build_config.rb`で使っていたスクリプトでは、呼び出しを削除してください。そこでは、このメソッドが`false`を返したことはありません。あるいは、mruby-encodingを加えてビルドし、[コアのgem](/ja/guides/install/#コアのgem)の説明に従ってスクリプトを確かめてください。`MRB_UTF8_STRING`を定義していた2.xのビルドで判定を続けるには、mruby-encodingが必要です。既定のビルドがmruby-encodingを含まない理由は次のとおりです。このgemはビルド全体に`MRB_UTF8_STRING`を定義するので、`String#size`、`#[]`、`#index`が、バイトでなく文字を数えます。そのため、`String#size`から`Content-Length`を計算するスクリプトは、別の数を得ます。オーナーは2026-10-04に、このgemを既定のビルドから外し、必要なときに加える形にすると決めました。

### シードを与えた`Random`が別の数を返す(#561)

- 変更前：`Random.new(seed)`と`srand(seed)`は、1つのシードに対して1つの数列を返します。アルゴリズムはxoshiroです。
- 変更後：同じシードに対して別の数列を返します。mruby 4.0は、xoshiroの代わりにPCGを使います。
- 影響の範囲：シードを与えた乱数生成器が返す数に依存するスクリプトです。
- 必要な対応：シードを与えた乱数生成器が返す数に、バージョンをまたいで依存しないでください。

### `Set#inspect`と`Set#to_s`の形式が変わり、`Set#flatten_merge`が無くなる(#561)

- 変更前：`#<Set: {1, 2}>`です。`Set#flatten_merge`はpublicメソッドです。例えば`Set.new([1]).flatten_merge(Set.new([2, Set.new([3])]))`は、1、2、3を要素とするSetです。
- 変更後：`Set[1, 2]`です。これらのメソッドでSetを文字列にするものは、すべて同じように変わります。文字列の式展開(`"#{set}"`)、`sprintf("%s", set)`、`Array#inspect`がこれに当たります。mruby 4.0.0は`Set#flatten_merge`を削除したので、呼ぶと`NoMethodError`が出ます。mrubyの利用者から見える変更の一覧は、この削除を挙げていません。
- 影響の範囲：Setの`inspect`や`to_s`をデータの形式として使うスクリプト、それを固定の文字列と比べるスクリプト、`Set#flatten_merge`を呼ぶスクリプトです。
- 必要な対応：`Hash#inspect`と同じく、文字列を自分で組み立ててください。`set.to_a.join(",")`は、どちらのバージョンでも同じ文字列を返します。`s.flatten_merge(t)`の代わりに`s.merge(Set.new(t).flatten)`を呼んでください。どちらのバージョンでも、この呼び出しは、2.xの`s.flatten_merge(t)`と同じSetを返します。`t`がSetでもArrayでも同じです。

### `Hash#default_proc=`がProcでないオブジェクトに`TypeError`を出す(#561)

- 変更前：受け付けます。
- 変更後：`TypeError`が出ます。
- 影響の範囲：`Hash#default_proc=`に、Procでないオブジェクトを渡すスクリプトです。
- 必要な対応：Procか`nil`を渡してください。

### キーワード引数を受けるブロックに、キーワード引数を付けて`yield`すると動く(#561)

- 変更前：`ArgumentError: missing keyword`が出ます。
- 変更後：ブロックがキーワード引数を受け取ります。
- 影響の範囲：キーワード引数を受けるブロックに、キーワード引数を付けてyieldするスクリプトです。例えば、この`ArgumentError`をrescueしていたスクリプトです。
- 必要な対応：何もしなくてかまいません。mrubyの不具合の修正です。

### ハンドラのコードで、ブロックや`for`の本体の中の`return`がコードを終える(#561)

- 変更前：ハンドラのコードのトップレベルで、`[0].each do ... end`や`3.times { ... }`のようなブロックの中や、`for`の本体の中に`return`を書くと、`LocalJumpError`が出ます。ハンドラは500を返します。`error.log`には`mrb_run failed: return 500 HTTP status code to client: error: unexpected return (LocalJumpError)`が出ます。`return`の前に出力を書いていたコンテンツハンドラも500を返します。その出力は送りません。2.7.0は、この出力を200の応答で送りました。例外はログに出すだけでした。2.7.1は、`Nginx.rputs`の後に出たすべての例外について、この挙動を変えました。詳しくは[2.7.1のリリースノートのエントリ3](/ja/releases/v2.7.1/#3-nginxrputsの後で例外が発生するとレスポンスは500になります)にあります。`mruby_set_code`の変数には空の値が入ります。ブロックの外でコードのトップレベルに書いた`return`は、コードを終えます。
- 変更後：この`return`は、トップレベルの`return`と同じくコードを終えます。後のコードは動きません。応答は、それまでにコードが決めたものになります。つまり、`Nginx.return`で決めたステータスと、`Nginx.rputs`で書いた出力です。`mruby_set_code`では、ブロックの中の`return`の値が変数に入ります。`error.log`には、この`return`についての行は出ません。
- 変更の理由：
  - 不具合：[#502](https://github.com/matsumotory/ngx_mruby/issues/502)が報告した不具合です。ハンドラを途中で終える`return`をブロックや`for`の本体の中に書くと、`LocalJumpError`が出ました。ハンドラは、コードが決めた応答の代わりに500を返しました。
  - 前の挙動を残せなかった理由：このエラーはmruby 3.3.0から来ていました。ngx_mrubyは、ハンドラのコードをファイバーの最初のフレームで動かします。mruby 3.3.0は、こうした`return`が抜けるフレームとしてこのフレームを受け付けません。mruby 4.0.0は受け付けます。詳しくは[ハンドラのコードのフレームについての提案の1.3節](https://github.com/matsumotory/ngx_mruby/blob/next/docs/proposals/archive/handler-code-frame.md#13-why-502-fails-on-master-and-not-on-next)にあります。エラーを残すには、同梱のmruby 4.0.0を3.3.0の規則に戻す必要がありました。#502は、このエラーを不具合として報告しています。
  - ドキュメントが示していた挙動：2.xの[docs/class_and_method/README.md](https://github.com/matsumotory/ngx_mruby/blob/v2.7.0/docs/class_and_method/README.md#nginxreturnnginx_status_code)は、ngx_mrubyがハンドラのコードで`return`文を使えることと、`return`がハンドラから戻ることを書いています。ブロックの中を例外とする記述はありません。
- 影響の範囲：トップレベルのブロックや`for`の本体の中に`return`を持つハンドラのコードです。メソッドやlambdaの中の`return`は当たりません。500や`LocalJumpError`の行に頼っていたログのアラートとスクリプトも当たります。
- 必要な対応：何もしなくてかまいません。2.xでの回避の書き方は、どちらのバージョンでも動きます。回避の書き方は、コードのトップレベルに`return`を書くことと、コードをメソッドやlambdaの中に置くことです。
- このリリースで変わらない挙動：ハンドラのコードを動かすフレームは変わりません。`self`は`main`です。ローカル変数は、コードを1回実行する間だけ使えます。定数、グローバル変数、`main`のインスタンス変数、`def`で定義したメソッドは、ワーカーの中に残ります。詳しくは[提案の1.4節](https://github.com/matsumotory/ngx_mruby/blob/next/docs/proposals/archive/handler-code-frame.md#14-what-handler-code-shares-today)にあります。

### 出力なしで終わるcontentハンドラが、500でなく、空のボディの200で応答する(#574)

- 変更前：2.7.1と2.7.2では、メインリクエストのcontentハンドラが出力なしで終わると、次の場合に500が返りました。ステータスを設定していない場合、`Nginx::HTTP_OK`を設定した場合、201と204以外の300未満のステータスを設定した場合です。出力なしとは、何も書かない場合、`Nginx.rputs`で`""`か`nil`だけを書く場合、レスポンスヘッダだけを設定する場合です。`Nginx::HTTP_OK`は、`Nginx.return`、`Nginx.send_header`、`Nginx.status_code=`のどれで設定しても同じです。300未満のステータスの例は`Nginx::HTTP_ACCEPTED`です。`Nginx::Async::HTTP.sub_request`が再開した後にこのように終わった場合も、同じでした。500のボディはnginxのエラーページか、500に設定した`error_page`で、ヘッダには`Connection: close`が付きました。詳しくは[2.7.1のリリースノートの項目13](/ja/releases/v2.7.1/#13-contentハンドラが出力なしで終わるとレスポンスは500になります)にあります。error.logには`error`レベルの行が出ました。その行は、`status code is 200, but response body is empty. return NGX_HTTP_INTERNAL_SERVER_ERROR`、`status code is not set, and response body is empty. return NGX_HTTP_INTERNAL_SERVER_ERROR`、`status code is <N>, but response body is empty. return NGX_HTTP_INTERNAL_SERVER_ERROR`のどれかです。2.7.0までは、出力なしの`Nginx::HTTP_OK`に同じ500が返りました。ほかの場合には、レスポンスがまったく返りませんでした。nginxは、HTTP/1.0の接続を1バイトも送らずに閉じ、keep-aliveの接続を`keepalive_timeout`までレスポンスなしで開いたままにしました。
- 変更後：そのようなハンドラは、nginx自身の`return 200;`と同じに応答します。ステータスはハンドラが設定したもので、設定していなければ200です。ヘッダには`Content-Length: 0`が付き、ボディは空です。`Content-Type`は付きません。ngx_mrubyの出力のある応答にも付きません。nginxの`return 200;`は、`default_type`の`Content-Type`を付けます。HEADリクエストにも同じヘッダが返ります。locationのヘッダフィルタとボディフィルタは、この空のレスポンスにも動きます。対象は`mruby_output_header_filter`、`mruby_output_body_filter`と、それぞれの`_code`の形です。ngx_mrubyは、空の応答を送る前に、読まれていないリクエストボディを破棄します。出力のある応答を送る前にも、2.7.1から同じように破棄します。詳しくは[2.7.1のリリースノートの項目12](/ja/releases/v2.7.1/#12-応答の前に読まれていないリクエストボディを破棄します)にあります。そのため、開いたままの接続の次のリクエストは、クライアントがボディの後に送ったリクエストになります。nginxは、keep-aliveの接続を次のリクエストのために開いておきます。例外は、mrubyの出力のボディフィルタがあるlocationへのHEADリクエストです。この場合、nginxはヘッダを送ってから接続を閉じます。出力のあるハンドラでも、2.7.1とこのリリースで同じです。error.logには、上の行は出ません。
- 変更の理由：
  - 不具合：[#200](https://github.com/matsumotory/ngx_mruby/issues/200)が報告した不具合です。`Nginx.return Nginx::HTTP_OK`を呼んでボディなしで終わるcontentハンドラには、500が返りました。nginx自身の`return 200;`は、空のボディの200で応答します。HTTPは、この応答を認めています。[RFC 9110の15.3.1節](https://www.rfc-editor.org/rfc/rfc9110#section-15.3.1)によると、200のレスポンスはメッセージのコンテントを含むと想定されますが、メッセージのフレーミングが長さ0を明示する場合は除きます。`Content-Length: 0`は、長さ0を明示します。2.7.1は、ステータスを設定していない場合と、nginxが自分では応答しない300未満のほかのステータスにも、同じ500を返すようにしました。それまで、これらのリクエストにはレスポンスがまったく返らなかったためです([#566](https://github.com/matsumotory/ngx_mruby/pull/566))。
  - 前の挙動を残せなかった理由：500のままでは、contentハンドラは空のボディの200で応答できません。ハンドラが選べる空の応答は204だけです。204は、クライアントとキャッシュにとって別のステータスです。v3の計画は、空の200をv3の挙動の変更として受け入れています。計画は[docs/proposals/v3-plan.md](https://github.com/matsumotory/ngx_mruby/blob/next/docs/proposals/v3-plan.md)の7節の項目8です。2.x系列は互換性を優先するので、500を残します。
  - ドキュメントが示していた挙動：2.7.1のドキュメントは、前の挙動を説明していました。出力なしで終わるcontentハンドラは500で応答し、空のボディには`Nginx::HTTP_NO_CONTENT`を使う、という説明です。この説明は[2.7.1のNginx.return](https://github.com/matsumotory/ngx_mruby/blob/v2.7.1/docs/class_and_method/README.md#nginxreturnnginx_status_code)にあります。2.7.1より前のドキュメントは、`Nginx.return`について「Returns nginx status code to send back HTTP status to the client」と書いているだけでした。この記述は[2.7.0のNginx.return](https://github.com/matsumotory/ngx_mruby/blob/v2.7.0/docs/class_and_method/README.md#nginxreturnnginx_status_code)にあります。
- 影響の範囲：出力なしで終わることのある`mruby_content_handler`と`mruby_content_handler_code`のハンドラと、上の行を見るログの監視です。ハンドラの例は、条件が成り立つときだけ書くハンドラ、空か`nil`になりうる値を`Nginx.rputs`に渡すハンドラ、レスポンスヘッダだけを設定するハンドラ、`Nginx.return Nginx::HTTP_OK`を呼んでボディなしで終わるハンドラです。変わらない挙動：出力なしの200未満のステータスは、2.7.1と2.7.2のときと同じく500になり、`status code is <N>, but response body is empty`の行が出ます。201、204、300以上のステータスには、nginx自身が応答します。出力のあるハンドラと`Nginx.redirect`も変わりません。ほかのハンドラも変わりません。rewriteハンドラやaccessハンドラで、出力なしで`Nginx.return Nginx::HTTP_OK`を呼ぶと、これまでどおり500が返り、`status code is 200, but response body is empty`の行が出ます。サブリクエストも変わりません。対象は`Nginx::Async::HTTP.sub_request`、SSIのinclude、`auth_request`です。サブリクエストのcontentハンドラが、出力なしで`Nginx::HTTP_OK`を返すと、サブリクエストのステータスはこれまでどおり500になります。何も書かず、ステータスも設定しないハンドラは、これまでどおり、レスポンスのボディもステータスも無いままサブリクエストを終えます。
- 必要な対応：ほとんどの設定では、何もしなくてかまいません。空のボディで応答すべきハンドラは、`Nginx::HTTP_OK`を返せるようになりました。返すものが無いことを500で知らせていたスクリプトは、そのステータスを自分で設定してください。例は`Nginx.return Nginx::HTTP_INTERNAL_SERVER_ERROR`と`Nginx.return Nginx::HTTP_NOT_FOUND`で、nginxはこれまでどおり応答します。`response body is empty. return NGX_HTTP_INTERNAL_SERVER_ERROR`に一致させるログの監視に見える行は、次の場合だけになります。contentハンドラが200未満のステータスを返した場合と、ほかのハンドラやサブリクエストで`Nginx::HTTP_OK`を返した場合です。
- テスト：`test/conf/conf.d/54-content-empty-body.conf`と`test/t/cases/content_empty_body.rb`の、ポート18136のテストです。1つの接続で、ハンドラが読まないボディを持つ`POST`を2つ送るテストも含みます。`test/t/ngx_mruby.rb`の「Nginx.return 200 dont have body」と、`test/t/cases/request_api.rb`の「send_header 200 without a body answers 200 with an empty body」も、この挙動を試します。

### 空のボディで終わる出力のボディフィルタが、接続を閉じずにレスポンスを送る(#574)

- 変更前：出力のボディフィルタが空のボディで終わると、nginxは`alert`レベルで`zero size buf in writer`をログに出し、ステータス行を書く前に接続を閉じました。クライアントは1バイトも受け取りませんでした。対象のボディフィルタは`mruby_output_body_filter`と`mruby_output_body_filter_code`です。空のボディで終わるのは、フィルタが`Nginx::Filter#body=`か`Nginx::Filter#output`で`""`を設定した場合と、ボディの無いレスポンスでフィルタがボディを空のままにした場合です。2.7.2と2.7.1でも、それより前のリリースでも同じです。
- 変更後：レスポンスは、そのステータスと`Content-Length: 0`と空のボディで送られます。error.logには、このレスポンスについての`alert`の行は出ません。
- 変更の理由：
  - 不具合：ボディフィルタは、空のボディを、`memory`のフラグを立てた0バイトのバッファとして次へ渡していました。nginxのwriterは、このバッファを拒否します(`zero size buf in writer`)。そのため、レスポンスは送られませんでした。nginx自身の`return 200;`は、このフラグを立てない空の最後のバッファを渡します(`ngx_http_send_response`)。2.x系列にも同じ不具合があります。2.7.1の`test/t/cases/filter_connection.rb`は、これを2.xの挙動として記録しています。テストの名前は「an empty String closes the connection without a response」です。
  - 前の挙動を残せなかった理由：送られないレスポンスは、クライアントを応答の無いままにします。上の項目の空の200も、そのlocationのボディフィルタを通ります。この変更が無いと、そのようなlocationは、空の200の代わりに何も送りません。
  - ドキュメントが示していた挙動：[2.7.1のNginx::Filter#body=](https://github.com/matsumotory/ngx_mruby/blob/v2.7.1/docs/class_and_method/README.md#nginxfilterbodystring)は、フィルタが設定したボディそのままでレスポンスを送り、`Content-Length`をその長さにすると書いています。空の文字列を例外とする記述はありません。
- 影響の範囲：空のボディで終わることのある出力のボディフィルタを持つlocationです。上の項目の、出力なしで終わるcontentハンドラのlocationも当たります。`zero size buf in writer`の行を見るログの監視も当たります。これらのレスポンスでは、この行が出なくなるからです。
- 必要な対応：ありません。
- テスト：`test/t/cases/filter_connection.rb`のポート18112のテスト「an empty String sends the status with Content-Length: 0」と、ポート18136のボディフィルタのあるlocationのテスト(`test/t/cases/content_empty_body.rb`)です。

### `Nginx::Var`のアクセサが、ワーカーで最初に使われたときに`Nginx::Var`のメソッドになる(#610)

- 変更前：`Nginx::Var`への`v.NAME`と`v.NAME = value`は、毎回`Nginx::Var#method_missing`を通りました。`Nginx::Var`が自分で持つメソッドは、`method_missing`、`exist?`、`set`の3つでした。`v.respond_to?(:request_method)`は`false`を返し、`Nginx::Var.instance_methods(false)`はこの3つだけを挙げました。スクリプトが変数と同じ名前のメソッドを`Object`か`Kernel`に定義すると、`v.NAME`は変数を読まずにそのメソッドを呼びました。例は、ハンドラのコードのトップレベルの`def`です。
- 変更後：ワーカープロセスで、ある名前の最初の`v.NAME`か`v.NAME = value`は、`NAME`か`NAME=`を`Nginx::Var`のメソッドとして定義します。そのワーカーでその名前を後で使うと、このメソッドが呼ばれます。このメソッドは、`method_missing`と同じに変数を読み書きします。値、変数でない名前への`nil`、例外、`error.log`の行は変わりません。ワーカーは、スクリプトが使う宣言済みの変数ごとに、getterとsetterを定義します。宣言済みの変数とは、nginxとそのモジュールの変数と、`set`が宣言する変数です。接頭辞の変数には、スクリプトが使う最初の16の名前にgetterを定義します。接頭辞の変数の名前の例は、`arg_q`と`http_x_request_id`です。メソッドを定義するのは、名前が`a`から`z`、`0`から`9`、`_`だけでできているときです。setterの名前は、その後に`=`が付きます。`v.Request_Method`は、これまでどおり`method_missing`を通って`$request_method`を読みます。次の場合には、メソッドを定義しません。変数でない名前、接頭辞の変数のsetter、`Nginx::Var`のサブクラスのインスタンス、凍結した`Nginx::Var`、`Nginx::Var`かその祖先が同じ名前のメソッドを既に持つ名前です。最初に使った後は、`v.respond_to?(:NAME)`、`v.methods`、`Nginx::Var.instance_methods(false)`、`Nginx::Var.method_defined?(:NAME)`がそのメソッドを示します。何を示すかはワーカーがそれまでに処理したリクエストで決まるので、2つのワーカーが違う答えを返すことがあります。メソッドができた後は、スクリプトが同じ名前のメソッドを後から`Object`か`Kernel`に定義しても、`v.NAME`は変数を読みます。
- 変更の理由：
  - 背景：mruby 4.0.0では、どのクラスも定義していないメソッド名を探すと、その名前を`Nginx::Var`、`Object`、`Kernel`、`BasicObject`の全部のメソッドと比べます。比べる項目は110を超えます。mrubyは、見つからなかった名前をキャッシュしません。そのため、`v.NAME`は毎回、`method_missing`が動く前にこの探索をしていました。#561のcallgrindの比較では、mruby 3.3.0との差のうち、`var`のシナリオの74%と、`auth`のシナリオの59%が、この探索の分でした。説明は[構想の1.1節](https://github.com/matsumotory/ngx_mruby/blob/next/docs/proposals/archive/nginx-var-method-lookup.md#11-what-the-comparison-of-561-counts)にあります。名前のメソッドがあれば、mrubyのメソッドのキャッシュがそれを見つけます。
  - 前の挙動を残せなかった理由：mrubyのメソッドのキャッシュは、探索で見つけたメソッドにしか答えません。`v.NAME`が探索を飛ばすには、メソッドを定義するしかなく、定義したメソッドはイントロスペクションに見えます。構想のほかの案は、いま書かれているスクリプトを遅い経路に残すか、mrubyのリリースを待つ案です。説明は[構想の2節](https://github.com/matsumotory/ngx_mruby/blob/next/docs/proposals/archive/nginx-var-method-lookup.md#2-candidates)にあります。オーナーは、2026-10-15に、イントロスペクションの変化を3.0.0の挙動の変更として受け入れ、2026-10-19にそれを確かめました。記録は[構想の状態](https://github.com/matsumotory/ngx_mruby/blob/next/docs/proposals/archive/nginx-var-method-lookup.md)にあります。
  - ドキュメントが示していた挙動：[2.7.1のNginx::Varのクラス](https://github.com/matsumotory/ngx_mruby/blob/v2.7.1/docs/class_and_method/README.md#nginxvar-class)は、`Nginx::Var#VARNAME`か`Nginx::Var#VARNAME=`を評価すると`Nginx::Var#method_missing`が呼ばれると書いています。`respond_to?`と`Nginx::Var`のメソッドについては、何も書いていませんでした。
- 影響の範囲：`Nginx::Var`かそのインスタンスに`respond_to?`、`methods`、`instance_methods`、`method_defined?`を呼ぶスクリプトです。例は、名前が変数かどうかをこれで判断するスクリプトです。変数と同じ名前のメソッドを`Object`か`Kernel`に定義し、その変数を`v.NAME`でも読むスクリプトも当たります。`Nginx::Var#method_missing`を包むスクリプトも当たります。例は、`super`を呼ぶ`method_missing`を持つモジュールを`Nginx::Var`にprependするスクリプトです。包んだ処理は、メソッドを定義する名前については最初のアクセスのときだけ動きます。
- 必要な対応：変数があるかどうかは、`v.exist?(name)`で判断してください。スクリプトのメソッドには、nginxの変数の名前でない名前を付けてください。
- テスト：`test/conf/conf.d/68-var-accessor.conf`と`test/t/cases/var_method_lookup.rb`の、ポート18159のテストです。

### `Nginx::Connection`、`Nginx::Server`、`Nginx::Request`が、`Nginx::Var`を呼ばずに変数を読む(#610)

- 変更前：次のメソッドは、自分の変数のアクセサを`Nginx::Var`に呼んでいました。`Nginx::Connection#remote_ip`、`#remote_port`、`#local_ip`、`#local_port`、`Nginx::Server#document_root`、`#realpath_root`、`#path`、`Nginx::Request#hostname`、`#authority`、`#filename`、`#user`、`#get_body`です。変数は、`remote_addr`、`remote_port`、`server_addr`、`server_port`、`document_root`、`realpath_root`、`host`、`http_host`、`request_filename`、`remote_user`、`request_body`です。その`Nginx::Var`は、オブジェクトが作ってインスタンス変数`@iv_var`に持っていました。スクリプトがそのようなメソッドか独自の`method_missing`を`Nginx::Var`に定義するか、`@iv_var`に別のオブジェクトを入れると、これらのメソッドが返す値が変わりました。
- 変更後：これらのメソッドは、nginxから変数をCで読みます。スクリプトが`Nginx::Var`にどんなメソッドを定義しても、nginxがその変数に持つ値を返します。`Nginx::Var`を作らず、`@iv_var`も設定しません。`Nginx::Request#var`は、これまでどおりオブジェクトの`Nginx::Var`を作って`@iv_var`に持ちます。リクエストの外では、これまでと同じ`RuntimeError`を出します。
- 変更の理由：
  - 背景：これらの変数の名前は決まっています。`AGENTS.md`の「Design principles」は、初期化のときに一度だけ用意できる決まったものを、リクエストごとに探したり確保したりしないように求めています。Rubyの呼び出しは、呼ぶたびに`Nginx::Var`でメソッドを探しました。この探索は、上の項目の探索と同じです。また、オブジェクトごとに`Nginx::Var`を作り、そのクラスを探しました。いまは、名前とそのハッシュのキーを一度だけ用意します。説明は[構想の案(d)](https://github.com/matsumotory/ngx_mruby/blob/next/docs/proposals/archive/nginx-var-method-lookup.md#d-ngx_mrubys-own-methods-read-the-variable-in-c)にあります。
  - 前の挙動を残せなかった理由：スクリプトが値を変えられたのは、`@iv_var`のオブジェクトへのRubyの呼び出しがあったからです。この呼び出しをせずに変数を読むと、その費用とその効果の両方が無くなります。
  - ドキュメントが示していた挙動：[2.7.1のNginx::Connectionのクラス](https://github.com/matsumotory/ngx_mruby/blob/v2.7.1/docs/class_and_method/README.md#nginxconnection-class)は、`remote_ip`、`remote_port`、`local_ip`、`local_port`がnginxの変数`$remote_addr`、`$remote_port`、`$server_addr`、`$server_port`と同じだと書いています。[Nginx::Server#realpath_root](https://github.com/matsumotory/ngx_mruby/blob/v2.7.1/docs/class_and_method/README.md#nginxserverrealpath_root)も、`$realpath_root`について同じことを書いています。いまは、どの場合にもその値を返します。
- 影響の範囲：`Nginx::Var`へのメソッドの定義、独自の`method_missing`、`@iv_var`の別のオブジェクトで、これらのメソッドが返す値を変えるスクリプトです。`Nginx::Request#var`を先に呼ばずに、これらのオブジェクトの`@iv_var`を読むスクリプトも当たります。
- 必要な対応：別の値を返すには、`Nginx::Connection`、`Nginx::Server`、`Nginx::Request`そのものにメソッドを定義するか、自分のメソッドを呼んでください。変数は、`@iv_var`でなく`Nginx::Var`で読んでください。`Nginx::Var`は、`Nginx::Request#var`、`Nginx.var`、`Nginx::Var.new`で得られます。
- テスト：`test/t/cases/var_method_lookup.rb`の、ポート18159のテストです。

### `Dir`をmrubyのコアgemが定義するようになり、閉じた`Dir`が`RuntimeError`でなく`IOError`を出す(#559)

- 変更前：`Dir`はiij/mruby-dirが定義します。閉じた`Dir`を読んだり、その項目を繰り返し処理したり、もう一度閉じたりすると、`RuntimeError`が出ます。メッセージは`closed directory`です。ブロックの中で`Dir`を閉じたときの`Dir.open`も、`RuntimeError`を出します。ブロックなしの`Dir#each`と`Dir.foreach`は、`NoMethodError`を出します。
- 変更後：`Dir`は、mruby 4.0.0のコアgemであるmruby-dirが定義します。このgemはiij/mruby-dirをもとにしていて、iij/mruby-dirのメソッドをすべて持ちます。閉じた`Dir`を読んだり、その項目を繰り返し処理したり、もう一度閉じたりすると、`IOError`が出ます。メッセージは`closed directory`です。ブロック付きの`Dir.open`は、ブロックの中で`Dir`を閉じたときも、ブロックの値を返します。ブロックなしの`Dir#each`と`Dir.foreach`は、`Enumerator`を返します。ブロック付きの`Dir.foreach`は、開いた`Dir`を閉じます。これは「不具合の修正」に挙げます。また、`Dir`には、iij/mruby-dirに無いメソッドがあります。それは「新機能」に挙げます。
- 変更の理由：
  - 背景：v3の計画は、サードパーティのgemのiij/mruby-env、iij/mruby-process、iij/mruby-dirを、mrubyのコアgemに置き換えます。根拠は`docs/proposals/v3-plan.md`の4節のPillar Aです。3つのうち、mruby 4.0.0がコアgemを持つのは`Dir`だけです。
  - 前の挙動を残せなかった理由：`RuntimeError`は、iij/mruby-dirが出します。iij/mruby-dirは、`ENABLE_IO`なしでコンパイルすると、閉じたディレクトリに`RuntimeError`を出します。既定のビルドは`ENABLE_IO`を定義しません。`RuntimeError`を残すには、iij/mruby-dirを残すしかありませんでした。iij/mruby-dirには、2018-09-14からコミットがありません。また、iij/mruby-dirの`Dir.foreach`は、開いた`Dir`をGCが解放するまで閉じません。
  - ドキュメントが示していた挙動：2.xの[docs/class_and_method/README.md](https://github.com/matsumotory/ngx_mruby/blob/v2.7.0/docs/class_and_method/README.md#built-in-mrbgems)は、既定のビルドで使えるクラスに`Dir`のクラスを挙げ、iij/mruby-dirへリンクしています。iij/mruby-dirのREADMEはメソッドを挙げていますが、閉じた`Dir`の例外については何も書いていません。
- 影響の範囲：閉じることのある`Dir`のメソッドや、ブロックの中で`Dir`を閉じる`Dir.open`の周りで、`RuntimeError`をrescueするスクリプトです。`rescue RuntimeError`が例外を捕まえなくなると、ハンドラは500を返します。このときログに出る行は`mrb_run failed: ... error: #<IOError: closed directory>`です。
- 必要な対応：`IOError`をrescueしてください。両方のバージョンで動かすスクリプトは、`IOError`と`RuntimeError`の両方か、`StandardError`をrescueしてください。

### C拡張：`MRB_TT_DATA`と宣言していないクラスのオブジェクトでは、Cのデータをラップできない(#561)

- 変更前：mruby 3.xは、インスタンスの型を設定していないクラスを検査しませんでした。`Data_Wrap_Struct`や`mrb_data_object_alloc`で、Cの構造体を自分のクラスのオブジェクトでラップするgemは、そのオブジェクトを得られました。
- 変更後：mruby 4.0は、クラスを`MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA)`で宣言していないと、割り当てのときに`TypeError: allocation failure of <class>`を出します。
- 影響の範囲：その宣言をしていないクラスのオブジェクトでCのデータをラップするmrbgemとC拡張です。matsumotory/mruby-unameの、matsumotory/mruby-uname#1より前のコミットがその1つです。このとき、`Uname`のどのメソッドも`TypeError: allocation failure of Uname`を出します。それを呼ぶハンドラは、500を返します。ngx_mrubyのテストスイートでもこの変化が出ました。変化が出たのは`test/t/cases/gem_uname.rb`です。
- 必要な対応：クラスを`MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA)`で宣言してください。既定のビルドは、matsumotory/mruby-unameを、この宣言をするコミットに固定します。詳しくは「ビルドとテストの変更」を参照してください。mruby-unameを取り込む自前の`build_config.rb`には、そのコミットか、それより後のコミットが必要です。

### C拡張：mrubyが、Cのメソッドに渡す引数の数を引数仕様で検査する(#561)

- 変更前：mruby 3.3は、Cのメソッドに渡す引数の数を、定義したときの引数仕様で検査しました。仕様は`MRB_ARGS_REQ(2)`などです。ただし、検査したのは仕様が`MRB_ARGS_NONE()`のときだけです。他の仕様では、`mrb_get_args`だけが、自分が読むものに対して引数を検査しました。
- 変更後：mruby 4.0は、すべてのCのメソッドで、呼ぶ前に引数の数を検査します。仕様が求めるより少ない引数で呼ぶと、`ArgumentError`が出ます。仕様に可変長引数(`MRB_ARGS_REST()`、`MRB_ARGS_ANY()`)が無ければ、仕様が許すより多い引数で呼んでも`ArgumentError`が出ます。`mrb_get_args`が受け付けるかどうかは関係ありません。仕様がキーワードを受けないとき、空でないキーワードのハッシュは1つの引数と数えます。`MRB_ARGS_REQ(1)`で定義して`"o|o"`を読むメソッドは、2つの引数で呼ぶと`ArgumentError: wrong number of arguments (given 2, expected 1)`を出します。`MRB_ARGS_REQ(2)`で定義して`"S"`を読むメソッドは、1つの引数で呼ぶと`(given 1, expected 2)`を出します。mruby 3.3では、どちらの呼び出しも動きました。
- 影響の範囲：仕様と`mrb_get_args`が読むものが、どちらかの向きで食い違う、mrbgemとC拡張のCのメソッドです。ngx_mruby自身のCのメソッドは影響を受けません。`src/`にある110の定義のそれぞれで、仕様は、その`mrb_get_args`が受け付ける引数の数をすべて受け付けます。
- 必要な対応：`mrb_get_args`が読むものに合う仕様で、メソッドを定義してください。`"o|o"`なら`MRB_ARGS_ARG(1, 1)`です。

### C拡張：ヘッダと関数の名前が変わり、失敗したときの`mrb_open()`の戻り値が変わる(#561)

- 変更前：`mruby/ext/io.h`、`mrb_alloca()`、`mrb_open_allocf(f, ud)`、`mrb_open_core(f, ud)`があります。後の2つは、`mrb_allocf`の型のアロケータを受け取ります。既定のアロケータは`mrb_default_allocf()`です。プログラムは、このアロケータを定義し直せました。gemの初期化が失敗すると、`mrb_open()`は`NULL`を返します。
- 変更後：IOのヘッダは`mruby/io.h`になりました。`mruby/ext/io.h`はありません。`mrb_alloca()`は`mrb_temp_alloc()`になりました。`mruby.h`は`mrb_alloca()`をそのマクロとして残し、コメントに「for compatibility」と書いています。`mrb_open_allocf()`、`mrb_allocf`、`mrb_default_allocf()`はありません。`mrb_open_core()`は引数を取りません。mrubyは、`mrb_basic_alloc_func(void *ptr, size_t size)`でメモリを割り当てます。プログラムはこの関数を定義して、mrubyのアロケータを置き換えられます。説明は、mrubyの[`doc/guides/memory.md`](https://github.com/mruby/mruby/blob/4.0.0/doc/guides/memory.md)にあります。gemの初期化が失敗すると、`mrb_open()`は`NULL`でなく、`mrb->exc`を設定したmrb_stateを返します。
- 影響の範囲：mrbgemと、mrubyを組み込むプログラムのうち、Cのソースが次のどれかに当たるものです。`mruby/ext/io.h`をインクルードするもの、`mrb_open_allocf()`を呼ぶもの、`mrb_open_core()`を引数付きで呼ぶものは、ビルドが止まります。自分の`mrb_default_allocf()`を定義するものでは、mrubyがそれを呼ばなくなります。`mrb_open()`の結果を`NULL`かどうかだけで判定するものも当たります。`mrb_alloca()`の呼び出しは、今もコンパイルできます。
- 必要な対応：`mruby/io.h`をインクルードし、`mrb_temp_alloc()`を呼んでください。`mrb_open_allocf(f, ud)`の代わりに`mrb_open()`を呼び、`mrb_open_core()`は引数なしで呼んでください。プログラムがアロケータを置き換えるところでは、`mrb_default_allocf()`の代わりに`mrb_basic_alloc_func()`を定義してください。`mrb_open()`の結果は、`mruby.h`の`MRB_OPEN_FAILURE()`で判定してください。このマクロは、`NULL`のときと、`exc`を設定したmrb_stateのときに真になります。

### C拡張：`mruby.h`をインクルードするソースに、生成されたヘッダが必要になる(#561)

- 変更前：`mruby.h`は`mruby/presym.h`をインクルードしませんでした。そのため、`MRB_SYM()`を使わないソースは、`mruby/include`だけでコンパイルできました。`MRB_NO_PRESYM`でpresymを無効にすることもできました。ngx_mruby 2.xは、自分のソースをこの形でコンパイルしていました。2.xの`config.in`は、インクルードパスに`mruby/src`と`mruby/include`だけを置きます。
- 変更後：`mruby.h`は`mruby/presym.h`をインクルードし、`mruby/presym.h`は生成された`mruby/presym/id.h`をインクルードします(mruby/mruby#6733)。`MRB_NO_PRESYM`も無くなりました。そのため、`mruby.h`をインクルードするすべてのソースに`build/host/include`が必要です。`mruby/include`だけでコンパイルすると、そのソースは`fatal error: mruby/presym/id.h: No such file or directory`で止まります。
- 影響の範囲：mrubyのビルドとは別にコンパイルする、`mruby.h`をインクルードするCのソースです。`./configure --with-mruby-incdir`で、そのディレクトリを含まないディレクトリの一覧を与えたビルドでの、ngx_mrubyのソースもこれに入ります。
- 必要な対応：mrubyのビルドが作る`include`ディレクトリ、`mruby/build/host/include`をインクルードパスに加えてください。ngx_mrubyのビルドは、自分のソースにはこれを加えます。`--with-mruby-incdir`の既定の一覧は`<mruby_root>/src <mruby_root>/include <mruby_root>/build/host/include`です(#559)。`--with-mruby-incdir`で自分で一覧を与えるときも、このディレクトリが必要です。ngx_mrubyのソースが`mruby.h`と`mruby/presym.h`をインクルードするためです(#572)。詳しくは[3-B. Makefileを使う](/ja/guides/install/#3-b-makefileを使う)を参照してください。

### 既定のビルドからauto-sslのmrbgemと、それに伴うクラスが無くなる(#556)

- 変更前：2.xの既定の`build_config.rb`は、同梱のauto-sslのmrbgemと、それが依存するgemをビルドします。auto-sslは`mrbgems/auto-ssl`にあり、`Nginx::SSL::ACME`のクラスを定義します。依存するgemは、pyama86/mruby-acme-client、pyama86/mruby-polarssl、matsumotory/mruby-httprequest、matsumotory/mruby-simplehttp、mattn/mruby-http、mattn/mruby-base64、takahashim/mruby-forwardable、iij/mruby-tempfileです。スクリプトは、これらのgemが定義するものを使えます。`Nginx::SSL::ACME::Client`と`Nginx::SSL::ACME::Dehydrated`、クラスとモジュールの`Acme`、`CustomHttpRequest`、`OpenSSL`、`PolarSSL`、`HttpRequest`、`SimpleHttp`、`HTTP`、`Base64`、`Forwardable`、`FORWARDABLE`、`Tempfile`、`TempfilePath`、そして`Dir.tmpdir`と`Dir.mktmpdir`です。
- 変更後：既定のビルドには、これらがどれもありません。これらの定数は無く、`Dir.tmpdir`と`Dir.mktmpdir`は`NoMethodError`を出します。これらのどれかを使うハンドラは、500を返します。そのときログに出る行は、`mrb_run failed: ... error: #<NameError: uninitialized constant Base64>`のような形です。`Dir`のクラス自体は残ります。このリリースには、auto-sslのmrbgem自体がありません。次の項目を参照してください。
- 変更の理由：
  - 背景：v3の計画の決定6は、v3の既定のビルドからauto-sslを外し、nginx-acmeと、ストアから証明書を引く例に置き換えます。根拠は`docs/proposals/v3-plan.md`の7節です。auto-sslのACMEのクライアントである`Nginx::SSL::ACME::Client`は、ACMEv1を使います。Let's Encryptは、ACMEv1をもう提供していません。こちらの根拠は計画の2.2節と3.4節です。
  - 前の挙動を残せなかった理由：このgemは、Let's Encryptから証明書を取得できません。また、既定のビルドに入る他のgemが必要としないサードパーティのgemを8つ、すべての既定のビルドに持ち込んでいました。その中には、GPLのpyama86/mruby-polarsslもあります。さらに、auto-sslを既定のビルドに残すと、mruby 4.0.0では既定のビルドも止まります。pyama86/mruby-polarsslが`mruby/ext/io.h`をインクルードするためです。次の項目を参照してください。
  - ドキュメントが示していた挙動：2.xの[docs/class_and_method/README.md](https://github.com/matsumotory/ngx_mruby/blob/v2.7.0/docs/class_and_method/README.md#auto-ssl-mrbgem)は、auto-sslを、開発の初期段階にある任意で使う同梱のmrbgemと呼んでいます。既定のビルドに入るかどうかは書いていません。同じ文書の[Nginx::Var Class](https://github.com/matsumotory/ngx_mruby/blob/v2.7.0/docs/class_and_method/README.md#nginxvar-class)にある`mruby_set_code`の例は、`Base64.encode`を呼びます。既定のビルドで`Base64.encode`が使えたのは、auto-sslが入っていたからです。
- 影響の範囲：nginxの中で、上の定数のどれか、`Dir.tmpdir`、`Dir.mktmpdir`を使うスクリプトです。
- 必要な対応：`Base64.encode(s)`の代わりに`[s].pack('m0')`を、`Base64.decode(s)`の代わりに`s.unpack1('m')`を使ってください。どちらもコアgemのmruby-packにあります。`Dir.tmpdir`の代わりに`ENV['TMPDIR'] || '/tmp'`を使い、`Dir.mktmpdir`の代わりに、自分で決めた名前で`Dir.mkdir(path, 0700)`を使ってください。例は[auto-sslのmrbgemと、それと一緒に入っていたクラス](/ja/guides/install/#auto-sslのmrbgemとそれと一緒に入っていたクラス)にあります。他の定数には、それを定義するgemを、自前の`build_config.rb`に`conf.gem`の行で加えてください。pyama86/mruby-polarsslに依存するgemは、mruby 4ではビルドできません。`Nginx::SSL::ACME`が必要なサーバーは、2.xのビルドを使い続けてください。次の項目を参照してください。

### auto-sslのmrbgemと`NGX_MRUBY_AUTO_SSL`が無くなる(#640)

- 変更前：ngx_mruby 2.xは、auto-sslのmrbgemを同梱し、既定のビルドに入れます。このgemは`mrbgems/auto-ssl`にあります。このgemは、ACMEのプロトコルのクライアントである`Nginx::SSL::ACME::Client`と、ACMEのクライアントのdehydratedを使うための`Nginx::SSL::ACME::Dehydrated`を定義します。`test/conf/auto-ssl/`には、両方の設定の例が入っています。
- 変更後：このリリースには、`mrbgems/auto-ssl`も`test/conf/auto-ssl/`もありません。`build_config.rb`は`NGX_MRUBY_AUTO_SSL`をもう読みません。そのため、このリリースのどのビルドにも`Nginx::SSL::ACME`はありません。環境に`NGX_MRUBY_AUTO_SSL=1`を与えたビルドは、与えないときと同じく既定のgemをビルドします。`Nginx::SSL::ACME`を使うスクリプトは`NameError`を出し、そのハンドラは500を返します。そのとき`error.log`には`mrb_run failed`の行が出ます。
- 変更の理由：
  - 背景：v3の計画の決定6は、auto-sslを、nginx-acmeと、ストアから証明書を引く例に置き換えます。根拠は`docs/proposals/v3-plan.md`の7節です。また、このgemは同梱のmrubyでは動きません。このgemは、TLSのためにpyama86/mruby-polarsslを必要とします。pyama86/mruby-polarsslは、ngx_mrubyが保守していないgemで、2017-03-03からコミットがありません。このgemは`mruby/ext/io.h`をインクルードします。mruby 4.0はこのヘッダを`mruby/io.h`に改名したので、auto-sslを入れたmrubyのビルドは`fatal error: mruby/ext/io.h: No such file or directory`で止まります(#561)。auto-sslのACMEのクライアントであるpyama86/mruby-acme-clientはACMEv1を使います。Let's Encryptは、2021-06にACMEv1を止めました。こちらの根拠は計画の2.2節と3.4節です。
  - 前の挙動を残せなかった理由：pyama86/mruby-polarsslが変わらない限り、このgemはmruby 4でビルドできません。ビルドできたとしても、Let's Encryptから証明書を取得できません。`next`に残すと、v3のどのビルドも使えないgemと、ビルドが止まるだけの任意の変数を残すことになります。ngx_mruby 2.xには、このgemが残ります。
  - ドキュメントが示していた挙動：2.xの[docs/class_and_method/README.md](https://github.com/matsumotory/ngx_mruby/blob/v2.7.0/docs/class_and_method/README.md#auto-ssl-mrbgem)は、auto-sslを、開発の初期段階にある任意で使う同梱のmrbgemと呼び、APIについては`mrbgems/auto-ssl/mrblib`のスクリプトを参照するよう書いています。このgemをいつまで残すかは書いていません。
- 影響の範囲：`Nginx::SSL::ACME::Client`か`Nginx::SSL::ACME::Dehydrated`を使うスクリプト、`test/conf/auto-ssl/`の例をもとにした設定、`NGX_MRUBY_AUTO_SSL=1`を与えるビルドです。
- 必要な対応：ACMEのサーバーから証明書を取得するには、nginx自身のモジュールである[ngx_http_acme_module](https://nginx.org/en/docs/http/ngx_http_acme_module.html)、つまりnginx-acmeを使ってください。`Nginx::SSL::ACME`が必要なサーバーは、2.xのビルドを使い続けてください。このgemの説明は[2.xのドキュメント](https://github.com/matsumotory/ngx_mruby/blob/v2.7.2/docs/class_and_method/README.md#auto-ssl-mrbgem)にあります。ビルドの環境から`NGX_MRUBY_AUTO_SSL`を除いてください。この変数は何の効果もありません。

## 新機能

- スクリプトで、mruby 3.4と4.0で加わった機能を使えます。`case`と`in`によるパターンマッチ、`Array#rfind`、メソッドの引数の末尾に付けるカンマ、メソッドの引数の`&nil`です(#561)。
- スクリプトで、mruby 3.3.0に無いメソッドを呼べます。例えば`Kernel#public_send`、`String#b`、`Hash#slice!`、`Array#fetch_values`、`Integer#bit_length`、`Integer.sqrt`、`Module#private_instance_methods`です。mrubyの利用者から見える変更の一覧である[`doc/mruby3.4.md`](https://github.com/mruby/mruby/blob/4.0.0/doc/mruby3.4.md)と[`doc/mruby4.0.md`](https://github.com/mruby/mruby/blob/4.0.0/doc/mruby4.0.md)は、さらに多くを挙げています(#561)。
- `Dir.children`と`Dir#each_child`は、CRubyと同じく`.`と`..`を除いてディレクトリの項目を挙げます。`Dir.empty?`は、ディレクトリに項目が無いかどうかを返します(#559, #561)。ngx_mruby 2.xは、`Dir`をiij/mruby-dirから取っていました。iij/mruby-dirには、この3つのメソッドがどれもありません。`Dir`は、今はmrubyのコアgemのmruby-dirが定義します。[Class and Method](/ja/reference/ruby/)を参照してください。mruby 4.0.0では、この2つのメソッドは`.`と`..`を除きます。これはmruby 3.4からの変更で、mruby/mruby#6265です。mruby 3.3.0では、この2つは`Dir.entries`と`Dir#each`の別名で、`.`と`..`を含んでいました。ngx_mrubyのリリースに、mruby 3.3.0とmruby-dirを組み合わせたものはありません。ngx_mrubyのテストスイートでもこの変化が出ました。変化が出たのは`test/t/cases/gem_dir.rb`です。そうしたビルド向けに書いたスクリプトで、これらの呼び出しの後に`.`と`..`を飛ばしていたものは、そのコードを削除できます。`Dir.entries`を使い続けることもできます。`Dir`は`Enumerable`もインクルードします。iij/mruby-dirはインクルードしないので、`Dir.open(path) { |d| d.select { |name| name.end_with?(".txt") } }`は、このリリースから動きます。ブロック付きの`Dir.open`は、ブロックが終わると`Dir`を閉じます。

## 不具合の修正

- ブロック付きの`Dir.foreach`は、開いた`Dir`を閉じます。2.xのiij/mruby-dirでは、その`Dir`が持つworkerのファイルディスクリプタは、GCが`Dir`を解放するまで開いたままでした(#559)。
- nginxが設定を読む間に`mrb_open()`が失敗すると、httpのモジュールは`ngx_mruby: mrb_open() failed`を、streamのモジュールは`ngx_mruby-stream-module: mrb_open() failed`を、`emerg`のレベルで出します。mrubyかgemの初期化が例外を出したときは、その後に`: <class> raised while initializing mruby`が続きます。nginxはこれまでどおり止まります。ngx_mruby 2.xは、この場合に自分の行を出しませんでした(#559)。

## ビルドとテストの変更

- 導入ガイドに#660のビルド・インストール手順を統合し、対象を`next`開発ブランチへ合わせました。v3のコアgemとlockファイルの仕様を維持し、英日で同じコマンドを使います。新しいcheckoutでのビルドとループバックHTTP試用の結果に、対象コミットと検証範囲を記録しました。

- サイトはHTMLと同じ正本から、版ごとのMarkdownページとJSON文書索引を出力します。言語、出典コミットとハッシュ、未コミット変更のあるプレビューかどうかを記録します。両系列の全文・出典・未翻訳ページのリンクを検査し、表示用の改行位置とSVGを除きつつ、コード、テスト対象のサンプル、図の出典を保ちます。開発中のAPIを安定版として扱ったり、過去の例を現在の実測値として保証したりするものではありません。

- サイトの英日トップページに、テスト対象のnginx設定・Rubyハンドラ・HTTPのやり取りをまとめて表示し、専用の配色と画面幅に応じたレイアウトを加えます。サイトの検査はその配色・文字サイズ・共通のコード色も確認します。リブランドのプレビューでは、深紺・黒鉛色の面と銅系の差し色をドキュメントにも適用します。

- `build_config.rb.lock`は、mruby 4.0.0を記録します。rakeが書く`version: 4.0.0`と`release_no: 40000`です。luisbebop/mruby-polarsslの項目は無くなりました。テストのビルドが、このgemをクローンしなくなったためです(#561)。
- ロックは、hostのビルドとtestのビルドで、matsumotory/mruby-unameをgemの`master`の`50031c81b101f44e89bf482f5c31213b6c07af36`に固定します。ブランチの項目は`branch: master`です。このコミットはmatsumotory/mruby-uname#1のマージのコミットで、`Uname`のインスタンスをデータのオブジェクトとして宣言します。宣言は`MRB_SET_INSTANCE_TT(uname, MRB_TT_DATA)`です。このコミットのツリーは、修正のコミット`c82f8a6`が持つツリーと同じです。ビルドは、gemのブランチ`mruby-4`に依存しなくなりました(#561)。
- テストのクライアント、つまり`build_config.rb`の`test`のビルドは、`NO_SSL`でビルドします。設定は`ENV['NO_SSL'] ||= '1'`です。理由は次のとおりです。matsumotory/mruby-simplehttpは、`NO_SSL`が無いとmruby-polarsslに依存します。また、luisbebop/mruby-polarsslはmruby-printに依存します。テストのクライアントの`SimpleHttp`と`HttpRequest`は、`https`のリクエストを送れません。テストは、`curl -k`と`openssl s_client`でHTTPSを送ります。説明は[docs/test/README.md](/ja/contributing/test/)にあります。rakeはすべてのビルドのgemを1つのプロセスで読み込むので、`NO_SSL`は、mruby-simplehttpを持つ自前のhostのビルドにも届きます(#561)。
- 既定のビルドは21のクローンを作ります。`mruby/build/repos/host`に14、`mruby/build/repos/test`に7で、合わせて約9.8 MiBです。また、matsumotory/mruby-redisのビルドスクリプトが、hiredisのタグ`v1.5.0`を`mruby/build/host/mrbgems/mruby-redis/hiredis-v1.5.0`にクローンします。luisbebop/mruby-polarsslとそのサブモジュールのARMmbed/mbedtls、mruby/mgem-listは、クローンしなくなりました(#561、#606)。
- 既定のビルドに、matsumotory/mruby-redisが戻りました。2.7.2の既定のビルドと同じです。2.7.2のリリースノートの「Redisがデフォルトのビルドに戻り」で始まる項目と、#604に書いてあります。ロックは、hostのビルドで、このgemをgemの`master`の`8d939104923bc86bb16d2c203d91e22bfa3196df`に固定します。ブランチの項目は`branch: master`です。このコミットはmatsumotory/mruby-redis#109のマージのコミットで、`Redis.connect_set_udptr`の接続を`mrb->ud`でなく`mrb_state`に持ちます。2.7.2のリリースノートの「Redis.connect_set_udptrと引数の無いRedis.newは、接続をmrb->udでなくmrb_stateに持つようになり」で始まる項目に書いてあります。このコミットのビルドは、matsumotory/mruby-redis#108から、hiredisのタグ`v1.5.0`をクローンし、そのコミット`5bb7f030f6631b243438cf0fdd3be84352b905bb`を確かめ、`USE_WERROR=0`でビルドします。また、gemは`Redis#ttl`を1つの引数で宣言します。mruby 4.0.0はCのメソッドの引数の数をその宣言と照らすので、gemの前の宣言では、`r.ttl "key"`で`ArgumentError`が発生しました。ロックは、mruby-redisが依存するmatsumotory/mruby-pointerも、その`master`の`8b46506dfdb12a79a16be1d1172ef3c9324bef96`に固定します。mruby-pointerはクラスを加えません(#606)。
- `mruby/`は、mrubyのタグ`4.0.0`のツリーを持ちます。コミットは`831da26b9021`です。このツリーはサブツリーのsquashとしてマージし、`git-subtree-split: 831da26b9021de0369d17b71b5667e2941a1a32d`を記録しているので、次の`update-mruby-subtree`はそのコミットからマージします。[docs/DEVELOPMENT.md](/ja/contributing/development/)は、`mruby/`の下の衝突で止まった`update-mruby-subtree`を仕上げる手順を説明します。`git read-tree`で、サブツリーをrefと同じツリーに置き換えます。`git write-tree --prefix=mruby/`と`git rev-parse REF^{tree}`が同じidを出すことを確かめます。マージだけをコミットし、ビルドの変更はその後のコミットに入れます(#561)。
- mrubyのビルドの環境に`NGX_MRUBY_ALLOW_MISSING_CORE_GEMS=1`を与えると、`NGX_MRUBY_CORE_GEMS`の名前のうち、ビルドするmrubyに無いものを、メッセージを出して飛ばします。この値が無いと、ビルドはそこで止まります。この値は、同梱のmrubyを更新する間に使うためのものです。説明は[docs/DEVELOPMENT.md](/ja/contributing/development/)にあります(#559)。
- メモリのソークテスト：`sh test/soak/run.sh`は、`-DNGX_MRUBY_DEBUG_STATS`を付けてngx_mrubyを`build_soak/`にビルドし、そのビルドでシナリオを流します。この定義は、`Nginx::Debug`のクラスを加えます。このクラスには、`Nginx::Debug.gc`と、ngx_mrubyが数えたGCの登録を返す`Nginx::Debug.stats`があります。テストは12360と12361で待ち受けます。agent proxyのシナリオのためには、12362でモックのLLMのupstreamを起動します。build.shとtest.shの既定のビルドには、`Nginx::Debug`がありません。CIの`soak`ジョブが、このテストを流します。`next`では、必須のチェックである`ci-ok`がこのジョブを必要とします。説明は、[docs/test/README.md](/ja/contributing/test/)の「Soak test for memory」にあります(#542, #554, #557)。
- 性能の比較：`sh test/perf/compare.sh BASE_DIR`は、`BASE_DIR`のチェックアウトと、このチェックアウトを`build_perf/`にビルドします。そして、callgrindが数えるリクエストあたりの命令数を、シナリオごとに比べます。比較は12370と12371で待ち受け、12372でモックのLLMのupstreamを起動します。CIの`perf`ジョブは、測るバイナリの入力、測定、ワークフローを変えるプルリクエストで、この比較を流します。説明は、[docs/test/README.md](/ja/contributing/test/)の「Performance comparison with callgrind」にあります(#549, #554)。
- agent proxyのテスト：`test/t/cases/agent_proxy.rb`は、ポート18132で待ち受ける`test/conf/conf.d/60-agent-proxy.conf`のagent proxyのレシピに、リクエストを送ります。モックのLLMのupstreamである`test/soak/mock_llm.rb`は、`test/t/cases/_agent_proxy_client.rb`が12372と12373で起動します。説明は、[docs/test/README.md](/ja/contributing/test/)の「Mock LLM upstream」にあります(#554)。
- モックのLLMのupstreamである`test/soak/mock_llm.rb`は、`POST /v1/responses`にも、OpenAI Responses APIと同じ形で答えます。ストリームを使うリクエストにも、使わないリクエストにも答えます。ストリームは、`response.completed`、`response.incomplete`、`response.failed`のどれかのイベントで終わります。どのイベントで終わるかは、`--terminal`のオプションか、リクエストヘッダの`x-mock-terminal`で選びます。性能の比較は、既定のシナリオで`responses_stream_plain_50`を測ります。`PERF_SCENARIOS`で名前を挙げると、`responses_stream_plain_1000`も測ります。メモリのソークテストは`agent_responses_stream`を流します。`test/t/cases/agent_proxy.rb`は、agent proxyのレシピを`/v1/responses`でも確かめます。ポートは増えません。説明は、[docs/test/README.md](/ja/contributing/test/)の「Mock LLM upstream」にあります(#600)。
- 新しいテストケースと、そのサーバーのポート：`test/t/cases/gem_dir.rb`は`Dir`のテストで18127、`test/t/cases/gem_uname.rb`はmruby-unameのテストで18128です(#559)。`test/t/cases/config_time_log.rb`は、nginxが設定を読む間のメッセージのテストで18140です(#565)。`test/t/cases/return_in_block.rb`は、ハンドラのコードのブロックや`for`の本体の中の`return`のテストで18117です(#584)。`test/t/cases/var_method_lookup.rb`は、`Nginx::Var`のアクセサと、変数を読むメソッドのテストで18159です(#610)。`test/t/cases/home_example.rb`は、サイトのホームページの例のテストで18160です(#617)。`test/t/cases/guides.rb`は、サイトのガイドとユースケースのサンプルのテストで、18161から18168と、streamの12364です(#619)。
- `dependence/ngx_devel_kit/`は、ngx_devel_kitのタグ`v0.3.4`のツリーを持ちます。コミットは`bd44d1630`です。ngx_mrubyの変更は1つだけ残しました。`src/ndk_set_var.c`では、`mruby_set`の変数のハンドラが`NGX_DONE`を返すと、それがnginxのスクリプトエンジンのステータスになります。このツリーは`update-devkit-subtree v0.3.4`でサブツリーのsquashとしてマージし、`git-subtree-split: bd44d16302273052d6005d7bdb55f74e23813de3`を記録しているので、次の`update-devkit-subtree`はそのコミットからマージします。前のツリーはタグ`v0.3.1`の`a22dade76`で、その`src/ndk.h`は0.2.15と書いていました。ngx_mrubyは、`config.in`の`have=NDK_SET_VAR`で、NDKの`set_var`の部分だけを有効にします。このビルドがコンパイルするファイルのうち、v0.3.1の後のコミットが変えるのは`src/ndk.h`と`src/ndk_string_util.h`だけで、その変更は機械語を生みません。`src/ndk.h`の版のマクロはどこからも使われていません。NDKの`config`は常に`NDK`を定義するので、削除した`#error`は効いていませんでした。`ndk_memcpyp`はマクロで、それを使う唯一のファイルの`src/ndk_conf_file.c`を、このビルドはコンパイルしません。これらのコミットは、`ndk_conf_set_http_complex_path_slot`がpostのハンドラに渡す引数と、`ndk_memcpyp`がコピーする大きさを直します。`ndk_upstream_list`が確保するバケットの配列については、大きさの式の型を直します。確保するバイト数は変わりません。また、`NDK`を定義しないビルドで`src/ndk.h`が出していた`#error`を削除し、`NDK_VERSION`を"0.3.4"にします。NDKのこれらの部分を有効にするモジュールを一緒に加えたビルドは、直したコードをコンパイルします(#597)。
- nginx自身のテストスイート：`sh test/nginx-tests/run.sh`は、固定したコミットの[nginx-tests](https://github.com/nginx/nginx-tests)を`prove`で流します。対象は、`test.sh`がngx_mrubyを入れてビルドしたnginxと、同じ版と同じconfigureのオプションでngx_mrubyを入れずにビルドしたnginxです。両方のビルドの件数と、それぞれで失敗したテストファイルは、`build_nginxtests/summary.md`に書きます。実行には、Linuxとroot以外のユーザーとperlが要ります。テストファイルは、8000から8999のポートで待ち受けます。`TEST_SH_SKIP_TESTS=1 sh test.sh`は、ビルドとインストールの後で止まります。CIの`nginx-tests`のワークフローは、nginxのバイナリか`test.sh`かこのスクリプトを変える`next`へのプルリクエストと、`next`へのpushで、これを流します。必須のチェックである`ci-ok`は、このワークフローを必要としません。説明は、[docs/test/README.md](/ja/contributing/test/)の「nginx's own test suite (nginx-tests)」にあります(#602)。
- メモリのソークテストは、`Nginx::Debug`そのものも確かめます。`test/soak/nginx.conf`の各シナリオは、ウォームアップの前に、新しいlocationの`/debug/check`へ1回リクエストを送ります。そのシナリオは、次の3つがすべて成り立たないと失敗します。`Nginx::Debug.stats`がドキュメントのとおりのキーとIntegerの値を返すこと、`Nginx::Debug.gc`が`nil`を返すこと、`Nginx::Debug.gc`のフルGCが、どこからも参照されないオブジェクトを解放することです。説明は、[docs/test/README.md](/ja/contributing/test/)の「Soak test for memory」にあります(#605)。
- サイトの`/start/`のページの例：`examples/start/`には、チェックアウトからngx_mrubyを組み込んだnginxをビルドする`compose.yaml`と`Dockerfile`、`nginx.conf`とRubyのスクリプトがあります。その`README.md`が、ページの`/start/`です。CIの`examples`ワークフローは、`examples/check_example.py`でこのREADMEのコマンドを順に実行し、その出力を、READMEに書いてある出力と比べます。このワークフローは、`next`へのプルリクエストと`next`へのpushのうち、`examples/`、ワークフロー自身、ビルドの入力のどれかを変えるもので動きます。ビルドの入力は、`src/`、`mrbgems/`、`mruby/`、`dependence/`、`build.sh`、`build_config.rb`、`build_config.rb.lock`、`nginx_version`、`configure`、`config.in`、`Makefile.in`です。必須のチェックの`ci-ok`は、このワークフローを必要としません(#618)。
- `test/t/cases/agent_proxy.rb`は、Messages APIのレシピについて比べる値を、`test/html/agent_proxy_auth.expected`、`agent_proxy_route.expected`、`agent_proxy_limit.expected`、`agent_proxy_log.expected`から読みます。各ファイルは1行に1つの`key=value`を持ちます。値がその文字列を含むことを比べる行は`key~=text`です。サイトのagent proxyのページは、これらのファイルを載せます。`test/t/cases/_agent_proxy_client.rb`は、3つ目の引数でnginxのポートを受け取ります。省略できます(#622)。
- `test.sh`は、自分が起こしたnginxだけを、そのpidで止めます。テスト用のnginxを起こす前に`killall nginx`を流すのをやめました。NetBSDとFreeBSDとCentOSでは`pkill nginx`でした。どちらも、マシンのすべてのnginxを止めていました。起こす前には、同じビルドのディレクトリで前の実行が止めずに残したnginxを、`logs/nginx.pid`のpidで止めます。止めるのは、そのプロセスがこのビルドの`sbin/nginx`を動かしているときだけです。終わるときは、失敗の後と、SIGHUP、SIGINT、SIGTERMを受けたときも含めて、テスト用のnginxにSIGTERMを送ります。シグナルを受けたときは、そのとき動いているコマンドが終わった後に送ります。たとえば、nginxの待ち受けを待つ処理や、実行中のテストファイルです。プロセスが残っていれば、1、3、7、15、31秒後に送り直します。単一プロセスのnginxは、イベントを待つ直前に届いたSIGTERMを取りこぼすことがあるためです。`NGINX_STOPTIME`秒を過ぎるとSIGKILLを送り、終了コード1で終わります。`NGINX_STOPTIME`の既定は60です。シグナルを送る前には毎回、そのpidがまだこのビルドの`sbin/nginx`を動かしているかを確かめます。nginxが終わった後にほかのプロセスがそのpidを使っていても、そのプロセスにはシグナルを送りません。`test/t/cases/_second_instance.rb`も、2つ目のnginxへのSIGQUITを同じように送り直します。説明は、[docs/test/README.md](/ja/contributing/test/)の「Stopping nginx」にあります(#635)。
- `TEST_SH_PORT_OFFSET=N`は、テストスイートのすべてのポートをNだけずらします。Nは-2345から47336までの整数で、既定は0です。2つのcheckoutが、それぞれ別のオフセットで、1台のマシンで同時に`test.sh`を流せます。スイートのポートは、`test/t`、`test/conf`、`test/html`と、agent proxyのテストが読み込む`test/soak`の2つのファイルにある、12345から12399までと18080から18199までの数です。`test.sh`は、新しいスクリプトの`test/t/cases/_stage.rb`で、これらのファイルを`build/nginx/harness/test/`にコピーします。そのとき、5桁で書いたこの範囲の数をNだけずらします。設定とフックのスクリプトはこのコピーからインストールし、テストもこのコピーから流します。テストは、`test/t/cases/_prelude.rb`に足したメソッドの`suite_path`で、コピーの側のCRubyの補助のスクリプトを動かします。オフセットが0なら、コピーは元のファイルと同じです。この範囲の数を桁区切りの`_`入りで書いたときと、ポートが10000から65535の外に出るオフセットのとき、`_stage.rb`は失敗します。説明は、[docs/test/README.md](/ja/contributing/test/)の「Ports」にあります(#641)。
- `test.sh`がテスト用のnginxにSIGKILLを送ったときの文は、実際に送ったときだけ出ます。そのときpidがもうこのビルドのnginxを動かしていなければ、シグナルを送らずに停止を終え、停止は済んだと扱います。`test.sh`の終了コードはテストの結果のままです。前は、SIGKILLを送ったという文を出し、`test.sh`は終了コード1で終わっていました。起こす前に、前の実行が残したnginxを止めるときは、そこで実行が終わっていました(#641)。
- valgrindの下でnginxを動かすCIのセルは、valgrindのエラーで失敗します。そのセルは、`valgrind --error-exitcode=99 --leak-check=full --errors-for-leak-kinds=definite,indirect`と、新しいファイル`test/valgrind.supp`のsuppressionでnginxを動かします。ステップ「Check the valgrind reports」は、valgrindのログの`ERROR SUMMARY`がエラーを数えたときに、セルを失敗にします。エラーは、メモリのエラーと、このファイルがsuppressしないdefinitely lostとindirectly lostのブロックです。このファイルは、nginxが終了時に確保したまま残す環境変数の配列(`ngx_set_environment()`、8バイト)をsuppressします。possibly lostのブロックはログに出ますが、エラーにはなりません。プルリクエストとpushでは、`build`のマトリクスの1つのセル(nginx 1.31.6、静的モジュール)が、valgrindの下でnginxを動かします。サニタイザを使わない他のセルは、nginxを直接動かします。`test.yml`を新しい入力`valgrind`を付けて手動で実行すると、サニタイザのセルを除く全部のセルがvalgrindの下でnginxを動かします。新しいワークフロー`valgrind-nightly.yml`は、この実行を毎日起動します。毎日の起動は、このファイルが既定のブランチの`master`に入ってから効きます。それまでは、このファイル、`test.yml`、`test/valgrind.supp`を変えるプルリクエストで起動します。`test.sh`は、今もvalgrindのエラーを終了ステータスに含めません。説明は、[docs/test/README.md](/ja/contributing/test/)の「valgrind in CI」にあります(#634)。
- サイトのデプロイ：`.github/workflows/site.yml`の`deploy`ジョブは、`build`ジョブがビルドしてチェックしたサイトを、GitHub Pagesで`https://ngx.mruby.org/`に公開します。このジョブは`next`へのpushと`next`での`workflow_dispatch`で動き、プルリクエストでは動きません。`actions/configure-pages`、`actions/upload-pages-artifact`、`actions/deploy-pages`はコミットで固定し、権限は`pages: write`と`id-token: write`だけです。Pagesの設定のoriginが`https://ngx.mruby.org`でなければ、ジョブは止まります。サイトは、古いサイトにあったGoogleの検証ファイル`googleba3435e4002729b6.html`を同じURLで配信し、アナリティクスのスクリプトを読み込みません。`site/scripts/check-deploy.mjs`が、この2つを毎回のビルドで確かめます。デプロイの後は、セッションが`site/scripts/check-live.mjs`を手で流し、公開されたサイトを確かめます。手順は、[AGENTS.md](https://github.com/matsumotory/ngx_mruby/blob/next/AGENTS.md)の「The site」にあります(#653)。
- サイトは、2.xのドキュメントを`master`の`docs/`から`/v2/`の下にビルドします。`site/`で`npm run build`の後に`node site/scripts/build-v2.mjs --tree DIR`（`npm run build:v2`）を流すと、2.xのページが専用の検索インデックスと共に`site/dist/v2/`に入ります。`site/scripts/check-v2.mjs`は、すべての2.xのページに2.xのバナーがあること、`/v2/`と`/docs/`の間のバージョンのリンク、それぞれのバージョンの検索が自分のバージョンのページだけを出すことを確かめます。`site`のワークフローは、毎回`master`をチェックアウトして`/v2/`をビルドします。`master`では、`master`へのすべてのプルリクエストで、`site-v2`のワークフローがそのプルリクエストの`docs/`でサイトをビルドし、`/v2/`の壊れたリンクで失敗します。`master`へのすべてのpushの後には、`site-dispatch`のワークフローが`next`の`site`のワークフローを起動します(#657、#656)。

## アップグレード

サポートするnginxのバージョンは、nginxのmainlineとstableの系列です。[README.md](https://github.com/matsumotory/ngx_mruby/blob/next/README.md)を参照してください。先に、使っているバージョンより新しい2.xのリリースのリリースノートを読み、その後でこのファイルを読んでください。同梱のmruby 4.0.0と一緒に、モジュールをビルドし直してください。自前の`build_config.rb`には、上の2つ目の項目にある変更が必要です。[Migrating from ngx_mruby 2.x to 3.0.0](/ja/releases/migration/)に、各項目が影響するスクリプトとビルドを見つける手順があります。アップグレードの前に、次を確かめてください。

- 同梱のmruby 4.0.0：一緒にモジュールをビルドし直し、これらの項目が扱わない変更をmrubyの一覧で確かめてください(#561)。
- 自前の`build_config.rb`：mruby-printを除き、hal-posix-io、hal-posix-dir、hal-posix-socketを加えてください。mruby-taskとmruby-encodingを使うかどうかを決めてください(#561)。
- `build_config.rb.lock`：新しいチェックアウトとソースのアーカイブでは、何もしなくてかまいません。gemを別のコミットでビルドするには項目を変えてください。ロックが変わったら、`mruby/build`を削除してください(#558)。
- `Hash#inspect`と`Hash#to_s`：データの形式として使わないでください。文字列を自分で組み立てるか、`JSON.generate`を使ってください(#561)。
- `Exception#inspect`：`mrb_run failed`の行を古い形式で読むログのパーサーとアラートを直してください(#561)。
- nginxが設定を読む間のメッセージ：見るには、`nginx -t -e stderr`を実行するか、`nginx -t`の後で起動時のログを読むか、`error_log`を`info`にしてreloadしてください(#565)。
- `NoMethodError`：メッセージでなく、例外のクラスで判定してください(#561)。
- `private`と`protected`：そうしたメソッドは、レシーバなしで呼ぶか、`send`で呼んでください。例えば、`Kernel.Integer(x)`の代わりに`Integer(x)`と書きます。privateメソッドは、`private_instance_methods`か`private_methods`で挙げてください(#561)。
- `Module#remove_const`、`#private`、`#public`、`#protected`、`#module_function`とフック：クラスやモジュールの本体の中でレシーバなしで呼ぶか、`send`で呼んでください(#561)。
- `append_features`、`prepend_features`、`extend_object`のオーバーライド：そのコードを`included`、`prepended`、`extended`に移してください(#561)。
- Floatへの`allbits?`、`anybits?`、`nobits?`：先に`to_i`で変換してください(#561)。
- `FileTest`：メソッドを呼ぶだけなら、何もしなくてかまいません(#561)。
- メソッドの本体で代入する定数：`Object.const_set`か`Kernel.const_set`を使ってください(#561)。
- Floatのビット演算：先に`to_i`で変換するか、項目の説明に従って前の数を計算してください(#561)。
- `String#valid_encoding?`：呼び出しを削除するか、mruby-encodingを加えてビルドし、スクリプトを確かめてください(#561)。
- シードを与えた`Random`と`srand`：バージョンをまたいで、その数に依存しないでください(#561)。
- `Set#inspect`、`Set#to_s`、`Set#flatten_merge`：前の2つをデータの形式として使わないでください。`s.flatten_merge(t)`の代わりに`s.merge(Set.new(t).flatten)`を呼んでください(#561)。
- `Hash#default_proc=`：Procか`nil`を渡してください(#561)。
- キーワード引数を付けた`yield`：何もしなくてかまいません(#561)。
- ハンドラのコードのブロックや`for`の本体の中の`return`：何もしなくてかまいません(#561)。
- 出力なしで終わるcontentハンドラ：500に頼っていたハンドラは、意図したステータスを設定してください。例は`Nginx::HTTP_INTERNAL_SERVER_ERROR`です。`response body is empty. return NGX_HTTP_INTERNAL_SERVER_ERROR`に一致させるログの監視には、メインリクエストのそのようなハンドラのうち、ステータスが無いものと、nginxが自分では応答しない200から299のステータスのものが見えなくなります(#574)。
- 空のボディで終わる出力のボディフィルタ：何もしなくてかまいません(#574)。
- `Nginx::Var`のアクセサ：変数があるかどうかは`v.exist?(name)`で判断し、スクリプトのメソッドにはnginxの変数の名前でない名前を付けてください(#610)。
- `Nginx::Connection`、`Nginx::Server`、`Nginx::Request`：別の値を返すには、これらのクラスにメソッドを定義してください。変数は、`@iv_var`でなく`Nginx::Var`で読んでください(#610)。
- `Dir`：閉じることのある`Dir`の周りでは、`RuntimeError`の代わりに`IOError`をrescueしてください。両方のバージョン向けのスクリプトは、両方をrescueしてください(#559)。
- C拡張：Cのデータをラップするクラスを`MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA)`で宣言し、Cのメソッドを`mrb_get_args`が読むものに合う仕様で定義してください。`mruby/io.h`、`mrb_temp_alloc()`、`MRB_OPEN_FAILURE()`を使ってください。`mrb_open()`と`mrb_open_core()`はアロケータなしで呼び、自分のアロケータには`mrb_basic_alloc_func()`を定義してください。`mruby/build/host/include`をインクルードパスに加え、`--with-mruby-incdir`で与える一覧にも加えてください(#561, #572)。
- auto-sslのmrbgemに伴うクラス：`Base64`の代わりに`pack('m0')`と`unpack1('m')`を、`Dir.tmpdir`の代わりに`ENV['TMPDIR'] || '/tmp'`を、`Dir.mktmpdir`の代わりに`Dir.mkdir`を使ってください。または、gemを自前の`build_config.rb`に加えてください(#556)。
- auto-sslのmrbgem：証明書はngx_http_acme_moduleで取得してください。`Nginx::SSL::ACME`が必要なサーバーは、2.xのビルドを使い続けてください。ビルドの環境から`NGX_MRUBY_AUTO_SSL`を除いてください(#640)。
