standard_ledger 0.5.0 → 0.5.1
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/CHANGELOG.md +22 -1
- data/README.md +7 -4
- data/lib/standard_ledger/engine.rb +4 -2
- data/lib/standard_ledger/rspec/matchers.rb +53 -3
- data/lib/standard_ledger/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 74163637dfcb14c019f6481391644b45849cad04108b580e5a8de524720ed1ca
|
|
4
|
+
data.tar.gz: d022e52db16ba6e838c47c9e94ead8fa1f876afb37ffa5f8b3b5390d4877b157
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e9b7f1b51851431f1e44c5129dac815517ce064860a83d210d8f94ed8b30e7a90dc393d92af4e702516fcc0a804e613cc7859d582b4ce042d31220970835fb5d
|
|
7
|
+
data.tar.gz: c11d063fd3e01c8feb06176742df0167ff363c375de4c03d979a7dee52ca21e1388917fd2e1b10e770409b2a703aa5f223f496bc8f2619368b40fa0c323a1cb9
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,26 @@ project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.5.1] - 2026-09-24
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- The `post_ledger_entry` RSpec matcher now listens on the channel
|
|
13
|
+
`StandardLedger::EventEmitter` emits through. It only subscribed to
|
|
14
|
+
`ActiveSupport::Notifications`, but on Rails 8.1+ the gem emits through
|
|
15
|
+
`Rails.event.notify`, so the matcher saw no events at all: every positive
|
|
16
|
+
expectation failed and every `not_to post_ledger_entry` passed without
|
|
17
|
+
checking anything. When `EventEmitter.rails_event_available?` is true, the
|
|
18
|
+
matcher now subscribes a collector to `Rails.event` for the block and
|
|
19
|
+
unsubscribes it afterwards.
|
|
20
|
+
|
|
21
|
+
### Documentation
|
|
22
|
+
- README **Testing** section (and `AGENTS.md`) said the RSpec support hook
|
|
23
|
+
calls `StandardLedger.reset!`. It calls `reset_mode_overrides!`, which keeps
|
|
24
|
+
host initializer configuration intact.
|
|
25
|
+
- The engine initializer comment now tells hosts to subscribe via
|
|
26
|
+
`Rails.event.subscribe` on Rails 8.1+ rather than
|
|
27
|
+
`ActiveSupport::Notifications.subscribe`.
|
|
28
|
+
|
|
9
29
|
## [0.5.0] - 2026-09-22
|
|
10
30
|
|
|
11
31
|
### Changed
|
|
@@ -446,7 +466,8 @@ roadmap.
|
|
|
446
466
|
and `:trigger` (host-owned, gem records rebuild SQL).
|
|
447
467
|
- `standard_ledger:doctor` rake task (verifies trigger presence, etc.).
|
|
448
468
|
|
|
449
|
-
[Unreleased]: https://github.com/rarebit-one/standard_ledger/compare/v0.5.
|
|
469
|
+
[Unreleased]: https://github.com/rarebit-one/standard_ledger/compare/v0.5.1...HEAD
|
|
470
|
+
[0.5.1]: https://github.com/rarebit-one/standard_ledger/compare/v0.5.0...v0.5.1
|
|
450
471
|
[0.5.0]: https://github.com/rarebit-one/standard_ledger/compare/v0.4.0...v0.5.0
|
|
451
472
|
[0.4.0]: https://github.com/rarebit-one/standard_ledger/compare/v0.3.0...v0.4.0
|
|
452
473
|
[0.3.0]: https://github.com/rarebit-one/standard_ledger/compare/v0.2.0...v0.3.0
|
data/README.md
CHANGED
|
@@ -381,12 +381,15 @@ The gem ships an opt-in RSpec support file. Hosts add this to their
|
|
|
381
381
|
require "standard_ledger/rspec"
|
|
382
382
|
```
|
|
383
383
|
|
|
384
|
-
That registers a `before(:each)` hook that calls
|
|
385
|
-
between examples (so
|
|
384
|
+
That registers a `before(:each)` hook that calls
|
|
385
|
+
`StandardLedger.reset_mode_overrides!` between examples (so `with_modes`
|
|
386
|
+
overrides don't leak). It deliberately does not call the full `reset!`, which
|
|
387
|
+
would wipe configuration your initializers set up. It also exposes:
|
|
386
388
|
|
|
387
389
|
- `post_ledger_entry(EntryClass).with(...)` — a block matcher that
|
|
388
|
-
subscribes to the `<namespace>.entry.created`
|
|
389
|
-
|
|
390
|
+
subscribes to the `<namespace>.entry.created` event for the duration of
|
|
391
|
+
the block, on the same channel the gem emits through (`Rails.event` on
|
|
392
|
+
Rails 8.1+, `ActiveSupport::Notifications` otherwise), and asserts an entry of the expected class was
|
|
390
393
|
written (with optional `kind:`/`targets:`/`attrs:` constraints).
|
|
391
394
|
|
|
392
395
|
```ruby
|
|
@@ -12,8 +12,10 @@ module StandardLedger
|
|
|
12
12
|
|
|
13
13
|
initializer "standard_ledger.notifications", after: :load_config_initializers do
|
|
14
14
|
# Notification wiring lands here in a follow-up PR. Today this is a
|
|
15
|
-
# no-op — the gem emits events but ships no internal subscribers
|
|
16
|
-
#
|
|
15
|
+
# no-op — the gem emits events but ships no internal subscribers. On
|
|
16
|
+
# Rails 8.1+ events go through `Rails.event.notify`, so hosts subscribe
|
|
17
|
+
# with `Rails.event.subscribe`; on older Rails they fall back to
|
|
18
|
+
# ActiveSupport::Notifications (see StandardLedger::EventEmitter).
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
# Engines auto-discover `lib/tasks/*.rake` in most Rails versions, but
|
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
require "rspec/expectations"
|
|
2
2
|
require "active_support/notifications"
|
|
3
|
+
require "standard_ledger/event_emitter"
|
|
4
|
+
|
|
5
|
+
module StandardLedger
|
|
6
|
+
module RSpec
|
|
7
|
+
# Collects `<namespace>.entry.created` payloads from `Rails.event` for the
|
|
8
|
+
# duration of a `post_ledger_entry` block. A dedicated object (not a
|
|
9
|
+
# Proc) because `EventReporter#unsubscribe` matches with `===`.
|
|
10
|
+
#
|
|
11
|
+
# @api private
|
|
12
|
+
class RailsEventCollector
|
|
13
|
+
attr_reader :payloads
|
|
14
|
+
|
|
15
|
+
def initialize(event_name)
|
|
16
|
+
@event_name = event_name
|
|
17
|
+
@payloads = []
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def emit(event)
|
|
21
|
+
@payloads << event[:payload] if event[:name] == @event_name
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
3
26
|
|
|
4
27
|
# `post_ledger_entry` — assert that a block of code wrote a ledger entry.
|
|
5
28
|
#
|
|
@@ -22,7 +45,9 @@ require "active_support/notifications"
|
|
|
22
45
|
# expect { ... }.to_not post_ledger_entry(VoucherRecord)
|
|
23
46
|
#
|
|
24
47
|
# The matcher subscribes to `<namespace>.entry.created` for the duration of
|
|
25
|
-
# the block,
|
|
48
|
+
# the block, on whichever channel `StandardLedger::EventEmitter` emits through
|
|
49
|
+
# (`Rails.event` on Rails 8.1+, `ActiveSupport::Notifications` otherwise),
|
|
50
|
+
# captures every fired event, and asserts that at least one event
|
|
26
51
|
# matched the expected class (and, when chained, the expected `kind`,
|
|
27
52
|
# `targets`, and `attrs`). The notification namespace is read from
|
|
28
53
|
# `StandardLedger.config.notification_namespace`, so a host that customised
|
|
@@ -71,10 +96,35 @@ RSpec::Matchers.define :post_ledger_entry do |entry_class|
|
|
|
71
96
|
# Helpers
|
|
72
97
|
# ----------------------------------------------------------------------
|
|
73
98
|
|
|
99
|
+
# Listens on the same channel `EventEmitter.emit` picks. Listening only on
|
|
100
|
+
# AS::Notifications meant that on Rails 8.1 (where emit goes through
|
|
101
|
+
# `Rails.event`) the matcher saw nothing — every positive expectation
|
|
102
|
+
# failed and every negated one passed vacuously.
|
|
74
103
|
def capture_entry_created_events(&block)
|
|
104
|
+
if StandardLedger::EventEmitter.rails_event_available?
|
|
105
|
+
capture_via_rails_event(&block)
|
|
106
|
+
else
|
|
107
|
+
capture_via_notifications(&block)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def capture_via_rails_event(&block)
|
|
112
|
+
bus = ::Rails.event
|
|
113
|
+
collector = StandardLedger::RSpec::RailsEventCollector.new(notification_event_name)
|
|
114
|
+
bus.subscribe(collector)
|
|
115
|
+
|
|
116
|
+
begin
|
|
117
|
+
block.call
|
|
118
|
+
ensure
|
|
119
|
+
bus.unsubscribe(collector)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
collector.payloads
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def capture_via_notifications(&block)
|
|
75
126
|
events = []
|
|
76
|
-
|
|
77
|
-
subscriber = ActiveSupport::Notifications.subscribe(name) do |*args|
|
|
127
|
+
subscriber = ActiveSupport::Notifications.subscribe(notification_event_name) do |*args|
|
|
78
128
|
events << ActiveSupport::Notifications::Event.new(*args).payload
|
|
79
129
|
end
|
|
80
130
|
|