sorbet_typed-short_circuit 1.0.2 → 1.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5e3ce050f87a57dca5dccb55c765783dd0f84fb69579b93e892b77b87b850cd7
4
- data.tar.gz: 7b26b4e2a158b895e711e3f2b5027e707c6e2fddf741157ab67878721a607eb2
3
+ metadata.gz: 9ea0d37eb463742ceea59c842b41be2e3b6a4d713a345ab75d2f5951253bcbbb
4
+ data.tar.gz: 03a370f7e2176db0571b0c9c26f5839be331e5f6dc923dca8275ed5ae30f6ced
5
5
  SHA512:
6
- metadata.gz: 8fd009c77ba8a63fc5b5c092ede8a3116a1e4e69efb7966af4db5fb537686b5adf5f0f901852322b6b9e7212a9f6bc08da8dce6f4c81b4749d70023dae66e765
7
- data.tar.gz: 36b79c49f3deb3d4f57d6cb78606f4b7187bf2bdfb3086ae29401fc0e1c3428b8ea3ee3294daec10d238341d7faaf1e742f3265a8578cfd0b95ca76891a3a85b
6
+ metadata.gz: abcea411c26737957a5a1574127fc69dccd5f7ead0628adf19056d4b5f1c70fa5df21fe58870fcdfd81f8172bb6b6a2090a967b10f5c8adf1b90be57545857e2
7
+ data.tar.gz: ce68d1218e72944b9b4bec1563d02f5e412e2bd6bf390c50763d5a119cf8a0c2290892bb3a38e7c65dc72bd4d18b9fb281f22a824522e4757a9280a146eb54e0
data/.cz.yaml CHANGED
@@ -10,11 +10,12 @@ commitizen:
10
10
  name: cz_conventional_commits
11
11
  pre_bump_hooks:
12
12
  - mise x -- bundle install
13
+ - mise x -- bun install
13
14
  - mise run update
14
15
  - mise run format
15
16
  tag_format: v$version
16
17
  update_changelog_on_bump: true
17
- version: 1.0.2
18
+ version: 1.0.3
18
19
  version_files:
19
20
  - lib/sorbet_typed/short_circuit/version.rb
20
21
  version_scheme: semver2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## v1.0.3 (2025-11-18)
2
+
3
+ ### Fix
4
+
5
+ - **deps**: update sorbet to v0.6.12778
6
+ - **deps**: update sorbet to v0.6.12768
7
+ - **deps**: update sorbet to v0.6.12765
8
+ - **deps**: update sorbet to v0.6.12753
9
+ - **deps**: update dependency markdownlint-cli2 to v0.19.0
10
+ - **deps**: update dependency cspell to v9.3.1
11
+
1
12
  ## v1.0.2 (2025-11-10)
2
13
 
3
14
  ### Fix
data/README.md CHANGED
@@ -1,3 +1,192 @@
1
1
  # SorbetTyped::ShortCircuit
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/sorbet_typed-short_circuit.svg?icon=si%3Arubygems)](https://badge.fury.io/rb/sorbet_typed-short_circuit)
4
+
5
+ Fully sorbet typed implementation of a fast-fail pattern based on signaling. It allows to chain multiple step-methods
6
+ which each could fail and abort the whole process while keeping return values flexible to communicate eventual errors or
7
+ further use some result. It should prevent `if...else` patterns after every part of a bigger process to ensure a step
8
+ worked or bubble up failure message if not.
9
+
10
+ Using this, you can break down more complex processes into smaller steps and make methods smaller and more readable
11
+ while keeping full type safety.
12
+
13
+ Inspiration for this comes from [dry-monads](https://dry-rb.org/gems/dry-monads/). The focus lies on strict type-safety
14
+ while iteratively calling different steps of a bigger process and not relying on any instance-state or custom DSL.
15
+
16
+ - [Installation](#installation)
17
+ - [Usage](#usage)
18
+ - [Basic Usage](#basic-usage)
19
+ - [Step Method Signature](#step-method-signature)
20
+ - [Signaling a failure](#signaling-a-failure)
21
+ - [Circuit Interface](#circuit-interface)
22
+ - [Passing Circuit Breakers as Method Parameters](#passing-circuit-breakers-as-method-parameters)
23
+ - [Nesting Circuits](#nesting-circuits)
24
+ - [Development](#development)
25
+ - [Contributing](#contributing)
26
+
27
+ ## Installation
28
+
29
+ Install the gem and add to the application's Gemfile by executing:
30
+
31
+ ```bash
32
+ bundle add sorbet_typed-short_circuit
33
+ ```
34
+
35
+ If bundler is not being used to manage dependencies, install the gem by executing:
36
+
37
+ ```bash
38
+ gem install sorbet_typed-short_circuit
39
+ ```
40
+
41
+ ## Usage
42
+
43
+ The following examples demonstrate the basics of how you can use this gem. For a detailed look at what you can and
44
+ cannot do, you could look at [the type checker specs](spec/typechecking/sorbet_typed/short_circuit_spec.rb) and
45
+ [usage specs](lib/sorbet_typed/short_circuit_spec.rb).
46
+
47
+ ### Basic Usage
48
+
49
+ Initialize a new circuit with defined Success- and Failure-Type and call the run method. This method takes a block which
50
+ gets a `CircuitBreaker` as parameter. The circuit breaker stops the block execution early, if it receives a `Shorted`
51
+ signal.
52
+
53
+ ```ruby
54
+ circuit = SorbetTyped::ShortCircuit[
55
+ Symbol, # this will be the return type, when the block executes successfully
56
+ T::Array[String] # this will be the type of the Signal-Payload, when the block exits early
57
+ ].new
58
+
59
+ result = circuit.run do |circuit_breaker|
60
+ foo = circuit_breaker.(get_foo) # breaks the block, if `get_foo` returns a shorted signal. Otherwise returns a predictable success type.
61
+ bar = circuit_breaker.(do_bar(foo:)) # breaks the block, if `do_bar` returns a shorted signal.
62
+
63
+ transform_baz(bar:) # must return the success type or a shorted signal. CircuitBreaker not needed, because it is the last block statement
64
+ end
65
+
66
+ T.reveal_type(result) # => T.any(Symbol, SorbetTyped::ShortCircuit::Signals::Shorted[T::Array[String]])
67
+
68
+ if result.is_a? SorbetTyped::ShortCircuit::Signals::Shorted
69
+ T.reveal_type(result.payload) # => T::Array[String]
70
+ else
71
+ T.reveal_type(result) # => Symbol
72
+ end
73
+ ```
74
+
75
+ ### Step Method Signature
76
+
77
+ For step methods to be useful for the circuit breaker, they should return a union of any type you want to return and a
78
+ shorted signal corresponding to the circuits failure type. Passing a signal type with unfitting payload type, will
79
+ result in a type error.
80
+
81
+ ```ruby
82
+ extend T::Sig
83
+
84
+ sig { returns(T.any(String, SorbetTyped::ShortCircuit::Signals::Shorted[T::Array[String]])) }
85
+ def get_foo
86
+ # ...
87
+ end
88
+ ```
89
+
90
+ ### Signaling a failure
91
+
92
+ You can generate a shorting signal using the `::short` method of the `SorbetTyped::ShortCircuit` class. Passing this
93
+ signal to a circuit breaker will breaker the corresponding circuit. The payload type of the signal will be automatically
94
+ inferred from the passed parameter.
95
+
96
+ ```ruby
97
+ extend T::Sig
98
+
99
+ sig { params(foo: String).returns(T.any(String, SorbetTyped::ShortCircuit::Signals::Shorted[T::Array[String]])) }
100
+ def do_bar(foo:)
101
+ if foo == 'foo'
102
+ return 'bar'
103
+ else
104
+ SorbetTyped::ShortCircuit.short(['Unexpected value for foo:', foo])
105
+ end
106
+ end
107
+ ```
108
+
109
+ ### Circuit Interface
110
+
111
+ After initializing a circuit, it will respond to the following methods:
112
+
113
+ - `#run` => Run a number of methods and use the circuit breaker to exit early. Returns either a successful value or the
114
+ shorted signal
115
+ - `#run_without_signal` => Like run, but already extracts the signal payload on failure. Useful, if you don't want to
116
+ use the return value for flow-control. E.g. when success and failure use the same type, like a custom result-object
117
+ that gets filled with different information depending on the outcome.
118
+ - `#last_run_short_circuited?` => `true` or `false`, depending on the outcome of the last run. Not really useful with
119
+ sorbet, as you cannot use it for flow control. But it's there.
120
+
121
+ ### Passing Circuit Breakers as Method Parameters
122
+
123
+ Because the gems implementation relies heavily on generics and uses a raise/rescue pattern to implement the early exit,
124
+ there are few edge-cases where directly using internal classes like the `CircuitBreaker` would allow to return different
125
+ types than originally defined. This would introduce bugs, as static typing is circumvented and runtime type checks catch
126
+ them pretty late, as generics get removed from runtime checks.
127
+
128
+ To circumvent this, the custom error and the circuit breaker class are private constants, making accidental access
129
+ harder.
130
+
131
+ If you want to build some abstractions around the short circuit class, that need the circuit breaker to be passed around
132
+ to some method, you cannot use its private class within the type signature. Instead, use
133
+ `SorbetTyped::ShortCircuit::CircuitBreakerType`, which is a module without any behavior, but the circuit breaker
134
+ fulfills it and can be passed as parameter to methods accepting this type.
135
+
136
+ ```ruby
137
+ extend T::Sig
138
+
139
+ sig { params(circuit_breaker: SorbetTyped::ShortCircuit::CircuitBreakerType[String]).returns(T.any(NilClass, SorbetTyped::ShortCircuit::Signals::Shorted[String])) }
140
+ def foo(circuit_breaker:)
141
+ circuit_breaker.([SorbetTyped::ShortCircuit.short('shorted'), nil].sample)
142
+ end
143
+
144
+ SorbetTyped::ShortCircuit[NilClass, String].new.run do |circuit_breaker|
145
+ foo(circuit_breaker:)
146
+ end
147
+ ```
148
+
149
+ ### Nesting Circuits
150
+
151
+ It is possible to nest circuits. Especially when splitting your logic over multiple methods, each of them might use a
152
+ circuit themselves to portray a part of the process. When doing this, each circuit creates its own circuit breaker,
153
+ which can only break its original circuit. This is to prevent accidentally breaking inner circuits using outer circuit
154
+ breakers, leading to incorrect types being returned.
155
+
156
+ ```ruby
157
+ SorbetTyped::ShortCircuit[String, Symbol].new.run do |outer_circuit_breaker|
158
+ SorbetTyped::ShortCircuit[Integer, NilClass].new.run do |inner_circuit_breaker|
159
+ outer_circuit_breaker.(SorbetTyped::ShortCircuit.short(:failure)) # shorted signal must fulfill failure type of the outer circuit
160
+
161
+ # this will never be reached, as the breaker always gets a shorted signal.
162
+ # Sorbet detects this as unreachable
163
+ 'foo'
164
+ end
165
+
166
+ # this will never be reached, as the outer breaker used within the inner
167
+ # circuit will still break the outer circuit. But sorbet cannot statically
168
+ # detect this as unreachable.
169
+ 'bar'
170
+ end
171
+ ```
172
+
173
+ ## Development
174
+
175
+ The project uses [mise-en-place](https://mise.jdx.dev/) as development tool.
176
+
177
+ After checking out the repo, run `mise run setup` to install dependencies. Then, run `mise test` to run the tests. You
178
+ can also run `mise task ls` for a list of available tasks.
179
+
180
+ RSpec is used as test suite. Spec files can and should be placed right beside their associated class files.
181
+
182
+ Use the command `mise run console` (or `./bin/console`) to start an interactive ruby console session with the gem
183
+ already loaded.
184
+
185
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, run
186
+ `mise run deploy`, which will update the version number, create a release commit, tag it and push the built gem to
187
+ [rubygems.org](https://rubygems.org).
188
+
189
+ ## Contributing
190
+
191
+ Bug reports and merge requests are welcome on GitLab at
192
+ [gitlab.com/sorbet_typed/short_circuit](https://gitlab.com/sorbet_typed/short_circuit).
@@ -6,7 +6,7 @@
6
6
  # -- Disabled, because this file gets required in gemspec, where zeitwerk is not active
7
7
  module SorbetTyped
8
8
  class ShortCircuit
9
- VERSION = '1.0.2'
9
+ VERSION = '1.0.3'
10
10
  end
11
11
  end
12
12
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sorbet_typed-short_circuit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Kramer
@@ -18,7 +18,7 @@ dependencies:
18
18
  version: '0.6'
19
19
  - - "<="
20
20
  - !ruby/object:Gem::Version
21
- version: 0.6.12731
21
+ version: 0.6.12778
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -28,7 +28,7 @@ dependencies:
28
28
  version: '0.6'
29
29
  - - "<="
30
30
  - !ruby/object:Gem::Version
31
- version: 0.6.12731
31
+ version: 0.6.12778
32
32
  description: ''
33
33
  email:
34
34
  - mail@richardkramer.de