hub_kernel 0.14.0 → 0.15.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/Rakefile +2 -0
- data/lib/hub_kernel/version.rb +1 -1
- data/the_local/agents/hub_kernel-develop.md +157 -0
- data/the_local/agents/hub_kernel-info.md +43 -0
- data/the_local/agents/hub_kernel-install.md +118 -0
- data/the_local/interface.yml +42 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 29b5aa4287a6ec25760b3816c4e6db7bc6f856786020bf32819561c854e257ae
|
|
4
|
+
data.tar.gz: a86e10c3eaf85f11c084b27d5bd50e093ebcdd5158ee3c3c49a1b40d0f1143d9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 81344e480c059afc59baba5aa1a2178ecce05603013454621b07f362ca5da7779df35d115f083d005fc01250423445604c5558e81afd2223be6d75c6e528152a
|
|
7
|
+
data.tar.gz: e269e54104dff49dfb4d4ef9478acf54b24b1d63590aeb6bb8bceb913cb90f99524957456e88b09292a24ffa052d0fcb3a078300911612135e643c0a8487267e
|
data/Rakefile
CHANGED
data/lib/hub_kernel/version.rb
CHANGED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hub_kernel-develop
|
|
3
|
+
description: Use PROACTIVELY for writing or changing a hub — generating one, declaring the ports it needs from other hubs, calling those ports from the hub's code, listing the methods outside callers may reach by name, refusing a request with a reason, calling a hub method by name from an interface such as a JSON API, and adding the check that the listed methods match the hub's real methods — MUST BE USED instead of calling another hub's classes directly or hand-writing a name-to-method lookup.
|
|
4
|
+
tools: Read, Write, Edit, Grep
|
|
5
|
+
scope: hubs — a domain gem declares the ports it needs and the methods it exposes, and the host app fills those ports and checks each hub is wired and crosses into no other hub
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
This local writes hubs and the code that calls them by name, following these steps exactly and inventing none. Where a step needs a value only the developer knows, it asks.
|
|
9
|
+
|
|
10
|
+
## What hub_kernel is
|
|
11
|
+
hub_kernel lets a hub, one domain area written as a module, state what it needs from outside itself as named ports and list the methods outside callers may reach by name. The hub's code never names another hub's classes, and an interface such as a JSON API reaches the hub only through its list. Use this local when creating a hub, adding a port, exposing a hub method, calling a hub method by name, or when hub code is about to call another hub directly.
|
|
12
|
+
|
|
13
|
+
## Interface
|
|
14
|
+
- `bin/rails generate hub_kernel:hub` — writes a new hub module with its ports declared, and in a gem adds hub_kernel to the gemspec.
|
|
15
|
+
- `HubKernel::Ports` — the module a hub extends to declare ports.
|
|
16
|
+
- `port` — declares one port by name and the method the hub's own code calls to use it.
|
|
17
|
+
- `HubKernel::Exposes` — the module a hub extends to list the methods callers may reach by name.
|
|
18
|
+
- `exposes` — lists one hub method with the values it takes and whether it writes.
|
|
19
|
+
- `exposed` — looks up one listed method by name and answers its entry, or `nil` when it is not listed.
|
|
20
|
+
- `call_exposed` — calls a listed method by name for a person and an account, after the host's permission check, inside the host's account scope.
|
|
21
|
+
- `HubKernel::Refused` — the error a hub method raises when it will not do what was asked, and its message reaches the caller unchanged.
|
|
22
|
+
- `HubKernel::UnexposedMethodError` — raised by `call_exposed` for a name the hub does not list.
|
|
23
|
+
- `HubKernel::MissingArgumentError` — raised by `call_exposed` for a call with no person, no account, or a value the method requires left out.
|
|
24
|
+
- `HubKernel::NotAllowed` — raised by `call_exposed` when the host's permission check answers `false`, before the method runs.
|
|
25
|
+
- `HubKernel::NonBooleanAnswerError` — raised by `call_exposed` when the host's permission check answers anything but `true` or `false`.
|
|
26
|
+
- `HubKernel::Conformance::Exposed` — a test module that fails naming each listed method the hub has no method for, and each one listed with values it does not take.
|
|
27
|
+
|
|
28
|
+
## How to use it
|
|
29
|
+
|
|
30
|
+
### Start a hub
|
|
31
|
+
1. Ask the developer for the hub's name and, for each thing it needs from another hub, a port name and the method name the hub's code will call. Do not invent ports.
|
|
32
|
+
|
|
33
|
+
2. Run the generator from the root of the gem or app that will hold the hub, naming each port as `port:method`:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
bin/rails generate hub_kernel:hub Ledger entry_recorder:record_entry
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- In a Rails engine gem it writes the hub under the gem's namespace, such as `app/models/billing/ledger.rb` holding `module Billing::Ledger`, and adds hub_kernel to the gemspec. It writes no test, since the gem never fills its own ports.
|
|
40
|
+
- In an app it writes the hub under `app/models` and the hub's wiring test under `test/models`.
|
|
41
|
+
|
|
42
|
+
The generated hub:
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
module Billing::Ledger
|
|
46
|
+
extend HubKernel::Ports
|
|
47
|
+
|
|
48
|
+
port :entry_recorder, as: :record_entry
|
|
49
|
+
end
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Declare and use a port
|
|
53
|
+
3. Add each new port to the hub with `port`, naming the port and the method the hub's code calls:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
module Supplies
|
|
57
|
+
extend HubKernel::Ports
|
|
58
|
+
|
|
59
|
+
port :spend_recorder, as: :record_spend
|
|
60
|
+
end
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- `port` gives the hub a writer for the port, here `Supplies.spend_recorder=`, which the host app uses to fill it.
|
|
64
|
+
- Filling ports and checking they are filled is the install local's work, not this one's.
|
|
65
|
+
|
|
66
|
+
4. In the hub's code, call the port through its method, passing whatever positional and keyword values the filler takes:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
Supplies.record_spend(amount: 5)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- It returns what the filler returns, and an error the filler raises reaches the caller unchanged.
|
|
73
|
+
- Calling a port the host left unfilled raises an error naming it, such as "Supplies' spend recorder is not wired".
|
|
74
|
+
- Never name another hub's classes in place of a port.
|
|
75
|
+
|
|
76
|
+
### Expose methods
|
|
77
|
+
5. Ask the developer which hub methods outside callers may reach by name, and for each, whether it writes. Do not decide either yourself.
|
|
78
|
+
|
|
79
|
+
6. Write each exposed method as a module method on the hub that takes keyword arguments only, since a call by name passes values as keywords:
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
module Supplies
|
|
83
|
+
extend HubKernel::Exposes
|
|
84
|
+
|
|
85
|
+
exposes :record_purchase, takes: %i[supplier_id bought_on lines], writes: true
|
|
86
|
+
|
|
87
|
+
def self.record_purchase(supplier_id:, bought_on:, lines: [])
|
|
88
|
+
raise HubKernel::Refused, "That supplier is closed" if Supplier.find(supplier_id).closed?
|
|
89
|
+
|
|
90
|
+
# …
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- `takes:` lists every value the method requires, and may list optional ones, as symbols.
|
|
96
|
+
- A method that takes `**` values may be listed with any values, as long as each one it requires is listed.
|
|
97
|
+
- `writes:` is `true` or `false`, and both `takes:` and `writes:` must be given.
|
|
98
|
+
- A hub can extend both `HubKernel::Ports` and `HubKernel::Exposes`.
|
|
99
|
+
|
|
100
|
+
7. When the method will not do what was asked, raise `HubKernel::Refused` with the reason a person should read. The reason reaches the caller unchanged.
|
|
101
|
+
|
|
102
|
+
### Check the exposed list
|
|
103
|
+
8. Add the exposed-list check to the tests of the gem or app that holds the hub, such as `test/models/supplies_exposed_test.rb`:
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
require "hub_kernel/conformance/exposed"
|
|
107
|
+
|
|
108
|
+
class SuppliesExposedTest < ActiveSupport::TestCase
|
|
109
|
+
include HubKernel::Conformance::Exposed
|
|
110
|
+
|
|
111
|
+
hub { Supplies }
|
|
112
|
+
end
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The `require` line is needed because the gem does not load the test modules on its own. This check needs no ports filled, so it runs in a domain gem's own suite.
|
|
116
|
+
|
|
117
|
+
### Call a hub method by name
|
|
118
|
+
9. In the interface that serves callers, such as a JSON API controller, look the method up with `exposed` and call it with `call_exposed`:
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
Supplies.exposed("record_purchase") # => entry with .name, .takes, .writes
|
|
122
|
+
Supplies.exposed("delete_everything") # => nil
|
|
123
|
+
|
|
124
|
+
Supplies.call_exposed("record_purchase",
|
|
125
|
+
values: { supplier_id: 4, bought_on: "2026-10-01", lines: [] },
|
|
126
|
+
person: current_person,
|
|
127
|
+
account: current_account)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
- The name may be a string or a symbol.
|
|
131
|
+
- `values:` is a hash with symbol keys, so symbolize request params before passing them, or every required value is reported missing.
|
|
132
|
+
- Only the values the method is listed with are passed on, and any others are dropped.
|
|
133
|
+
- `person:` and `account:` must both be given and not `nil`.
|
|
134
|
+
- The permission is asked for an action named after the hub, without its namespace, and the method, such as `"supplies:record_purchase"` or `"ledger:record_entry"`.
|
|
135
|
+
- It returns the result of the call made inside the host's account scope.
|
|
136
|
+
|
|
137
|
+
10. A call by name fails in this order, and each failure stops the call:
|
|
138
|
+
1. `HubKernel::MissingArgumentError` when `person:` or `account:` is `nil`.
|
|
139
|
+
2. `HubKernel::UnexposedMethodError` when the hub does not list the name.
|
|
140
|
+
3. An error naming the host's permission check when the host has not set it.
|
|
141
|
+
4. `HubKernel::NonBooleanAnswerError` when the permission check answers anything but `true` or `false`.
|
|
142
|
+
5. `HubKernel::NotAllowed` when the permission check answers `false`.
|
|
143
|
+
6. `HubKernel::MissingArgumentError` naming each required value left out, such as "Give supplier_id".
|
|
144
|
+
7. An error naming the host's account scope when the host has not set it.
|
|
145
|
+
8. `HubKernel::Refused`, or any other error, raised by the hub method itself.
|
|
146
|
+
|
|
147
|
+
11. Ask the developer how the interface answers each of those failures, such as which HTTP status each one returns. Do not pick the responses yourself. Show a `HubKernel::Refused` message to the caller as it is.
|
|
148
|
+
|
|
149
|
+
12. Run the test suite and confirm the conventions below hold.
|
|
150
|
+
|
|
151
|
+
## Conventions
|
|
152
|
+
- A hub's code reaches another hub only through a port, never by naming its classes.
|
|
153
|
+
- An outside caller reaches a hub only through `call_exposed`, never by sending a name to the hub with `public_send` or `send`.
|
|
154
|
+
- Every exposed method is listed with `exposes`, and the exposed-list check passes.
|
|
155
|
+
- When an exposed method gains, loses or renames a keyword, update its `takes:` in the same change.
|
|
156
|
+
- When a hub gains a port, tell the developer every host app must fill it, since calling it unfilled raises an error and the host's start check fails.
|
|
157
|
+
- Adding the gem to a host, filling ports, running the start check, setting the permission check and the account scope, and the host's hub and crossing checks belong to the install local and are out of scope here.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hub_kernel-info
|
|
3
|
+
description: Use to learn what hub_kernel offers — hubs, the ports a hub declares, the methods it lets outside callers reach by name, and the checks that a host app has filled every hub and that no hub reaches into another.
|
|
4
|
+
tools: Read
|
|
5
|
+
scope: hubs — a domain gem declares the ports it needs and the methods it exposes, and the host app fills those ports and checks each hub is wired and crosses into no other hub
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
This local explains hub_kernel and the words it uses. It makes no changes and gives no steps.
|
|
9
|
+
|
|
10
|
+
## What hub_kernel is
|
|
11
|
+
|
|
12
|
+
hub_kernel splits a Rails app into hubs, where each hub is one area of the domain, such as supplies or finance, usually shipped in its own domain gem. A hub states what it needs from outside itself as named ports, and the host app decides what fills each one, so a hub never names another hub's code directly.
|
|
13
|
+
|
|
14
|
+
A hub also lists the methods outside callers may reach by name, with the values each takes and whether it writes. An interface such as a JSON API calls through that list, and every call is checked against the host's permission rule and run inside the host's account scope. Reach for hub_kernel when an app has several domain areas that should talk to each other only through declared entry points, and you want the app to refuse to start, or the suite to fail, when that is not true.
|
|
15
|
+
|
|
16
|
+
## Interface
|
|
17
|
+
|
|
18
|
+
This local documents no commands. The surface belongs to the other two locals:
|
|
19
|
+
|
|
20
|
+
- **hub_kernel-install** owns everything the host app does: adding the gem, filling each hub's ports, running the start check, setting the permission rule and the account scope, and adding the hub check and the crossing check to the host's tests.
|
|
21
|
+
- **hub_kernel-develop** owns everything a hub's author does: generating a hub, declaring its ports, listing the methods callers may reach by name, refusing a request, and adding the check that the listed methods match the hub's real methods.
|
|
22
|
+
|
|
23
|
+
## How to use it
|
|
24
|
+
|
|
25
|
+
Decide which side you are on:
|
|
26
|
+
|
|
27
|
+
- You are wiring hubs into an app, or the app will not start because something is not wired: use **hub_kernel-install**.
|
|
28
|
+
- You are writing or changing a hub, inside a domain gem or the app: use **hub_kernel-develop**.
|
|
29
|
+
|
|
30
|
+
## Conventions
|
|
31
|
+
|
|
32
|
+
- **Hub** — one domain area, written as a module. In a domain gem it sits under the gem's namespace, such as Billing::Ledger.
|
|
33
|
+
- **Ports** — what a hub needs from outside. Each has a name and the method the hub's own code calls, such as a spend recorder called as record_spend.
|
|
34
|
+
- **Filling ports** — the host app sets each of a hub's ports to any callable, usually another hub's method, in its setup that runs again on every code reload. Ports are "wired" once they are filled.
|
|
35
|
+
- **Start check** — the app refuses to start while any hub's ports are not wired, and names each one, such as "Supplies' spend recorder is not wired".
|
|
36
|
+
- **Hub check** — a host test that fails naming each of a hub's ports left unfilled or filled with something that cannot be called. A domain gem never runs it, since the gem never fills its own ports.
|
|
37
|
+
- **Call by name** — a caller reaches a hub method by its name as a string, with the values sent, the person, and the account. Unknown names, a missing person or account, and missing required values are refused.
|
|
38
|
+
- **Action** — the name a permission is asked for, made of the hub and the method, such as supplies:record_purchase.
|
|
39
|
+
- **Permission check** — one host-wide rule answering true or false for a person, an action, and an account. Any other answer is an error.
|
|
40
|
+
- **Account scope** — one host-wide wrapper that runs each call by name inside the account it was made for.
|
|
41
|
+
- **Refusing** — what a hub does when it will not do what was asked, and its reason reaches the caller unchanged.
|
|
42
|
+
- **Crossing** — a file in one hub naming a class another hub owns. A constant inside that class counts.
|
|
43
|
+
- **Crossing map** — the host's statement of which classes each hub owns, plus the classes shared by all, the host's own layer, each hub's interface module, and any namespace a hub owns whole. Only the host's layer may name a hub's interface module, and a view belongs to the hub that owns its controller.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hub_kernel-install
|
|
3
|
+
description: Use to hook hub_kernel into a project — adding the gem, filling each hub's ports and running the start check, listing the loaded hubs, setting the permission check and the account scope, and adding the hub check and the crossing check to the host's tests.
|
|
4
|
+
tools: Bash, Read, Edit
|
|
5
|
+
scope: hubs — a domain gem declares the ports it needs and the methods it exposes, and the host app fills those ports and checks each hub is wired and crosses into no other hub
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
This local follows these steps exactly and invents none. Where a step needs a value only the developer knows, it asks.
|
|
9
|
+
|
|
10
|
+
## What hub_kernel is
|
|
11
|
+
hub_kernel lets a Rails host app fill the ports each hub declares, refuse to start while a port is unfilled, answer permission and account scope for calls made by name, and fail its suite when one hub's code names a class another hub owns. Hook it in when the app uses hubs, its own or ones shipped in domain gems.
|
|
12
|
+
|
|
13
|
+
## Interface
|
|
14
|
+
- `gem "hub_kernel"` — the Gemfile line that adds the gem to the host app.
|
|
15
|
+
- `HubKernel::Hubs.check!` — raises `HubKernel::UnwiredPortError` naming every unfilled port of every loaded hub, one per line, such as "Supplies' spend recorder is not wired".
|
|
16
|
+
- `HubKernel::Hubs.list` — the hubs that have loaded and declared at least one port.
|
|
17
|
+
- `HubKernel::UnwiredPortError` — raised by the start check, by calling an unfilled port, and by a call by name while the permission check or the account scope is unset.
|
|
18
|
+
- `HubKernel::Authz.check` — the host-wide permission rule, a callable taking a person, an action and an account and answering `true` or `false`.
|
|
19
|
+
- `HubKernel::Context.scope` — the host-wide account scope, a callable taking an account and a block and running the block inside that account.
|
|
20
|
+
- `HubKernel::Conformance::Hub` — a test module that fails naming each of one hub's ports left unfilled or filled with something that cannot be called.
|
|
21
|
+
- `HubKernel::Crossings` — the crossing map: which classes each hub owns, the shared classes, the host's layer, each hub's interface module, and any namespace a hub owns whole.
|
|
22
|
+
- `HubKernel::Conformance::Crossings` — a test module that reads the host's files against the crossing map and fails on each crossing, each unowned class, each class owned twice, and each mapped class that does not exist.
|
|
23
|
+
|
|
24
|
+
## How to use it
|
|
25
|
+
1. Add the gem to the host's `Gemfile`, then run `bundle install`:
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
gem "hub_kernel"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
2. List the hubs the app uses and each port they declare. Ask the developer what fills each port, such as another hub's method. Do not pick a filler yourself.
|
|
32
|
+
|
|
33
|
+
3. Fill every port and run the start check in a `to_prepare` block in an initializer, such as `config/initializers/hubs.rb`, so both run again after every code reload:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
Rails.application.config.to_prepare do
|
|
37
|
+
Supplies.spend_recorder = Finance.method(:record_spend)
|
|
38
|
+
Billing::Ledger.entry_recorder = Finance.method(:record_entry)
|
|
39
|
+
HubKernel::Hubs.check!
|
|
40
|
+
end
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
A port accepts any object that responds to `call`. The start check only sees hubs that have loaded, so name every hub in this block. Run `HubKernel::Hubs.list` in `bin/rails console` to see which hubs it saw.
|
|
44
|
+
|
|
45
|
+
4. Ask the developer whether any interface, such as a JSON API, calls hub methods by name. If not, skip to step 6.
|
|
46
|
+
|
|
47
|
+
5. Ask the developer for the app's permission rule and the account scope, since neither has a default. Set both once, in the same initializer:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
HubKernel::Authz.check = ->(person, action, account) { Permissions.allow?(person, action, account) }
|
|
51
|
+
HubKernel::Context.scope = ->(account, &call) { Current.set(account: account, &call) }
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- The action is a string made of the hub and the method, such as `"supplies:record_purchase"`.
|
|
55
|
+
- The permission check must answer exactly `true` or `false`, and any other answer makes the call raise an error.
|
|
56
|
+
- The account scope must take the block and run it, or the hub method never runs.
|
|
57
|
+
|
|
58
|
+
6. Add one hub check per hub to the host's tests, such as `test/hubs/supplies_hub_test.rb`:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
require "hub_kernel/conformance/hub"
|
|
62
|
+
|
|
63
|
+
class SuppliesHubTest < ActiveSupport::TestCase
|
|
64
|
+
include HubKernel::Conformance::Hub
|
|
65
|
+
|
|
66
|
+
hub { Supplies }
|
|
67
|
+
end
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The `require` line is needed because the gem does not load the test modules on its own.
|
|
71
|
+
|
|
72
|
+
7. Ask the developer for the crossing map, since only they know which hub owns which class:
|
|
73
|
+
- which classes each hub owns;
|
|
74
|
+
- which classes all hubs share, such as a base controller;
|
|
75
|
+
- which hub name stands for the host's own layer;
|
|
76
|
+
- each hub's interface module;
|
|
77
|
+
- any namespace a hub owns whole, such as a hub gem's `Billing`.
|
|
78
|
+
|
|
79
|
+
Also ask which files the check should read, and which to skip, such as the file that defines the interface modules.
|
|
80
|
+
|
|
81
|
+
8. Add the crossing check to the host's tests, such as `test/hub_crossings_test.rb`:
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
require "hub_kernel/conformance/crossings"
|
|
85
|
+
|
|
86
|
+
class HubCrossingsTest < ActiveSupport::TestCase
|
|
87
|
+
include HubKernel::Conformance::Crossings
|
|
88
|
+
|
|
89
|
+
crossings files: "app/{models,controllers,jobs,views}/shop/**/*.{rb,erb}", except: [ "app/models/shop/hubs.rb" ] do
|
|
90
|
+
HubKernel::Crossings.new(
|
|
91
|
+
owners: { supplies: %w[Shop::Purchase Shop::PurchasesController], finance: %w[Shop::Expense], shop: %w[Shop::Home] },
|
|
92
|
+
shared: %w[Shop::BaseController],
|
|
93
|
+
host_layer: :shop,
|
|
94
|
+
interfaces: { supplies: "Shop::Hubs::Supplies", finance: "Shop::Hubs::Finance" },
|
|
95
|
+
namespaces: { billing: %w[Billing] }
|
|
96
|
+
)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- `files:` is a glob read from `Rails.root`, and defaults to `"app/**/*.{rb,erb}"`.
|
|
102
|
+
- `root:` changes the folder the glob is read from.
|
|
103
|
+
- `except:` lists paths to skip, written relative to that folder.
|
|
104
|
+
- Hub names are symbols, and class names are strings.
|
|
105
|
+
|
|
106
|
+
9. Run the app and the test suite, and confirm the checks below.
|
|
107
|
+
|
|
108
|
+
## Conventions
|
|
109
|
+
- After installing, `bin/rails runner 'HubKernel::Hubs.check!'` exits with no error, and every hub check and the crossing check pass.
|
|
110
|
+
- The start check reports unfilled ports only, while the hub check also reports a port filled with something that cannot be called.
|
|
111
|
+
- A domain gem never runs the hub check, since it never fills its own ports, so the hub check always lives in the host's tests.
|
|
112
|
+
- A view belongs to the hub that owns its controller, then to the hub that owns the record its folder is named after, and otherwise to the host's layer.
|
|
113
|
+
- A constant inside another hub's class counts as naming that class.
|
|
114
|
+
- Only the host's layer may name a hub's interface module.
|
|
115
|
+
- A class listed by name under `owners` belongs to that hub even inside another hub's namespace.
|
|
116
|
+
- The crossing check fails with "The crossing check found no files to read" when its `files:` pattern matches nothing the map owns, so fix the pattern or the map rather than the test.
|
|
117
|
+
- When a hub gains a port, fill it in the `to_prepare` block. When a class is added, renamed or removed, update the crossing map, since the check fails on a class no hub owns and on a mapped class that no longer exists.
|
|
118
|
+
- Writing a hub, declaring its ports, and listing the methods it exposes are not part of installing and are out of scope here.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
scope: hubs — a domain gem declares the ports it needs and the methods it exposes, and the host app fills those ports and checks each hub is wired and crosses into no other hub
|
|
2
|
+
|
|
3
|
+
install:
|
|
4
|
+
- gem "hub_kernel"
|
|
5
|
+
- HubKernel::Hubs.check!
|
|
6
|
+
- HubKernel::Hubs.list
|
|
7
|
+
- HubKernel::UnwiredPortError
|
|
8
|
+
- HubKernel::Authz.check
|
|
9
|
+
- HubKernel::Context.scope
|
|
10
|
+
- HubKernel::Conformance::Hub
|
|
11
|
+
- HubKernel::Crossings
|
|
12
|
+
- HubKernel::Conformance::Crossings
|
|
13
|
+
|
|
14
|
+
develop:
|
|
15
|
+
- bin/rails generate hub_kernel:hub
|
|
16
|
+
- HubKernel::Ports
|
|
17
|
+
- port
|
|
18
|
+
- HubKernel::Exposes
|
|
19
|
+
- exposes
|
|
20
|
+
- exposed
|
|
21
|
+
- call_exposed
|
|
22
|
+
- HubKernel::Refused
|
|
23
|
+
- HubKernel::UnexposedMethodError
|
|
24
|
+
- HubKernel::MissingArgumentError
|
|
25
|
+
- HubKernel::NotAllowed
|
|
26
|
+
- HubKernel::NonBooleanAnswerError
|
|
27
|
+
- HubKernel::Conformance::Exposed
|
|
28
|
+
|
|
29
|
+
sources:
|
|
30
|
+
- lib/hub_kernel.rb
|
|
31
|
+
- lib/hub_kernel/ports.rb
|
|
32
|
+
- lib/hub_kernel/hubs.rb
|
|
33
|
+
- lib/hub_kernel/exposes.rb
|
|
34
|
+
- lib/hub_kernel/action.rb
|
|
35
|
+
- lib/hub_kernel/authz.rb
|
|
36
|
+
- lib/hub_kernel/context.rb
|
|
37
|
+
- lib/hub_kernel/crossings.rb
|
|
38
|
+
- lib/hub_kernel/conformance/hub.rb
|
|
39
|
+
- lib/hub_kernel/conformance/exposed.rb
|
|
40
|
+
- lib/hub_kernel/conformance/crossings.rb
|
|
41
|
+
- lib/generators/hub_kernel/hub/hub_generator.rb
|
|
42
|
+
- README.md
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hub_kernel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.15.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- tylercschneider
|
|
@@ -55,6 +55,10 @@ files:
|
|
|
55
55
|
- lib/hub_kernel/markup.rb
|
|
56
56
|
- lib/hub_kernel/ports.rb
|
|
57
57
|
- lib/hub_kernel/version.rb
|
|
58
|
+
- the_local/agents/hub_kernel-develop.md
|
|
59
|
+
- the_local/agents/hub_kernel-info.md
|
|
60
|
+
- the_local/agents/hub_kernel-install.md
|
|
61
|
+
- the_local/interface.yml
|
|
58
62
|
homepage: https://github.com/tylercschneider/hub_kernel
|
|
59
63
|
licenses:
|
|
60
64
|
- MIT
|