fluxus 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 +7 -0
- data/.rubocop.yml +16 -0
- data/Gemfile +20 -0
- data/Gemfile.lock +83 -0
- data/LICENSE.txt +21 -0
- data/README.md +241 -0
- data/Rakefile +16 -0
- data/lib/fluxus/caller.rb +11 -0
- data/lib/fluxus/results/chainable.rb +35 -0
- data/lib/fluxus/results/failure.rb +15 -0
- data/lib/fluxus/results/result.rb +40 -0
- data/lib/fluxus/results/success.rb +15 -0
- data/lib/fluxus/runner.rb +43 -0
- data/lib/fluxus/safe/caller.rb +18 -0
- data/lib/fluxus/version.rb +5 -0
- data/lib/fluxus.rb +10 -0
- metadata +74 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 53b87715576086932fa0632d366b8f17a9abb4790a7115777f2891795e4762bc
|
4
|
+
data.tar.gz: 0c1efd6a6a09618de16a27690c936ab6911a751b17f3943f637efcfb35a356e6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f833f3d13d02259e8e6fdb4a003e1af89e2a8a50ae85353122b1bd4a130723acb6a9c1dceacdf1d28692569cae032e0760757e2e1a4c4e8333abb1d94f6f0ec7
|
7
|
+
data.tar.gz: ff4fee21d2f14dc6feb32bd3c539643830df5e4d017b27d9edd60705ae468d4c38173133295ef3cfa9eb63ba0d799c07185ecdfab9bed730d2cb7c63f52aa709
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.7
|
3
|
+
|
4
|
+
Style/Documentation:
|
5
|
+
Enable: false
|
6
|
+
|
7
|
+
Style/StringLiterals:
|
8
|
+
Enabled: true
|
9
|
+
EnforcedStyle: single_quotes
|
10
|
+
|
11
|
+
Style/StringLiteralsInInterpolation:
|
12
|
+
Enabled: true
|
13
|
+
EnforcedStyle: double_quotes
|
14
|
+
|
15
|
+
Layout/LineLength:
|
16
|
+
Max: 120
|
data/Gemfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
gem 'rake', '~> 13.0'
|
6
|
+
|
7
|
+
group :development, :test do
|
8
|
+
gem 'rubocop', '~> 1.21'
|
9
|
+
|
10
|
+
gem 'byebug', '~> 11'
|
11
|
+
gem 'pry', '~> 0.14'
|
12
|
+
gem 'pry-byebug', '~> 3.10'
|
13
|
+
end
|
14
|
+
|
15
|
+
group :test do
|
16
|
+
gem 'minitest', '~> 5'
|
17
|
+
gem 'simplecov', '~> 0.22'
|
18
|
+
end
|
19
|
+
|
20
|
+
gemspec
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
fluxus (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ast (2.4.2)
|
10
|
+
byebug (11.1.3)
|
11
|
+
coderay (1.1.3)
|
12
|
+
coveralls (0.7.2)
|
13
|
+
multi_json (~> 1.3)
|
14
|
+
rest-client (= 1.6.7)
|
15
|
+
simplecov (>= 0.7)
|
16
|
+
term-ansicolor (= 1.2.2)
|
17
|
+
thor (= 0.18.1)
|
18
|
+
docile (1.4.0)
|
19
|
+
json (2.6.1)
|
20
|
+
method_source (1.0.0)
|
21
|
+
mime-types (3.4.1)
|
22
|
+
mime-types-data (~> 3.2015)
|
23
|
+
mime-types-data (3.2022.0105)
|
24
|
+
minitest (5.16.3)
|
25
|
+
multi_json (1.15.0)
|
26
|
+
parallel (1.22.1)
|
27
|
+
parser (3.2.0.0)
|
28
|
+
ast (~> 2.4.1)
|
29
|
+
pry (0.14.2)
|
30
|
+
coderay (~> 1.1)
|
31
|
+
method_source (~> 1.0)
|
32
|
+
pry-byebug (3.10.1)
|
33
|
+
byebug (~> 11.0)
|
34
|
+
pry (>= 0.13, < 0.15)
|
35
|
+
rainbow (3.1.1)
|
36
|
+
rake (13.0.6)
|
37
|
+
regexp_parser (2.6.2)
|
38
|
+
rest-client (1.6.7)
|
39
|
+
mime-types (>= 1.16)
|
40
|
+
rexml (3.2.5)
|
41
|
+
rubocop (1.44.1)
|
42
|
+
json (~> 2.3)
|
43
|
+
parallel (~> 1.10)
|
44
|
+
parser (>= 3.2.0.0)
|
45
|
+
rainbow (>= 2.2.2, < 4.0)
|
46
|
+
regexp_parser (>= 1.8, < 3.0)
|
47
|
+
rexml (>= 3.2.5, < 4.0)
|
48
|
+
rubocop-ast (>= 1.24.1, < 2.0)
|
49
|
+
ruby-progressbar (~> 1.7)
|
50
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
51
|
+
rubocop-ast (1.24.1)
|
52
|
+
parser (>= 3.1.1.0)
|
53
|
+
ruby-progressbar (1.11.0)
|
54
|
+
simplecov (0.22.0)
|
55
|
+
docile (~> 1.1)
|
56
|
+
simplecov-html (~> 0.11)
|
57
|
+
simplecov_json_formatter (~> 0.1)
|
58
|
+
simplecov-html (0.12.3)
|
59
|
+
simplecov_json_formatter (0.1.4)
|
60
|
+
term-ansicolor (1.2.2)
|
61
|
+
tins (~> 0.8)
|
62
|
+
thor (0.18.1)
|
63
|
+
tins (0.13.2)
|
64
|
+
unicode-display_width (2.4.2)
|
65
|
+
|
66
|
+
PLATFORMS
|
67
|
+
arm64-darwin-21
|
68
|
+
x86_64-linux
|
69
|
+
|
70
|
+
DEPENDENCIES
|
71
|
+
bundler
|
72
|
+
byebug (~> 11)
|
73
|
+
coveralls
|
74
|
+
fluxus!
|
75
|
+
minitest (~> 5)
|
76
|
+
pry (~> 0.14)
|
77
|
+
pry-byebug (~> 3.10)
|
78
|
+
rake (~> 13.0)
|
79
|
+
rubocop (~> 1.21)
|
80
|
+
simplecov (~> 0.22)
|
81
|
+
|
82
|
+
BUNDLED WITH
|
83
|
+
2.3.7
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2023 Henrique Aparecido Lavezzo
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,241 @@
|
|
1
|
+
# Fluxus
|
2
|
+
|
3
|
+
[](https://github.com/Rynaro/fluxus/actions/workflows/ci.yml)
|
4
|
+
[](https://codeclimate.com/github/Rynaro/fluxus/maintainability)
|
5
|
+
|
6
|
+
|
7
|
+
Fluxus [[ˈfluːk.sus]](https://en.wiktionary.org/wiki/fluxus#Latin) is a simple way to bring use cases to your code. The library uses what Ruby can provide and a little taste of pure object-oriented concepts.
|
8
|
+
|
9
|
+
_This library takes inspiration from the Clean Architecture concepts of use cases._
|
10
|
+
|
11
|
+
_Some similarities with [dry-monads](https://github.com/dry-rb/dry-monads) and [u-case](https://github.com/serradura/u-case) can easily be perceived. This library operates to bring interoperability with them._
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
You can add as your project as a dependency:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'fluxus'
|
19
|
+
```
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
An use case is a set of business instructions that will be carefully followed by the runtime code and its dependencies to achieve a great purpose. The level of complexity can vary, but _Fluxus_ is here to create readability and scope around it!
|
24
|
+
|
25
|
+
_Fluxus_ always tries to deliver more from an object-oriented paradigm than from showing itself. This means _Fluxus_ is more about directions than dependency. And that's why we call our definition classes as `Fluxus::Object` and `Fluxus::SafeObject`.
|
26
|
+
|
27
|
+
### Creating a basic Fluxus::Object
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
class IsEven < Fluxus::Object
|
31
|
+
def call!(number)
|
32
|
+
return Failure(result: "#{number} is odd") if number.odd?
|
33
|
+
|
34
|
+
Success(result: "#{number} is even")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
IsEven.call!(2)
|
39
|
+
```
|
40
|
+
|
41
|
+
### Creating a basic Fluxus::SafeObject
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
class IsEven < Fluxus::SafeObject
|
45
|
+
def call!(number)
|
46
|
+
return Failure(result: "#{number} is odd") if number.odd?
|
47
|
+
|
48
|
+
Success(result: "#{number} is even")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
IsEven.call!(2)
|
53
|
+
```
|
54
|
+
|
55
|
+
#### Differences of `Object` and `SafeObject`
|
56
|
+
|
57
|
+
While `Fluxus::Object` preserves the actual Ruby code autonomy to dictate the flow breakers like error management. `SafeObject` stays in the middle and defines safe positions by respecting the `Fluxus` contract and delivering the `Fluxus::Results::Result` interface.
|
58
|
+
|
59
|
+
This approach could be useful for some error recovery systems. Since the application will always recover from it by using the error as a dependency not a runtime flow control.
|
60
|
+
|
61
|
+
|
62
|
+
---
|
63
|
+
|
64
|
+
### The return `Flow::Results`
|
65
|
+
|
66
|
+
The expected `Fluxus` contract expects a `Fluxus::Results::Result` interface compatible as a return value.
|
67
|
+
|
68
|
+
While `Object` (and `SafeObject`) are responsible for delivering a place to hold the actual logic and control this code runtime. The `Results::Result` contract will be responsible for delivering back the necessary hooks and their processed data to the application.
|
69
|
+
|
70
|
+
We natively support two kinds of `Fluxus::Results::Result` the `Success` and `Failure`. Using this idiom is closer to the natural conception of use cases, when they fail or are successful.
|
71
|
+
|
72
|
+
#### Success
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
Success(result: true)
|
76
|
+
Success(type: :shinning, result: true)
|
77
|
+
```
|
78
|
+
|
79
|
+
#### Failure
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
Failure(result: false)
|
83
|
+
Failure(type: :dusty, result: false)
|
84
|
+
|
85
|
+
```
|
86
|
+
|
87
|
+
#### The `Fluxus::Results::Result` contract
|
88
|
+
|
89
|
+
All results share the same (abstract) ancestor definitions which mean they are interchangeable. This brings more coherence in your code when you are handling the most crucial part of the flow, their results.
|
90
|
+
|
91
|
+
The `Success` and `Failure` public contracts could be defined by
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
success_object = Success(type: :ok, result: 1+1)
|
95
|
+
|
96
|
+
success_object.success? # => true
|
97
|
+
success_object.failure? # => false
|
98
|
+
success_object.unknown? # => false
|
99
|
+
|
100
|
+
success_object.type # => :ok
|
101
|
+
success_object.data # => 2
|
102
|
+
|
103
|
+
failure_object = Failure(type: :fail, result: 1-1)
|
104
|
+
|
105
|
+
failure_object.success? # => false
|
106
|
+
failure_object.failure? # => true
|
107
|
+
failure_object.unknown? # => false
|
108
|
+
|
109
|
+
failure_object.type # => :fail
|
110
|
+
failure_object.data # => 0
|
111
|
+
|
112
|
+
```
|
113
|
+
|
114
|
+
#### The `result` and `data` relationship
|
115
|
+
|
116
|
+
You already noticed the `Success` and `Failure` receiving `result:` but getting the data from `data`. In fact, inside the `Fluxus::Results::Result,` the actual contract handles `data` directly. But `result` is a wrapper defined by `Fluxus` to bring more meaning inside the use case concept.
|
117
|
+
|
118
|
+
#### The `type` importance
|
119
|
+
|
120
|
+
The `type` is a way to categorize the major events inside the use case. Your use case can hold a variety of `Success` and `Failure` and depend on how the business is defined different paths are taken.
|
121
|
+
|
122
|
+
The `Fluxus` also defines a default value to bring simplicity to small use cases. The default value is `:ok` for `Success` and `:error` for `Failure`.
|
123
|
+
|
124
|
+
Prefer using `symbols` for handling those types.
|
125
|
+
|
126
|
+
#### Results are chainable
|
127
|
+
|
128
|
+
Was described that `Fluxus::Results::Result` are responsible for handling the (obviously) result. This means, this also needs to control the post-use case without leaking data to the runtime void.
|
129
|
+
|
130
|
+
With this in mind, the Result implements **chainable** methods. You can call them hooks if you wish.
|
131
|
+
|
132
|
+
Each hook represents one of the expected states.
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
Fluxus::Results::Result#on_success
|
136
|
+
Fluxus::Results::Result#on_failure
|
137
|
+
Fluxus::Results::Result#on_exception
|
138
|
+
```
|
139
|
+
|
140
|
+
The `on_exception` is a contract for `SafeObject`, but they are basically a `Failure` with a specialized eye for `Exception` looking.
|
141
|
+
|
142
|
+
#### Hooks are blocks
|
143
|
+
|
144
|
+
All hooks are essentially blocks, and `data` is available there. This means, you can define the code routine that will handle the `data`, and `data` is immutable. Each hook handles its own version of `data`, and this belongs there.
|
145
|
+
|
146
|
+
#### Hooks respect `self`
|
147
|
+
|
148
|
+
All hook implementation preserves the `Success` or `Failure` instance. And this brings a powerful feature to your pipeline. Use cases can chain various conclusions.
|
149
|
+
|
150
|
+
|
151
|
+
|
152
|
+
---
|
153
|
+
|
154
|
+
## Compiling the knowledge
|
155
|
+
|
156
|
+
Using the `IsEven` simple use case, let's implement a fully covered `Fluxus::Object`, so you can fully understand how to build your own use cases.
|
157
|
+
|
158
|
+
### Basic flow
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
class IsEven < Fluxus::Object
|
162
|
+
def call!(number)
|
163
|
+
return Failure(result: "#{number} is odd") if number.odd?
|
164
|
+
|
165
|
+
Success(result: "#{number} is even")
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def my_use_case(number)
|
170
|
+
IsEven
|
171
|
+
.call!(number)
|
172
|
+
.on_success { |data| puts data << '!' }
|
173
|
+
.on_failure { |data| puts 'Why? ' << data }
|
174
|
+
end
|
175
|
+
|
176
|
+
my_use_case(2) #=> 2 is even!
|
177
|
+
my_use_case(3) #=> Why? 3 is odd
|
178
|
+
my_use_case(nil) #=> NoMethodError
|
179
|
+
```
|
180
|
+
|
181
|
+
### Scoped Results flow
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
class IsEven < Fluxus::Object
|
185
|
+
def call!(number)
|
186
|
+
return Failure(type: :zero, result: 'you got zero') if number.zero?
|
187
|
+
return Failure(type: :odd, result: "#{number} is odd") if number.odd?
|
188
|
+
|
189
|
+
Success(type: :even, result: "#{number} is even")
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def my_use_case(number)
|
194
|
+
IsEven
|
195
|
+
.call!(number)
|
196
|
+
.on_success(:even) { |data| p data << '!' }
|
197
|
+
.on_failure(:odd) { |data| p 'Why? ' << data }
|
198
|
+
.on_failure(:zero) { |data| p data }
|
199
|
+
end
|
200
|
+
|
201
|
+
my_use_case(0) #=> you got zero
|
202
|
+
my_use_case(2) #=> 2 is even!
|
203
|
+
my_use_case(3) #=> Why? 3 is odd
|
204
|
+
my_use_case(nil) #=> NoMethodError
|
205
|
+
```
|
206
|
+
|
207
|
+
### Safe Results flow
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
class IsEven < Fluxus::SafeObject
|
211
|
+
def call!(number)
|
212
|
+
return Failure(type: :zero, result: 'you got zero') if number.zero?
|
213
|
+
return Failure(type: :odd, result: "#{number} is odd") if number.odd?
|
214
|
+
|
215
|
+
Success(type: :even, result: "#{number} is even")
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def my_use_case(number)
|
220
|
+
IsEven
|
221
|
+
.call!(number)
|
222
|
+
.on_success(:even) { |data| p data << '!' }
|
223
|
+
.on_failure(:odd) { |data| p 'Why? ' << data }
|
224
|
+
.on_failure(:zero) { |data| p data }
|
225
|
+
.on_exception(NoMethodError) { |data| p }
|
226
|
+
end
|
227
|
+
|
228
|
+
my_use_case(0) #=> you got zero
|
229
|
+
my_use_case(2) #=> 2 is even!
|
230
|
+
my_use_case(3) #=> Why? 3 is odd
|
231
|
+
my_use_case(nil) #=> Failure with exception: data
|
232
|
+
```
|
233
|
+
|
234
|
+
|
235
|
+
## Contributing
|
236
|
+
|
237
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Rynaro/fluxus.
|
238
|
+
|
239
|
+
## License
|
240
|
+
|
241
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << 'test'
|
8
|
+
t.libs << 'lib'
|
9
|
+
t.test_files = FileList['test/**/*_test.rb']
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'rubocop/rake_task'
|
13
|
+
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
|
16
|
+
task default: %i[test rubocop]
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fluxus
|
4
|
+
module Results
|
5
|
+
module Chainable
|
6
|
+
def on_success(expected_type = nil)
|
7
|
+
yield(data) if __success_type?(expected_type)
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
def on_failure(expected_type = nil)
|
12
|
+
yield(data) if __failure_type?(expected_type)
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def on_exception(expected_exception = nil)
|
17
|
+
return self unless __failure_type?(:exception)
|
18
|
+
|
19
|
+
if expected_exception.nil? ||
|
20
|
+
(expected_exception.is_a?(Exception) && data[:exception].is_a?(expected_exception))
|
21
|
+
yield(data)
|
22
|
+
end
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def __success_type?(expected_type)
|
27
|
+
success? && (expected_type.nil? || expected_type == type)
|
28
|
+
end
|
29
|
+
|
30
|
+
def __failure_type?(expected_type = nil)
|
31
|
+
failure? && (expected_type.nil? || expected_type == type)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fluxus
|
4
|
+
module Results
|
5
|
+
require 'fluxus/results/chainable'
|
6
|
+
|
7
|
+
class Result
|
8
|
+
include Chainable
|
9
|
+
attr_reader :type, :data
|
10
|
+
|
11
|
+
class StateNotImplemented < StandardError; end
|
12
|
+
|
13
|
+
def initialize(type: :unknown, data: {})
|
14
|
+
@type = type
|
15
|
+
@data = data
|
16
|
+
@state = define_state
|
17
|
+
end
|
18
|
+
|
19
|
+
def success?
|
20
|
+
state == :success
|
21
|
+
end
|
22
|
+
|
23
|
+
def failure?
|
24
|
+
state == :failure
|
25
|
+
end
|
26
|
+
|
27
|
+
def unknown?
|
28
|
+
!(failure? || success?)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :state
|
34
|
+
|
35
|
+
def define_state
|
36
|
+
raise StateNotImplemented, 'the #define_state hook must be implemented by a concrete class'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fluxus
|
4
|
+
require 'fluxus/results/success'
|
5
|
+
require 'fluxus/results/failure'
|
6
|
+
|
7
|
+
class Runner
|
8
|
+
class ResultTypeNotDefinedError < StandardError; end
|
9
|
+
class CallerNotImplemented < StandardError; end
|
10
|
+
|
11
|
+
private_class_method :new
|
12
|
+
|
13
|
+
def self.call!(...)
|
14
|
+
raise CallerNotImplemented, 'the flow must be implemented by a caller'
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.__call__(instance, ...)
|
18
|
+
result = instance.call!(...)
|
19
|
+
raise ResultTypeNotDefinedError, 'flow results must be Success or Failure' unless result.is_a?(Results::Result)
|
20
|
+
|
21
|
+
result
|
22
|
+
end
|
23
|
+
private_class_method :__call__
|
24
|
+
|
25
|
+
def call!
|
26
|
+
raise NotImplementedError, '#call! must be implemented'
|
27
|
+
end
|
28
|
+
|
29
|
+
# rubocop:disable Naming/MethodName
|
30
|
+
def Success(type: :ok, result: nil)
|
31
|
+
@__result = Results::Success.new(type: type, data: result)
|
32
|
+
end
|
33
|
+
|
34
|
+
def Failure(type: :error, result: nil)
|
35
|
+
@__result = Results::Failure.new(type: type, data: result)
|
36
|
+
end
|
37
|
+
# rubocop:enable Naming/MethodName
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
attr_reader :__result
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fluxus/runner'
|
4
|
+
|
5
|
+
module Fluxus
|
6
|
+
module Safe
|
7
|
+
class Caller < Runner
|
8
|
+
def self.call!(...)
|
9
|
+
instance = new
|
10
|
+
__call__(instance, ...)
|
11
|
+
rescue StandardError => e
|
12
|
+
raise e if e.is_a?(ResultTypeNotDefinedError)
|
13
|
+
|
14
|
+
instance.Failure(type: :exception, result: { exception: e })
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/fluxus.rb
ADDED
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluxus
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Henrique Aparecido Lavezzo
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-02-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: Really simple fluxus objects for use cases.
|
28
|
+
email:
|
29
|
+
- hi@hlavezzo.me
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- ".rubocop.yml"
|
35
|
+
- Gemfile
|
36
|
+
- Gemfile.lock
|
37
|
+
- LICENSE.txt
|
38
|
+
- README.md
|
39
|
+
- Rakefile
|
40
|
+
- lib/fluxus.rb
|
41
|
+
- lib/fluxus/caller.rb
|
42
|
+
- lib/fluxus/results/chainable.rb
|
43
|
+
- lib/fluxus/results/failure.rb
|
44
|
+
- lib/fluxus/results/result.rb
|
45
|
+
- lib/fluxus/results/success.rb
|
46
|
+
- lib/fluxus/runner.rb
|
47
|
+
- lib/fluxus/safe/caller.rb
|
48
|
+
- lib/fluxus/version.rb
|
49
|
+
homepage: https://github.com/Rynaro/fluxus
|
50
|
+
licenses:
|
51
|
+
- MIT
|
52
|
+
metadata:
|
53
|
+
homepage_uri: https://github.com/Rynaro/fluxus
|
54
|
+
source_code_uri: https://github.com/Rynaro/fluxus
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 2.7.0
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
requirements: []
|
70
|
+
rubygems_version: 3.2.33
|
71
|
+
signing_key:
|
72
|
+
specification_version: 4
|
73
|
+
summary: Simple use case objects
|
74
|
+
test_files: []
|