yaso 1.2.0 → 1.3.1

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: 293839b577b5832d54938e07a07729d49ddd74fd226f0077076fe6f4986340ae
4
- data.tar.gz: 72d9d2bde9edbc0050f1473e3efc33a9c81952fe78906eaeb35acbba2ccc80bf
3
+ metadata.gz: 82a14582b1dadeb5c6103880c2ec7b3d7afe887ec9d8eb90601d77c02cfaf785
4
+ data.tar.gz: 94eab6547c4c0eaa87285bf09aa78534c33c06164fb98435dc7fe0b2f6d84d54
5
5
  SHA512:
6
- metadata.gz: a54b6acc15d5d8e71b25a4273ce87816ae58a1e63bd815e4cf338d671b5b71b3378016c076d9db44122e7612619e69e06c60e63cf7afd388b0de7509ad42ac0f
7
- data.tar.gz: 55a031ce994ac21ed04e659d70b2871cae67ed64d088799e26663b1d5e2ac5f76593d0ea4d0e3e181ff72b63fed7aa626abf67b063eed696be4418e74930e9e8
6
+ metadata.gz: 0104e325136a9952cff6309951c67915d015cf67897fcf257e73a51e335eb0d8e12bf87ecf2ec09bb5d326bf3c7622101f2b02a6c06deb75c16f511c91eff3a5
7
+ data.tar.gz: 04525a4314e1417f48f699e71d0b77ecf888ce44524e972fb2b811ddcfe9ef68f399c1771cf81031df6127d63287091e2b9fe36e3679cd0e6c26775554b7c3e7
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.1.2
1
+ 3.1.3
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- yaso (1.2.0)
4
+ yaso (1.3.1)
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.0)
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.0)
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.0)
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,10 +59,11 @@ 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.2.0)
62
+ unicode-display_width (2.3.0)
63
63
 
64
64
  PLATFORMS
65
65
  x86_64-darwin-21
66
+ x86_64-darwin-22
66
67
  x86_64-linux
67
68
 
68
69
  DEPENDENCIES
data/README.md CHANGED
@@ -1,8 +1,7 @@
1
1
  # Yaso
2
2
  [![Ruby](https://github.com/Ar2emis/yaso/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/Ar2emis/yaso/actions/workflows/main.yml) ![gem](https://img.shields.io/gem/v/yaso) [![GitHub license](https://img.shields.io/github/license/Ar2emis/yaso)](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 new branch from the master, do your dark business, open a pull request and assign me as a reviewer.
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
@@ -3,11 +3,23 @@
3
3
  source 'https://rubygems.org'
4
4
 
5
5
  gem 'benchmark-ips', '~> 2.10.0'
6
+
7
+ DRY_CONTAINER = {
8
+ '2.5' => '~> 0.7.2',
9
+ '2.6' => '~> 0.9.0'
10
+ }.freeze
11
+ gem 'dry-container', DRY_CONTAINER.fetch(RUBY_VERSION.match(/\A\d+\.\d+/)[0], '~> 0.11.0')
12
+ DRY_TRANSACTION = {
13
+ '2.5' => '~> 0.13.2',
14
+ '2.6' => '~> 0.13.3'
15
+ }.freeze
16
+ gem 'dry-transaction', DRY_TRANSACTION.fetch(RUBY_VERSION.match(/\A\d+\.\d+/)[0], '~> 0.15.0')
6
17
  gem 'interactor', '~> 3.1.2'
7
18
  gem 'kalibera', '~> 0.1.2'
8
19
  gem 'simple_command', RUBY_VERSION.include?('2.5') ? '~> 0.2.0' : '~> 1.0.1'
9
20
  gem 'trailblazer', '~> 2.1.0'
21
+ gem 'yaso', path: '..'
10
22
 
11
23
  gem 'active_interaction', %w[2.5 2.6].any? { |version| RUBY_VERSION.include?(version) } ? '~> 4.1.0' : '~> 5.1.0'
12
24
 
13
- RUBY_VERSION.include?('2.5') || gem('decouplio', '~> 1.0.0alpha8')
25
+ RUBY_VERSION.include?('2.5') || gem('decouplio', '~> 1.0.0rc')
data/benchmark/index.rb CHANGED
@@ -2,14 +2,16 @@
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'
12
10
  require 'simple_command'
11
+ require 'yaso'
12
+ require 'dry/container'
13
+ require 'dry/transaction'
14
+ require 'dry/transaction/operation'
13
15
 
14
16
  require_relative 'shared/yaso_service'
15
17
  RUBY_VERSION.include?('2.5') || require_relative('shared/decouplio_service')
@@ -27,4 +29,5 @@ require_relative 'step/simple_command'
27
29
  require_relative 'step/interactor'
28
30
  require_relative 'step/active_interaction'
29
31
  require_relative 'step/trailblazer'
32
+ require_relative 'step/dry_transaction'
30
33
  require_relative 'step/benchmark'
@@ -13,6 +13,7 @@ Benchmark.ips do |x|
13
13
  x.report('Interactor') { InteractorStepsService.call }
14
14
  x.report('ActiveInteraction') { ActiveInteractionStepsService.run }
15
15
  x.report('Trailblazer') { TrailblazerStepsService.call }
16
+ x.report('DryTransaction') { DryTransactionStepsService.new.call({}) }
16
17
 
17
18
  x.compare!
18
19
  end
@@ -28,6 +29,7 @@ Benchmark.ips do |x|
28
29
  x.report('Interactor') { InteractorCallablesService.call }
29
30
  x.report('ActiveInteraction') { ActiveInteractionCallablesService.run }
30
31
  x.report('Trailblazer') { TrailblazerCallablesService.call }
32
+ x.report('DryTransaction') { DryTransactionCallablesService.new.call({}) }
31
33
 
32
34
  x.compare!
33
35
  end
@@ -56,7 +56,7 @@ class DecouplioStepsService < DecouplioService
56
56
  end
57
57
 
58
58
  class DecouplioCallableStep
59
- def self.call(ctx:, key:, value:, **)
59
+ def self.call(ctx, _, key:, value:, **)
60
60
  ctx[key] = value
61
61
  end
62
62
  end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DryTransactionStepsService
4
+ include Dry::Transaction
5
+
6
+ step :one
7
+ step :two
8
+ step :three
9
+ step :four
10
+ step :five
11
+ step :six
12
+ step :seven
13
+ step :eight
14
+ step :nine
15
+ step :ten
16
+
17
+ private
18
+
19
+ def one(ctx)
20
+ ctx[:one] = true
21
+ Success(ctx)
22
+ end
23
+
24
+ def two(ctx)
25
+ ctx[:two] = true
26
+ Success(ctx)
27
+ end
28
+
29
+ def three(ctx)
30
+ ctx[:three] = true
31
+ Success(ctx)
32
+ end
33
+
34
+ def four(ctx)
35
+ ctx[:four] = true
36
+ Success(ctx)
37
+ end
38
+
39
+ def five(ctx)
40
+ ctx[:five] = true
41
+ Success(ctx)
42
+ end
43
+
44
+ def six(ctx)
45
+ ctx[:six] = true
46
+ Success(ctx)
47
+ end
48
+
49
+ def seven(ctx)
50
+ ctx[:seven] = true
51
+ Success(ctx)
52
+ end
53
+
54
+ def eight(ctx)
55
+ ctx[:eight] = true
56
+ Success(ctx)
57
+ end
58
+
59
+ def nine(ctx)
60
+ ctx[:nine] = true
61
+ Success(ctx)
62
+ end
63
+
64
+ def ten(ctx)
65
+ ctx[:ten] = true
66
+ Success(ctx)
67
+ end
68
+ end
69
+
70
+ class DryTansactionCallable
71
+ include Dry::Transaction::Operation
72
+
73
+ def initialize(key)
74
+ @key = key
75
+ end
76
+
77
+ def call(ctx)
78
+ ctx[@key] = true
79
+ Success(ctx)
80
+ end
81
+ end
82
+
83
+ class DryTransactionContainer
84
+ extend Dry::Container::Mixin
85
+
86
+ namespace :callable do
87
+ register(:one) { DryTansactionCallable.new(:one) }
88
+ register(:two) { DryTansactionCallable.new(:two) }
89
+ register(:three) { DryTansactionCallable.new(:three) }
90
+ register(:four) { DryTansactionCallable.new(:four) }
91
+ register(:five) { DryTansactionCallable.new(:five) }
92
+ register(:six) { DryTansactionCallable.new(:six) }
93
+ register(:seven) { DryTansactionCallable.new(:seven) }
94
+ register(:eight) { DryTansactionCallable.new(:eight) }
95
+ register(:nine) { DryTansactionCallable.new(:nine) }
96
+ register(:ten) { DryTansactionCallable.new(:ten) }
97
+ end
98
+ end
99
+
100
+ class DryTransactionCallablesService
101
+ include Dry::Transaction(container: DryTransactionContainer)
102
+
103
+ step :one, with: :'callable.one'
104
+ step :two, with: :'callable.two'
105
+ step :three, with: :'callable.three'
106
+ step :four, with: :'callable.four'
107
+ step :five, with: :'callable.five'
108
+ step :six, with: :'callable.six'
109
+ step :seven, with: :'callable.seven'
110
+ step :eight, with: :'callable.eight'
111
+ step :nine, with: :'callable.nine'
112
+ step :ten, with: :'callable.ten'
113
+ end
@@ -64,7 +64,7 @@ module TrailblazerMacro
64
64
  ctx[:"result.#{id}"] = Trailblazer::Operation::Result.new(false, {})
65
65
  false
66
66
  end
67
- task = Trailblazer::Activity::TaskBuilder::Binary(step)
67
+ task = Trailblazer::Activity::Circuit::TaskAdapter.for_step(step)
68
68
  { task: task, id: id }
69
69
  end
70
70
  # rubocop:enable Naming/MethodName
data/docker/Dockerfile ADDED
@@ -0,0 +1,7 @@
1
+ ARG VERSION=latest
2
+
3
+ FROM ruby:${VERSION}
4
+
5
+ ENTRYPOINT [ "/yaso/docker/entrypoint.sh" ]
6
+
7
+ WORKDIR /yaso/benchmark
@@ -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
@@ -0,0 +1,9 @@
1
+ services:
2
+ benchmark:
3
+ build: docker
4
+ volumes:
5
+ - .:/yaso
6
+ - bundle:/bundle/cache
7
+
8
+ volumes:
9
+ bundle:
@@ -7,12 +7,12 @@ module Yaso
7
7
  YASO = :yaso
8
8
 
9
9
  class << self
10
- def call(object, options: {}, **)
10
+ def call(object, options: {}, with_block: false, **)
11
11
  type = object_type(object)
12
12
  invocable = 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_invocable(object)
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
16
  end
17
17
  [type, invocable]
18
18
  end
@@ -25,11 +25,25 @@ module Yaso
25
25
  object < ::Yaso::Service ? Invocable::YASO : Invocable::CALLABLE
26
26
  end
27
27
 
28
- def method_invocable(object)
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
+
29
43
  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
- } # }
44
+ proc { |context, instance| # proc { |context, instance|
45
+ instance.#{object}(context, **context) # instance.<method_name>(context, **context)
46
+ } # }
33
47
  RUBY
34
48
  end
35
49
  end
@@ -4,7 +4,7 @@ module Yaso
4
4
  module Logic
5
5
  class Failure < Base
6
6
  def call(context, instance)
7
- context.success = false
7
+ instance.success = false
8
8
  @invocable.call(context, instance) ? @next_step : @failure
9
9
  end
10
10
  end
@@ -4,7 +4,7 @@ module Yaso
4
4
  module Logic
5
5
  class Pass < Base
6
6
  def call(context, instance)
7
- context.success = true
7
+ instance.success = true
8
8
  @invocable.call(context, instance) ? @next_step : @failure
9
9
  end
10
10
  end
@@ -4,11 +4,11 @@ module Yaso
4
4
  module Logic
5
5
  class Step < Base
6
6
  def call(context, instance)
7
- context.success = true
7
+ instance.success = true
8
8
  if @invocable.call(context, instance)
9
9
  @next_step
10
10
  else
11
- context.success = false
11
+ instance.success = false
12
12
  @failure
13
13
  end
14
14
  end
@@ -16,8 +16,8 @@ module Yaso
16
16
  end
17
17
 
18
18
  def call(object:, category:, block:, **opts)
19
- invocable_type, invocable = Invocable.call(object, **opts)
20
19
  logic_class = CATEGORIES[category]
20
+ invocable_type, invocable = Invocable.call(object, with_block: logic_class == Wrap, **opts)
21
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
@@ -51,14 +51,11 @@ module Yaso
51
51
  end
52
52
 
53
53
  def build_wrapper_methods(wrapper_class, service_class)
54
- wrapper_class.define_singleton_method(:flow) do
55
- service_class.flow
56
- end
57
54
  wrapper_class.define_singleton_method(:call) do |context, instance|
58
- @entry ||= flow.call(service_class, steps)
55
+ @entry ||= service_class.flow.call(service_class, steps)
59
56
  step = @entry
60
57
  step = step.call(context, instance) while step
61
- context
58
+ instance
62
59
  end
63
60
  end
64
61
  end
@@ -4,13 +4,12 @@ module Yaso
4
4
  module Logic
5
5
  class Switch < Base
6
6
  def call(context, instance)
7
- context.success = true
7
+ instance.success = true
8
8
  switch_case = @invocable.call(context, instance) || raise(UnhandledSwitchCaseError, instance.class)
9
-
10
9
  if Invocable.call(switch_case).last.call(context, instance)
11
10
  @next_step
12
11
  else
13
- context.success = false
12
+ instance.success = false
14
13
  @failure
15
14
  end
16
15
  end
@@ -9,11 +9,12 @@ module Yaso
9
9
  end
10
10
 
11
11
  def call(context, instance)
12
- context.success = true
13
- if @invocable.call(context, instance) { @wrapper.call(context, instance).success? }
12
+ instance.success = true
13
+ result = @invocable.call(context, instance) { @wrapper.call(context, instance).success? }
14
+ if result
14
15
  @next_step
15
16
  else
16
- context.success = false
17
+ instance.success = false
17
18
  @failure
18
19
  end
19
20
  end
data/lib/yaso/service.rb CHANGED
@@ -4,14 +4,44 @@ module Yaso
4
4
  class Service
5
5
  extend Stepable
6
6
 
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
+
7
38
  class << self
8
39
  def call(context = {})
9
- context = context.is_a?(Context) ? context : Context.new(context)
10
40
  @entry ||= flow.call(self, steps)
11
41
  step = @entry
12
- instance = new
42
+ instance = new(context)
13
43
  step = step.call(context, instance) while step
14
- context
44
+ instance
15
45
  end
16
46
 
17
47
  def flow(name = nil)
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.2.0'
4
+ VERSION = '1.3.1'
5
5
  end
data/lib/yaso.rb CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  require_relative 'yaso/version'
4
4
  require_relative 'yaso/errors'
5
- require_relative 'yaso/context'
6
5
  require_relative 'yaso/invocable'
7
6
  require_relative 'yaso/stepable'
8
7
  require_relative 'yaso/logic'
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.2.0
4
+ version: 1.3.1
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-27 00:00:00.000000000 Z
11
+ date: 2022-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffaker
@@ -203,14 +203,17 @@ files:
203
203
  - benchmark/step/active_interaction.rb
204
204
  - benchmark/step/benchmark.rb
205
205
  - benchmark/step/decouplio.rb
206
+ - benchmark/step/dry_transaction.rb
206
207
  - benchmark/step/interactor.rb
207
208
  - benchmark/step/pure.rb
208
209
  - benchmark/step/simple_command.rb
209
210
  - benchmark/step/trailblazer.rb
210
211
  - benchmark/step/yaso.rb
212
+ - docker-compose.yml
213
+ - docker/Dockerfile
214
+ - docker/entrypoint.sh
211
215
  - lefthook.yml
212
216
  - lib/yaso.rb
213
- - lib/yaso/context.rb
214
217
  - lib/yaso/errors.rb
215
218
  - lib/yaso/invocable.rb
216
219
  - lib/yaso/logic.rb
@@ -248,7 +251,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
248
251
  - !ruby/object:Gem::Version
249
252
  version: '0'
250
253
  requirements: []
251
- rubygems_version: 3.3.7
254
+ rubygems_version: 3.3.26
252
255
  signing_key:
253
256
  specification_version: 4
254
257
  summary: Yet Another Service Object
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