opera 0.4.1 → 0.5.1
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 +1223 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +45 -1
- data/README.md +106 -957
- data/Rakefile +5 -3
- data/benchmarks/operation_benchmark.rb +330 -0
- data/bin/console +4 -3
- data/docs/examples/basic-operation.md +79 -0
- data/docs/examples/context-params-dependencies.md +122 -0
- data/docs/examples/finish-if.md +67 -0
- data/docs/examples/inner-operations.md +94 -0
- data/docs/examples/success-blocks.md +68 -0
- data/docs/examples/transactions.md +227 -0
- data/docs/examples/validations.md +139 -0
- data/docs/examples/within.md +166 -0
- data/lib/opera/errors.rb +1 -0
- data/lib/opera/operation/attributes_dsl.rb +16 -7
- data/lib/opera/operation/base.rb +7 -6
- data/lib/opera/operation/builder.rb +2 -2
- data/lib/opera/operation/config.rb +3 -7
- data/lib/opera/operation/executor.rb +16 -7
- data/lib/opera/operation/instructions/executors/finish_if.rb +1 -2
- data/lib/opera/operation/instructions/executors/operation.rb +1 -2
- data/lib/opera/operation/instructions/executors/operations.rb +2 -3
- data/lib/opera/operation/instructions/executors/step.rb +1 -6
- data/lib/opera/operation/instructions/executors/success.rb +5 -2
- data/lib/opera/operation/instructions/executors/validate.rb +1 -2
- data/lib/opera/operation/instructions/executors/within.rb +23 -0
- data/lib/opera/operation.rb +1 -1
- data/lib/opera/version.rb +1 -1
- data/opera.gemspec +12 -10
- metadata +13 -3
- data/lib/opera/operation/instructions/executors/benchmark.rb +0 -26
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Opera
|
|
4
4
|
module Operation
|
|
5
5
|
module Builder
|
|
6
|
-
INSTRUCTIONS = %I[validate transaction
|
|
6
|
+
INSTRUCTIONS = %I[validate transaction step success finish_if operation operations within].freeze
|
|
7
7
|
|
|
8
8
|
def self.included(base)
|
|
9
9
|
base.extend(ClassMethods)
|
|
@@ -16,7 +16,7 @@ module Opera
|
|
|
16
16
|
|
|
17
17
|
INSTRUCTIONS.each do |instruction|
|
|
18
18
|
define_method instruction do |method = nil, &blk|
|
|
19
|
-
|
|
19
|
+
check_method_availability!(method) if method
|
|
20
20
|
instructions.concat(InnerBuilder.new.send(instruction, method, &blk))
|
|
21
21
|
end
|
|
22
22
|
end
|
|
@@ -17,7 +17,7 @@ module Opera
|
|
|
17
17
|
@instrumentation_class = self.class.instrumentation_class
|
|
18
18
|
|
|
19
19
|
@mode = self.class.mode || DEVELOPMENT_MODE
|
|
20
|
-
@reporter =
|
|
20
|
+
@reporter = self.class.reporter
|
|
21
21
|
|
|
22
22
|
validate!
|
|
23
23
|
end
|
|
@@ -26,15 +26,11 @@ module Opera
|
|
|
26
26
|
yield self
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def custom_reporter
|
|
30
|
-
Rails.application.config.x.reporter.presence if defined?(Rails)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
29
|
private
|
|
34
30
|
|
|
35
31
|
def validate!
|
|
36
32
|
unless [DEVELOPMENT_MODE, PRODUCTION_MODE].include?(mode)
|
|
37
|
-
raise ArgumentError, 'Mode is incorrect. Can be either: development or production'
|
|
33
|
+
raise ArgumentError, 'Mode is incorrect. Can be either: development or production'
|
|
38
34
|
end
|
|
39
35
|
end
|
|
40
36
|
|
|
@@ -47,7 +43,7 @@ module Opera
|
|
|
47
43
|
end
|
|
48
44
|
|
|
49
45
|
def development_mode?
|
|
50
|
-
mode ==
|
|
46
|
+
mode == DEVELOPMENT_MODE
|
|
51
47
|
end
|
|
52
48
|
|
|
53
49
|
def production_mode?
|
|
@@ -20,15 +20,24 @@ module Opera
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def evaluate_instructions(instructions = [])
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
while instruction_copy.any?
|
|
26
|
-
instruction = instruction_copy.shift
|
|
23
|
+
instructions.each do |instruction|
|
|
27
24
|
evaluate_instruction(instruction)
|
|
28
25
|
break if break_condition
|
|
29
26
|
end
|
|
30
27
|
end
|
|
31
28
|
|
|
29
|
+
# Executes the operation method named in the instruction, instruments it,
|
|
30
|
+
# and records the execution. This is the shared primitive that all executors
|
|
31
|
+
# use to invoke a step method without mutating the instruction hash.
|
|
32
|
+
def execute_step(instruction)
|
|
33
|
+
method = instruction[:method]
|
|
34
|
+
|
|
35
|
+
Instrumentation.new(operation).instrument(name: "##{method}", level: :step) do
|
|
36
|
+
result.add_execution(method) unless production_mode?
|
|
37
|
+
operation.send(method)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
32
41
|
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
33
42
|
def evaluate_instruction(instruction)
|
|
34
43
|
case instruction[:kind]
|
|
@@ -44,10 +53,10 @@ module Opera
|
|
|
44
53
|
Instructions::Executors::Validate.new(operation).call(instruction)
|
|
45
54
|
when :transaction
|
|
46
55
|
Instructions::Executors::Transaction.new(operation).call(instruction)
|
|
47
|
-
when :benchmark
|
|
48
|
-
Instructions::Executors::Benchmark.new(operation).call(instruction)
|
|
49
56
|
when :finish_if
|
|
50
57
|
Instructions::Executors::FinishIf.new(operation).call(instruction)
|
|
58
|
+
when :within
|
|
59
|
+
Instructions::Executors::Within.new(operation).call(instruction)
|
|
51
60
|
else
|
|
52
61
|
raise(UnknownInstructionError, "Unknown instruction #{instruction[:kind]}")
|
|
53
62
|
end
|
|
@@ -79,7 +88,7 @@ module Opera
|
|
|
79
88
|
end
|
|
80
89
|
|
|
81
90
|
def add_instruction_output(instruction, output = {})
|
|
82
|
-
context["#{instruction[:method]}_output"
|
|
91
|
+
context[:"#{instruction[:method]}_output"] = output
|
|
83
92
|
end
|
|
84
93
|
end
|
|
85
94
|
end
|
|
@@ -9,8 +9,7 @@ module Opera
|
|
|
9
9
|
|
|
10
10
|
# rubocop:disable Metrics/MethodLength
|
|
11
11
|
def call(instruction)
|
|
12
|
-
|
|
13
|
-
operations_results = super
|
|
12
|
+
operations_results = execute_step(instruction)
|
|
14
13
|
|
|
15
14
|
case operations_results
|
|
16
15
|
when Array
|
|
@@ -42,7 +41,7 @@ module Opera
|
|
|
42
41
|
def add_results(instruction, results)
|
|
43
42
|
add_instruction_output(instruction, results.map(&:output))
|
|
44
43
|
execution = result.executions.pop
|
|
45
|
-
result.add_execution(execution => results.map(&:executions))
|
|
44
|
+
result.add_execution(execution => results.map(&:executions)) unless production_mode?
|
|
46
45
|
end
|
|
47
46
|
|
|
48
47
|
def raise_error
|
|
@@ -6,12 +6,7 @@ module Opera
|
|
|
6
6
|
module Executors
|
|
7
7
|
class Step < Executor
|
|
8
8
|
def call(instruction)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Instrumentation.new(operation).instrument(name: "##{method}", level: :step) do
|
|
12
|
-
operation.result.add_execution(method) unless production_mode?
|
|
13
|
-
operation.send(method)
|
|
14
|
-
end
|
|
9
|
+
execute_step(instruction)
|
|
15
10
|
end
|
|
16
11
|
end
|
|
17
12
|
end
|
|
@@ -6,8 +6,11 @@ module Opera
|
|
|
6
6
|
module Executors
|
|
7
7
|
class Success < Executor
|
|
8
8
|
def call(instruction)
|
|
9
|
-
instruction[:
|
|
10
|
-
|
|
9
|
+
if instruction[:instructions]
|
|
10
|
+
evaluate_instructions(instruction[:instructions])
|
|
11
|
+
else
|
|
12
|
+
execute_step(instruction)
|
|
13
|
+
end
|
|
11
14
|
end
|
|
12
15
|
|
|
13
16
|
def break_condition
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Opera
|
|
4
|
+
module Operation
|
|
5
|
+
module Instructions
|
|
6
|
+
module Executors
|
|
7
|
+
class Within < Executor
|
|
8
|
+
def call(instruction)
|
|
9
|
+
wrapper_method = instruction[:label]
|
|
10
|
+
nested_instructions = instruction[:instructions]
|
|
11
|
+
|
|
12
|
+
raise ArgumentError, 'within requires a method name' unless wrapper_method
|
|
13
|
+
raise ArgumentError, 'within requires a block with at least one instruction' if nested_instructions.nil?
|
|
14
|
+
|
|
15
|
+
operation.send(wrapper_method) do
|
|
16
|
+
evaluate_instructions(nested_instructions)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/opera/operation.rb
CHANGED
|
@@ -9,12 +9,12 @@ require 'opera/operation/result'
|
|
|
9
9
|
require 'opera/operation/config'
|
|
10
10
|
require 'opera/operation/instructions/executors/success'
|
|
11
11
|
require 'opera/operation/instructions/executors/transaction'
|
|
12
|
-
require 'opera/operation/instructions/executors/benchmark'
|
|
13
12
|
require 'opera/operation/instructions/executors/finish_if'
|
|
14
13
|
require 'opera/operation/instructions/executors/validate'
|
|
15
14
|
require 'opera/operation/instructions/executors/operation'
|
|
16
15
|
require 'opera/operation/instructions/executors/operations'
|
|
17
16
|
require 'opera/operation/instructions/executors/step'
|
|
17
|
+
require 'opera/operation/instructions/executors/within'
|
|
18
18
|
|
|
19
19
|
module Opera
|
|
20
20
|
module Operation
|
data/lib/opera/version.rb
CHANGED
data/opera.gemspec
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative 'lib/opera/version'
|
|
2
4
|
|
|
3
5
|
Gem::Specification.new do |spec|
|
|
4
|
-
spec.name
|
|
5
|
-
spec.version
|
|
6
|
-
spec.authors
|
|
7
|
-
spec.email
|
|
6
|
+
spec.name = 'opera'
|
|
7
|
+
spec.version = Opera::VERSION
|
|
8
|
+
spec.authors = ['ProFinda Development Team']
|
|
9
|
+
spec.email = ['dev@profinda.com']
|
|
8
10
|
|
|
9
|
-
spec.summary
|
|
10
|
-
spec.homepage
|
|
11
|
-
spec.license
|
|
11
|
+
spec.summary = 'Use simple DSL language to keep your Operations clean and maintainable'
|
|
12
|
+
spec.homepage = 'https://github.com/Profinda/opera'
|
|
13
|
+
spec.license = 'MIT'
|
|
12
14
|
spec.required_ruby_version = Gem::Requirement.new('>= 3.1.0')
|
|
13
15
|
|
|
14
16
|
spec.metadata['homepage_uri'] = spec.homepage
|
|
@@ -17,11 +19,11 @@ Gem::Specification.new do |spec|
|
|
|
17
19
|
|
|
18
20
|
# Specify which files should be added to the gem when it is released.
|
|
19
21
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
20
|
-
spec.files
|
|
22
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
|
21
23
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
22
24
|
end
|
|
23
|
-
spec.bindir
|
|
24
|
-
spec.executables
|
|
25
|
+
spec.bindir = 'exe'
|
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
25
27
|
spec.require_paths = ['lib']
|
|
26
28
|
|
|
27
29
|
spec.add_development_dependency 'dry-validation', '>= 1.0'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: opera
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ProFinda Development Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-04-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: dry-validation
|
|
@@ -63,6 +63,7 @@ files:
|
|
|
63
63
|
- ".github/workflows/specs.yml"
|
|
64
64
|
- ".gitignore"
|
|
65
65
|
- ".rspec"
|
|
66
|
+
- ".rubocop.yml"
|
|
66
67
|
- ".travis.yml"
|
|
67
68
|
- CHANGELOG.md
|
|
68
69
|
- CODE_OF_CONDUCT.md
|
|
@@ -72,9 +73,18 @@ files:
|
|
|
72
73
|
- LICENSE.txt
|
|
73
74
|
- README.md
|
|
74
75
|
- Rakefile
|
|
76
|
+
- benchmarks/operation_benchmark.rb
|
|
75
77
|
- bin/console
|
|
76
78
|
- bin/setup
|
|
77
79
|
- docker-compose.yml
|
|
80
|
+
- docs/examples/basic-operation.md
|
|
81
|
+
- docs/examples/context-params-dependencies.md
|
|
82
|
+
- docs/examples/finish-if.md
|
|
83
|
+
- docs/examples/inner-operations.md
|
|
84
|
+
- docs/examples/success-blocks.md
|
|
85
|
+
- docs/examples/transactions.md
|
|
86
|
+
- docs/examples/validations.md
|
|
87
|
+
- docs/examples/within.md
|
|
78
88
|
- lib/opera.rb
|
|
79
89
|
- lib/opera/errors.rb
|
|
80
90
|
- lib/opera/operation.rb
|
|
@@ -83,7 +93,6 @@ files:
|
|
|
83
93
|
- lib/opera/operation/builder.rb
|
|
84
94
|
- lib/opera/operation/config.rb
|
|
85
95
|
- lib/opera/operation/executor.rb
|
|
86
|
-
- lib/opera/operation/instructions/executors/benchmark.rb
|
|
87
96
|
- lib/opera/operation/instructions/executors/finish_if.rb
|
|
88
97
|
- lib/opera/operation/instructions/executors/operation.rb
|
|
89
98
|
- lib/opera/operation/instructions/executors/operations.rb
|
|
@@ -91,6 +100,7 @@ files:
|
|
|
91
100
|
- lib/opera/operation/instructions/executors/success.rb
|
|
92
101
|
- lib/opera/operation/instructions/executors/transaction.rb
|
|
93
102
|
- lib/opera/operation/instructions/executors/validate.rb
|
|
103
|
+
- lib/opera/operation/instructions/executors/within.rb
|
|
94
104
|
- lib/opera/operation/instrumentation.rb
|
|
95
105
|
- lib/opera/operation/result.rb
|
|
96
106
|
- lib/opera/version.rb
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Opera
|
|
4
|
-
module Operation
|
|
5
|
-
module Instructions
|
|
6
|
-
module Executors
|
|
7
|
-
class Benchmark < Executor
|
|
8
|
-
def call(instruction)
|
|
9
|
-
benchmark = ::Benchmark.measure do
|
|
10
|
-
instruction[:kind] = :step
|
|
11
|
-
super
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
result.add_information(benchmark_key(instruction) => { real: benchmark.real, total: benchmark.total })
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
private
|
|
18
|
-
|
|
19
|
-
def benchmark_key(instruction)
|
|
20
|
-
instruction[:method] || instruction[:label] || instruction[:instructions].map { |e| e[:method] }.join('-').to_sym
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|