service_operator 0.2.2
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/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +54 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +22 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +67 -0
- data/LICENSE.txt +21 -0
- data/README.md +90 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/service_operator/configuration.rb +18 -0
- data/lib/service_operator/context.rb +39 -0
- data/lib/service_operator/hooks.rb +66 -0
- data/lib/service_operator/step.rb +70 -0
- data/lib/service_operator/steps.rb +111 -0
- data/lib/service_operator/version.rb +5 -0
- data/lib/service_operator.rb +75 -0
- data/service_operator.gemspec +36 -0
- metadata +136 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bbf2f3da24a3a69f4bdb08d13390973c846a732b8b15a46c0857cbf3c638e002
|
4
|
+
data.tar.gz: 9f9b1b3cd9b7bc9da0d093879aaff4f9b7c94d86bec63a46e640e05e24c17ce1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1d7ff1d4a0ed6b5102b94c4b852b59afc378596ab9c5f2280407992568b0d5b626c1d143b81dbf6ebfc9e99e628a1001a4c68e26c65c622d51f1f7cd2346c8fc
|
7
|
+
data.tar.gz: 19f1f61c75495088b1a6e62d89a8c7df6334a8a7f4c7d93b06c7da9bc74bb17a38e7a46ffd37ddf570ae7f8e494413f65a127b4091c351853550bf3e176082db
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-performance
|
3
|
+
- rubocop-rake
|
4
|
+
- rubocop-rspec
|
5
|
+
|
6
|
+
AllCops:
|
7
|
+
Exclude:
|
8
|
+
- 'bin/*'
|
9
|
+
NewCops: enable
|
10
|
+
TargetRubyVersion: 2.7
|
11
|
+
|
12
|
+
Style/StringLiterals:
|
13
|
+
Enabled: true
|
14
|
+
EnforcedStyle: single_quotes
|
15
|
+
|
16
|
+
Style/StringLiteralsInInterpolation:
|
17
|
+
Enabled: true
|
18
|
+
EnforcedStyle: double_quotes
|
19
|
+
|
20
|
+
Style/Documentation:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Style/BlockDelimiters:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Layout/LineLength:
|
27
|
+
Max: 120
|
28
|
+
|
29
|
+
# No space makes the method definition shorter and differentiates
|
30
|
+
# from a regular assignment.
|
31
|
+
Layout/SpaceAroundEqualsInParameterDefault:
|
32
|
+
EnforcedStyle: no_space
|
33
|
+
|
34
|
+
RSpec/ExampleLength:
|
35
|
+
Max: 20
|
36
|
+
|
37
|
+
RSpec/NestedGroups:
|
38
|
+
Max: 6
|
39
|
+
|
40
|
+
RSpec/ContextWording:
|
41
|
+
Prefixes:
|
42
|
+
- when
|
43
|
+
- with
|
44
|
+
- without
|
45
|
+
- and
|
46
|
+
- if
|
47
|
+
- in
|
48
|
+
- for
|
49
|
+
|
50
|
+
RSpec/MultipleMemoizedHelpers:
|
51
|
+
Enabled: false
|
52
|
+
|
53
|
+
Gemspec/RequireMFA:
|
54
|
+
Enabled: false
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.1.2
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Changelog
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
5
|
+
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
6
|
+
|
7
|
+
## [0.2.2] - 2022-09-12
|
8
|
+
### Modified
|
9
|
+
- generating arguments for method call in Step
|
10
|
+
- readme
|
11
|
+
|
12
|
+
## [0.2.1] - 2022-08-29
|
13
|
+
### Added
|
14
|
+
- Configuration with customizable settings
|
15
|
+
|
16
|
+
## [0.2.0] - 2022-08-28
|
17
|
+
### Added
|
18
|
+
- modules for configuring steps execution
|
19
|
+
|
20
|
+
## [0.1.0] - 2022-08-28
|
21
|
+
### Added
|
22
|
+
- Start project
|
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem 'rspec', '~> 3.0'
|
9
|
+
end
|
10
|
+
|
11
|
+
# Specify your gem's dependencies in service_operator.gemspec
|
12
|
+
gemspec
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
service_operator (0.2.2)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ast (2.4.2)
|
10
|
+
diff-lcs (1.5.0)
|
11
|
+
json (2.6.2)
|
12
|
+
parallel (1.22.1)
|
13
|
+
parser (3.1.2.1)
|
14
|
+
ast (~> 2.4.1)
|
15
|
+
rainbow (3.1.1)
|
16
|
+
rake (13.0.6)
|
17
|
+
regexp_parser (2.5.0)
|
18
|
+
rexml (3.2.5)
|
19
|
+
rspec (3.11.0)
|
20
|
+
rspec-core (~> 3.11.0)
|
21
|
+
rspec-expectations (~> 3.11.0)
|
22
|
+
rspec-mocks (~> 3.11.0)
|
23
|
+
rspec-core (3.11.0)
|
24
|
+
rspec-support (~> 3.11.0)
|
25
|
+
rspec-expectations (3.11.0)
|
26
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
27
|
+
rspec-support (~> 3.11.0)
|
28
|
+
rspec-mocks (3.11.1)
|
29
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
30
|
+
rspec-support (~> 3.11.0)
|
31
|
+
rspec-support (3.11.0)
|
32
|
+
rubocop (1.35.1)
|
33
|
+
json (~> 2.3)
|
34
|
+
parallel (~> 1.10)
|
35
|
+
parser (>= 3.1.2.1)
|
36
|
+
rainbow (>= 2.2.2, < 4.0)
|
37
|
+
regexp_parser (>= 1.8, < 3.0)
|
38
|
+
rexml (>= 3.2.5, < 4.0)
|
39
|
+
rubocop-ast (>= 1.20.1, < 2.0)
|
40
|
+
ruby-progressbar (~> 1.7)
|
41
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
42
|
+
rubocop-ast (1.21.0)
|
43
|
+
parser (>= 3.1.1.0)
|
44
|
+
rubocop-performance (1.14.3)
|
45
|
+
rubocop (>= 1.7.0, < 2.0)
|
46
|
+
rubocop-ast (>= 0.4.0)
|
47
|
+
rubocop-rake (0.6.0)
|
48
|
+
rubocop (~> 1.0)
|
49
|
+
rubocop-rspec (2.12.1)
|
50
|
+
rubocop (~> 1.31)
|
51
|
+
ruby-progressbar (1.11.0)
|
52
|
+
unicode-display_width (2.2.0)
|
53
|
+
|
54
|
+
PLATFORMS
|
55
|
+
x86_64-darwin-20
|
56
|
+
|
57
|
+
DEPENDENCIES
|
58
|
+
rake (~> 13.0)
|
59
|
+
rspec (~> 3.0)
|
60
|
+
rubocop (~> 1.3)
|
61
|
+
rubocop-performance (~> 1.8)
|
62
|
+
rubocop-rake (~> 0.6)
|
63
|
+
rubocop-rspec (~> 2.0)
|
64
|
+
service_operator!
|
65
|
+
|
66
|
+
BUNDLED WITH
|
67
|
+
2.3.19
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2022 Bogdanov Anton
|
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,90 @@
|
|
1
|
+
# ServiceOperator
|
2
|
+
Simple interactor is a gem based on ideas of gems [interactor](https://github.com/collectiveidea/interactor) and [dry-transaction](https://github.com/dry-rb/dry-transaction). ServiceOperator provides a simple way to processing over many steps and by many different objects.
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
Add this line to your application's Gemfile:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem 'service_operator'
|
9
|
+
```
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
```bash
|
13
|
+
$ bundle install
|
14
|
+
```
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
|
18
|
+
First you need create ApplicationOperator - basis class for your operators
|
19
|
+
```ruby
|
20
|
+
class ApplicationOperator
|
21
|
+
include ServiceOperator
|
22
|
+
|
23
|
+
# configuration
|
24
|
+
configure do |config|
|
25
|
+
config.call_parameters_method_name = :call_parameters
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# this around action is useful when you need to wrap your steps inside transaction
|
31
|
+
def use_transaction(operator)
|
32
|
+
ActiveRecord::Base.transaction do
|
33
|
+
operator.call
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
And then you can start creating operators for wrapping services with business logic
|
40
|
+
```ruby
|
41
|
+
module Weeks
|
42
|
+
class RefreshOperator < ApplicationOperator
|
43
|
+
# validating provided parameters for operator
|
44
|
+
required_context :week
|
45
|
+
|
46
|
+
# definition for around hooks
|
47
|
+
around :use_transaction
|
48
|
+
|
49
|
+
# definition for before hooks
|
50
|
+
before :turn_off
|
51
|
+
|
52
|
+
# definition for main steps
|
53
|
+
step :finish_week, service: Weeks::FinishService, week: :previous_week
|
54
|
+
step :start_week, service: Weeks::StartService
|
55
|
+
step :prepare_week, service: Weeks::ComingService
|
56
|
+
|
57
|
+
# definition for after hooks
|
58
|
+
after :turn_on
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def turn_off; end
|
63
|
+
|
64
|
+
def turn_on; end
|
65
|
+
|
66
|
+
def previous_week
|
67
|
+
context.week.previous
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
And run your operator
|
74
|
+
```ruby
|
75
|
+
Weeks::RefreshOperator.call(week: week)
|
76
|
+
```
|
77
|
+
|
78
|
+
## Development
|
79
|
+
|
80
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
81
|
+
|
82
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
83
|
+
|
84
|
+
## Contributing
|
85
|
+
|
86
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/kortirso/service_operator.
|
87
|
+
|
88
|
+
## License
|
89
|
+
|
90
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'service_operator'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ServiceOperator
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :call_method_name, :call_parameters_method_name, :failure_method_name
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
# Operator tries to run this method on step's service defined by `with` argument.
|
9
|
+
@call_method_name = :call
|
10
|
+
|
11
|
+
# Operator tries to run this method on step's service for fetching arguments list.
|
12
|
+
@call_parameters_method_name = :call
|
13
|
+
|
14
|
+
# Operator tries to run this method on step's service for checking failure status.
|
15
|
+
@failure_method_name = nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
# rubocop: disable Style/OpenStructUse
|
6
|
+
module ServiceOperator
|
7
|
+
Failure = Class.new(StandardError)
|
8
|
+
|
9
|
+
class Context < OpenStruct
|
10
|
+
def self.build(args={})
|
11
|
+
context = new(args)
|
12
|
+
context.failure = false
|
13
|
+
context
|
14
|
+
end
|
15
|
+
|
16
|
+
# Public: Validate the ServiceOperator::Context.
|
17
|
+
# If any required param is missed in context then it fails context
|
18
|
+
def validate(required_params: [])
|
19
|
+
fail if required_params.any?(&:nil?)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Public: Fail the ServiceOperator::Context.
|
23
|
+
# Failing a context raises an error that rollback all changes at transaction steps.
|
24
|
+
# The context is also flagged as having failed.
|
25
|
+
def fail
|
26
|
+
self.failure = true
|
27
|
+
raise Failure
|
28
|
+
end
|
29
|
+
|
30
|
+
def success?
|
31
|
+
!failure
|
32
|
+
end
|
33
|
+
|
34
|
+
def failure?
|
35
|
+
failure
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
# rubocop: enable Style/OpenStructUse
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ServiceOperator
|
4
|
+
module Hooks
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval do
|
7
|
+
extend ClassMethods
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def around_hooks
|
13
|
+
@around_hooks ||= []
|
14
|
+
end
|
15
|
+
|
16
|
+
# Examples
|
17
|
+
#
|
18
|
+
# class MyOperator
|
19
|
+
# include ServiceOperator
|
20
|
+
#
|
21
|
+
# around :use_transaction
|
22
|
+
#
|
23
|
+
# around do |operator|
|
24
|
+
# puts 'started'
|
25
|
+
# operator.call
|
26
|
+
# puts 'finished'
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# private
|
30
|
+
#
|
31
|
+
# def use_transaction(operator)
|
32
|
+
# context.start_time = Time.now
|
33
|
+
# operator.call
|
34
|
+
# context.finish_time = Time.now
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
def around(name=nil, &block)
|
39
|
+
around_hooks << Step.new(name: name, service: nil, args: nil, block: block)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def with_hooks(&block)
|
46
|
+
run_before_steps
|
47
|
+
run_around_hooks(&block)
|
48
|
+
run_after_steps
|
49
|
+
end
|
50
|
+
|
51
|
+
# Internal: Run around step.
|
52
|
+
def run_around_hooks(&block)
|
53
|
+
self.class.around_hooks.reverse.inject(block) { |proc_chain, hook|
|
54
|
+
proc { run_hook(hook, proc_chain) }
|
55
|
+
}.call
|
56
|
+
# rescue catches errors in around hooks and main steps and allow to run after steps
|
57
|
+
rescue StandardError
|
58
|
+
end
|
59
|
+
|
60
|
+
def run_hook(hook, proc_chain)
|
61
|
+
return hook.run(operator: self, proc: proc_chain) if hook.is_a?(Step)
|
62
|
+
|
63
|
+
instance_exec(proc_chain, &hook)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ServiceOperator
|
4
|
+
Step = Struct.new(:name, :service, :args, :block, keyword_init: true) do
|
5
|
+
def run(operator:, proc: nil)
|
6
|
+
@operator = operator
|
7
|
+
|
8
|
+
return instance_exec(proc || @operator, &block) if block
|
9
|
+
return perform_service_step if service
|
10
|
+
|
11
|
+
perform_method_step(proc)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def perform_method_step(proc)
|
17
|
+
proc ? @operator.send(name, proc) : @operator.send(name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def perform_service_step
|
21
|
+
service_object = service.new
|
22
|
+
|
23
|
+
service_object_call(service_object)
|
24
|
+
validate_service_object_call_result(service_object)
|
25
|
+
end
|
26
|
+
|
27
|
+
def service_object_call(service_object)
|
28
|
+
service_call_arguments = fetch_service_call_arguments(service_object)
|
29
|
+
|
30
|
+
if service_call_arguments
|
31
|
+
service_object.public_send(@operator.configuration.call_method_name, *service_call_arguments)
|
32
|
+
else
|
33
|
+
service_object.public_send(@operator.configuration.call_method_name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_service_object_call_result(service_object)
|
38
|
+
failure_method_name = @operator.configuration.failure_method_name
|
39
|
+
@operator.context.fail if failure_method_name && service_object.public_send(failure_method_name)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Private: Find parameters names for step object's call.
|
43
|
+
# Then generate hash with these parameters from operator.context.
|
44
|
+
# Then overwrite some of them from step's args.
|
45
|
+
def fetch_service_call_arguments(service_object)
|
46
|
+
parameters_list =
|
47
|
+
service_object
|
48
|
+
.method(@operator.configuration.call_parameters_method_name)
|
49
|
+
.parameters
|
50
|
+
return if parameters_list.empty?
|
51
|
+
|
52
|
+
generate_argument_for_method_call(parameters_list)
|
53
|
+
end
|
54
|
+
|
55
|
+
def generate_argument_for_method_call(parameters_list, positional_arguments=[], keyword_arguments={})
|
56
|
+
parameters_list.each { |type, name|
|
57
|
+
case type
|
58
|
+
when :req, :opt, :rest then positional_arguments << fetch_value(name)
|
59
|
+
when :keyreq, :key, :keyrest then keyword_arguments[name] = fetch_value(name)
|
60
|
+
end
|
61
|
+
}
|
62
|
+
|
63
|
+
[*positional_arguments, keyword_arguments]
|
64
|
+
end
|
65
|
+
|
66
|
+
def fetch_value(name)
|
67
|
+
args[name] ? @operator.send(name) : @operator.context[name]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ServiceOperator
|
4
|
+
module Steps
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval do
|
7
|
+
extend ClassMethods
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def before_steps
|
13
|
+
@before_steps ||= []
|
14
|
+
end
|
15
|
+
|
16
|
+
def steps
|
17
|
+
@steps ||= []
|
18
|
+
end
|
19
|
+
|
20
|
+
def after_steps
|
21
|
+
@after_steps ||= []
|
22
|
+
end
|
23
|
+
|
24
|
+
# Examples
|
25
|
+
#
|
26
|
+
# class MyOperator
|
27
|
+
# include ServiceOperator
|
28
|
+
#
|
29
|
+
# before :set_start_time
|
30
|
+
# before :initial, service: SomeService
|
31
|
+
#
|
32
|
+
# before do
|
33
|
+
# puts 'started'
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# private
|
37
|
+
#
|
38
|
+
# def set_start_time
|
39
|
+
# context.start_time = Time.now
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
def before(name=nil, service: nil, **args, &block)
|
44
|
+
before_steps << Step.new(name: name, service: service, args: args, block: block)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Examples
|
48
|
+
#
|
49
|
+
# class MyOperator
|
50
|
+
# include ServiceOperator
|
51
|
+
#
|
52
|
+
# step :set_initiated
|
53
|
+
# step :perform_work, service: AnotherService
|
54
|
+
#
|
55
|
+
# step do
|
56
|
+
# puts 'going to finish'
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# private
|
60
|
+
#
|
61
|
+
# def set_initiated
|
62
|
+
# context.initiated = true
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
def step(name=nil, service: nil, **args, &block)
|
67
|
+
steps << Step.new(name: name, service: service, args: args, block: block)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Examples
|
71
|
+
#
|
72
|
+
# class MyOperator
|
73
|
+
# include ServiceOperator
|
74
|
+
#
|
75
|
+
# after :set_finish_time
|
76
|
+
# after :finishing, service: SomeService
|
77
|
+
#
|
78
|
+
# after do
|
79
|
+
# puts 'finished'
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# private
|
83
|
+
#
|
84
|
+
# def set_finish_time
|
85
|
+
# context.finish_time = Time.now
|
86
|
+
# end
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
def after(name=nil, service: nil, **args, &block)
|
90
|
+
after_steps << Step.new(name: name, service: service, args: args, block: block)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
# Internal: Run before steps.
|
97
|
+
def run_before_steps
|
98
|
+
run_steps(self.class.before_steps)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Internal: Run after steps.
|
102
|
+
def run_after_steps
|
103
|
+
run_steps(self.class.after_steps)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Internal: Run a colection of steps.
|
107
|
+
def run_steps(steps)
|
108
|
+
steps.each { |step| step.run(operator: self) }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'service_operator/version'
|
4
|
+
require_relative 'service_operator/steps'
|
5
|
+
require_relative 'service_operator/step'
|
6
|
+
require_relative 'service_operator/hooks'
|
7
|
+
require_relative 'service_operator/context'
|
8
|
+
require_relative 'service_operator/configuration'
|
9
|
+
|
10
|
+
module ServiceOperator
|
11
|
+
def self.included(base)
|
12
|
+
base.class_eval do
|
13
|
+
extend ClassMethods
|
14
|
+
include Steps
|
15
|
+
include Hooks
|
16
|
+
|
17
|
+
attr_reader :configuration
|
18
|
+
attr_reader :context
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
def configuration
|
24
|
+
@configuration ||= Configuration.new
|
25
|
+
end
|
26
|
+
|
27
|
+
# Examples
|
28
|
+
#
|
29
|
+
# class MyOperator
|
30
|
+
# include ServiceOperator
|
31
|
+
#
|
32
|
+
# configure do |config|
|
33
|
+
# config.call_method_name = :call
|
34
|
+
# config.call_parameters_method_name = :call
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
def configure
|
39
|
+
yield(configuration)
|
40
|
+
end
|
41
|
+
|
42
|
+
def required_params
|
43
|
+
@required_params ||= []
|
44
|
+
end
|
45
|
+
|
46
|
+
# Examples
|
47
|
+
#
|
48
|
+
# class MyOperator
|
49
|
+
# include ServiceOperator
|
50
|
+
#
|
51
|
+
# required_context :week
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
def required_context(*args)
|
55
|
+
@required_params = args.flatten
|
56
|
+
end
|
57
|
+
|
58
|
+
def call(args={})
|
59
|
+
new(**args).call
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize(args={})
|
64
|
+
@context = Context.build(args)
|
65
|
+
@context.validate(required_params: self.class.required_params)
|
66
|
+
end
|
67
|
+
|
68
|
+
def call
|
69
|
+
with_hooks { run_steps(self.class.steps) }
|
70
|
+
context
|
71
|
+
# rescue catches errors in before and after steps and stops execution
|
72
|
+
rescue StandardError
|
73
|
+
context
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/service_operator/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'service_operator'
|
7
|
+
spec.version = ServiceOperator::VERSION
|
8
|
+
spec.authors = ['Bogdanov Anton']
|
9
|
+
spec.email = ['kortirso@gmail.com']
|
10
|
+
|
11
|
+
spec.summary = 'Write a short summary, because RubyGems requires one.'
|
12
|
+
spec.description = 'Write a longer description or delete this line.'
|
13
|
+
spec.homepage = 'https://github.com/kortirso/service_operator'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.required_ruby_version = '>= 2.7'
|
17
|
+
|
18
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
19
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
20
|
+
spec.metadata['changelog_uri'] = 'https://github.com/kortirso/service_operator/blob/master/CHANGELOG.md'
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
25
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
26
|
+
end
|
27
|
+
spec.bindir = 'exe'
|
28
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
29
|
+
spec.require_paths = ['lib']
|
30
|
+
|
31
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
32
|
+
spec.add_development_dependency 'rubocop', '~> 1.3'
|
33
|
+
spec.add_development_dependency 'rubocop-performance', '~> 1.8'
|
34
|
+
spec.add_development_dependency 'rubocop-rake', '~> 0.6'
|
35
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 2.0'
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: service_operator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bogdanov Anton
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-09-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '13.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '13.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rubocop
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop-performance
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.8'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop-rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.6'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.6'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop-rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.0'
|
83
|
+
description: Write a longer description or delete this line.
|
84
|
+
email:
|
85
|
+
- kortirso@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".rubocop.yml"
|
93
|
+
- ".ruby-version"
|
94
|
+
- CHANGELOG.md
|
95
|
+
- Gemfile
|
96
|
+
- Gemfile.lock
|
97
|
+
- LICENSE.txt
|
98
|
+
- README.md
|
99
|
+
- Rakefile
|
100
|
+
- bin/console
|
101
|
+
- bin/setup
|
102
|
+
- lib/service_operator.rb
|
103
|
+
- lib/service_operator/configuration.rb
|
104
|
+
- lib/service_operator/context.rb
|
105
|
+
- lib/service_operator/hooks.rb
|
106
|
+
- lib/service_operator/step.rb
|
107
|
+
- lib/service_operator/steps.rb
|
108
|
+
- lib/service_operator/version.rb
|
109
|
+
- service_operator.gemspec
|
110
|
+
homepage: https://github.com/kortirso/service_operator
|
111
|
+
licenses:
|
112
|
+
- MIT
|
113
|
+
metadata:
|
114
|
+
homepage_uri: https://github.com/kortirso/service_operator
|
115
|
+
source_code_uri: https://github.com/kortirso/service_operator
|
116
|
+
changelog_uri: https://github.com/kortirso/service_operator/blob/master/CHANGELOG.md
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '2.7'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
requirements: []
|
132
|
+
rubygems_version: 3.3.7
|
133
|
+
signing_key:
|
134
|
+
specification_version: 4
|
135
|
+
summary: Write a short summary, because RubyGems requires one.
|
136
|
+
test_files: []
|