resol 0.8.0 → 1.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4eb71da351b1379daa165b6223a0bb9fd2ff2ae5fd3436642b7cfdc782413917
4
- data.tar.gz: 62712882caa637dfcfbf9a8f25e1026afeed72cea67c677acdf93c6802ac5cb4
3
+ metadata.gz: c7a4e82d0b30c1d86f47db975689b82768d672fd2c2db7088d2ac41a68346b90
4
+ data.tar.gz: 838c52bf67feb5442213b6e485a3f024ee8323e5c36618492743ad761455dc7e
5
5
  SHA512:
6
- metadata.gz: 4ae925f82e9deda9fa0c180976a446aff26822eb39e20371065d5e1c185e0473e0ae4e7811dd5f9c07cb09205bec9a3eec5b0458d0a807a81daaf1313133d09d
7
- data.tar.gz: 5942e294f2a6e99386802e1d2848b6f754a6d8700268aa57079099058e161dd481d4aaec1000eb835dd80ab699f9e5ec2670a54038481dff4c42d324b1d803c5
6
+ metadata.gz: e5bf12a60de921e46f762c74d9dac977b6761d045a214895788dfc5374e19977563c73aa737cc8ebe691dd2b4034f99a2fc78d6ad2df1479232cf0fb57ce7842
7
+ data.tar.gz: 4aedc9b8ca631ce5b2e1c8cb79eb1eea49d0aa2085e162fbf4f2fb671dd58e860be66f2c90fd42241fbd81f932775700f733c631f3dd97b53c4d1f8ce5d481d7
@@ -16,7 +16,7 @@ jobs:
16
16
  - uses: actions/checkout@v2
17
17
  - uses: ruby/setup-ruby@v1
18
18
  with:
19
- ruby-version: "3.1"
19
+ ruby-version: "3.4"
20
20
  bundler-cache: true
21
21
  - name: Run Linter
22
22
  run: bundle exec ci-helper RubocopLint
@@ -43,7 +43,7 @@ jobs:
43
43
  strategy:
44
44
  fail-fast: false
45
45
  matrix:
46
- ruby: ["2.7", "3.0"]
46
+ ruby: ["3.1", "3.2", "3.3"]
47
47
  experimental: [false]
48
48
  include:
49
49
  - ruby: head
data/.rubocop.yml CHANGED
@@ -3,7 +3,7 @@ inherit_gem:
3
3
 
4
4
  AllCops:
5
5
  DisplayCopNames: true
6
- TargetRubyVersion: 2.7
6
+ TargetRubyVersion: 3.1
7
7
 
8
8
  Naming/MethodParameterName:
9
9
  AllowedNames: ["x", "y", "z"]
data/Gemfile CHANGED
@@ -3,3 +3,15 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
+
7
+ gem "bundler-audit"
8
+ gem "ci-helper"
9
+ gem "pry"
10
+ gem "rake"
11
+ gem "rspec"
12
+ gem "rubocop-config-umbrellio"
13
+ gem "simplecov"
14
+ gem "simplecov-lcov"
15
+
16
+ gem "dry-initializer"
17
+ gem "smart_initializer"
data/Gemfile.lock CHANGED
@@ -1,126 +1,161 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- resol (0.8.0)
5
- smart_initializer (~> 0.7)
4
+ resol (1.0.0)
5
+ dry-configurable (~> 1.2.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activesupport (7.0.2.2)
11
- concurrent-ruby (~> 1.0, >= 1.0.2)
10
+ activesupport (7.2.2.1)
11
+ base64
12
+ benchmark (>= 0.3)
13
+ bigdecimal
14
+ concurrent-ruby (~> 1.0, >= 1.3.1)
15
+ connection_pool (>= 2.2.5)
16
+ drb
12
17
  i18n (>= 1.6, < 2)
18
+ logger (>= 1.4.2)
13
19
  minitest (>= 5.1)
14
- tzinfo (~> 2.0)
20
+ securerandom (>= 0.3)
21
+ tzinfo (~> 2.0, >= 2.0.5)
15
22
  ast (2.4.2)
16
- bundler-audit (0.9.0.1)
23
+ base64 (0.2.0)
24
+ benchmark (0.4.0)
25
+ bigdecimal (3.1.9)
26
+ bundler-audit (0.9.2)
17
27
  bundler (>= 1.2.0, < 3)
18
28
  thor (~> 1.0)
19
- ci-helper (0.4.2)
20
- colorize (~> 0.8)
21
- dry-inflector (~> 0.2)
22
- umbrellio-sequel-plugins (~> 0.4)
29
+ ci-helper (0.7.0)
30
+ colorize (~> 1.1)
31
+ dry-inflector (~> 1.0)
32
+ umbrellio-sequel-plugins (~> 0.14)
23
33
  coderay (1.1.3)
24
- colorize (0.8.1)
25
- concurrent-ruby (1.1.9)
26
- diff-lcs (1.5.0)
27
- docile (1.4.0)
28
- dry-inflector (0.2.1)
29
- i18n (1.10.0)
34
+ colorize (1.1.0)
35
+ concurrent-ruby (1.3.4)
36
+ connection_pool (2.5.0)
37
+ diff-lcs (1.5.1)
38
+ docile (1.4.1)
39
+ drb (2.2.1)
40
+ dry-configurable (1.2.0)
41
+ dry-core (~> 1.0, < 2)
42
+ zeitwerk (~> 2.6)
43
+ dry-core (1.1.0)
30
44
  concurrent-ruby (~> 1.0)
31
- method_source (1.0.0)
32
- minitest (5.15.0)
33
- parallel (1.21.0)
34
- parser (3.1.1.0)
45
+ logger
46
+ zeitwerk (~> 2.6)
47
+ dry-inflector (1.2.0)
48
+ dry-initializer (3.2.0)
49
+ i18n (1.14.6)
50
+ concurrent-ruby (~> 1.0)
51
+ json (2.9.1)
52
+ language_server-protocol (3.17.0.3)
53
+ logger (1.6.5)
54
+ method_source (1.1.0)
55
+ minitest (5.25.4)
56
+ parallel (1.26.3)
57
+ parser (3.3.6.0)
35
58
  ast (~> 2.4.1)
36
- pry (0.14.1)
59
+ racc
60
+ pry (0.15.2)
37
61
  coderay (~> 1.1)
38
62
  method_source (~> 1.0)
39
- qonfig (0.27.0)
40
- rack (2.2.3)
63
+ qonfig (0.30.0)
64
+ base64 (>= 0.2)
65
+ racc (1.8.1)
66
+ rack (3.1.8)
41
67
  rainbow (3.1.1)
42
- rake (13.0.6)
43
- regexp_parser (2.2.1)
44
- rexml (3.2.5)
45
- rspec (3.11.0)
46
- rspec-core (~> 3.11.0)
47
- rspec-expectations (~> 3.11.0)
48
- rspec-mocks (~> 3.11.0)
49
- rspec-core (3.11.0)
50
- rspec-support (~> 3.11.0)
51
- rspec-expectations (3.11.0)
68
+ rake (13.2.1)
69
+ regexp_parser (2.10.0)
70
+ rspec (3.13.0)
71
+ rspec-core (~> 3.13.0)
72
+ rspec-expectations (~> 3.13.0)
73
+ rspec-mocks (~> 3.13.0)
74
+ rspec-core (3.13.2)
75
+ rspec-support (~> 3.13.0)
76
+ rspec-expectations (3.13.3)
52
77
  diff-lcs (>= 1.2.0, < 2.0)
53
- rspec-support (~> 3.11.0)
54
- rspec-mocks (3.11.0)
78
+ rspec-support (~> 3.13.0)
79
+ rspec-mocks (3.13.2)
55
80
  diff-lcs (>= 1.2.0, < 2.0)
56
- rspec-support (~> 3.11.0)
57
- rspec-support (3.11.0)
58
- rubocop (1.25.1)
81
+ rspec-support (~> 3.13.0)
82
+ rspec-support (3.13.2)
83
+ rubocop (1.69.2)
84
+ json (~> 2.3)
85
+ language_server-protocol (>= 3.17.0)
59
86
  parallel (~> 1.10)
60
- parser (>= 3.1.0.0)
87
+ parser (>= 3.3.0.2)
61
88
  rainbow (>= 2.2.2, < 4.0)
62
- regexp_parser (>= 1.8, < 3.0)
63
- rexml
64
- rubocop-ast (>= 1.15.1, < 2.0)
89
+ regexp_parser (>= 2.9.3, < 3.0)
90
+ rubocop-ast (>= 1.36.2, < 2.0)
65
91
  ruby-progressbar (~> 1.7)
66
- unicode-display_width (>= 1.4.0, < 3.0)
67
- rubocop-ast (1.16.0)
68
- parser (>= 3.1.1.0)
69
- rubocop-config-umbrellio (1.25.0.61)
70
- rubocop (~> 1.25.0)
71
- rubocop-performance (~> 1.13.0)
72
- rubocop-rails (~> 2.13.0)
92
+ unicode-display_width (>= 2.4.0, < 4.0)
93
+ rubocop-ast (1.37.0)
94
+ parser (>= 3.3.1.0)
95
+ rubocop-config-umbrellio (1.69.0.101)
96
+ rubocop (~> 1.69.0)
97
+ rubocop-factory_bot (~> 2.26.0)
98
+ rubocop-performance (~> 1.23.0)
99
+ rubocop-rails (~> 2.28.0)
73
100
  rubocop-rake (~> 0.6.0)
74
- rubocop-rspec (~> 2.7.0)
75
- rubocop-sequel (~> 0.3.3)
76
- rubocop-performance (1.13.2)
77
- rubocop (>= 1.7.0, < 2.0)
78
- rubocop-ast (>= 0.4.0)
79
- rubocop-rails (2.13.2)
101
+ rubocop-rspec (~> 3.3.0)
102
+ rubocop-sequel (~> 0.3.0)
103
+ rubocop-factory_bot (2.26.1)
104
+ rubocop (~> 1.61)
105
+ rubocop-performance (1.23.1)
106
+ rubocop (>= 1.48.1, < 2.0)
107
+ rubocop-ast (>= 1.31.1, < 2.0)
108
+ rubocop-rails (2.28.0)
80
109
  activesupport (>= 4.2.0)
81
110
  rack (>= 1.1)
82
- rubocop (>= 1.7.0, < 2.0)
111
+ rubocop (>= 1.52.0, < 2.0)
112
+ rubocop-ast (>= 1.31.1, < 2.0)
83
113
  rubocop-rake (0.6.0)
84
114
  rubocop (~> 1.0)
85
- rubocop-rspec (2.7.0)
86
- rubocop (~> 1.19)
87
- rubocop-sequel (0.3.3)
115
+ rubocop-rspec (3.3.0)
116
+ rubocop (~> 1.61)
117
+ rubocop-sequel (0.3.8)
88
118
  rubocop (~> 1.0)
89
- ruby-progressbar (1.11.0)
90
- sequel (5.54.0)
91
- simplecov (0.21.2)
119
+ ruby-progressbar (1.13.0)
120
+ securerandom (0.4.1)
121
+ sequel (5.88.0)
122
+ bigdecimal
123
+ simplecov (0.22.0)
92
124
  docile (~> 1.1)
93
125
  simplecov-html (~> 0.11)
94
126
  simplecov_json_formatter (~> 0.1)
95
- simplecov-html (0.12.3)
127
+ simplecov-html (0.13.1)
96
128
  simplecov-lcov (0.8.0)
97
129
  simplecov_json_formatter (0.1.4)
98
- smart_engine (0.12.0)
99
- smart_initializer (0.9.0)
130
+ smart_engine (0.17.0)
131
+ smart_initializer (0.11.1)
100
132
  qonfig (~> 0.24)
133
+ smart_engine (~> 0.16)
134
+ smart_types (~> 0.8)
135
+ smart_types (0.8.0)
101
136
  smart_engine (~> 0.11)
102
- smart_types (~> 0.4)
103
- smart_types (0.7.0)
104
- smart_engine (~> 0.11)
105
- symbiont-ruby (0.7.0)
106
- thor (1.2.1)
107
- tzinfo (2.0.4)
137
+ thor (1.3.2)
138
+ tzinfo (2.0.6)
108
139
  concurrent-ruby (~> 1.0)
109
- umbrellio-sequel-plugins (0.5.1.27)
140
+ umbrellio-sequel-plugins (0.17.0)
110
141
  sequel
111
- symbiont-ruby
112
- unicode-display_width (2.1.0)
142
+ unicode-display_width (3.1.3)
143
+ unicode-emoji (~> 4.0, >= 4.0.4)
144
+ unicode-emoji (4.0.4)
145
+ zeitwerk (2.6.18)
113
146
 
114
147
  PLATFORMS
115
148
  arm64-darwin-21
116
149
  x86_64-darwin-19
117
150
  x86_64-darwin-20
118
151
  x86_64-darwin-21
152
+ x86_64-darwin-22
119
153
  x86_64-linux
120
154
 
121
155
  DEPENDENCIES
122
156
  bundler-audit
123
157
  ci-helper
158
+ dry-initializer
124
159
  pry
125
160
  rake
126
161
  resol!
@@ -128,6 +163,7 @@ DEPENDENCIES
128
163
  rubocop-config-umbrellio
129
164
  simplecov
130
165
  simplecov-lcov
166
+ smart_initializer
131
167
 
132
168
  BUNDLED WITH
133
- 2.3.8
169
+ 2.6.2
data/README.md CHANGED
@@ -54,7 +54,38 @@ and method `.call!` returns a value or throws an error (in case of `fail!` has b
54
54
 
55
55
  #### Params defining
56
56
 
57
- All incoming params and options can be defined using a [smart_initializer](https://github.com/smart-rb/smart_initializer) gem interface.
57
+ `Resol` supports two gems, which provide abstract initialization flow for classes:
58
+
59
+ 1. [smart_initializer](https://github.com/smart-rb/smart_initializer), which was default provider for a very long time.
60
+ 2. [dry-initializer](https://dry-rb.org/gems/dry-initializer/3.1), additional provider with DSL almost identical to the smart_core's DSL.
61
+
62
+ There is an _important restriction_ on using different initializers in different services.
63
+ Descendants of a parent, into which initializer logic has already been imported, cannot override the provider
64
+
65
+ You can use both providers for a different services:
66
+
67
+ ```ruby
68
+ # Types is a namespace for all types, defined by smart_types.
69
+ class FirstService < Resol::Service
70
+ inject_initializer :smartcore_injector
71
+
72
+ param :first, Types::String
73
+ param :second, Types::Integer
74
+ end
75
+
76
+ # Types is a namespace for all types, defined by dry-types.
77
+ class SecondService < Resol::Service
78
+ inject_initializer :dry_injector
79
+
80
+ param :first, Types::Strict::String
81
+ param :second, Types::Strict::Integer
82
+ end
83
+ ```
84
+
85
+ Both initializers support inheritance. And base features for initialization flow
86
+ like default value, arguments accessors visibility level, coercible attributes and so on.
87
+
88
+ List of all supported initializers you can see at `DependencyContainer` definition.
58
89
 
59
90
  #### Return a result
60
91
 
@@ -95,13 +126,15 @@ end
95
126
 
96
127
  Methods:
97
128
 
98
- - `success?` returns `true` for success result and `false` for failure result
99
- - `failure?` returns `true` for failure result and `false` for success result
100
- - `value!` unwraps a result object, returns the value for success result, and throws an error for failure result
101
- - `value_or(other_value, &block)` returns a value for success result or `other_value` for failure result (either calls `block` in case it given)
102
- - `error` returns `nil` for success result and error object (with code and data) for failure result
103
- - `or(&block)` calls block for failure result, for success result does nothing
104
- - `either(success_proc, failure_proc)` for success result calls success_proc with result value in args, for failure result calls failure_proc with error in args.
129
+ - `success?` returns `true` for success result and `false` for failure result
130
+ - `failure?` returns `true` for failure result and `false` for success result
131
+ - `value!` unwraps a result object, returns the value for success result, and throws an error for failure result
132
+ - `value_or(other_value, &block)` returns a value for success result or `other_value` for failure result (either calls `block` in case it given)
133
+ - `error` returns `nil` for success result and error object (with code and data) for failure result
134
+ - `or(&block)` calls block for failure result, for success result does nothing
135
+ - `either(success_proc, failure_proc)` for success result calls success_proc with result value in args, for failure result calls failure_proc with error in args.
136
+ - `bind` — using with `block` for success result resolve value and pass it to the `block`, used to chain multiple monads. Block can return anything. Failure result ignore block and return `self`.
137
+ - `fmap` — like the `bind`, but wraps value returned by block by success monad.
105
138
 
106
139
  ### Error object
107
140
 
@@ -115,6 +148,11 @@ methods `code` and `data`.
115
148
  Configuration constant references to `SmartCore::Initializer::Configuration`. You can read
116
149
  about available configuration options [here](https://github.com/smart-rb/smart_initializer#configuration).
117
150
 
151
+ ### Plugin System
152
+
153
+ Resol implements the basic logic of using plugins to extend and change the base service class.
154
+ You can write your own plugin and applie it by calling `Resol::Service#plugin(plugin_name)`.
155
+
118
156
  ## Development
119
157
 
120
158
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rspec` to run the tests.
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resol
4
+ # The Injector class is responsible for injecting initialization logic provider.
5
+ #
6
+ # Supported providers:
7
+ # - :smart -> uses the `smart_core/initializer`
8
+ # - :dry -> uses the `dry-initializer`
9
+ class Injector
10
+ InjectMarker = Module.new
11
+ NAME_TO_METHOD_MAPPING = {
12
+ smart: :inject_smart,
13
+ dry: :inject_dry,
14
+ }.freeze
15
+
16
+ def self.inject_smart(service)
17
+ require "smart_core/initializer"
18
+
19
+ service.include(SmartCore::Initializer)
20
+ end
21
+
22
+ def self.inject_dry(service)
23
+ require "dry/initializer"
24
+
25
+ service.extend(Dry::Initializer)
26
+ end
27
+
28
+ def initialize(initializer_name)
29
+ self.called_method = NAME_TO_METHOD_MAPPING.fetch(initializer_name.to_sym)
30
+ end
31
+
32
+ def inject!(service_class)
33
+ error!("parent or this class already injected") if service_class.include?(InjectMarker)
34
+
35
+ self.class.public_send(called_method, service_class)
36
+ service_class.include(InjectMarker)
37
+ end
38
+
39
+ private
40
+
41
+ attr_accessor :called_method
42
+
43
+ def error!(msg)
44
+ raise msg
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resol
4
+ module Plugins
5
+ module Dummy; end
6
+ end
7
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resol
4
+ module Plugins
5
+ module ReturnInService
6
+ module ClassMethods
7
+ private
8
+
9
+ def handle_catch(_service)
10
+ yield
11
+ end
12
+ end
13
+
14
+ module InstanceMethods
15
+ module PrependedMethods
16
+ private
17
+
18
+ def proceed_return(_service, data) = data
19
+ end
20
+
21
+ def self.included(service)
22
+ service.prepend(PrependedMethods)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+
5
+ module Resol
6
+ module Plugins
7
+ PLUGINS_PATH = Pathname("resol/plugins")
8
+
9
+ class Manager
10
+ def self.resolve_module(module_name)
11
+ Plugins.const_get(module_name)
12
+ end
13
+
14
+ def initialize
15
+ self.allowed_classes = resolve_allowed_classes
16
+ self.plugins = []
17
+ end
18
+
19
+ def plugin(caller_class, plugin_name)
20
+ plugin_name = plugin_name.to_s
21
+
22
+ return unless allowed_classes.include?(caller_class)
23
+ return if plugins.include?(plugin_name)
24
+
25
+ plugin_module = find_plugin_module(plugin_name)
26
+ if defined?(plugin_module::InstanceMethods)
27
+ caller_class.include(plugin_module::InstanceMethods)
28
+ end
29
+
30
+ if defined?(plugin_module::ClassMethods)
31
+ caller_class.extend(plugin_module::ClassMethods)
32
+ end
33
+
34
+ plugins << plugin_name
35
+ end
36
+
37
+ private
38
+
39
+ attr_accessor :allowed_classes, :plugins
40
+
41
+ def resolve_allowed_classes
42
+ Resol.config.classes_allowed_to_patch.map { |name| Object.const_get(name) }
43
+ end
44
+
45
+ def find_plugin_module(plugin_name)
46
+ require PLUGINS_PATH.join(plugin_name)
47
+ self.class.resolve_module(classify_plugin_name(plugin_name))
48
+ rescue LoadError, NameError => e
49
+ raise ArgumentError, "Failed to load plugin '#{plugin_name}': #{e.message}"
50
+ end
51
+
52
+ def classify_plugin_name(string)
53
+ string.split(/_|-/).map!(&:capitalize).join
54
+ end
55
+ end
56
+ end
57
+ end
data/lib/resol/result.rb CHANGED
@@ -3,26 +3,13 @@
3
3
  module Resol
4
4
  class UnwrapError < StandardError; end
5
5
 
6
- class Result
7
- # @!method success?
8
- # @!method failure?
9
- # @!method value_or
10
- # @!method value!
11
-
12
- def initialize(*); end
13
-
14
- def or
15
- yield(@value) if failure?
16
- end
17
-
18
- def either(success_proc, failure_proc)
19
- success? ? success_proc.call(@value) : failure_proc.call(@value)
20
- end
21
- end
6
+ # rubocop:disable Lint/EmptyClass
7
+ class Result; end
8
+ # rubocop:enable Lint/EmptyClass
22
9
 
23
10
  class Success < Result
24
11
  def initialize(value)
25
- super
12
+ super()
26
13
  @value = value
27
14
  end
28
15
 
@@ -34,7 +21,7 @@ module Resol
34
21
  false
35
22
  end
36
23
 
37
- def value_or(*)
24
+ def value_or(_other_value = nil)
38
25
  @value
39
26
  end
40
27
 
@@ -42,14 +29,26 @@ module Resol
42
29
  @value
43
30
  end
44
31
 
45
- def error
46
- nil
32
+ def error = nil
33
+
34
+ def or = nil
35
+
36
+ def either(success_proc, _failure_proc)
37
+ success_proc.call(@value)
38
+ end
39
+
40
+ def bind
41
+ yield @value
42
+ end
43
+
44
+ def fmap(&)
45
+ Resol.Success(bind(&))
47
46
  end
48
47
  end
49
48
 
50
49
  class Failure < Result
51
50
  def initialize(error)
52
- super
51
+ super()
53
52
  @value = error
54
53
  end
55
54
 
@@ -62,11 +61,7 @@ module Resol
62
61
  end
63
62
 
64
63
  def value_or(other_value = nil)
65
- if block_given?
66
- yield(@value)
67
- else
68
- other_value
69
- end
64
+ block_given? ? yield(@value) : other_value
70
65
  end
71
66
 
72
67
  def value!
@@ -76,13 +71,29 @@ module Resol
76
71
  def error
77
72
  @value
78
73
  end
74
+
75
+ def or
76
+ yield @value
77
+ end
78
+
79
+ def either(_success_proc, failure_proc)
80
+ failure_proc.call(@value)
81
+ end
82
+
83
+ def bind = self
84
+
85
+ alias fmap bind
79
86
  end
80
87
 
81
- def self.Success(...)
88
+ # TODO: Should be in a module, which includes in classes.
89
+ # Example;
90
+ # rubocop:disable Naming/MethodName
91
+ def Success(...)
82
92
  Success.new(...)
83
93
  end
84
94
 
85
- def self.Failure(...)
95
+ def Failure(...)
86
96
  Failure.new(...)
87
97
  end
98
+ # rubocop:enable Naming/MethodName
88
99
  end
data/lib/resol/service.rb CHANGED
@@ -27,7 +27,6 @@ module Resol
27
27
  end
28
28
  end
29
29
 
30
- include SmartCore::Initializer
31
30
  include Resol::Builder
32
31
  include Resol::Callbacks
33
32
 
@@ -39,59 +38,109 @@ module Resol
39
38
  super
40
39
  end
41
40
 
42
- def call(*args, **kwargs, &block)
41
+ # Allows you to configure an initializer library for this service,
42
+ # such as `dry-initializer` or `smart_core/initializer`.
43
+ #
44
+ # @param initializer_name [String, Symbol]
45
+ # The name of the initializer (e.g., `:dry` or `:smart`).
46
+ # @return [void]
47
+ def use_initializer!(initializer_name)
48
+ Resol::Injector.new(initializer_name).inject!(self)
49
+ end
50
+
51
+ def plugin(...)
52
+ manager.plugin(self, ...)
53
+ end
54
+
55
+ # Calls the service using class-level invocation. Builds the service object,
56
+ # runs any callbacks, and invokes the `#call` instance method.
57
+ #
58
+ # @param args [Array] Positional arguments for building service instance.
59
+ # @param kwargs [Hash] Keyword arguments for building service instance.
60
+ # @yield [block] An optional block passed into service's `#call`.
61
+ #
62
+ # @return [Resol::Success, Resol::Failure]
63
+ # Returns a `Resol::Success` if the service completed via `success!`,
64
+ # or a `Resol::Failure` if exited with`fail!` calling.
65
+ #
66
+ # @raise [InvalidCommandImplementation]
67
+ # If neither `#success!` nor `#fail!` is called inside the `#call` method.
68
+ def call(*args, **kwargs, &)
43
69
  service = build(*args, **kwargs)
44
70
 
45
- result = catch(service) do
71
+ result = handle_catch(service) do
46
72
  service.instance_variable_set(:@__performing__, true)
47
73
  __run_callbacks__(service)
48
- service.call(&block)
49
- :uncaught
74
+ service.call(&)
50
75
  end
76
+ return Resol::Success(result.data) if service.__result_method__called__
51
77
 
52
- if result == :uncaught
53
- error_message = "No `#success!` or `#fail!` called in `#call` method in #{service.class}."
54
- raise InvalidCommandImplementation, error_message
55
- else
56
- Resol::Success(result.data)
57
- end
78
+ error_message = "No `#success!` or `#fail!` called in `#call` method in #{service.class}."
79
+ raise InvalidCommandImplementation, error_message
58
80
  rescue self::Failure => e
59
81
  Resol::Failure(e)
60
82
  end
61
83
 
84
+ # Same as {call}, but attempts to resolve value from monad.
85
+ # If the result is a failure, it raises the error instead of returning a `Resol::Failure`.
86
+ #
87
+ # @param args [Array] Positional arguments for building the service instance.
88
+ # @param kwargs [Hash] Keyword arguments for building the service instance.
89
+ # @yield [block] An optional block passed to the service's `#call`.
90
+ #
91
+ # @return [Object]
92
+ # Returns a value, with which instance of service interrupts with {#success!}.
93
+ #
94
+ # @raise [self::Failure]
95
+ # Raises an error if the service fails.
62
96
  def call!(...)
63
97
  call(...).value_or { |error| raise error }
64
98
  end
99
+
100
+ private
101
+
102
+ def manager
103
+ @manager ||= Plugins::Manager.new
104
+ end
105
+
106
+ def handle_catch(service, &)
107
+ catch(service, &)
108
+ end
65
109
  end
66
110
 
67
- # @!method call
111
+ attr_accessor :__result_method__called__
68
112
 
69
113
  private
70
114
 
71
115
  attr_reader :__performing__
72
116
 
73
117
  def fail!(code, data = nil)
74
- check_performing do
75
- raise self.class::Failure.new(code, data)
76
- end
118
+ check_performing!
119
+ raise self.class::Failure.new(code, data)
77
120
  end
78
121
 
79
122
  def success!(data = nil)
80
- check_performing do
81
- throw(self, Result.new(data))
82
- end
123
+ check_performing!
124
+ result_method_called!
125
+ proceed_return(self, Result.new(data))
83
126
  end
84
127
 
85
- def check_performing
86
- if __performing__
87
- yield
88
- else
89
- error_message =
90
- "It looks like #call instance method was called directly in #{self.class}. " \
91
- "You must always use class-level `.call` or `.call!` method."
128
+ def check_performing!
129
+ return if __performing__
92
130
 
93
- raise InvalidCommandCall, error_message
94
- end
131
+ error_message =
132
+ "It looks like #call instance method was called directly in #{self.class}. " \
133
+ "You must always use class-level `.call` or `.call!` method."
134
+
135
+ raise InvalidCommandCall, error_message
136
+ end
137
+
138
+ def result_method_called!
139
+ self.__result_method__called__ = true
140
+ end
141
+
142
+ def proceed_return(service, data)
143
+ throw(service, data)
95
144
  end
96
145
  end
97
146
  end
data/lib/resol/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Resol
4
- VERSION = "0.8.0"
4
+ VERSION = "1.0.0"
5
5
  end
data/lib/resol.rb CHANGED
@@ -1,10 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "smart_core/initializer"
4
-
3
+ require "dry-configurable"
5
4
  require_relative "resol/version"
5
+
6
+ require_relative "resol/injector"
7
+ require_relative "resol/plugins"
6
8
  require_relative "resol/service"
7
9
 
8
10
  module Resol
9
- Configuration = SmartCore::Initializer::Configuration
11
+ extend self
12
+
13
+ extend Dry::Configurable
14
+
15
+ setting :classes_allowed_to_patch, default: ["Resol::Service"]
10
16
  end
metadata CHANGED
@@ -1,141 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resol
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aleksei Bespalov
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2022-03-04 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: smart_initializer
13
+ name: dry-configurable
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '0.7'
18
+ version: 1.2.0
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: '0.7'
27
- - !ruby/object:Gem::Dependency
28
- name: bundler-audit
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: ci-helper
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: pry
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: rake
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rspec
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: rubocop-config-umbrellio
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: simplecov
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: simplecov-lcov
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
25
+ version: 1.2.0
139
26
  description: Gem for creating (any) object patterns
140
27
  email:
141
28
  - nulldefiner@gmail.com
@@ -158,6 +45,10 @@ files:
158
45
  - lib/resol.rb
159
46
  - lib/resol/builder.rb
160
47
  - lib/resol/callbacks.rb
48
+ - lib/resol/injector.rb
49
+ - lib/resol/plugins.rb
50
+ - lib/resol/plugins/dummy.rb
51
+ - lib/resol/plugins/return_in_service.rb
161
52
  - lib/resol/result.rb
162
53
  - lib/resol/service.rb
163
54
  - lib/resol/version.rb
@@ -165,7 +56,6 @@ homepage: https://github.com/umbrellio/resol
165
56
  licenses:
166
57
  - MIT
167
58
  metadata: {}
168
- post_install_message:
169
59
  rdoc_options: []
170
60
  require_paths:
171
61
  - lib
@@ -173,15 +63,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
173
63
  requirements:
174
64
  - - ">="
175
65
  - !ruby/object:Gem::Version
176
- version: 2.7.0
66
+ version: 3.1.0
177
67
  required_rubygems_version: !ruby/object:Gem::Requirement
178
68
  requirements:
179
69
  - - ">="
180
70
  - !ruby/object:Gem::Version
181
71
  version: '0'
182
72
  requirements: []
183
- rubygems_version: 3.3.5
184
- signing_key:
73
+ rubygems_version: 3.6.9
185
74
  specification_version: 4
186
75
  summary: Gem for creating (any) object patterns
187
76
  test_files: []