torikago 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.ja.md +102 -15
- data/README.md +106 -15
- data/lib/torikago/checker.rb +279 -30
- data/lib/torikago/cli.rb +24 -10
- data/lib/torikago/configuration.rb +4 -3
- data/lib/torikago/controller_endpoint.rb +30 -0
- data/lib/torikago/engine_container.rb +485 -58
- data/lib/torikago/gateway.rb +75 -14
- data/lib/torikago/invocation.rb +26 -0
- data/lib/torikago/package_api_updater.rb +32 -11
- data/lib/torikago/rack_endpoint.rb +23 -0
- data/lib/torikago/registry.rb +4 -2
- data/lib/torikago/root_constant_resolver.rb +69 -0
- data/lib/torikago/version.rb +1 -1
- data/lib/torikago.rb +8 -0
- data/sig/torikago.rbs +440 -0
- data/test/test_helper.rb +0 -1
- data/test/torikago/checker.rb +119 -93
- data/test/torikago/cli.rb +19 -4
- data/test/torikago/configuration.rb +2 -0
- data/test/torikago/controller_endpoint.rb +30 -0
- data/test/torikago/engine_container.rb +824 -30
- data/test/torikago/gateway.rb +138 -92
- data/test/torikago/package_api_updater.rb +6 -3
- data/test/torikago/rack_endpoint.rb +25 -0
- data/test/torikago/registry.rb +15 -0
- data/test/torikago/root_constant_resolver.rb +114 -0
- metadata +9 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0af7286987b986ed0366120312c488e768ab119e79cf025ea20b8e1e51039878
|
|
4
|
+
data.tar.gz: 0235edbb0503573d4caaaf702284f75604989d99ccee1cf189cd81a1eb04c178
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 06628e161d1f2210bcca6e99f1dd7bb9d5697ed89f863ae351d349ec3844030185a61856e195a4c41cff3605b6d58f818986d21fb14ca8b52948ae68b58c8783
|
|
7
|
+
data.tar.gz: 35cf7e1d20061c198e7fcf2fcaadd4f9014dc58ed9d08fc4f5307f5ae8ca494ba79599519eaa4747763cef6219594e32c92b128d09e01be9cd4cb188b5dfdf19
|
data/README.ja.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`torikago`は、Railsのmodular monolithでmoduleごとの実行境界を扱うためのgemです。`packwerk`や`Rails::Engine`で構造上の境界を作るだけでなく、`Ruby::Box`を使って実行時の境界も強くすることを目指しています。
|
|
4
4
|
|
|
5
|
-
`torikago`では、module間の呼び出しを`Torikago::Gateway.
|
|
5
|
+
`torikago`では、module間の呼び出しを`Torikago::Gateway.invoke(...)`に集約し、各moduleが公開するPackage APIのclass・methodと呼び出し可能なmoduleを事前に定義します。これによって、意図していないmodule間参照を実行時に防ぎやすくします。
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
@@ -16,6 +16,7 @@ Torikago.configure do |config|
|
|
|
16
16
|
:foo,
|
|
17
17
|
root: Rails.root.join("modules/foo"),
|
|
18
18
|
entrypoint: "app/package_api", # optional
|
|
19
|
+
rails_engine: true, # optional
|
|
19
20
|
setup: "config/box_setup.rb", # optional
|
|
20
21
|
gemfile: "Gemfile" # optional
|
|
21
22
|
)
|
|
@@ -29,6 +30,10 @@ end
|
|
|
29
30
|
- `entrypoint`
|
|
30
31
|
- public APIを探索するディレクトリ、またはその配下のファイル
|
|
31
32
|
- 未指定時は`app/package_api`
|
|
33
|
+
- `rails_engine`
|
|
34
|
+
- moduleが所有するRails::Engineのroute setを有効にし、Rails runtimeを同じBoxへ読み込む
|
|
35
|
+
- host routerでは`Foo::Engine`ではなく`Torikago::RackEndpoint.new(:foo)`をmountする
|
|
36
|
+
- host routeから`Torikago.action(...)`でControllerを呼ぶ場合は不要
|
|
32
37
|
- `setup`
|
|
33
38
|
- Box boot前に読み込むsetup hook
|
|
34
39
|
- monkey patchやbox固有の初期化処理に使う
|
|
@@ -42,26 +47,101 @@ module側では、公開するPackage APIと、どのmoduleから呼べるかを
|
|
|
42
47
|
```yaml
|
|
43
48
|
exports:
|
|
44
49
|
Foo::ListProductsQuery:
|
|
50
|
+
methods:
|
|
51
|
+
- call
|
|
52
|
+
- execute!
|
|
45
53
|
allowed_callers:
|
|
46
54
|
- baz
|
|
47
55
|
```
|
|
48
56
|
|
|
49
57
|
module自身からの呼び出しとmain boxからの呼び出しは許可されます。`allowed_callers`は、他moduleからの参照だけを制限します。
|
|
50
58
|
|
|
51
|
-
|
|
59
|
+
constructorに引数がない場合は、公開methodを直接指定します。
|
|
52
60
|
|
|
53
61
|
```ruby
|
|
54
|
-
Torikago::Gateway.
|
|
62
|
+
Torikago::Gateway.invoke("Foo::ListProductsQuery", :call)
|
|
55
63
|
|
|
56
|
-
#
|
|
57
|
-
Torikago::Gateway.
|
|
64
|
+
# method引数はmethod名より後ろへ渡す
|
|
65
|
+
Torikago::Gateway.invoke("Bar::SubmitOrderCommand", :execute!, title: "Book")
|
|
58
66
|
```
|
|
59
67
|
|
|
60
|
-
|
|
68
|
+
constructorに引数がある場合は`build`を使います。`build`の引数は`new`だけへ、`invoke`の引数は指定したpublic methodだけへ渡ります。
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
Torikago::Gateway
|
|
72
|
+
.build("Foo::ListProductsQuery", page: 2)
|
|
73
|
+
.invoke(:execute!, per_page: 20)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
対象Box内で`Foo::ListProductsQuery.new(page: 2).public_send(:execute!, per_page: 20)`を実行します。GatewayはBoxをbootする前にclass・method・callerを`package_api.yml`と照合します。private methodは呼べず、constructorや対象methodの例外は包まずそのまま伝播します。
|
|
77
|
+
|
|
78
|
+
`Gateway.call`は削除されました。`Gateway.call("Foo::Query", value)`は`Gateway.invoke("Foo::Query", :call, value)`へ変更し、manifestへ`methods: [call]`を追加してください。`update-package-api`は既存の`methods`を保持し、新規発見したentryには`methods: []`を生成するため、公開methodを明示的に選ぶ必要があります。
|
|
79
|
+
|
|
80
|
+
## Root Moduleの定数参照
|
|
81
|
+
|
|
82
|
+
Registered Moduleから、Railsアプリケーション本体(Root Module)のtop-level定数はmanifestへの宣言なしで参照できます。main boxの同じclass/module objectを共有するため、QueryやCommandの呼び出しだけでなく、継承にも利用できます。
|
|
83
|
+
|
|
84
|
+
Module namespace内から参照するときは、`::`で始まる絶対定数参照を使います。これにより、`Foo::Order`のtypoがRootの`::Order`へ暗黙にfallbackすることを防ぎます。
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
# Railsアプリケーション本体
|
|
88
|
+
class Order
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class CustomerQuery
|
|
92
|
+
def self.call(customer_id:)
|
|
93
|
+
# ...
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# config.register(:foo, ...)されたmodule内
|
|
98
|
+
class Foo::SpecialOrder < ::Order
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
::CustomerQuery.call(customer_id: 1)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
ownershipはtop-level定数単位で判定します。top-level定数の定義元が`config.register(..., root:)`配下なら、その定数は別のModule Boxへ自動公開されません。Root-owned class/moduleは同じオブジェクトを共有するため、そのnamespaceをregistered rootから再オープンして子定数を追加すると、子定数だけを隔離できません。torikagoは検出可能な場合にnamespace全体の共有を拒否しますが、mixed-ownership namespace自体をサポートしません。隔離が必要な定数は、module-ownedなtop-level namespace配下へ配置してください。
|
|
105
|
+
|
|
106
|
+
Module Box内に同名定数がある場合は、そのmodule-local定数が優先されます。Root ModuleからRegistered Module、およびRegistered Module間の呼び出しには、引き続き`Torikago::Gateway`を使用してください。
|
|
61
107
|
|
|
62
108
|
## Example app
|
|
63
109
|
|
|
64
|
-
`example/rails-modular-monolith
|
|
110
|
+
`example/rails-modular-monolith-with-rails-engine/`に、Rails::EngineをBox内で動かすexample appが入っています。
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
# config/routes.rb(host application)
|
|
114
|
+
mount Torikago::RackEndpoint.new(:foo) => "/"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
endpointは現在のlazy bootを維持します。最初のHTTP requestまたはGateway呼び出しでmodule Boxを生成し、以降は同じBoxを再利用します。
|
|
118
|
+
この橋渡しにはRack互換のroute endpointを使います。process全体へRack middlewareを
|
|
119
|
+
追加する仕組みではありません。
|
|
120
|
+
|
|
121
|
+
Controllerの隔離にRails::Engineは必須ではありません。host側のrouteから、
|
|
122
|
+
torikagoがmodule Box内だけで解決するControllerへdispatchできます。
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
# config/initializers/torikago.rb
|
|
126
|
+
Torikago.configure do |config|
|
|
127
|
+
config.register(:qux, root: Rails.root.join("modules/qux"))
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# config/routes.rb(host application)
|
|
131
|
+
get "/qux/showcase" => Torikago.action(
|
|
132
|
+
:qux,
|
|
133
|
+
"Qux::ShowcaseController",
|
|
134
|
+
:show
|
|
135
|
+
)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Controllerの所有moduleは、`config/initializers/torikago.rb`へ登録したmodule名と
|
|
139
|
+
rootで決まり、このhost route方式のために追加の`config.register` optionは必要ありません。
|
|
140
|
+
ただし、現在のRails integrationでは、実際のController classを登録module名から導かれる
|
|
141
|
+
namespace内に置く必要があります。namespaceを持たないRails Controllerへの対応は
|
|
142
|
+
[issue #15](https://github.com/se4weed/torikago/issues/15)で追跡しています。
|
|
143
|
+
Controller、Model、helper、view、Package APIをhost applicationのautoload pathへ
|
|
144
|
+
追加する必要はありません。
|
|
65
145
|
|
|
66
146
|
## 使い方
|
|
67
147
|
|
|
@@ -74,15 +154,15 @@ bundle exec rake test
|
|
|
74
154
|
### example appのテスト
|
|
75
155
|
|
|
76
156
|
```sh
|
|
77
|
-
cd example/rails-modular-monolith
|
|
78
|
-
|
|
157
|
+
cd example/rails-modular-monolith-with-rails-engine
|
|
158
|
+
bundle exec bin/box-rails test
|
|
79
159
|
```
|
|
80
160
|
|
|
81
161
|
### example appの起動
|
|
82
162
|
|
|
83
163
|
```sh
|
|
84
|
-
cd example/rails-modular-monolith
|
|
85
|
-
|
|
164
|
+
cd example/rails-modular-monolith-with-rails-engine
|
|
165
|
+
bundle exec bin/box-rails s
|
|
86
166
|
```
|
|
87
167
|
|
|
88
168
|
`Ruby::Box`を実際に有効にするには`RUBY_BOX=1`が必要です。
|
|
@@ -100,15 +180,17 @@ bundle exec ruby exe/torikago --help
|
|
|
100
180
|
- `torikago init`
|
|
101
181
|
- 対話式で`package_api.yml`と`config/initializers/torikago.rb`を生成する
|
|
102
182
|
- `torikago check`
|
|
103
|
-
- `Gateway.
|
|
183
|
+
- `Gateway.invoke`および`Gateway.build(...).invoke(...)`とmanifestの整合性を検証する
|
|
104
184
|
- `torikago update-package-api [BOX]`
|
|
105
185
|
- 設定済みentrypointから`package_api.yml`を更新する
|
|
106
186
|
|
|
107
|
-
`torikago check`は、`
|
|
187
|
+
`torikago check`は、`Ripper`で静的なGateway呼び出しを走査し、
|
|
108
188
|
|
|
109
189
|
- manifestにそのclassが定義されているか
|
|
190
|
+
- 呼び出すmethodが空でない`methods`配列に定義されているか
|
|
110
191
|
- 呼び出し元moduleが`allowed_callers`に含まれているか
|
|
111
192
|
- manifest上のclassに対応するファイルが存在するか
|
|
193
|
+
- 静的に確認できる場合、公開したinstance methodが実装されているか
|
|
112
194
|
|
|
113
195
|
を確認します。
|
|
114
196
|
|
|
@@ -130,14 +212,19 @@ bundle exec ruby exe/torikago --help
|
|
|
130
212
|
- segfaultや不安定さに遭遇することがある
|
|
131
213
|
- Railsや一部gemとの相性問題がある
|
|
132
214
|
- とくにVM全体へ影響するglobal-effect gemは、きれいに分離しきれない
|
|
133
|
-
-
|
|
215
|
+
- Rails integrationにはprocess-globalなframework stateが残る
|
|
216
|
+
- Rails initializerやnative extensionはBoxごとに完全分離されない
|
|
217
|
+
- 実際のRails Controllerは、現在は登録moduleのnamespace内に置く必要がある
|
|
218
|
+
- namespaceを持たないControllerへの対応はissue #15で追跡中
|
|
134
219
|
|
|
135
220
|
代表的な例外:
|
|
136
221
|
|
|
137
222
|
- `Torikago::DependencyError`
|
|
138
223
|
- 許可されていないmodule間参照
|
|
139
224
|
- `Torikago::PublicApiError`
|
|
140
|
-
- manifestに宣言されていないPackage APIの呼び出し
|
|
225
|
+
- manifestに宣言されていないPackage API classまたはmethodの呼び出し
|
|
226
|
+
- `Torikago::BoxUnavailableError`
|
|
227
|
+
- `RUBY_BOX=1`を指定したが対象Boxを生成・準備できなかった場合。main processへはfallbackしない
|
|
141
228
|
- `Torikago::GemfileOverrideError`
|
|
142
229
|
- Box用Gemfileの解決やactivateに失敗したとき
|
|
143
230
|
|
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`torikago` is a gem for introducing per-module runtime boundaries to Rails modular monoliths. It aims to strengthen runtime isolation with `Ruby::Box`, in addition to the structural boundaries you can already get from tools like `packwerk` and `Rails::Engine`.
|
|
4
4
|
|
|
5
|
-
With `torikago`, module-to-module calls are funneled through `Torikago::Gateway.
|
|
5
|
+
With `torikago`, module-to-module calls are funneled through `Torikago::Gateway.invoke(...)`, and each module declares which Package API classes and methods it exposes and which modules may call them. This makes it easier to prevent unintended cross-module references at runtime.
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
@@ -16,6 +16,7 @@ Torikago.configure do |config|
|
|
|
16
16
|
:foo,
|
|
17
17
|
root: Rails.root.join("modules/foo"),
|
|
18
18
|
entrypoint: "app/package_api", # optional
|
|
19
|
+
rails_engine: true, # optional
|
|
19
20
|
setup: "config/box_setup.rb", # optional
|
|
20
21
|
gemfile: "Gemfile" # optional
|
|
21
22
|
)
|
|
@@ -29,6 +30,10 @@ The main `config.register` options are:
|
|
|
29
30
|
- `entrypoint`
|
|
30
31
|
- the directory, or file under that directory, used to discover public APIs
|
|
31
32
|
- defaults to `app/package_api`
|
|
33
|
+
- `rails_engine`
|
|
34
|
+
- enables the module-owned Rails::Engine route set and loads its Rails runtime into the same Box
|
|
35
|
+
- mount `Torikago::RackEndpoint.new(:foo)` in the host router instead of mounting `Foo::Engine`
|
|
36
|
+
- not required when host routes dispatch controllers with `Torikago.action(...)`
|
|
32
37
|
- `setup`
|
|
33
38
|
- a setup hook loaded before Box boot completes
|
|
34
39
|
- useful for monkey patches or Box-specific initialization
|
|
@@ -42,26 +47,105 @@ On the module side, declare the Package APIs you expose and which modules may ca
|
|
|
42
47
|
```yaml
|
|
43
48
|
exports:
|
|
44
49
|
Foo::ListProductsQuery:
|
|
50
|
+
methods:
|
|
51
|
+
- call
|
|
52
|
+
- execute!
|
|
45
53
|
allowed_callers:
|
|
46
54
|
- baz
|
|
47
55
|
```
|
|
48
56
|
|
|
49
57
|
Calls from the module itself and from the main box are allowed implicitly. `allowed_callers` only restricts calls coming from other modules.
|
|
50
58
|
|
|
51
|
-
|
|
59
|
+
For an argumentless constructor, invoke the exported public method directly:
|
|
52
60
|
|
|
53
61
|
```ruby
|
|
54
|
-
Torikago::Gateway.
|
|
62
|
+
Torikago::Gateway.invoke("Foo::ListProductsQuery", :call)
|
|
55
63
|
|
|
56
|
-
#
|
|
57
|
-
Torikago::Gateway.
|
|
64
|
+
# arguments after the method name go to that method
|
|
65
|
+
Torikago::Gateway.invoke("Bar::SubmitOrderCommand", :execute!, title: "Book")
|
|
58
66
|
```
|
|
59
67
|
|
|
60
|
-
`
|
|
68
|
+
Use `build` when the constructor takes arguments. `build` arguments go only to `new`; `invoke` arguments go only to the selected public method:
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
Torikago::Gateway
|
|
72
|
+
.build("Foo::ListProductsQuery", page: 2)
|
|
73
|
+
.invoke(:execute!, per_page: 20)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This runs `Foo::ListProductsQuery.new(page: 2).public_send(:execute!, per_page: 20)` entirely inside the target Box. Before booting that Box, Gateway checks the class, method, and caller against `package_api.yml`. Private methods cannot be invoked and target constructor/method exceptions are propagated unchanged.
|
|
77
|
+
|
|
78
|
+
`Gateway.call` has been removed. Migrate `Gateway.call("Foo::Query", value)` to `Gateway.invoke("Foo::Query", :call, value)`, and add `methods: [call]` to its manifest entry. `update-package-api` preserves existing `methods`; newly discovered entries use `methods: []` so the public surface must be chosen explicitly.
|
|
79
|
+
|
|
80
|
+
## Referencing Root Module constants
|
|
81
|
+
|
|
82
|
+
A Registered Module can reference top-level constants from the Rails application (the Root Module) without declaring them in a manifest. Torikago shares the same class or module object from the main Box, so Root constants can be used for inheritance as well as Query or Command calls.
|
|
83
|
+
|
|
84
|
+
Use an absolute constant reference beginning with `::` from inside a module namespace. This prevents a typo such as `Foo::Order` from silently falling back to the Root `::Order`.
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
# Rails application
|
|
88
|
+
class Order
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class CustomerQuery
|
|
92
|
+
def self.call(customer_id:)
|
|
93
|
+
# ...
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Inside a config.register(:foo, ...) module
|
|
98
|
+
class Foo::SpecialOrder < ::Order
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
::CustomerQuery.call(customer_id: 1)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Ownership is atomic at the top-level constant. A top-level constant whose definition is below a `config.register(..., root:)` path is not exposed automatically to another Module Box. Because a Root-owned class or module is shared as the same object, reopening that namespace from a registered root cannot isolate only the newly added child constants. Torikago rejects the whole namespace when it can detect this conflict, but mixed-ownership namespaces are not supported. Put constants that need isolation below a module-owned top-level namespace instead.
|
|
105
|
+
|
|
106
|
+
A module-local constant with the same name takes precedence. Calls from the Root Module to a Registered Module, and calls between Registered Modules, must still use `Torikago::Gateway`.
|
|
61
107
|
|
|
62
108
|
## Example app
|
|
63
109
|
|
|
64
|
-
|
|
110
|
+
The Rails::Engine confinement example lives in
|
|
111
|
+
`example/rails-modular-monolith-with-rails-engine/`.
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
# config/routes.rb (host application)
|
|
115
|
+
mount Torikago::RackEndpoint.new(:foo) => "/"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The endpoint preserves lazy boot: the module Box is created on the first HTTP
|
|
119
|
+
request or Gateway invocation and reused afterward.
|
|
120
|
+
Torikago uses Rack-compatible route endpoints for this bridge; it does not add
|
|
121
|
+
process-wide Rack middleware.
|
|
122
|
+
|
|
123
|
+
Rails::Engine is optional for controller isolation. A host-owned route can
|
|
124
|
+
dispatch to a controller constant that Torikago resolves only inside the module
|
|
125
|
+
Box:
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
# config/initializers/torikago.rb
|
|
129
|
+
Torikago.configure do |config|
|
|
130
|
+
config.register(:qux, root: Rails.root.join("modules/qux"))
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# config/routes.rb (host application)
|
|
134
|
+
get "/qux/showcase" => Torikago.action(
|
|
135
|
+
:qux,
|
|
136
|
+
"Qux::ShowcaseController",
|
|
137
|
+
:show
|
|
138
|
+
)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The module name and root registered in `config/initializers/torikago.rb` identify
|
|
142
|
+
the owner, and no additional `config.register` option is required for this
|
|
143
|
+
host-route mode. The current Rails integration still requires real controller
|
|
144
|
+
classes to live under the namespace derived from the registered module name.
|
|
145
|
+
Support for non-namespaced Rails controllers is tracked in
|
|
146
|
+
[issue #15](https://github.com/se4weed/torikago/issues/15). Controllers, models,
|
|
147
|
+
helpers, views, and Package APIs stay under the registered module root; they do
|
|
148
|
+
not need to be added to the host application's autoload paths.
|
|
65
149
|
|
|
66
150
|
## Usage
|
|
67
151
|
|
|
@@ -74,15 +158,15 @@ bundle exec rake test
|
|
|
74
158
|
### Run example app tests
|
|
75
159
|
|
|
76
160
|
```sh
|
|
77
|
-
cd example/rails-modular-monolith
|
|
78
|
-
|
|
161
|
+
cd example/rails-modular-monolith-with-rails-engine
|
|
162
|
+
bundle exec bin/box-rails test
|
|
79
163
|
```
|
|
80
164
|
|
|
81
165
|
### Start the example app
|
|
82
166
|
|
|
83
167
|
```sh
|
|
84
|
-
cd example/rails-modular-monolith
|
|
85
|
-
|
|
168
|
+
cd example/rails-modular-monolith-with-rails-engine
|
|
169
|
+
bundle exec bin/box-rails s
|
|
86
170
|
```
|
|
87
171
|
|
|
88
172
|
`RUBY_BOX=1` is required to actually enable `Ruby::Box`.
|
|
@@ -100,15 +184,17 @@ Main commands:
|
|
|
100
184
|
- `torikago init`
|
|
101
185
|
- interactively generate `package_api.yml` files and `config/initializers/torikago.rb`
|
|
102
186
|
- `torikago check`
|
|
103
|
-
- validate `Gateway.
|
|
187
|
+
- validate `Gateway.invoke` and `Gateway.build(...).invoke(...)` usage against manifests
|
|
104
188
|
- `torikago update-package-api [BOX]`
|
|
105
189
|
- regenerate `package_api.yml` from the configured entrypoint
|
|
106
190
|
|
|
107
|
-
`torikago check`
|
|
191
|
+
`torikago check` uses `Ripper` to scan static Gateway invocations and verifies:
|
|
108
192
|
|
|
109
193
|
- the class is declared in a manifest
|
|
194
|
+
- the invoked method is listed in the non-empty `methods` array
|
|
110
195
|
- the caller module is included in `allowed_callers`
|
|
111
196
|
- the manifest entry has a matching implementation file
|
|
197
|
+
- the exported public instance method is defined when it can be checked statically
|
|
112
198
|
|
|
113
199
|
## About `RUBY_BOX=1` and boot
|
|
114
200
|
|
|
@@ -128,14 +214,19 @@ These are pragmatic workarounds for the current example app, not a finalized lon
|
|
|
128
214
|
- segfaults and instability can happen
|
|
129
215
|
- Some gems do not cooperate well with this model
|
|
130
216
|
- especially global-effect gems that influence the whole VM
|
|
131
|
-
-
|
|
217
|
+
- Rails integration still relies on process-global framework state
|
|
218
|
+
- Rails initializers and native extensions are not completely isolated per Box
|
|
219
|
+
- Real Rails controllers currently need the registered module namespace
|
|
220
|
+
- non-namespaced controller support is tracked in issue #15
|
|
132
221
|
|
|
133
222
|
Common errors:
|
|
134
223
|
|
|
135
224
|
- `Torikago::DependencyError`
|
|
136
225
|
- an unauthorized cross-module reference
|
|
137
226
|
- `Torikago::PublicApiError`
|
|
138
|
-
- calling a Package API that is not declared in the manifest
|
|
227
|
+
- calling a Package API class or method that is not declared in the manifest
|
|
228
|
+
- `Torikago::BoxUnavailableError`
|
|
229
|
+
- `RUBY_BOX=1` was requested but the target Box could not be created or prepared; Torikago does not fall back to the main process
|
|
139
230
|
- `Torikago::GemfileOverrideError`
|
|
140
231
|
- failure while resolving or activating a Box-specific Gemfile override
|
|
141
232
|
|