opera 0.2.14 → 0.2.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +7 -10
- data/.github/workflows/specs.yml +3 -6
- data/CHANGELOG.md +8 -0
- data/Dockerfile +1 -1
- data/Gemfile.lock +1 -1
- data/README.md +140 -8
- data/lib/opera/operation/base.rb +1 -0
- data/lib/opera/operation/config.rb +24 -2
- data/lib/opera/operation/instructions/executors/operation.rb +1 -1
- data/lib/opera/operation/instructions/executors/operations.rb +1 -1
- data/lib/opera/operation/instructions/executors/transaction.rb +7 -2
- data/lib/opera/operation/result.rb +8 -0
- data/lib/opera/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc70b9316e79f9ca5de85afc65ea0ea0f667c8a99aa72d0828f267383b8e76c2
|
4
|
+
data.tar.gz: 8ae3e726adc06851d36fdfd1314f001f678b35b7840be2bb96f833065198497a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9cf2f017c1ba44975e3968912d7859514ca6c900c824130922e9d1ab7a537cdc7e0d69b0a014d8d4ceb5eb9250be7246a7671af5ff00919764e734cce333f3f
|
7
|
+
data.tar.gz: 1ee6be5b16d95fd0d9174028e93784f6afa18a249553fcc2d5ef1725ac959733e4eba2598249a53c39314937299a7d55889d1919ea7e7bef670d48c712740331
|
@@ -9,15 +9,12 @@ jobs:
|
|
9
9
|
runs-on: ubuntu-latest
|
10
10
|
strategy:
|
11
11
|
matrix:
|
12
|
-
ruby-version: [ '2.6', '2.7', '3.0', 'jruby' ]
|
12
|
+
ruby-version: [ '2.6', '2.7', '3.0', '3.2', 'jruby' ]
|
13
13
|
|
14
14
|
steps:
|
15
|
-
- uses: actions/checkout@
|
15
|
+
- uses: actions/checkout@v4
|
16
16
|
- name: Set up Ruby
|
17
|
-
|
18
|
-
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
19
|
-
# uses: ruby/setup-ruby@v1
|
20
|
-
uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
|
17
|
+
uses: ruby/setup-ruby@v1
|
21
18
|
with:
|
22
19
|
ruby-version: ${{ matrix.ruby-version }}
|
23
20
|
bundler-cache: false # runs 'bundle install' and caches installed gems automatically
|
@@ -31,7 +28,7 @@ jobs:
|
|
31
28
|
runs-on: ubuntu-latest
|
32
29
|
|
33
30
|
steps:
|
34
|
-
- uses: actions/checkout@
|
31
|
+
- uses: actions/checkout@v4
|
35
32
|
|
36
33
|
- name: Tag automatically
|
37
34
|
run: git tag v`cat lib/opera/version.rb | grep 'VERSION' | awk '{ print $3 $4 }' | sed "s/'//g"`
|
@@ -48,11 +45,11 @@ jobs:
|
|
48
45
|
packages: write
|
49
46
|
|
50
47
|
steps:
|
51
|
-
- uses: actions/checkout@
|
52
|
-
- name: Set up Ruby 2
|
48
|
+
- uses: actions/checkout@v4
|
49
|
+
- name: Set up Ruby 3.2
|
53
50
|
uses: ruby/setup-ruby@v1
|
54
51
|
with:
|
55
|
-
ruby-version: 2
|
52
|
+
ruby-version: 3.2
|
56
53
|
|
57
54
|
- name: Publish to RubyGems
|
58
55
|
run: |
|
data/.github/workflows/specs.yml
CHANGED
@@ -16,15 +16,12 @@ jobs:
|
|
16
16
|
runs-on: ubuntu-latest
|
17
17
|
strategy:
|
18
18
|
matrix:
|
19
|
-
ruby-version: ['2.6', '2.7', '3.0', 'jruby']
|
19
|
+
ruby-version: ['2.6', '2.7', '3.0', '3.2', 'jruby']
|
20
20
|
|
21
21
|
steps:
|
22
|
-
- uses: actions/checkout@
|
22
|
+
- uses: actions/checkout@v4
|
23
23
|
- name: Set up Ruby
|
24
|
-
|
25
|
-
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
26
|
-
# uses: ruby/setup-ruby@v1
|
27
|
-
uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
|
24
|
+
uses: ruby/setup-ruby@v1
|
28
25
|
with:
|
29
26
|
ruby-version: ${{ matrix.ruby-version }}
|
30
27
|
bundler-cache: false # runs 'bundle install' and caches installed gems automatically
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Opera Changelog
|
2
2
|
|
3
|
+
### 0.2.16 - June 8, 2024
|
4
|
+
|
5
|
+
- add `mode` configuration option. When set to `:production` we optimize memory usage by skipping storing executions.
|
6
|
+
|
7
|
+
### 0.2.15 - September 4, 2023
|
8
|
+
|
9
|
+
- Make the Transaction executor work with the keyword arguments
|
10
|
+
|
3
11
|
### 0.2.14 - April 25, 2023
|
4
12
|
|
5
13
|
- Added support for objects responding to `to_hash` method in error handling for easier integration with Rails.
|
data/Dockerfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -36,6 +36,7 @@ Opera::Operation::Config.configure do |config|
|
|
36
36
|
config.transaction_class = ActiveRecord::Base
|
37
37
|
config.transaction_method = :transaction
|
38
38
|
config.transaction_options = { requires_new: true }
|
39
|
+
config.mode = :development # Can be set to production too
|
39
40
|
config.reporter = defined?(Rollbar) ? Rollbar : Rails.logger
|
40
41
|
end
|
41
42
|
```
|
@@ -885,9 +886,147 @@ Opera::Operation::Result.new(output: 'success')
|
|
885
886
|
- add_exceptions(Hash) - Adds multiple exceptions
|
886
887
|
- add_information(Hash) - Adss new information - Useful informations for developers
|
887
888
|
|
889
|
+
## Opera::Operation::Base - Instance Methods
|
890
|
+
>
|
891
|
+
- context [Hash] - used to pass information between steps - only for internal usage
|
892
|
+
- params [Hash] - immutable and received in call method
|
893
|
+
- dependencies [Hash] - immutable and received in call method
|
894
|
+
- finish! - this method interrupts the execution of steps after is invoked
|
895
|
+
|
888
896
|
## Opera::Operation::Base - Class Methods
|
897
|
+
|
898
|
+
#### `context_reader`
|
899
|
+
|
900
|
+
The `context_reader` helper method is designed to facilitate easy access to specified keys within a `context` hash. It dynamically defines a method that acts as a getter for the value associated with a specified key, simplifying data retrieval.
|
901
|
+
|
902
|
+
#### Parameters
|
903
|
+
**key (Symbol):** The key(s) for which the getter and setter methods are to be created. These symbols should correspond to keys in the context hash.
|
904
|
+
|
905
|
+
**default (Proc, optional):** A lambda or proc that returns a default value for the key if it is not present in the context hash. This proc is lazily evaluated only when the getter is invoked and the key is not present in the hash.
|
906
|
+
|
907
|
+
#### Usage
|
908
|
+
|
909
|
+
**GOOD**
|
910
|
+
|
911
|
+
```ruby
|
912
|
+
# USE context_reader to read steps outputs from the context hash
|
913
|
+
|
914
|
+
context_reader :schema_output
|
915
|
+
|
916
|
+
validate :schema # context = { schema_output: { id: 1 } }
|
917
|
+
step :do_something
|
918
|
+
|
919
|
+
def do_something
|
920
|
+
puts schema_output # outputs: { id: 1 }
|
921
|
+
end
|
922
|
+
```
|
923
|
+
|
924
|
+
```ruby
|
925
|
+
# USE context_reader with 'default' option to provide default value when key is missing in the context hash
|
926
|
+
|
927
|
+
context_reader :profile, default: -> { Profile.new }
|
928
|
+
|
929
|
+
step :fetch_profile
|
930
|
+
step :do_something
|
931
|
+
|
932
|
+
def fetch_profile
|
933
|
+
return if App.http_disabled?
|
934
|
+
|
935
|
+
context[:profile] = ProfileFetcher.call
|
936
|
+
end
|
937
|
+
|
938
|
+
def update_profile
|
939
|
+
profile.name = 'John'
|
940
|
+
profile.save!
|
941
|
+
end
|
942
|
+
```
|
943
|
+
|
944
|
+
**BAD**
|
945
|
+
|
946
|
+
```ruby
|
947
|
+
# Using `context_reader` to create read-only methods that instantiate objects,
|
948
|
+
# especially when these objects are not stored or updated in the `context` hash, is not recommended.
|
949
|
+
# This approach can lead to confusion and misuse of the context hash,
|
950
|
+
# as it suggests that the object might be part of the persistent state.
|
951
|
+
context_reader :serializer, default: -> { ProfileSerializer.new }
|
952
|
+
|
953
|
+
step :output
|
954
|
+
|
955
|
+
def output
|
956
|
+
self.result = serializer.to_json({...})
|
957
|
+
end
|
958
|
+
|
959
|
+
|
960
|
+
# A better practice is to use private methods to define read-only access to resources
|
961
|
+
# that are instantiated on the fly and not intended for storage in any state context.
|
962
|
+
|
963
|
+
step :output
|
964
|
+
|
965
|
+
def output
|
966
|
+
self.result = serializer.to_json({...})
|
967
|
+
end
|
968
|
+
|
969
|
+
private
|
970
|
+
|
971
|
+
def serializer
|
972
|
+
ProfileSerializer.new
|
973
|
+
end
|
974
|
+
```
|
975
|
+
**Conclusion**
|
976
|
+
|
977
|
+
For creating instance methods that are meant to be read-only and not stored within a context hash, defining these methods as private is a more suitable and clear approach compared to using context_reader with a default. This method ensures that transient dependencies remain well-encapsulated and are not confused with persistent application state.
|
978
|
+
|
979
|
+
#### `context_writer`
|
980
|
+
|
981
|
+
The `context_writer` helper method is designed to enable setting of values for specified keys within a `context` hash. This method dynamically defines a method that acts as a setter, allowing for the direct modification of the value associated with a given key.
|
982
|
+
|
983
|
+
#### Usage
|
984
|
+
```ruby
|
985
|
+
context_writer :profile
|
986
|
+
|
987
|
+
step :fetch_profile
|
988
|
+
|
989
|
+
def fetch_profile
|
990
|
+
self.profile = ProfileFetcher.call # sets context[:profile]
|
991
|
+
end
|
992
|
+
```
|
993
|
+
|
994
|
+
#### `context_accessor`
|
995
|
+
|
996
|
+
The `context_accessor` helper method is designed to enable easy access to and modification of values for specified keys within a `context` hash. This method dynamically defines both getter and setter methods for the designated keys, facilitating straightforward retrieval and update of values.
|
997
|
+
|
998
|
+
#### Parameters
|
999
|
+
|
1000
|
+
**key (Symbol):** The key(s) for which the getter and setter methods are to be created. These symbols will correspond to keys in the context hash.
|
1001
|
+
|
1002
|
+
**default (Proc, optional):** A lambda or proc that returns a default value for the key if it is not present in the context hash. This proc is lazily evaluated only when the getter is invoked and the key is not present in the hash.
|
1003
|
+
|
1004
|
+
#### Usage
|
1005
|
+
```ruby
|
1006
|
+
context_accessor :profile
|
1007
|
+
|
1008
|
+
step :fetch_profile
|
1009
|
+
step :update_profile
|
1010
|
+
|
1011
|
+
def fetch_profile
|
1012
|
+
self.profile = ProfileFetcher.call # sets context[:profile]
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
def update_profile
|
1016
|
+
profile.update!(name: 'John') # reads profile from context[:profile]
|
1017
|
+
end
|
1018
|
+
```
|
1019
|
+
|
1020
|
+
```ruby
|
1021
|
+
context_accessor :profile, default: -> { Profile.new }
|
1022
|
+
```
|
1023
|
+
|
1024
|
+
```ruby
|
1025
|
+
context_accessor :profile, :account
|
1026
|
+
```
|
1027
|
+
|
1028
|
+
#### Other methods
|
889
1029
|
>
|
890
|
-
- context_[reader|writer|accessor] - predefined methods for easy access
|
891
1030
|
- [params|dependencies]_reader - predefined readers for immutable arguments
|
892
1031
|
- step(Symbol) - single instruction
|
893
1032
|
- return [Truthly] - continue operation execution
|
@@ -903,13 +1042,6 @@ Opera::Operation::Result.new(output: 'success')
|
|
903
1042
|
- call(params: Hash, dependencies: Hash?)
|
904
1043
|
- return [Opera::Operation::Result] - never raises an exception
|
905
1044
|
|
906
|
-
## Opera::Operation::Base - Instance Methods
|
907
|
-
>
|
908
|
-
- context [Hash] - used to pass information between steps - only for internal usage
|
909
|
-
- params [Hash] - immutable and received in call method
|
910
|
-
- dependencies [Hash] - immutable and received in call method
|
911
|
-
- finish! - this method interrupts the execution of steps after is invoked
|
912
|
-
|
913
1045
|
## Development
|
914
1046
|
|
915
1047
|
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.
|
data/lib/opera/operation/base.rb
CHANGED
@@ -3,13 +3,19 @@
|
|
3
3
|
module Opera
|
4
4
|
module Operation
|
5
5
|
class Config
|
6
|
-
|
6
|
+
DEVELOPMENT_MODE = :development
|
7
|
+
PRODUCTION_MODE = :production
|
8
|
+
|
9
|
+
attr_accessor :transaction_class, :transaction_method, :transaction_options, :reporter, :mode
|
7
10
|
|
8
11
|
def initialize
|
9
12
|
@transaction_class = self.class.transaction_class
|
10
13
|
@transaction_method = self.class.transaction_method || :transaction
|
11
14
|
@transaction_options = self.class.transaction_options
|
15
|
+
@mode = self.class.mode || DEVELOPMENT_MODE
|
12
16
|
@reporter = custom_reporter || self.class.reporter
|
17
|
+
|
18
|
+
validate!
|
13
19
|
end
|
14
20
|
|
15
21
|
def configure
|
@@ -20,12 +26,28 @@ module Opera
|
|
20
26
|
Rails.application.config.x.reporter.presence if defined?(Rails)
|
21
27
|
end
|
22
28
|
|
29
|
+
private
|
30
|
+
|
31
|
+
def validate!
|
32
|
+
unless [DEVELOPMENT_MODE, PRODUCTION_MODE].include?(mode)
|
33
|
+
raise ArgumentError, 'Mode is incorrect. Can be either: development or production'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
23
37
|
class << self
|
24
|
-
attr_accessor :transaction_class, :transaction_method, :transaction_options, :reporter
|
38
|
+
attr_accessor :transaction_class, :transaction_method, :transaction_options, :reporter, :mode
|
25
39
|
|
26
40
|
def configure
|
27
41
|
yield self
|
28
42
|
end
|
43
|
+
|
44
|
+
def development_mode?
|
45
|
+
mode == DEFAULT_MODE
|
46
|
+
end
|
47
|
+
|
48
|
+
def production_mode?
|
49
|
+
mode == PRODUCTION_MODE
|
50
|
+
end
|
29
51
|
end
|
30
52
|
end
|
31
53
|
end
|
@@ -45,7 +45,7 @@ module Opera
|
|
45
45
|
def add_results(instruction, results)
|
46
46
|
add_instruction_output(instruction, results.map(&:output))
|
47
47
|
execution = result.executions.pop
|
48
|
-
result.
|
48
|
+
result.add_execution(execution => results.map(&:executions))
|
49
49
|
end
|
50
50
|
|
51
51
|
def raise_error
|
@@ -8,8 +8,7 @@ module Opera
|
|
8
8
|
class RollbackTransactionError < Opera::Error; end
|
9
9
|
|
10
10
|
def call(instruction)
|
11
|
-
|
12
|
-
transaction_class.send(*arguments) do
|
11
|
+
transaction_wrapper do
|
13
12
|
super
|
14
13
|
|
15
14
|
raise(transaction_error) if result.failure?
|
@@ -18,6 +17,12 @@ module Opera
|
|
18
17
|
nil
|
19
18
|
end
|
20
19
|
|
20
|
+
def transaction_wrapper
|
21
|
+
return transaction_class.send(transaction_method) { yield } unless transaction_options
|
22
|
+
|
23
|
+
transaction_class.send(transaction_method, **transaction_options) { yield }
|
24
|
+
end
|
25
|
+
|
21
26
|
def transaction_class
|
22
27
|
config.transaction_class
|
23
28
|
end
|
data/lib/opera/version.rb
CHANGED
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.2.
|
4
|
+
version: 0.2.16
|
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:
|
11
|
+
date: 2024-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-validation
|
@@ -115,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
115
|
- !ruby/object:Gem::Version
|
116
116
|
version: '0'
|
117
117
|
requirements: []
|
118
|
-
rubygems_version: 3.
|
118
|
+
rubygems_version: 3.4.19
|
119
119
|
signing_key:
|
120
120
|
specification_version: 4
|
121
121
|
summary: Use simple DSL language to keep your Operations clean and maintainable
|