convenient_service 0.7.0 → 0.8.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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/ROADMAP.md +2 -0
  4. data/lib/convenient_service/aliases.rb +9 -0
  5. data/lib/convenient_service/common/plugins/has_constructor_without_initialize/concern.rb +19 -0
  6. data/lib/convenient_service/configs/minimal.rb +176 -0
  7. data/lib/convenient_service/configs/standard.rb +16 -104
  8. data/lib/convenient_service/configs.rb +1 -0
  9. data/lib/convenient_service/dependencies.rb +8 -0
  10. data/lib/convenient_service/examples/dry/gemfile/dry_service/config.rb +5 -5
  11. data/lib/convenient_service/examples/rails/gemfile/rails_service/config.rb +7 -7
  12. data/lib/convenient_service/rspec/helpers/custom/ignoring_error.rb +3 -0
  13. data/lib/convenient_service/rspec/helpers/custom/wrap_method/entities/wrapped_method.rb +29 -3
  14. data/lib/convenient_service/rspec/matchers/custom/results/base.rb +5 -0
  15. data/lib/convenient_service/service/plugins/has_result/concern/class_methods.rb +3 -3
  16. data/lib/convenient_service/service/plugins/has_result/constants.rb +0 -3
  17. data/lib/convenient_service/service/plugins/has_result/entities/result/plugins/has_jsend_status_and_attributes/entities/data.rb +13 -0
  18. data/lib/convenient_service/service/plugins/raises_on_double_result/middleware.rb +37 -2
  19. data/lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/commands/format_backtrace.rb +80 -0
  20. data/lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/commands/format_cause.rb +78 -0
  21. data/lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/commands/format_exception.rb +169 -0
  22. data/lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/commands/format_line.rb +40 -0
  23. data/lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/commands.rb +7 -0
  24. data/lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/constants.rb +13 -0
  25. data/lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/middleware.rb +58 -0
  26. data/lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions.rb +5 -0
  27. data/lib/convenient_service/support/undefined.rb +9 -0
  28. data/lib/convenient_service/support.rb +2 -0
  29. data/lib/convenient_service/version.rb +1 -1
  30. metadata +12 -2
@@ -22,7 +22,7 @@ module ConvenientService
22
22
  # NOTE: This method is internally used by custom RSpec helper `stub_service`. It should NOT be used in the client code.
23
23
  #
24
24
  def success(
25
- service: Constants::DEFAULT_SERVICE_INSTANCE,
25
+ service: create_without_initialize,
26
26
  data: Constants::DEFAULT_SUCCESS_DATA
27
27
  )
28
28
  result_class.create(
@@ -42,7 +42,7 @@ module ConvenientService
42
42
  # NOTE: This method is internally used by custom RSpec helper `stub_service`. It should NOT be used in the client code.
43
43
  #
44
44
  def failure(
45
- service: Constants::DEFAULT_SERVICE_INSTANCE,
45
+ service: create_without_initialize,
46
46
  data: Constants::DEFAULT_FAILURE_DATA,
47
47
  message: data.any? ? data.first.join(" ") : Constants::DEFAULT_FAILURE_MESSAGE
48
48
  )
@@ -63,7 +63,7 @@ module ConvenientService
63
63
  # NOTE: This method is internally used by custom RSpec helper `stub_service`. It should NOT be used in the client code.
64
64
  #
65
65
  def error(
66
- service: Constants::DEFAULT_SERVICE_INSTANCE,
66
+ service: create_without_initialize,
67
67
  message: Constants::DEFAULT_ERROR_MESSAGE,
68
68
  code: Constants::DEFAULT_ERROR_CODE
69
69
  )
@@ -5,9 +5,6 @@ module ConvenientService
5
5
  module Plugins
6
6
  module HasResult
7
7
  module Constants
8
- DEFAULT_SERVICE_CLASS = ::Class.new { include ::ConvenientService::Service::Plugins::HasResult::Concern }
9
- DEFAULT_SERVICE_INSTANCE = DEFAULT_SERVICE_CLASS.new
10
-
11
8
  SUCCESS_STATUS = :success
12
9
  FAILURE_STATUS = :failure
13
10
  ERROR_STATUS = :error
@@ -18,6 +18,19 @@ module ConvenientService
18
18
 
19
19
  attr_reader :value
20
20
 
21
+ ##
22
+ # @internal
23
+ # NOTE: Ruby hashes enumerate their values in the order that the corresponding keys were inserted.
24
+ # That is why the end-user can be 100% sure that the failure message is always generated from the first key/value pair.
25
+ # - https://ruby-doc.org/core-2.7.0/Hash.html
26
+ #
27
+ # TODO: A test that crashes when such behaviour is broken.
28
+ #
29
+ # NOTE: As a result, there is NO need to use any custom `OrderedHash` implementations.
30
+ # - https://api.rubyonrails.org/v5.1/classes/ActiveSupport/OrderedHash.html
31
+ # - https://github.com/rails/rails/issues/22681
32
+ # - https://api.rubyonrails.org/classes/ActiveSupport/OrderedOptions.html
33
+ #
21
34
  def initialize(value:)
22
35
  @value = value
23
36
  end
@@ -5,6 +5,26 @@ module ConvenientService
5
5
  module Plugins
6
6
  module RaisesOnDoubleResult
7
7
  class Middleware < Core::MethodChainMiddleware
8
+ ##
9
+ # @return [ConvenientService::Service::Plugins::HasResult::Entities::Result]
10
+ #
11
+ # @internal
12
+ # TODO: Rewrite `RaisesOnDoubleResult` to make it thread-safe.
13
+ #
14
+ # NOTE: Minimal reproducible example.
15
+ #
16
+ # class Service
17
+ # include ConvenientService::Standard::Config
18
+ #
19
+ # def result
20
+ # success
21
+ # end
22
+ # end
23
+ #
24
+ # service = Service.new
25
+ #
26
+ # 10.times.reduce([]) { |threads| threads << Thread.new { service.result } }.join
27
+ #
8
28
  def next(...)
9
29
  refute_has_result! || mark_as_has_result!
10
30
 
@@ -14,8 +34,14 @@ module ConvenientService
14
34
  private
15
35
 
16
36
  ##
17
- # NOTE: `refute` is `!assert`.
18
- # https://docs.seattlerb.org/minitest
37
+ # @return [Boolean]
38
+ # @raise [ConvenientService::Service::Plugins::RaisesOnDoubleResult::Errors::DoubleResult]
39
+ #
40
+ # @internal
41
+ # NOTE: `refute` is `!assert`.
42
+ # - https://docs.seattlerb.org/minitest
43
+ #
44
+ # NOTE: This method contains a trailing exclamation mark in its name since it is mutable.
19
45
  #
20
46
  def refute_has_result!
21
47
  return unless entity.internals.cache.exist?(:has_result)
@@ -23,6 +49,15 @@ module ConvenientService
23
49
  raise Errors::DoubleResult.new(service: entity)
24
50
  end
25
51
 
52
+ ##
53
+ # @return [Boolean]
54
+ #
55
+ # @internal
56
+ # NOTE: Name is inspired by `mark_as_read`.
57
+ # - https://github.com/ledermann/unread
58
+ #
59
+ # NOTE: This method contains a trailing exclamation mark in its name since it is mutable.
60
+ #
26
61
  def mark_as_has_result!
27
62
  entity.internals.cache.write(:has_result, true)
28
63
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ConvenientService
4
+ module Service
5
+ module Plugins
6
+ module RescuesResultUnhandledExceptions
7
+ module Commands
8
+ class FormatBacktrace < Support::Command
9
+ ##
10
+ # @!attribute [r] backtrace
11
+ # @return [Array, nil]
12
+ #
13
+ attr_reader :backtrace
14
+
15
+ ##
16
+ # @!attribute [r] max_size
17
+ # @return [Integer]
18
+ #
19
+ attr_reader :max_size
20
+
21
+ ##
22
+ # @param backtrace [Array, nil]
23
+ # @param max_size [Integer]
24
+ # @return [void]
25
+ #
26
+ # @internal
27
+ # IMPORTANT: Sometimes `exception.backtrace` can be `nil`.
28
+ # - https://blog.kalina.tech/2019/04/exception-without-backtrace-in-ruby.html
29
+ # - https://github.com/jruby/jruby/issues/4467
30
+ #
31
+ def initialize(backtrace:, max_size:)
32
+ @backtrace = backtrace.to_a
33
+ @max_size = max_size
34
+ end
35
+
36
+ ##
37
+ # @return [String]
38
+ #
39
+ # @note Exceptions formatting is inspired by RSpec. It has almost the same output (at least for RSpec 3).
40
+ #
41
+ # @example Backtrace with upto 10 lines.
42
+ #
43
+ # # /gem/lib/convenient_service/factories/services.rb:120:in `result'
44
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/caller/commands/define_method_middlewares_caller.rb:116:in `call'
45
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/caller/commands/define_method_middlewares_caller.rb:116:in `block in result'
46
+ # # /gem/lib/convenient_service/dependencies/extractions/ruby_middleware/middleware/runner.rb:67:in `block (2 levels) in build_call_chain'
47
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/chain.rb:35:in `next'
48
+ # # /gem/lib/convenient_service/common/plugins/caches_return_value/middleware.rb:17:in `block in next'
49
+ # # /gem/lib/convenient_service/support/cache.rb:110:in `fetch'
50
+ # # /gem/lib/convenient_service/common/plugins/caches_return_value/middleware.rb:17:in `next'
51
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/middleware.rb:73:in `call'
52
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/chain.rb:35:in `next'
53
+ #
54
+ # @example Backtrace with more than 10 lines.
55
+ #
56
+ # # /gem/lib/convenient_service/factories/services.rb:120:in `result'
57
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/caller/commands/define_method_middlewares_caller.rb:116:in `call'
58
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/caller/commands/define_method_middlewares_caller.rb:116:in `block in result'
59
+ # # /gem/lib/convenient_service/dependencies/extractions/ruby_middleware/middleware/runner.rb:67:in `block (2 levels) in build_call_chain'
60
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/chain.rb:35:in `next'
61
+ # # /gem/lib/convenient_service/common/plugins/caches_return_value/middleware.rb:17:in `block in next'
62
+ # # /gem/lib/convenient_service/support/cache.rb:110:in `fetch'
63
+ # # /gem/lib/convenient_service/common/plugins/caches_return_value/middleware.rb:17:in `next'
64
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/middleware.rb:73:in `call'
65
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/chain.rb:35:in `next'
66
+ # # ...
67
+ #
68
+ def call
69
+ message = backtrace.take(max_size).map { |line| Commands::FormatLine.call(line: line) }.join("\n")
70
+
71
+ message << "\n# ..." if backtrace.size > max_size
72
+
73
+ message
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ConvenientService
4
+ module Service
5
+ module Plugins
6
+ module RescuesResultUnhandledExceptions
7
+ module Commands
8
+ class FormatCause < Support::Command
9
+ ##
10
+ # @!attribute [r] exception
11
+ # @return [StandardError, nil]
12
+ #
13
+ attr_reader :cause
14
+
15
+ ##
16
+ # @param cause [StandardError]
17
+ # @return [void]
18
+ #
19
+ def initialize(cause:)
20
+ @cause = cause
21
+ end
22
+
23
+ ##
24
+ # @return [String]
25
+ #
26
+ # @note Cause formatting is inspired by RSpec. It has almost the same output (at least for RSpec 3).
27
+ #
28
+ # @example Cause.
29
+ #
30
+ # ------------------
31
+ # --- Caused by: ---
32
+ # StandardError:
33
+ # cause message
34
+ # # /gem/lib/convenient_service/factories/service/class.rb:41:in `result'
35
+ #
36
+ def call
37
+ return "" unless cause
38
+
39
+ <<~MESSAGE.chomp
40
+ ------------------
41
+ --- Caused by: ---
42
+ #{cause.class}:
43
+ #{cause.message}
44
+ #{formatted_cause_first_line}
45
+ MESSAGE
46
+ end
47
+
48
+ private
49
+
50
+ ##
51
+ # @return [String, nil]
52
+ #
53
+ # @internal
54
+ # IMPORTANT: Sometimes `exception.backtrace` can be `nil`.
55
+ # - https://blog.kalina.tech/2019/04/exception-without-backtrace-in-ruby.html
56
+ # - https://github.com/jruby/jruby/issues/4467
57
+ #
58
+ def cause_first_line
59
+ return "" unless cause
60
+ return "" unless cause.backtrace
61
+
62
+ cause.backtrace.first
63
+ end
64
+
65
+ ##
66
+ # @return [String, nil]
67
+ #
68
+ def formatted_cause_first_line
69
+ return "" unless cause_first_line
70
+
71
+ Commands::FormatLine.call(line: cause_first_line)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ConvenientService
4
+ module Service
5
+ module Plugins
6
+ module RescuesResultUnhandledExceptions
7
+ module Commands
8
+ class FormatException < Support::Command
9
+ ##
10
+ # @!attribute [r] exception
11
+ # @return [StandardError]
12
+ #
13
+ attr_reader :exception
14
+
15
+ ##
16
+ # @!attribute [r] args
17
+ # @return [StandardError]
18
+ #
19
+ attr_reader :args
20
+
21
+ ##
22
+ # @!attribute [r] kwargs
23
+ # @return [StandardError]
24
+ #
25
+ attr_reader :kwargs
26
+
27
+ ##
28
+ # @!attribute [r] block
29
+ # @return [StandardError]
30
+ #
31
+ attr_reader :block
32
+
33
+ ##
34
+ # @param exception [StandardError]
35
+ # @param args [Array]
36
+ # @param kwargs [Hash]
37
+ # @param block [Proc, nil]
38
+ # @return [void]
39
+ #
40
+ def initialize(exception:, args:, kwargs:, block:)
41
+ @exception = exception
42
+ @args = args
43
+ @kwargs = kwargs
44
+ @block = block
45
+ end
46
+
47
+ ##
48
+ # @return [String]
49
+ #
50
+ # @note Exceptions formatting is inspired by RSpec. It has almost the same output (at least for RSpec 3).
51
+ #
52
+ # @example Simple exception.
53
+ #
54
+ # StandardError:
55
+ # exception message
56
+ # # /gem/lib/convenient_service/factories/services.rb:120:in `result'
57
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/caller/commands/define_method_middlewares_caller.rb:116:in `call'
58
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/caller/commands/define_method_middlewares_caller.rb:116:in `block in result'
59
+ # # /gem/lib/convenient_service/dependencies/extractions/ruby_middleware/middleware/runner.rb:67:in `block (2 levels) in build_call_chain'
60
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/chain.rb:35:in `next'
61
+ # # /gem/lib/convenient_service/common/plugins/caches_return_value/middleware.rb:17:in `block in next'
62
+ # # /gem/lib/convenient_service/support/cache.rb:110:in `fetch'
63
+ # # /gem/lib/convenient_service/common/plugins/caches_return_value/middleware.rb:17:in `next'
64
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/middleware.rb:73:in `call'
65
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/chain.rb:35:in `next'
66
+ #
67
+ # @example Exception with backtrace with more than 10 lines.
68
+ #
69
+ # StandardError:
70
+ # exception message
71
+ # # /gem/lib/convenient_service/factories/services.rb:120:in `result'
72
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/caller/commands/define_method_middlewares_caller.rb:116:in `call'
73
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/caller/commands/define_method_middlewares_caller.rb:116:in `block in result'
74
+ # # /gem/lib/convenient_service/dependencies/extractions/ruby_middleware/middleware/runner.rb:67:in `block (2 levels) in build_call_chain'
75
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/chain.rb:35:in `next'
76
+ # # /gem/lib/convenient_service/common/plugins/caches_return_value/middleware.rb:17:in `block in next'
77
+ # # /gem/lib/convenient_service/support/cache.rb:110:in `fetch'
78
+ # # /gem/lib/convenient_service/common/plugins/caches_return_value/middleware.rb:17:in `next'
79
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/middleware.rb:73:in `call'
80
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/chain.rb:35:in `next'
81
+ # # ...
82
+ #
83
+ # @example Exception with cause.
84
+ #
85
+ # StandardError:
86
+ # exception message
87
+ # # /gem/lib/convenient_service/factories/service/class.rb:43:in `rescue in result'
88
+ # # /gem/lib/convenient_service/factories/service/class.rb:40:in `result'
89
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/caller/commands/define_method_middlewares_caller.rb:116:in `call'
90
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/caller/commands/define_method_middlewares_caller.rb:116:in `block in result'
91
+ # # /gem/lib/convenient_service/dependencies/extractions/ruby_middleware/middleware/runner.rb:67:in `block (2 levels) in build_call_chain'
92
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/chain.rb:35:in `next'
93
+ # # /gem/lib/convenient_service/common/plugins/caches_return_value/middleware.rb:17:in `block in next'
94
+ # # /gem/lib/convenient_service/support/cache.rb:110:in `fetch'
95
+ # # /gem/lib/convenient_service/common/plugins/caches_return_value/middleware.rb:17:in `next'
96
+ # # /gem/lib/convenient_service/core/entities/config/entities/method_middlewares/entities/middleware.rb:73:in `call'
97
+ # ------------------
98
+ # --- Caused by: ---
99
+ # StandardError:
100
+ # cause message
101
+ # # /gem/lib/convenient_service/factories/service/class.rb:41:in `result'
102
+ #
103
+ # @internal
104
+ # TODO: Think about the following questions:
105
+ # - How to format args, kwargs and block?
106
+ # - Who should format them? The end-user or this plugin?
107
+ #
108
+ def call
109
+ <<~MESSAGE.rstrip
110
+ #{formatted_exception}
111
+ #{formatted_exception_backtrace}
112
+ #{formatted_exception_cause}
113
+ MESSAGE
114
+ end
115
+
116
+ private
117
+
118
+ ##
119
+ # @return [String]
120
+ #
121
+ def formatted_exception
122
+ <<~MESSAGE.chomp
123
+ #{exception.class}:
124
+ #{exception.message}
125
+ MESSAGE
126
+ end
127
+
128
+ ##
129
+ # Formats exception backtrace. When backtrace has more then `max_backtrace_size` lines, the extra lines are trimmed.
130
+ # That is especially important for the monitoring system with the limited amount of memory, since it may too expensive to store the full backtrace all the time.
131
+ #
132
+ # @return [String]
133
+ #
134
+ # @internal
135
+ # TODO: Add an ability to set `max_backtrace_size` while configuring the middleware. For example:
136
+ #
137
+ # class Service
138
+ # include ConvenientService::Standard::Config
139
+ #
140
+ # middlewares :result, scope: :class do
141
+ # use ConvenientService::Service::Plugins::RescuesResultUnhandledExceptions::Middleware, max_backtrace_size: 1_000
142
+ # end
143
+ #
144
+ # # ...
145
+ # end
146
+ #
147
+ def formatted_exception_backtrace
148
+ Commands::FormatBacktrace.call(backtrace: exception.backtrace, max_size: max_backtrace_size)
149
+ end
150
+
151
+ ##
152
+ # @return [String]
153
+ #
154
+ def formatted_exception_cause
155
+ Commands::FormatCause.call(cause: exception.cause)
156
+ end
157
+
158
+ ##
159
+ # @return [Integer]
160
+ #
161
+ def max_backtrace_size
162
+ Constants::DEFAULT_MAX_BACKTRACE_SIZE
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ConvenientService
4
+ module Service
5
+ module Plugins
6
+ module RescuesResultUnhandledExceptions
7
+ module Commands
8
+ class FormatLine < Support::Command
9
+ ##
10
+ # @!attribute [r] line
11
+ # @return [String]
12
+ #
13
+ attr_reader :line
14
+
15
+ ##
16
+ # @param line [String]
17
+ # @return [void]
18
+ #
19
+ def initialize(line:)
20
+ @line = line
21
+ end
22
+
23
+ ##
24
+ # @return [String]
25
+ #
26
+ # @note Exceptions formatting is inspired by RSpec. It has almost the same output (at least for RSpec 3).
27
+ #
28
+ # @example Line.
29
+ #
30
+ # # /gem/lib/convenient_service/factories/services.rb:120:in `result'
31
+ #
32
+ def call
33
+ "# #{line}"
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "commands/format_backtrace"
4
+ require_relative "commands/format_cause"
5
+ require_relative "commands/format_line"
6
+
7
+ require_relative "commands/format_exception"
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ConvenientService
4
+ module Service
5
+ module Plugins
6
+ module RescuesResultUnhandledExceptions
7
+ module Constants
8
+ DEFAULT_MAX_BACKTRACE_SIZE = 10
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ConvenientService
4
+ module Service
5
+ module Plugins
6
+ module RescuesResultUnhandledExceptions
7
+ class Middleware < Core::MethodChainMiddleware
8
+ ##
9
+ # @param args [Array]
10
+ # @param kwargs [Hash]
11
+ # @param block [Proc, nil]
12
+ # @return [ConvenientService::Service::Plugins::HasResult::Entities::Result]
13
+ #
14
+ # @internal
15
+ # NOTE: `rescue => exception` is the same as `rescue ::StandardError => exception`.
16
+ #
17
+ # IMPORTANT: Never rescue `Exception` since its direct descendants are used internally by Ruby, rescue `StandardError` instead.
18
+ # - https://thoughtbot.com/blog/rescue-standarderror-not-exception
19
+ # - https://stackoverflow.com/questions/10048173/why-is-it-bad-style-to-rescue-exception-e-in-ruby
20
+ # - https://ruby-doc.org/core-2.7.0/Exception.html
21
+ #
22
+ def next(*args, **kwargs, &block)
23
+ chain.next(*args, **kwargs, &block)
24
+ rescue => exception
25
+ failure_result_from(exception, *args, **kwargs, &block)
26
+ end
27
+
28
+ private
29
+
30
+ ##
31
+ # @param exception [StandardError]
32
+ # @param args [Array]
33
+ # @param kwargs [Hash]
34
+ # @param block [Proc, nil]
35
+ # @return [ConvenientService::Service::Plugins::HasResult::Entities::Result]
36
+ #
37
+ def failure_result_from(exception, *args, **kwargs, &block)
38
+ entity.failure(
39
+ data: {exception: exception},
40
+ message: format_exception(exception, *args, **kwargs, &block)
41
+ )
42
+ end
43
+
44
+ ##
45
+ # @param exception [StandardError]
46
+ # @param args [Array]
47
+ # @param kwargs [Hash]
48
+ # @param block [Proc, nil]
49
+ # @return [String]
50
+ #
51
+ def format_exception(exception, *args, **kwargs, &block)
52
+ Commands::FormatException.call(exception: exception, args: args, kwargs: kwargs, block: block)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "rescues_result_unhandled_exceptions/commands"
4
+ require_relative "rescues_result_unhandled_exceptions/constants"
5
+ require_relative "rescues_result_unhandled_exceptions/middleware"
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ConvenientService
4
+ module Support
5
+ UNDEFINED = ::Object.new.tap do |object|
6
+ object.define_singleton_method(:inspect) { "undefined" }
7
+ end
8
+ end
9
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "support/not_passed"
4
+ require_relative "support/undefined"
5
+
4
6
  require_relative "support/concern"
5
7
 
6
8
  require_relative "support/abstract_method"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ConvenientService
4
- VERSION = "0.7.0"
4
+ VERSION = "0.8.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: convenient_service
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marian Kostyk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-13 00:00:00.000000000 Z
11
+ date: 2023-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appraisal
@@ -427,6 +427,7 @@ files:
427
427
  - lib/convenient_service/common/plugins/normalizes_env/middleware.rb
428
428
  - lib/convenient_service/configs.rb
429
429
  - lib/convenient_service/configs/aliases.rb
430
+ - lib/convenient_service/configs/minimal.rb
430
431
  - lib/convenient_service/configs/standard.rb
431
432
  - lib/convenient_service/core.rb
432
433
  - lib/convenient_service/core/aliases.rb
@@ -825,6 +826,14 @@ files:
825
826
  - lib/convenient_service/service/plugins/raises_on_double_result.rb
826
827
  - lib/convenient_service/service/plugins/raises_on_double_result/errors.rb
827
828
  - lib/convenient_service/service/plugins/raises_on_double_result/middleware.rb
829
+ - lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions.rb
830
+ - lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/commands.rb
831
+ - lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/commands/format_backtrace.rb
832
+ - lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/commands/format_cause.rb
833
+ - lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/commands/format_exception.rb
834
+ - lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/commands/format_line.rb
835
+ - lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/constants.rb
836
+ - lib/convenient_service/service/plugins/rescues_result_unhandled_exceptions/middleware.rb
828
837
  - lib/convenient_service/service/plugins/wraps_result_in_db_transaction.rb
829
838
  - lib/convenient_service/service/plugins/wraps_result_in_db_transaction/middleware.rb
830
839
  - lib/convenient_service/services.rb
@@ -867,6 +876,7 @@ files:
867
876
  - lib/convenient_service/support/not_passed.rb
868
877
  - lib/convenient_service/support/raw_value.rb
869
878
  - lib/convenient_service/support/ruby.rb
879
+ - lib/convenient_service/support/undefined.rb
870
880
  - lib/convenient_service/support/version.rb
871
881
  - lib/convenient_service/support/version/null_version.rb
872
882
  - lib/convenient_service/utils.rb