u-case 5.2.1 → 5.3.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: 007b0e8ba30a51777bce3c5665960238f0fe50d33c04d3102e444dd917d7a762
4
- data.tar.gz: d19a095e0540f218bc4a8dba0601999a3decc56a6990be10fe4a5ef7e35e31c8
3
+ metadata.gz: 68a2fca8a1808ae9a30ffcdca77631507d89de9fd070628442a9860ce1000fc3
4
+ data.tar.gz: bcdfdac58fd882e5ed1f912e29d8decbf83971638e43acfe62e84a8697530dc9
5
5
  SHA512:
6
- metadata.gz: f96b58e62d5fa9de89a664b748941ee4762a9bf4f58b83aa7a56fa745b447772b33df24272aa8d49b3768ce6d83a2af9138647baf2d1e704276db2f7ca335cdc
7
- data.tar.gz: 6260ad743a4a40da49d0bbd7cea4d5d7aba9ce374bce2df8bc496d61373b11de3c7315017936a8053625ba5298b4e8fb13d03c748ceccdd73c590690bffff366
6
+ metadata.gz: ef37188a66960746af6613e98c259198e489afb75f25821d15b91cf24cc485b1153f05a80745f702e158f0fcbb0cd84733bccf7fefb0581f03d3c81dbbd69a69
7
+ data.tar.gz: a89891142cbe3be3cc36ac5cdd22f257d164c47ff1b1a484768b76b9f199590dfb10725985369080a73105db23f42a2d5401ab0a6cd8f977df1cc8b9873e92aa
data/README.md CHANGED
@@ -60,6 +60,7 @@ unreleased| https://github.com/serradura/u-case/blob/main/README.md
60
60
  - [`Micro::Case::Safe` - Is there some feature to auto handle exceptions inside of a use case or flow?](#microcasesafe---is-there-some-feature-to-auto-handle-exceptions-inside-of-a-use-case-or-flow)
61
61
  - [`Micro::Cases::Safe::Flow`](#microcasessafeflow)
62
62
  - [`Micro::Case::Result#on_exception`](#microcaseresulton_exception)
63
+ - [Opting out of the safe mechanism](#opting-out-of-the-safe-mechanism)
63
64
  - [Validating attributes with `accept:` / `reject:`](#validating-attributes-with-accept--reject)
64
65
  - [`u-case/with_activemodel_validation` - How to validate the use case attributes?](#u-casewith_activemodel_validation---how-to-validate-the-use-case-attributes)
65
66
  - [If I enabled the auto validation, is it possible to disable it only in specific use cases?](#if-i-enabled-the-auto-validation-is-it-possible-to-disable-it-only-in-specific-use-cases)
@@ -1070,6 +1071,28 @@ As you can see, this hook has the same behavior of `result.on_failure(:exception
1070
1071
 
1071
1072
  [⬆️ Back to Top](#table-of-contents-)
1072
1073
 
1074
+ #### Opting out of the safe mechanism
1075
+
1076
+ The "safe" mechanism is opinionated: it converts any unhandled exception inside a use case (or any step of a flow) into a failure result with `type: :exception`. That is powerful, but it can also produce a **fragmented codebase**, where some exceptions are handled with `rescue` inside `call!` and others are handled later via `on_exception` / `on_failure(:exception)` — making the control flow hard to reason about.
1077
+
1078
+ If you prefer a single, explicit convention for exception handling — namely, plain `rescue` statements inside your use cases — you can disable the safe APIs entirely:
1079
+
1080
+ ```ruby
1081
+ Micro::Case.config do |config|
1082
+ config.disable_safe_features = true
1083
+ end
1084
+ ```
1085
+
1086
+ Once enabled, the following will raise `Micro::Case::Error::SafeFeaturesDisabled`, ensuring no one in the codebase can reintroduce the safe path by accident:
1087
+
1088
+ - Subclassing `Micro::Case::Safe`
1089
+ - Calling `Micro::Cases.safe_flow(...)`
1090
+ - Calling `Micro::Case::Result#on_exception`
1091
+
1092
+ See [`Micro::Case.config`](#microcaseconfig) for the full list of available toggles.
1093
+
1094
+ [⬆️ Back to Top](#table-of-contents-)
1095
+
1073
1096
  ### Validating attributes with `accept:` / `reject:`
1074
1097
 
1075
1098
  Since `u-case 5.2.0`, every use case includes the [`accept` extension](https://github.com/serradura/u-attributes#accept-extension) from [`u-attributes`](https://github.com/serradura/u-attributes) (requires `u-attributes >= 2.8`). You can declare type expectations (or any other check) directly on the attribute, and the use case will fail automatically with the `:invalid_attributes` type when any attribute is rejected — no need to validate inside `call!`.
@@ -1225,6 +1248,14 @@ Micro::Case.config do |config|
1225
1248
 
1226
1249
  # Use to enable/disable the `Micro::Case::Results#transitions`.
1227
1250
  config.enable_transitions = true
1251
+
1252
+ # Use to forbid the "safe" features and ensure a single way to handle exceptions
1253
+ # (via standard `rescue` statements). When set to `true`, the following will raise
1254
+ # `Micro::Case::Error::SafeFeaturesDisabled`:
1255
+ # - Subclassing `Micro::Case::Safe`
1256
+ # - Calling `Micro::Cases.safe_flow(...)`
1257
+ # - Calling `Micro::Case::Result#on_exception`
1258
+ config.disable_safe_features = false
1228
1259
  end
1229
1260
  ```
1230
1261
 
data/README.pt-BR.md CHANGED
@@ -58,6 +58,7 @@ unreleased| https://github.com/serradura/u-case/blob/main/README.md
58
58
  - [`Micro::Case::Safe` - Existe algum recurso para lidar automaticamente com exceções dentro de um caso de uso ou fluxo?](#microcasesafe---existe-algum-recurso-para-lidar-automaticamente-com-exceções-dentro-de-um-caso-de-uso-ou-fluxo)
59
59
  - [`Micro::Cases::Safe::Flow`](#microcasessafeflow)
60
60
  - [`Micro::Case::Result#on_exception`](#microcaseresulton_exception)
61
+ - [Desabilitando o mecanismo "safe"](#desabilitando-o-mecanismo-safe)
61
62
  - [Validando atributos com `accept:` / `reject:`](#validando-atributos-com-accept--reject)
62
63
  - [`u-case/with_activemodel_validation` - Como validar os atributos do caso de uso?](#u-casewith_activemodel_validation---como-validar-os-atributos-do-caso-de-uso)
63
64
  - [Se eu habilitei a validação automática, é possível desabilitá-la apenas em casos de uso específicos?](#se-eu-habilitei-a-validação-automática-é-possível-desabilitá-la-apenas-em-casos-de-uso-específicos)
@@ -1071,6 +1072,28 @@ Como você pode ver, este hook tem o mesmo comportamento de `result.on_failure(:
1071
1072
 
1072
1073
  [⬆️ Voltar para o índice](#índice-)
1073
1074
 
1075
+ #### Desabilitando o mecanismo "safe"
1076
+
1077
+ O mecanismo "safe" é opinativo: ele converte qualquer exceção não tratada dentro de um caso de uso (ou em qualquer passo de um fluxo) em um resultado de falha com `type: :exception`. Isso é poderoso, mas também pode gerar uma **base de código fragmentada**, onde algumas exceções são tratadas com `rescue` dentro do `call!` e outras só são tratadas mais tarde via `on_exception` / `on_failure(:exception)` — tornando o fluxo de controle difícil de acompanhar.
1078
+
1079
+ Se você prefere uma única convenção explícita para o tratamento de exceções — `rescue` padrão dentro dos seus casos de uso — é possível desabilitar as APIs "safe" por completo:
1080
+
1081
+ ```ruby
1082
+ Micro::Case.config do |config|
1083
+ config.disable_safe_features = true
1084
+ end
1085
+ ```
1086
+
1087
+ Com isso ativo, os usos abaixo levantarão `Micro::Case::Error::SafeFeaturesDisabled`, garantindo que ninguém na base de código reintroduza o caminho "safe" sem querer:
1088
+
1089
+ - Herdar de `Micro::Case::Safe`
1090
+ - Chamar `Micro::Cases.safe_flow(...)`
1091
+ - Chamar `Micro::Case::Result#on_exception`
1092
+
1093
+ Veja [`Micro::Case.config`](#microcaseconfig) para a lista completa de configurações disponíveis.
1094
+
1095
+ [⬆️ Voltar para o índice](#índice-)
1096
+
1074
1097
  ### Validando atributos com `accept:` / `reject:`
1075
1098
 
1076
1099
  Desde a versão `5.2.0` do `u-case`, todo caso de uso já inclui a [extensão `accept`](https://github.com/serradura/u-attributes#accept-extension) do [`u-attributes`](https://github.com/serradura/u-attributes) (requer `u-attributes >= 2.8`). Você pode declarar a expectativa de tipo (ou qualquer outra verificação) diretamente no atributo, e o caso de uso falhará automaticamente com o tipo `:invalid_attributes` quando algum atributo for rejeitado — sem precisar validar dentro do `call!`.
@@ -1226,6 +1249,14 @@ Micro::Case.config do |config|
1226
1249
 
1227
1250
  # Use para habilitar/desabilitar o `Micro::Case::Results#transitions`.
1228
1251
  config.enable_transitions = true
1252
+
1253
+ # Use para proibir as funcionalidades "safe" e garantir uma única forma de tratar
1254
+ # exceções (via `rescue` padrão). Quando `true`, os itens abaixo levantarão
1255
+ # `Micro::Case::Error::SafeFeaturesDisabled`:
1256
+ # - Herdar de `Micro::Case::Safe`
1257
+ # - Chamar `Micro::Cases.safe_flow(...)`
1258
+ # - Chamar `Micro::Case::Result#on_exception`
1259
+ config.disable_safe_features = false
1229
1260
  end
1230
1261
  ```
1231
1262
 
@@ -13,6 +13,16 @@ module Micro
13
13
  )
14
14
  end
15
15
 
16
+ def disable_safe_features=(value)
17
+ @disable_safe_features = Kind::Boolean[value]
18
+ end
19
+
20
+ def disable_safe_features
21
+ return @disable_safe_features if defined?(@disable_safe_features)
22
+
23
+ @disable_safe_features = false
24
+ end
25
+
16
26
  def enable_activemodel_validation=(value)
17
27
  return unless Kind::Boolean[value]
18
28
 
@@ -51,6 +51,15 @@ module Micro
51
51
  end
52
52
  end
53
53
 
54
+ class SafeFeaturesDisabled < StandardError
55
+ def initialize(context)
56
+ super(
57
+ "#{context} can't be used because the safe features are disabled. " \
58
+ "To re-enable them, set `config.disable_safe_features = false`."
59
+ )
60
+ end
61
+ end
62
+
54
63
  def self.by_wrong_usage?(exception)
55
64
  case exception
56
65
  when Kind::Error, ArgumentError, InvalidResult, UnexpectedResult then true
@@ -121,6 +121,10 @@ module Micro
121
121
  end
122
122
 
123
123
  def on_exception(expected_exception = nil)
124
+ if Config.instance.disable_safe_features
125
+ raise Error::SafeFeaturesDisabled.new('Micro::Case::Result#on_exception')
126
+ end
127
+
124
128
  return self unless __failure_type?(:exception)
125
129
 
126
130
  if !expected_exception || (Kind.is?(Exception, expected_exception) && data.fetch(:exception).is_a?(expected_exception))
@@ -3,6 +3,14 @@
3
3
  module Micro
4
4
  class Case
5
5
  class Safe < ::Micro::Case
6
+ def self.inherited(subclass)
7
+ if Config.instance.disable_safe_features
8
+ raise Error::SafeFeaturesDisabled.new('Micro::Case::Safe')
9
+ end
10
+
11
+ super
12
+ end
13
+
6
14
  def self.__flow_builder__
7
15
  Cases::Safe::Flow
8
16
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Micro
4
4
  class Case
5
- VERSION = '5.2.1'.freeze
5
+ VERSION = '5.3.0'.freeze
6
6
  end
7
7
  end
data/lib/micro/case.rb CHANGED
@@ -11,9 +11,9 @@ module Micro
11
11
  require 'micro/case/utils'
12
12
  require 'micro/case/error'
13
13
  require 'micro/case/result'
14
+ require 'micro/case/config'
14
15
  require 'micro/case/safe'
15
16
  require 'micro/case/strict'
16
- require 'micro/case/config'
17
17
 
18
18
  require 'micro/cases'
19
19
 
data/lib/micro/cases.rb CHANGED
@@ -13,6 +13,10 @@ module Micro
13
13
  end
14
14
 
15
15
  def self.safe_flow(args)
16
+ if Case::Config.instance.disable_safe_features
17
+ raise Case::Error::SafeFeaturesDisabled.new('Micro::Cases.safe_flow')
18
+ end
19
+
16
20
  Safe::Flow.build(args)
17
21
  end
18
22
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: u-case
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.1
4
+ version: 5.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura