yaso 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e562bf748ebc163661813eed594c0abdecc4bf2027f68cb3cfb389464066fd82
4
- data.tar.gz: 4fd59f39375881b4c9b04442405318a82f58792a7d759edfef302cc25b2b3107
3
+ metadata.gz: 293839b577b5832d54938e07a07729d49ddd74fd226f0077076fe6f4986340ae
4
+ data.tar.gz: 72d9d2bde9edbc0050f1473e3efc33a9c81952fe78906eaeb35acbba2ccc80bf
5
5
  SHA512:
6
- metadata.gz: bb6e535a13645a6831364324459a76808affb02715d6f6f173d3e913058befa03bd7af75828bdf627e54d8daccf060e7d0fae693dda4b65c224573c0afb0a7a5
7
- data.tar.gz: '0987332c9e58733298f8b7c5c164222d91835492afb2107fb7bffbfaaeeec2b3234d2f34fdf57b6b0fcc7055b95669a42b803449f351f4c8d243a00147ca4a9d'
6
+ metadata.gz: a54b6acc15d5d8e71b25a4273ce87816ae58a1e63bd815e4cf338d671b5b71b3378016c076d9db44122e7612619e69e06c60e63cf7afd388b0de7509ad42ac0f
7
+ data.tar.gz: 55a031ce994ac21ed04e659d70b2871cae67ed64d088799e26663b1d5e2ac5f76593d0ea4d0e3e181ff72b63fed7aa626abf67b063eed696be4418e74930e9e8
data/.rubocop.yml CHANGED
@@ -8,6 +8,7 @@ AllCops:
8
8
  NewCops: enable
9
9
  Exclude:
10
10
  - vendor/bundle/**/*
11
+ - benchmark/vendor/bundle/**/*
11
12
 
12
13
  Gemspec/RequiredRubyVersion:
13
14
  Enabled: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- yaso (1.1.0)
4
+ yaso (1.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/benchmark/Gemfile CHANGED
@@ -5,6 +5,7 @@ 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'
9
10
 
10
11
  gem 'active_interaction', %w[2.5 2.6].any? { |version| RUBY_VERSION.include?(version) } ? '~> 4.1.0' : '~> 5.1.0'
data/benchmark/index.rb CHANGED
@@ -9,10 +9,12 @@ RUBY_VERSION.include?('2.5') || require('decouplio')
9
9
  require 'interactor'
10
10
  require 'active_interaction'
11
11
  require 'trailblazer'
12
+ require 'simple_command'
12
13
 
13
14
  require_relative 'shared/yaso_service'
14
15
  RUBY_VERSION.include?('2.5') || require_relative('shared/decouplio_service')
15
16
  require_relative 'shared/pure_service'
17
+ require_relative 'shared/simple_command_service'
16
18
  require_relative 'shared/interactor_service'
17
19
  require_relative 'shared/active_interaction_service'
18
20
  require_relative 'shared/trailblazer_service'
@@ -21,6 +23,7 @@ require_relative 'shared/callable_step'
21
23
  require_relative 'step/yaso'
22
24
  RUBY_VERSION.include?('2.5') || require_relative('step/decouplio')
23
25
  require_relative 'step/pure'
26
+ require_relative 'step/simple_command'
24
27
  require_relative 'step/interactor'
25
28
  require_relative 'step/active_interaction'
26
29
  require_relative 'step/trailblazer'
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SimpleCommandService
4
+ prepend SimpleCommand
5
+
6
+ attr_reader :ctx
7
+
8
+ def initialize(**ctx)
9
+ @ctx = ctx
10
+ end
11
+ end
@@ -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/lib/yaso/errors.rb CHANGED
@@ -20,4 +20,10 @@ module Yaso
20
20
  super("Unhandled switch case in #{klass}")
21
21
  end
22
22
  end
23
+
24
+ class UnknownFlowError < Error
25
+ def initialize(klass, name)
26
+ super("Unknown flow \"#{name}\" is set in #{klass}")
27
+ end
28
+ end
23
29
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Yaso
4
- class Invokable
4
+ class Invocable
5
5
  METHOD = :method
6
6
  CALLABLE = :callable
7
7
  YASO = :yaso
@@ -9,23 +9,23 @@ module Yaso
9
9
  class << self
10
10
  def call(object, options: {}, **)
11
11
  type = object_type(object)
12
- invokable = case type
12
+ invocable = case type
13
13
  when YASO then proc { |context, _| object.call(context.clone).success? }
14
14
  when CALLABLE then proc { |context, _, &block| object.call(context, **options, &block) }
15
- else method_invokable(object)
15
+ else method_invocable(object)
16
16
  end
17
- [type, invokable]
17
+ [type, invocable]
18
18
  end
19
19
 
20
20
  private
21
21
 
22
22
  def object_type(object)
23
- return Invokable::METHOD unless object.is_a?(Class)
23
+ return Invocable::METHOD unless object.is_a?(Class)
24
24
 
25
- object < ::Yaso::Service ? Invokable::YASO : Invokable::CALLABLE
25
+ object < ::Yaso::Service ? Invocable::YASO : Invocable::CALLABLE
26
26
  end
27
27
 
28
- def method_invokable(object)
28
+ def method_invocable(object)
29
29
  instance_eval <<-RUBY, __FILE__, __LINE__ + 1
30
30
  proc { |context, instance, &block| # proc { |context, instance, &block|
31
31
  instance.#{object}(context, **context.data, &block) # instance.<method_name>(context, **context.data, &block)
@@ -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:, invokable:, **options)
8
+ def initialize(name:, invocable:, **options)
9
9
  @name = name
10
- @invokable = invokable
10
+ @invocable = invocable
11
11
  @fast = options[:fast]
12
12
  @on_success = options[:on_success]
13
13
  @on_failure = options[:on_failure]
@@ -5,7 +5,7 @@ module Yaso
5
5
  class Failure < Base
6
6
  def call(context, instance)
7
7
  context.success = false
8
- @invokable.call(context, instance) ? @next_step : @failure
8
+ @invocable.call(context, instance) ? @next_step : @failure
9
9
  end
10
10
  end
11
11
  end
@@ -5,7 +5,7 @@ module Yaso
5
5
  class Pass < Base
6
6
  def call(context, instance)
7
7
  context.success = true
8
- @invokable.call(context, instance) ? @next_step : @failure
8
+ @invocable.call(context, instance) ? @next_step : @failure
9
9
  end
10
10
  end
11
11
  end
@@ -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
@@ -5,7 +5,7 @@ module Yaso
5
5
  class Step < Base
6
6
  def call(context, instance)
7
7
  context.success = true
8
- if @invokable.call(context, instance)
8
+ if @invocable.call(context, instance)
9
9
  @next_step
10
10
  else
11
11
  context.success = false
@@ -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)
19
+ invocable_type, invocable = Invocable.call(object, **opts)
20
20
  logic_class = CATEGORIES[category]
21
- if invokable_type == Invokable::METHOD
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(invokable: invokable, **opts)
25
+ logic_class.new(invocable: invocable, **opts)
26
26
  end
27
27
 
28
28
  private
@@ -45,14 +45,17 @@ 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 build_wrapper_call(wrapper_class, service_class)
53
+ def build_wrapper_methods(wrapper_class, service_class)
54
+ wrapper_class.define_singleton_method(:flow) do
55
+ service_class.flow
56
+ end
54
57
  wrapper_class.define_singleton_method(:call) do |context, instance|
55
- @entry ||= Logic::Classic.call(service_class, steps)
58
+ @entry ||= flow.call(service_class, steps)
56
59
  step = @entry
57
60
  step = step.call(context, instance) while step
58
61
  context
@@ -5,9 +5,9 @@ module Yaso
5
5
  class Switch < Base
6
6
  def call(context, instance)
7
7
  context.success = true
8
- switch_case = @invokable.call(context, instance) || raise(UnhandledSwitchCaseError, instance.class)
8
+ switch_case = @invocable.call(context, instance) || raise(UnhandledSwitchCaseError, instance.class)
9
9
 
10
- if Invokable.call(switch_case).last.call(context, instance)
10
+ if Invocable.call(switch_case).last.call(context, instance)
11
11
  @next_step
12
12
  else
13
13
  context.success = false
@@ -10,7 +10,7 @@ module Yaso
10
10
 
11
11
  def call(context, instance)
12
12
  context.success = true
13
- if @invokable.call(context, instance) { @wrapper.call(context, instance).success? }
13
+ if @invocable.call(context, instance) { @wrapper.call(context, instance).success? }
14
14
  @next_step
15
15
  else
16
16
  context.success = false
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; end
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,22 @@ module Yaso
4
4
  class Service
5
5
  extend Stepable
6
6
 
7
- def self.call(context = {})
8
- context = context.is_a?(Context) ? context : Context.new(context)
9
- @entry ||= Logic::Classic.call(self, steps)
10
- step = @entry
11
- instance = new
12
- step = step.call(context, instance) while step
13
- context
7
+ class << self
8
+ def call(context = {})
9
+ context = context.is_a?(Context) ? context : Context.new(context)
10
+ @entry ||= flow.call(self, steps)
11
+ step = @entry
12
+ instance = new
13
+ step = step.call(context, instance) while step
14
+ context
15
+ end
16
+
17
+ def flow(name = nil)
18
+ @flow ||= Logic::FLOWS[:classic] if self == Yaso::Service
19
+ return @flow || Yaso::Service.flow if name.nil?
20
+
21
+ @flow = Logic::FLOWS[name] || raise(UnknownFlowError.new(self, name))
22
+ end
14
23
  end
15
24
  end
16
25
  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 failure wrap switch].each do |category|
10
- define_method(category) do |object, options = {}, &block|
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Yaso
4
- VERSION = '1.1.0'
4
+ VERSION = '1.2.0'
5
5
  end
data/lib/yaso.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require_relative 'yaso/version'
4
4
  require_relative 'yaso/errors'
5
5
  require_relative 'yaso/context'
6
- require_relative 'yaso/invokable'
6
+ require_relative 'yaso/invocable'
7
7
  require_relative 'yaso/stepable'
8
8
  require_relative 'yaso/logic'
9
9
  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.1.0
4
+ version: 1.2.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-08-25 00:00:00.000000000 Z
11
+ date: 2022-08-27 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,20 @@ 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
209
211
  - lefthook.yml
210
212
  - lib/yaso.rb
211
213
  - lib/yaso/context.rb
212
214
  - lib/yaso/errors.rb
213
- - lib/yaso/invokable.rb
215
+ - lib/yaso/invocable.rb
214
216
  - lib/yaso/logic.rb
215
217
  - lib/yaso/logic/base.rb
216
218
  - lib/yaso/logic/classic.rb
217
219
  - lib/yaso/logic/failure.rb
218
220
  - lib/yaso/logic/pass.rb
221
+ - lib/yaso/logic/rollback.rb
219
222
  - lib/yaso/logic/step.rb
220
223
  - lib/yaso/logic/step_builder.rb
221
224
  - lib/yaso/logic/switch.rb