yaso 1.1.0 → 1.3.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/.rubocop.yml +1 -0
- data/Gemfile.lock +5 -5
- data/README.md +2 -3
- data/benchmark/Gemfile +2 -0
- data/benchmark/index.rb +4 -2
- data/benchmark/shared/simple_command_service.rb +11 -0
- data/benchmark/step/benchmark.rb +2 -0
- data/benchmark/step/simple_command.rb +77 -0
- data/docker/Dockerfile +7 -0
- data/docker/entrypoint.sh +15 -0
- data/docker-compose.yml +15 -0
- data/lib/yaso/errors.rb +6 -0
- data/lib/yaso/invocable.rb +51 -0
- data/lib/yaso/logic/base.rb +2 -2
- data/lib/yaso/logic/failure.rb +1 -2
- data/lib/yaso/logic/pass.rb +1 -2
- data/lib/yaso/logic/rollback.rb +40 -0
- data/lib/yaso/logic/step.rb +1 -7
- data/lib/yaso/logic/step_builder.rb +10 -8
- data/lib/yaso/logic/switch.rb +2 -9
- data/lib/yaso/logic/wrap.rb +2 -7
- data/lib/yaso/logic.rb +7 -1
- data/lib/yaso/service.rb +48 -7
- data/lib/yaso/stepable.rb +11 -4
- data/lib/yaso/version.rb +1 -1
- data/lib/yaso.rb +1 -2
- metadata +9 -4
- data/lib/yaso/context.rb +0 -33
- data/lib/yaso/invokable.rb +0 -37
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1d9de791b4d45e8ea1cd2ffb6d75738f9d5eef8376261437b923d0795f81a5a2
|
|
4
|
+
data.tar.gz: 1d6234c4203c8cd9acdec73b5267ff16a45563caf67fd757f8fbed7fb2228d79
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8d8a4268ef7295d5eef6a6f8a45a73cc823f7d3322ad0c2cfea2f46a627f415af1c1974a8806318c290961ecd01bef29f4ad521e8d12f9f360c9f6a76d7426d9
|
|
7
|
+
data.tar.gz: 3b3e2a00818e075f555f47302033d6b6f292413291c4991e6d5e7831e58a95877a257dc0bb377b526736f516da5c71e58690b6e557e2805ac5a40e466e068bae
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
yaso (1.
|
|
4
|
+
yaso (1.3.0)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
@@ -14,7 +14,7 @@ GEM
|
|
|
14
14
|
lefthook (1.0.5)
|
|
15
15
|
method_source (1.0.0)
|
|
16
16
|
parallel (1.22.1)
|
|
17
|
-
parser (3.1.2.
|
|
17
|
+
parser (3.1.2.1)
|
|
18
18
|
ast (~> 2.4.1)
|
|
19
19
|
pry (0.14.1)
|
|
20
20
|
coderay (~> 1.1)
|
|
@@ -29,13 +29,13 @@ GEM
|
|
|
29
29
|
rspec-mocks (~> 3.11.0)
|
|
30
30
|
rspec-core (3.11.0)
|
|
31
31
|
rspec-support (~> 3.11.0)
|
|
32
|
-
rspec-expectations (3.11.
|
|
32
|
+
rspec-expectations (3.11.1)
|
|
33
33
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
34
34
|
rspec-support (~> 3.11.0)
|
|
35
35
|
rspec-mocks (3.11.1)
|
|
36
36
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
37
37
|
rspec-support (~> 3.11.0)
|
|
38
|
-
rspec-support (3.11.
|
|
38
|
+
rspec-support (3.11.1)
|
|
39
39
|
rubocop (1.28.2)
|
|
40
40
|
parallel (~> 1.10)
|
|
41
41
|
parser (>= 3.1.0.0)
|
|
@@ -59,7 +59,7 @@ GEM
|
|
|
59
59
|
simplecov_json_formatter (~> 0.1)
|
|
60
60
|
simplecov-html (0.12.3)
|
|
61
61
|
simplecov_json_formatter (0.1.4)
|
|
62
|
-
unicode-display_width (2.
|
|
62
|
+
unicode-display_width (2.3.0)
|
|
63
63
|
|
|
64
64
|
PLATFORMS
|
|
65
65
|
x86_64-darwin-21
|
data/README.md
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# Yaso
|
|
2
2
|
[](https://github.com/Ar2emis/yaso/actions/workflows/main.yml)  [](https://github.com/Ar2emis/yaso/blob/master/LICENSE.txt)
|
|
3
3
|
|
|
4
|
-
That's my (Yet Another) ServiceObject pattern implementation. I made it fast ([the fastest actually](https://github.com/Ar2emis/yaso/wiki/Benchmarks)) and simple to use.
|
|
5
|
-
I was inspired by those alternatives and I hope this will encourage them to be even better:
|
|
4
|
+
That's my (Yet Another) ServiceObject pattern implementation. I made it fast ([the fastest of this kind actually](https://github.com/Ar2emis/yaso/wiki/Benchmarks); [simple_command](https://github.com/nebulab/simple_command), you got me this time) and simple to use (I hope). I was inspired by those alternatives and I hope this will encourage them to be even better:
|
|
6
5
|
- [Trailblazer](https://github.com/trailblazer/trailblazer)
|
|
7
6
|
- [Decouplio](https://github.com/differencialx/decouplio)
|
|
8
7
|
|
|
@@ -28,7 +27,7 @@ All the information you can find in the gem [wiki](https://github.com/Ar2emis/ya
|
|
|
28
27
|
|
|
29
28
|
## Development
|
|
30
29
|
|
|
31
|
-
I don't think that someone would like to help me developing the gem but if so just fork a
|
|
30
|
+
I don't think that someone would like to help me developing the gem but if so just fork a repository, do your dark business, open a pull request and assign me as a reviewer.
|
|
32
31
|
|
|
33
32
|
## Contributing
|
|
34
33
|
|
data/benchmark/Gemfile
CHANGED
|
@@ -5,7 +5,9 @@ source 'https://rubygems.org'
|
|
|
5
5
|
gem 'benchmark-ips', '~> 2.10.0'
|
|
6
6
|
gem 'interactor', '~> 3.1.2'
|
|
7
7
|
gem 'kalibera', '~> 0.1.2'
|
|
8
|
+
gem 'simple_command', RUBY_VERSION.include?('2.5') ? '~> 0.2.0' : '~> 1.0.1'
|
|
8
9
|
gem 'trailblazer', '~> 2.1.0'
|
|
10
|
+
gem 'yaso', path: '..'
|
|
9
11
|
|
|
10
12
|
gem 'active_interaction', %w[2.5 2.6].any? { |version| RUBY_VERSION.include?(version) } ? '~> 4.1.0' : '~> 5.1.0'
|
|
11
13
|
|
data/benchmark/index.rb
CHANGED
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
require 'bundler/setup'
|
|
4
4
|
|
|
5
|
-
require_relative '../lib/yaso'
|
|
6
|
-
|
|
7
5
|
require 'benchmark/ips'
|
|
8
6
|
RUBY_VERSION.include?('2.5') || require('decouplio')
|
|
9
7
|
require 'interactor'
|
|
10
8
|
require 'active_interaction'
|
|
11
9
|
require 'trailblazer'
|
|
10
|
+
require 'simple_command'
|
|
11
|
+
require 'yaso'
|
|
12
12
|
|
|
13
13
|
require_relative 'shared/yaso_service'
|
|
14
14
|
RUBY_VERSION.include?('2.5') || require_relative('shared/decouplio_service')
|
|
15
15
|
require_relative 'shared/pure_service'
|
|
16
|
+
require_relative 'shared/simple_command_service'
|
|
16
17
|
require_relative 'shared/interactor_service'
|
|
17
18
|
require_relative 'shared/active_interaction_service'
|
|
18
19
|
require_relative 'shared/trailblazer_service'
|
|
@@ -21,6 +22,7 @@ require_relative 'shared/callable_step'
|
|
|
21
22
|
require_relative 'step/yaso'
|
|
22
23
|
RUBY_VERSION.include?('2.5') || require_relative('step/decouplio')
|
|
23
24
|
require_relative 'step/pure'
|
|
25
|
+
require_relative 'step/simple_command'
|
|
24
26
|
require_relative 'step/interactor'
|
|
25
27
|
require_relative 'step/active_interaction'
|
|
26
28
|
require_relative 'step/trailblazer'
|
data/benchmark/step/benchmark.rb
CHANGED
|
@@ -7,6 +7,7 @@ Benchmark.ips do |x|
|
|
|
7
7
|
x.config(stats: :bootstrap, confidence: 95)
|
|
8
8
|
|
|
9
9
|
x.report('Pure Service') { PureStepsService.call }
|
|
10
|
+
x.report('SimpleCommand') { SimpleCommandStepsService.call }
|
|
10
11
|
x.report('Yaso') { YasoStepsService.call }
|
|
11
12
|
x.report('Decouplio') { DecouplioStepsService.call } unless RUBY_VERSION.include?('2.5')
|
|
12
13
|
x.report('Interactor') { InteractorStepsService.call }
|
|
@@ -21,6 +22,7 @@ Benchmark.ips do |x|
|
|
|
21
22
|
x.config(stats: :bootstrap, confidence: 95)
|
|
22
23
|
|
|
23
24
|
x.report('Pure Service') { PureCallablesService.call }
|
|
25
|
+
x.report('SimpleCommand') { SimpleCommandCallablesService.call }
|
|
24
26
|
x.report('Yaso') { YasoCallablesService.call }
|
|
25
27
|
x.report('Decouplio') { DecouplioCallablesService.call } unless RUBY_VERSION.include?('2.5')
|
|
26
28
|
x.report('Interactor') { InteractorCallablesService.call }
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class SimpleCommandStepsService < SimpleCommandService
|
|
4
|
+
# rubocop:disable Metrics/MethodLength
|
|
5
|
+
def call
|
|
6
|
+
one
|
|
7
|
+
two
|
|
8
|
+
three
|
|
9
|
+
four
|
|
10
|
+
five
|
|
11
|
+
six
|
|
12
|
+
seven
|
|
13
|
+
eight
|
|
14
|
+
nine
|
|
15
|
+
ten
|
|
16
|
+
ctx
|
|
17
|
+
end
|
|
18
|
+
# rubocop:enable Metrics/MethodLength
|
|
19
|
+
|
|
20
|
+
def one
|
|
21
|
+
ctx[:one] = true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def two
|
|
25
|
+
ctx[:two] = true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def three
|
|
29
|
+
ctx[:three] = true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def four
|
|
33
|
+
ctx[:four] = true
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def five
|
|
37
|
+
ctx[:five] = true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def six
|
|
41
|
+
ctx[:six] = true
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def seven
|
|
45
|
+
ctx[:seven] = true
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def eight
|
|
49
|
+
ctx[:eight] = true
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def nine
|
|
53
|
+
ctx[:nine] = true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def ten
|
|
57
|
+
ctx[:ten] = true
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class SimpleCommandCallablesService < SimpleCommandService
|
|
62
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
63
|
+
def call
|
|
64
|
+
CallableStep.call(ctx, key: :one, value: true)
|
|
65
|
+
CallableStep.call(ctx, key: :two, value: true)
|
|
66
|
+
CallableStep.call(ctx, key: :three, value: true)
|
|
67
|
+
CallableStep.call(ctx, key: :four, value: true)
|
|
68
|
+
CallableStep.call(ctx, key: :five, value: true)
|
|
69
|
+
CallableStep.call(ctx, key: :six, value: true)
|
|
70
|
+
CallableStep.call(ctx, key: :seven, value: true)
|
|
71
|
+
CallableStep.call(ctx, key: :eight, value: true)
|
|
72
|
+
CallableStep.call(ctx, key: :nine, value: true)
|
|
73
|
+
CallableStep.call(ctx, key: :ten, value: true)
|
|
74
|
+
ctx
|
|
75
|
+
end
|
|
76
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
77
|
+
end
|
data/docker/Dockerfile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
if [[ `bundle -v` =~ "Bundler version 2" ]]; then
|
|
4
|
+
bundle config set --local path '/bundle/cache'
|
|
5
|
+
bundle config set --local without 'development'
|
|
6
|
+
else
|
|
7
|
+
bundle config --local path '/bundle/cache'
|
|
8
|
+
bundle config --local without 'development'
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
bundle
|
|
12
|
+
|
|
13
|
+
ruby index.rb
|
|
14
|
+
|
|
15
|
+
rm Gemfile.lock
|
data/docker-compose.yml
ADDED
data/lib/yaso/errors.rb
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yaso
|
|
4
|
+
class Invocable
|
|
5
|
+
METHOD = :method
|
|
6
|
+
CALLABLE = :callable
|
|
7
|
+
YASO = :yaso
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def call(object, options: {}, with_block: false, **)
|
|
11
|
+
type = object_type(object)
|
|
12
|
+
invocable = case type
|
|
13
|
+
when YASO then proc { |context| object.call(context).success? }
|
|
14
|
+
when CALLABLE then callable_invocable(object, options, with_block: with_block)
|
|
15
|
+
else method_invocable(object, with_block: with_block)
|
|
16
|
+
end
|
|
17
|
+
[type, invocable]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def object_type(object)
|
|
23
|
+
return Invocable::METHOD unless object.is_a?(Class)
|
|
24
|
+
|
|
25
|
+
object < ::Yaso::Service ? Invocable::YASO : Invocable::CALLABLE
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def callable_invocable(object, options, with_block:)
|
|
29
|
+
return proc { |context, &block| object.call(context, **options, &block) } if with_block
|
|
30
|
+
|
|
31
|
+
proc { |context| object.call(context, **options) }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def method_invocable(object, with_block:)
|
|
35
|
+
if with_block
|
|
36
|
+
return instance_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
37
|
+
proc { |context, instance, &block| # proc { |context, instance, &block|
|
|
38
|
+
instance.#{object}(context, **context, &block) # instance.<method_name>(context, **context, &block)
|
|
39
|
+
} # }
|
|
40
|
+
RUBY
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
instance_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
44
|
+
proc { |context, instance| # proc { |context, instance|
|
|
45
|
+
instance.#{object}(context, **context) # instance.<method_name>(context, **context)
|
|
46
|
+
} # }
|
|
47
|
+
RUBY
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
data/lib/yaso/logic/base.rb
CHANGED
|
@@ -5,9 +5,9 @@ module Yaso
|
|
|
5
5
|
class Base
|
|
6
6
|
attr_reader :name, :on_success, :on_failure
|
|
7
7
|
|
|
8
|
-
def initialize(name:,
|
|
8
|
+
def initialize(name:, invocable:, **options)
|
|
9
9
|
@name = name
|
|
10
|
-
@
|
|
10
|
+
@invocable = invocable
|
|
11
11
|
@fast = options[:fast]
|
|
12
12
|
@on_success = options[:on_success]
|
|
13
13
|
@on_failure = options[:on_failure]
|
data/lib/yaso/logic/failure.rb
CHANGED
data/lib/yaso/logic/pass.rb
CHANGED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yaso
|
|
4
|
+
module Logic
|
|
5
|
+
class Rollback < Classic
|
|
6
|
+
def call
|
|
7
|
+
super
|
|
8
|
+
logicals.detect { |step| !step.is_a?(Failure) }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def link_step(step, index)
|
|
14
|
+
next_success = step.on_success ? find_step(step.on_success) : next_step(index)
|
|
15
|
+
next_failure = if step.on_failure then find_step(step.on_failure)
|
|
16
|
+
else
|
|
17
|
+
step.is_a?(Pass) ? next_success : previous_failure(index)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
step.add_next_step(next_success)
|
|
21
|
+
step.add_failure(next_failure)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def link_previous_steps(failure, index)
|
|
25
|
+
prev_failure = previous_failure(index)
|
|
26
|
+
|
|
27
|
+
failure.add_failure(prev_failure) unless failure.on_failure
|
|
28
|
+
failure.add_next_step(prev_failure) unless failure.on_success
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def next_step(index)
|
|
32
|
+
logicals[index.next..-1].detect { |next_node| !next_node.is_a?(Failure) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def previous_failure(index)
|
|
36
|
+
logicals[0...index].reverse_each.detect { |previous_step| previous_step.is_a?(Failure) }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/yaso/logic/step.rb
CHANGED
|
@@ -4,13 +4,7 @@ module Yaso
|
|
|
4
4
|
module Logic
|
|
5
5
|
class Step < Base
|
|
6
6
|
def call(context, instance)
|
|
7
|
-
context
|
|
8
|
-
if @invokable.call(context, instance)
|
|
9
|
-
@next_step
|
|
10
|
-
else
|
|
11
|
-
context.success = false
|
|
12
|
-
@failure
|
|
13
|
-
end
|
|
7
|
+
@invocable.call(context, instance) ? [@next_step, true] : [@failure, false]
|
|
14
8
|
end
|
|
15
9
|
end
|
|
16
10
|
end
|
|
@@ -16,13 +16,13 @@ module Yaso
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def call(object:, category:, block:, **opts)
|
|
19
|
-
invokable_type, invokable = Invokable.call(object, **opts)
|
|
20
19
|
logic_class = CATEGORIES[category]
|
|
21
|
-
|
|
20
|
+
invocable_type, invocable = Invocable.call(object, with_block: logic_class == Wrap, **opts)
|
|
21
|
+
if invocable_type == Invocable::METHOD
|
|
22
22
|
opts[:name] = logic_class == Switch ? build_switch(object, **opts, &block) : build_method(object, &block)
|
|
23
23
|
end
|
|
24
24
|
opts[:wrapper] = build_wrapper(&block) if logic_class == Wrap
|
|
25
|
-
logic_class.new(
|
|
25
|
+
logic_class.new(invocable: invocable, **opts)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
private
|
|
@@ -45,17 +45,19 @@ module Yaso
|
|
|
45
45
|
|
|
46
46
|
def build_wrapper(&block)
|
|
47
47
|
wrapper_class = Class.new { extend Stepable }
|
|
48
|
+
build_wrapper_methods(wrapper_class, @klass)
|
|
48
49
|
wrapper_class.instance_exec(&block)
|
|
49
|
-
build_wrapper_call(wrapper_class, @klass)
|
|
50
50
|
wrapper_class
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
def
|
|
53
|
+
def build_wrapper_methods(wrapper_class, service_class)
|
|
54
54
|
wrapper_class.define_singleton_method(:call) do |context, instance|
|
|
55
|
-
@entry ||=
|
|
55
|
+
@entry ||= service_class.flow.call(service_class, steps)
|
|
56
56
|
step = @entry
|
|
57
|
-
|
|
58
|
-
context
|
|
57
|
+
success = true
|
|
58
|
+
step, success = step.call(context, instance) while step
|
|
59
|
+
instance.success = success
|
|
60
|
+
instance
|
|
59
61
|
end
|
|
60
62
|
end
|
|
61
63
|
end
|
data/lib/yaso/logic/switch.rb
CHANGED
|
@@ -4,15 +4,8 @@ module Yaso
|
|
|
4
4
|
module Logic
|
|
5
5
|
class Switch < Base
|
|
6
6
|
def call(context, instance)
|
|
7
|
-
|
|
8
|
-
switch_case
|
|
9
|
-
|
|
10
|
-
if Invokable.call(switch_case).last.call(context, instance)
|
|
11
|
-
@next_step
|
|
12
|
-
else
|
|
13
|
-
context.success = false
|
|
14
|
-
@failure
|
|
15
|
-
end
|
|
7
|
+
switch_case = @invocable.call(context, instance) || raise(UnhandledSwitchCaseError, instance.class)
|
|
8
|
+
Invocable.call(switch_case).last.call(context, instance) ? [@next_step, true] : [@failure, false]
|
|
16
9
|
end
|
|
17
10
|
end
|
|
18
11
|
end
|
data/lib/yaso/logic/wrap.rb
CHANGED
|
@@ -9,13 +9,8 @@ module Yaso
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def call(context, instance)
|
|
12
|
-
context.success
|
|
13
|
-
|
|
14
|
-
@next_step
|
|
15
|
-
else
|
|
16
|
-
context.success = false
|
|
17
|
-
@failure
|
|
18
|
-
end
|
|
12
|
+
result = @invocable.call(context, instance) { @wrapper.call(context, instance).success? }
|
|
13
|
+
result ? [@next_step, true] : [@failure, false]
|
|
19
14
|
end
|
|
20
15
|
end
|
|
21
16
|
end
|
data/lib/yaso/logic.rb
CHANGED
|
@@ -8,7 +8,13 @@ require_relative 'logic/wrap'
|
|
|
8
8
|
require_relative 'logic/switch'
|
|
9
9
|
require_relative 'logic/step_builder'
|
|
10
10
|
require_relative 'logic/classic'
|
|
11
|
+
require_relative 'logic/rollback'
|
|
11
12
|
|
|
12
13
|
module Yaso
|
|
13
|
-
module Logic
|
|
14
|
+
module Logic
|
|
15
|
+
FLOWS = {
|
|
16
|
+
classic: Logic::Classic,
|
|
17
|
+
rollback: Logic::Rollback
|
|
18
|
+
}.freeze
|
|
19
|
+
end
|
|
14
20
|
end
|
data/lib/yaso/service.rb
CHANGED
|
@@ -4,13 +4,54 @@ module Yaso
|
|
|
4
4
|
class Service
|
|
5
5
|
extend Stepable
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
attr_writer :success
|
|
8
|
+
|
|
9
|
+
def initialize(context)
|
|
10
|
+
@context = context
|
|
11
|
+
@success = true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def [](key)
|
|
15
|
+
@context[key]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def []=(key, value)
|
|
19
|
+
@context[key] = value
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def success?
|
|
23
|
+
@success
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def failure?
|
|
27
|
+
!@success
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_h
|
|
31
|
+
@context.dup
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def inspect
|
|
35
|
+
"Result:#{self.class} successful: #{@success}, context: #{@context}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class << self
|
|
39
|
+
def call(context = {})
|
|
40
|
+
@entry ||= flow.call(self, steps)
|
|
41
|
+
step = @entry
|
|
42
|
+
instance = new(context)
|
|
43
|
+
success = true
|
|
44
|
+
step, success = step.call(context, instance) while step
|
|
45
|
+
instance.success = success
|
|
46
|
+
instance
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def flow(name = nil)
|
|
50
|
+
@flow ||= Logic::FLOWS[:classic] if self == Yaso::Service
|
|
51
|
+
return @flow || Yaso::Service.flow if name.nil?
|
|
52
|
+
|
|
53
|
+
@flow = Logic::FLOWS[name] || raise(UnknownFlowError.new(self, name))
|
|
54
|
+
end
|
|
14
55
|
end
|
|
15
56
|
end
|
|
16
57
|
end
|
data/lib/yaso/stepable.rb
CHANGED
|
@@ -6,15 +6,22 @@ module Yaso
|
|
|
6
6
|
@steps ||= []
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
%i[step pass
|
|
10
|
-
define_method(category) do |object, options
|
|
11
|
-
raise InvalidFirstStepError, category if category == :failure && steps.empty?
|
|
12
|
-
|
|
9
|
+
%i[step pass wrap switch].each do |category|
|
|
10
|
+
define_method(category) do |object, **options, &block|
|
|
13
11
|
steps << {
|
|
14
12
|
object: object, category: category, fast: options.delete(:fast), on_success: options.delete(:on_success),
|
|
15
13
|
on_failure: options.delete(:on_failure), options: options, block: block, name: options.delete(:name)
|
|
16
14
|
}
|
|
17
15
|
end
|
|
18
16
|
end
|
|
17
|
+
|
|
18
|
+
def failure(object, **options, &block)
|
|
19
|
+
raise InvalidFirstStepError, :failure if flow == Logic::Classic && steps.empty?
|
|
20
|
+
|
|
21
|
+
steps << {
|
|
22
|
+
object: object, category: :failure, fast: options.delete(:fast), on_success: options.delete(:on_success),
|
|
23
|
+
on_failure: options.delete(:on_failure), options: options, block: block, name: options.delete(:name)
|
|
24
|
+
}
|
|
25
|
+
end
|
|
19
26
|
end
|
|
20
27
|
end
|
data/lib/yaso/version.rb
CHANGED
data/lib/yaso.rb
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'yaso/version'
|
|
4
4
|
require_relative 'yaso/errors'
|
|
5
|
-
require_relative 'yaso/
|
|
6
|
-
require_relative 'yaso/invokable'
|
|
5
|
+
require_relative 'yaso/invocable'
|
|
7
6
|
require_relative 'yaso/stepable'
|
|
8
7
|
require_relative 'yaso/logic'
|
|
9
8
|
require_relative 'yaso/service'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yaso
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Artem Shevchenko
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-
|
|
11
|
+
date: 2022-09-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ffaker
|
|
@@ -197,6 +197,7 @@ files:
|
|
|
197
197
|
- benchmark/shared/decouplio_service.rb
|
|
198
198
|
- benchmark/shared/interactor_service.rb
|
|
199
199
|
- benchmark/shared/pure_service.rb
|
|
200
|
+
- benchmark/shared/simple_command_service.rb
|
|
200
201
|
- benchmark/shared/trailblazer_service.rb
|
|
201
202
|
- benchmark/shared/yaso_service.rb
|
|
202
203
|
- benchmark/step/active_interaction.rb
|
|
@@ -204,18 +205,22 @@ files:
|
|
|
204
205
|
- benchmark/step/decouplio.rb
|
|
205
206
|
- benchmark/step/interactor.rb
|
|
206
207
|
- benchmark/step/pure.rb
|
|
208
|
+
- benchmark/step/simple_command.rb
|
|
207
209
|
- benchmark/step/trailblazer.rb
|
|
208
210
|
- benchmark/step/yaso.rb
|
|
211
|
+
- docker-compose.yml
|
|
212
|
+
- docker/Dockerfile
|
|
213
|
+
- docker/entrypoint.sh
|
|
209
214
|
- lefthook.yml
|
|
210
215
|
- lib/yaso.rb
|
|
211
|
-
- lib/yaso/context.rb
|
|
212
216
|
- lib/yaso/errors.rb
|
|
213
|
-
- lib/yaso/
|
|
217
|
+
- lib/yaso/invocable.rb
|
|
214
218
|
- lib/yaso/logic.rb
|
|
215
219
|
- lib/yaso/logic/base.rb
|
|
216
220
|
- lib/yaso/logic/classic.rb
|
|
217
221
|
- lib/yaso/logic/failure.rb
|
|
218
222
|
- lib/yaso/logic/pass.rb
|
|
223
|
+
- lib/yaso/logic/rollback.rb
|
|
219
224
|
- lib/yaso/logic/step.rb
|
|
220
225
|
- lib/yaso/logic/step_builder.rb
|
|
221
226
|
- lib/yaso/logic/switch.rb
|
data/lib/yaso/context.rb
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Yaso
|
|
4
|
-
class Context
|
|
5
|
-
attr_writer :success
|
|
6
|
-
attr_reader :data
|
|
7
|
-
|
|
8
|
-
def initialize(kwargs)
|
|
9
|
-
@success = true
|
|
10
|
-
@data = kwargs
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def [](key)
|
|
14
|
-
@data[key]
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def []=(key, value)
|
|
18
|
-
@data[key] = value
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def to_h
|
|
22
|
-
@data.dup
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def success?
|
|
26
|
-
@success
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def failure?
|
|
30
|
-
!@success
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
data/lib/yaso/invokable.rb
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Yaso
|
|
4
|
-
class Invokable
|
|
5
|
-
METHOD = :method
|
|
6
|
-
CALLABLE = :callable
|
|
7
|
-
YASO = :yaso
|
|
8
|
-
|
|
9
|
-
class << self
|
|
10
|
-
def call(object, options: {}, **)
|
|
11
|
-
type = object_type(object)
|
|
12
|
-
invokable = case type
|
|
13
|
-
when YASO then proc { |context, _| object.call(context.clone).success? }
|
|
14
|
-
when CALLABLE then proc { |context, _, &block| object.call(context, **options, &block) }
|
|
15
|
-
else method_invokable(object)
|
|
16
|
-
end
|
|
17
|
-
[type, invokable]
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def object_type(object)
|
|
23
|
-
return Invokable::METHOD unless object.is_a?(Class)
|
|
24
|
-
|
|
25
|
-
object < ::Yaso::Service ? Invokable::YASO : Invokable::CALLABLE
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def method_invokable(object)
|
|
29
|
-
instance_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
30
|
-
proc { |context, instance, &block| # proc { |context, instance, &block|
|
|
31
|
-
instance.#{object}(context, **context.data, &block) # instance.<method_name>(context, **context.data, &block)
|
|
32
|
-
} # }
|
|
33
|
-
RUBY
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|