hubbado-sequence 0.7.0 → 0.8.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/CHANGELOG.md +23 -0
- data/README.md +27 -11
- data/hubbado-sequence.gemspec +1 -1
- data/lib/hubbado/sequence/pipeline.rb +5 -6
- data/lib/hubbado/sequence/sequencer.rb +12 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bae3a73329cdbf0194b5074fae10bd5e2d4035e773ee70f238ca802a5d0f2ae7
|
|
4
|
+
data.tar.gz: 8ff2d5bc1088333c8480695d411000f7b361efb22e296057c0111f88c0886113
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 16069e3f557800e6c0c18e2f6b52c5bec482d2d8610d244e2679403879bf81ab742bbcf4da74d63a03fbaa12614103e51ffe53a6889d45b6cc3a73509ca3ecd5
|
|
7
|
+
data.tar.gz: c92c360d5fe1995cf05eefb330ab1949d0870d6ede7fcc308f350e7c23f98118544cda4d218580ba62d12793e7bbf6329af7f2b33a4c0adc6b5d87db2bc85dea
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [0.8.0] - Instance calls take only a Ctx; chained pipeline carries the i18n scope
|
|
8
|
+
|
|
9
|
+
### Changed (breaking)
|
|
10
|
+
|
|
11
|
+
- **`pipeline` rejects anything but a `Ctx`.** A sequencer's instance
|
|
12
|
+
`call` takes a `Ctx`, as `docs/design.md` already stated, and
|
|
13
|
+
`pipeline` now raises `ArgumentError` when it gets keyword arguments or
|
|
14
|
+
a plain Hash. A spec that calls an instance
|
|
15
|
+
(`seq = Seq.new; seq.(params: ...)`) must pass
|
|
16
|
+
`Hubbado::Sequence::Ctx.build(params: ...)`. On a plain Hash, a read of a
|
|
17
|
+
missing ctx key returned `nil` in the spec while it raised `KeyError` in
|
|
18
|
+
production through the class-level `.()`, so specs could not find that
|
|
19
|
+
fault. The class-level `.()` still accepts keyword arguments.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- **A chained `pipeline(ctx).step(...).result` carries the sequencer's
|
|
24
|
+
i18n scope.** Only the block form tagged its Result, so a sequencer
|
|
25
|
+
using the chained form got no scope on an instance call, and its
|
|
26
|
+
parent's scope when nested through `p.invoke`. The pipeline now applies
|
|
27
|
+
the scope in both forms. The README states that a failure returned
|
|
28
|
+
without `pipeline` should be built with the `failure` helper.
|
|
29
|
+
|
|
7
30
|
## [0.7.0] - Macros::Policy::Check record-less policies; Sequencer i18n_scope applied at boundary
|
|
8
31
|
|
|
9
32
|
### Changed (breaking)
|
data/README.md
CHANGED
|
@@ -519,11 +519,18 @@ the same kwargs as `Result.failure` (`code:`, `data:`, `step:`,
|
|
|
519
519
|
4. **Humanized code** — `:not_found` → `"Not found"`.
|
|
520
520
|
|
|
521
521
|
The sequencer's scope is applied automatically. Both the `failure(ctx, ...)`
|
|
522
|
-
helper *and* the boundary itself (
|
|
523
|
-
tag the returned `Result` with
|
|
524
|
-
That means an unscoped failure
|
|
525
|
-
step, or anywhere else in the
|
|
526
|
-
scope when the Result bubbles out — no
|
|
522
|
+
helper *and* the boundary itself (the result of `pipeline(ctx)`, in block
|
|
523
|
+
and chained form, and `Sequencer.()`) tag the returned `Result` with
|
|
524
|
+
`i18n_scope` via `Result#with_i18n_scope`. That means an unscoped failure
|
|
525
|
+
produced inside a macro, a hand-rolled step, or anywhere else in the
|
|
526
|
+
pipeline picks up the sequencer's scope when the Result bubbles out — no
|
|
527
|
+
`failure` call required.
|
|
528
|
+
|
|
529
|
+
A sequencer that returns a failure without `pipeline` must build it with
|
|
530
|
+
`failure(ctx, ...)`, not `Result.failure(...)`. An instance call (a test,
|
|
531
|
+
or a nested sequencer run through `p.invoke`) reaches the sequencer's
|
|
532
|
+
`call` directly, so only the helper gives that failure the sequencer's
|
|
533
|
+
scope there.
|
|
527
534
|
|
|
528
535
|
### Defining translations for a sequencer
|
|
529
536
|
|
|
@@ -628,6 +635,13 @@ as substitutes. Tests configure the substitutes for the scenario at hand.
|
|
|
628
635
|
Substitutes default to pass-through `Result.success(ctx)` so a test only
|
|
629
636
|
configures the ones whose return matters.
|
|
630
637
|
|
|
638
|
+
An instance call takes a `Ctx`, the same strict ctx that the class-level
|
|
639
|
+
`.()` builds for production, so a test passes one:
|
|
640
|
+
`seq.(Hubbado::Sequence::Ctx.build(params: ..., current_user: ...))`.
|
|
641
|
+
`pipeline` raises `ArgumentError` for keyword arguments or a plain Hash,
|
|
642
|
+
because on a Hash a read of a missing key would return `nil` in the test
|
|
643
|
+
and raise `KeyError` in production.
|
|
644
|
+
|
|
631
645
|
### Substituting macros directly
|
|
632
646
|
|
|
633
647
|
```ruby
|
|
@@ -639,7 +653,7 @@ context "Seqs::UpdateUser::Present happy path" do
|
|
|
639
653
|
seq.find.succeed_with(user)
|
|
640
654
|
seq.build_contract.succeed_with(contract)
|
|
641
655
|
|
|
642
|
-
result = seq.(params: { id: 1 }, current_user: User.new)
|
|
656
|
+
result = seq.(Hubbado::Sequence::Ctx.build(params: { id: 1 }, current_user: User.new))
|
|
643
657
|
|
|
644
658
|
test "Is success" do
|
|
645
659
|
assert(result.success?)
|
|
@@ -662,7 +676,7 @@ context "Seqs::UpdateUser::Present when the user is not found" do
|
|
|
662
676
|
seq = Seqs::UpdateUser::Present.new
|
|
663
677
|
seq.find.fail_with(code: :not_found)
|
|
664
678
|
|
|
665
|
-
result = seq.(params: { id: 999 }, current_user: User.new)
|
|
679
|
+
result = seq.(Hubbado::Sequence::Ctx.build(params: { id: 999 }, current_user: User.new))
|
|
666
680
|
|
|
667
681
|
test "Fails with :not_found" do
|
|
668
682
|
assert(result.code == :not_found)
|
|
@@ -703,8 +717,10 @@ context "Seqs::UpdateUser happy path" do
|
|
|
703
717
|
seq.present.succeed_with(user: user, contract: contract)
|
|
704
718
|
|
|
705
719
|
result = seq.(
|
|
706
|
-
|
|
707
|
-
|
|
720
|
+
Hubbado::Sequence::Ctx.build(
|
|
721
|
+
params: { user: { email: "new@example.com" } },
|
|
722
|
+
current_user: User.new
|
|
723
|
+
)
|
|
708
724
|
)
|
|
709
725
|
|
|
710
726
|
test "Is success" do
|
|
@@ -724,7 +740,7 @@ context "Seqs::UpdateUser when Present denies access" do
|
|
|
724
740
|
seq = Seqs::UpdateUser.new
|
|
725
741
|
seq.present.fail_with(code: :forbidden)
|
|
726
742
|
|
|
727
|
-
result = seq.(params: { user: {} }, current_user: User.new)
|
|
743
|
+
result = seq.(Hubbado::Sequence::Ctx.build(params: { user: {} }, current_user: User.new))
|
|
728
744
|
|
|
729
745
|
test "Fails" do
|
|
730
746
|
assert(result.failure?)
|
|
@@ -747,7 +763,7 @@ context "Seqs::UpdateUser when Present cannot find the record" do
|
|
|
747
763
|
seq = Seqs::UpdateUser.new
|
|
748
764
|
seq.present.fail_with(code: :not_found)
|
|
749
765
|
|
|
750
|
-
result = seq.(params: { id: 999, user: {} }, current_user: User.new)
|
|
766
|
+
result = seq.(Hubbado::Sequence::Ctx.build(params: { id: 999, user: {} }, current_user: User.new))
|
|
751
767
|
|
|
752
768
|
test "Fails with :not_found" do
|
|
753
769
|
assert(result.code == :not_found)
|
data/hubbado-sequence.gemspec
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
2
|
Gem::Specification.new do |s|
|
|
3
3
|
s.name = "hubbado-sequence"
|
|
4
|
-
s.version = "0.
|
|
4
|
+
s.version = "0.8.0"
|
|
5
5
|
s.summary = "A small framework for the short sequences of common steps that controller actions usually boil down to"
|
|
6
6
|
s.description = "A sequencer takes input, runs an ordered sequence of steps, and returns a Result carrying a success-or-failure flag, a structured error, and the working context that was built up during execution. Built with Rails in mind but framework-agnostic."
|
|
7
7
|
|
|
@@ -4,11 +4,12 @@ module Hubbado
|
|
|
4
4
|
# `pipeline(ctx)` helper. Not part of the public API — sequencers reach
|
|
5
5
|
# it through the helper.
|
|
6
6
|
class Pipeline
|
|
7
|
-
def initialize(ctx, dispatcher:)
|
|
7
|
+
def initialize(ctx, dispatcher:, i18n_scope: nil)
|
|
8
8
|
@ctx = ctx
|
|
9
9
|
@successful_steps = []
|
|
10
10
|
@failed_result = nil
|
|
11
11
|
@dispatcher = dispatcher
|
|
12
|
+
@i18n_scope = i18n_scope
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
# `step(:name)` dispatches to `dispatcher.send(name, ctx)`. The method
|
|
@@ -55,11 +56,9 @@ module Hubbado
|
|
|
55
56
|
end
|
|
56
57
|
|
|
57
58
|
def result
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
Result.success(@ctx, successful_steps: @successful_steps.dup)
|
|
62
|
-
end
|
|
59
|
+
result = @failed_result || Result.success(@ctx, successful_steps: @successful_steps.dup)
|
|
60
|
+
|
|
61
|
+
result.with_i18n_scope(@i18n_scope)
|
|
63
62
|
end
|
|
64
63
|
|
|
65
64
|
private
|
|
@@ -95,12 +95,22 @@ module Hubbado
|
|
|
95
95
|
# block, and returns the final Result — no trailing `.result` needed. The
|
|
96
96
|
# non-block form returns the Pipeline so chained `.step(...)...result`
|
|
97
97
|
# calls still work.
|
|
98
|
+
#
|
|
99
|
+
# Anything but a Ctx means an instance call skipped the Ctx that the
|
|
100
|
+
# class-level `.()` builds; run on a plain Hash, a missing key would
|
|
101
|
+
# read as nil rather than raise.
|
|
98
102
|
def pipeline(ctx, &block)
|
|
99
|
-
|
|
103
|
+
unless ctx.is_a?(Ctx)
|
|
104
|
+
raise ArgumentError,
|
|
105
|
+
"#{self.class.name}#pipeline expects a Hubbado::Sequence::Ctx, got #{ctx.class}; " \
|
|
106
|
+
"pass Hubbado::Sequence::Ctx.build(...) to an instance call"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
pipe = Pipeline.new(ctx, dispatcher: self, i18n_scope: i18n_scope)
|
|
100
110
|
|
|
101
111
|
if block
|
|
102
112
|
block.call(pipe)
|
|
103
|
-
pipe.result
|
|
113
|
+
pipe.result
|
|
104
114
|
else
|
|
105
115
|
pipe
|
|
106
116
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hubbado-sequence
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Hubbado Devs
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: evt-casing
|