u-case 5.0.0 → 5.2.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: d654bd6a59c3920ef02a3fa0c2b82fb32ff5f695cfe1f4d4565a84c53bf1d86c
4
- data.tar.gz: e42a81c72ad2f49d01f2464e220e72bd201ca0adce6be06f14defa4ee84f67fe
3
+ metadata.gz: 2c0d84e916ac431f822d767a3485ce0a6ec9db47bba8b9b6cbc914ec72ec18da
4
+ data.tar.gz: b272186504907f0f2e88fe3fd19c241a7135bfa191a621a55ae912c95f680b57
5
5
  SHA512:
6
- metadata.gz: '090c4536a5205ed89e0cf2e76b163ca127455f90df793980bd33cdc28efecabd35736e543dc2f003954b8131367672dea79319382412dd7ce6ae25121847eab6'
7
- data.tar.gz: 0a9f2345b82957003238137fcd5a4ca081205f3b83c1f8f092d92f153ef3b57dd7d726abef600cdd1b76b7e6983b222931d8903edf984573cf8dd4696851a7cd
6
+ metadata.gz: ee96e3cc845c753481a94e394b496b8a923c0a15d220713c610dbb77046d4f79f434291f31cc5b8e88fa16d55dba12db11953d1553b0a8aa284277aa4558512a
7
+ data.tar.gz: 4edb2ce9cb98319bab947ebfb9166518eaeca467d68198e5b3ac4a258ac907b16e1eb8c44ffd991140dddf863e4a821a146c29ef007139ad8c2e666732630fce
data/Gemfile CHANGED
@@ -9,6 +9,8 @@ gem "rake", "~> 13.0"
9
9
 
10
10
  group :test do
11
11
  gem "simplecov", "~> 0.22.0", require: false
12
+ gem "minitest", (RUBY_VERSION >= "4.0") ? "~> 6.0" : "~> 5.27" if RUBY_VERSION >= "3.1"
13
+ gem "ostruct", "~> 0.6.3" if RUBY_VERSION >= "3.5"
12
14
  end
13
15
 
14
16
  group :development, :test do
data/README.md CHANGED
@@ -27,7 +27,7 @@ The main project goals are:
27
27
  Version | Documentation
28
28
  --------- | -------------
29
29
  unreleased| https://github.com/serradura/u-case/blob/main/README.md
30
- 5.0.0 | https://github.com/serradura/u-case/blob/v5.x/README.md
30
+ 5.2.0 | https://github.com/serradura/u-case/blob/v5.x/README.md
31
31
  4.5.1 | https://github.com/serradura/u-case/blob/v4.x/README.md
32
32
 
33
33
  > **Note:** Você entende português? 🇧🇷 🇵🇹 Verifique o [README traduzido em pt-BR](https://github.com/serradura/u-case/blob/main/README.pt-BR.md).
@@ -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
+ - [Validating attributes with `accept:` / `reject:`](#validating-attributes-with-accept--reject)
63
64
  - [`u-case/with_activemodel_validation` - How to validate the use case attributes?](#u-casewith_activemodel_validation---how-to-validate-the-use-case-attributes)
64
65
  - [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)
65
66
  - [`Kind::Validator`](#kindvalidator)
@@ -87,8 +88,9 @@ unreleased| https://github.com/serradura/u-case/blob/main/README.md
87
88
 
88
89
  | u-case | branch | ruby | activemodel | u-attributes |
89
90
  | ---------------- | ------ | -------- | -------------- | -------------- |
90
- | unreleased | main | >= 2.7 | >= 6.0 | >= 2.7, < 4.0 |
91
- | 5.0.0 | v5.x | >= 2.7 | >= 6.0 | >= 2.7, < 4.0 |
91
+ | unreleased | main | >= 2.7 | >= 6.0 | >= 2.8, < 4.0 |
92
+ | 5.2.0 | v5.x | >= 2.7 | >= 6.0 | >= 2.8, < 4.0 |
93
+ | 5.1.0 | v5.x | >= 2.7 | >= 6.0 | >= 2.7, < 4.0 |
92
94
  | 4.5.1 | v4.x | >= 2.2.0 | >= 3.2, <= 8.1 | >= 2.7, < 3.0 |
93
95
 
94
96
  This library is tested (CI matrix) against:
@@ -189,6 +191,8 @@ A `Micro::Case::Result` stores the use cases output data. These are their main m
189
191
  - `#type` a Symbol which gives meaning for the result, this is useful to declare different types of failures or success.
190
192
  - `#data` the result data itself.
191
193
  - `#[]` and `#values_at` are shortcuts to access the `#data` values.
194
+ - `#fetch` and `#fetch_values` are another way of accessing values of the result data, but raises a `KeyError` if the one of the keys are not present in the result.
195
+ - `#keys` returns an array of keys present in the result data.
192
196
  - `#key?` returns `true` if the key is present in `#data`.
193
197
  - `#value?` returns `true` if the given value is present in `#data`.
194
198
  - `#slice` returns a new hash that includes only the given keys. If the given keys don't exist, an empty hash is returned.
@@ -1066,6 +1070,43 @@ As you can see, this hook has the same behavior of `result.on_failure(:exception
1066
1070
 
1067
1071
  [⬆️ Back to Top](#table-of-contents-)
1068
1072
 
1073
+ ### Validating attributes with `accept:` / `reject:`
1074
+
1075
+ 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!`.
1076
+
1077
+ ```ruby
1078
+ class CreateUser < Micro::Case
1079
+ attribute :name, accept: String
1080
+ attribute :email, accept: ->(value) { value.is_a?(String) && value.include?('@') }
1081
+ attribute :age, accept: Integer, allow_nil: true
1082
+
1083
+ def call!
1084
+ Success result: { user: User.create!(attributes) }
1085
+ end
1086
+ end
1087
+
1088
+ CreateUser.call(name: 'Bob', email: 'bob@example.com')
1089
+ # => #<Success type=:ok ...>
1090
+
1091
+ CreateUser.call(name: 42, email: 'not-an-email')
1092
+ # => #<Failure type=:invalid_attributes data={
1093
+ # errors: {
1094
+ # "name" => "expected to be a kind of String",
1095
+ # "email" => "is invalid"
1096
+ # }
1097
+ # }>
1098
+ ```
1099
+
1100
+ The failure type follows the same setting used by the ActiveModel validation integration — see [`Micro::Case.config`](#microcaseconfig) and `set_activemodel_validation_errors_failure`.
1101
+
1102
+ When combined with [`u-case/with_activemodel_validation`](#u-casewith_activemodel_validation---how-to-validate-the-use-case-attributes), the execution order is:
1103
+
1104
+ 1. `u-attributes` resolves the default value of each attribute.
1105
+ 2. `u-attributes` runs the `accept:` / `reject:` checks.
1106
+ 3. `u-case` runs the `ActiveModel` validations **only if** every attribute was accepted.
1107
+
1108
+ [⬆️ Back to Top](#table-of-contents-)
1109
+
1069
1110
  ### `u-case/with_activemodel_validation` - How to validate the use case attributes?
1070
1111
 
1071
1112
  **Requirement:**
data/README.pt-BR.md CHANGED
@@ -27,7 +27,7 @@ Principais objetivos deste projeto:
27
27
  Versão | Documentação
28
28
  --------- | -------------
29
29
  unreleased| https://github.com/serradura/u-case/blob/main/README.md
30
- 5.0.0 | https://github.com/serradura/u-case/blob/v5.x/README.md
30
+ 5.2.0 | https://github.com/serradura/u-case/blob/v5.x/README.md
31
31
  4.5.1 | https://github.com/serradura/u-case/blob/v4.x/README.md
32
32
 
33
33
  ## Índice <!-- omit in toc -->
@@ -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
+ - [Validando atributos com `accept:` / `reject:`](#validando-atributos-com-accept--reject)
61
62
  - [`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)
62
63
  - [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)
63
64
  - [`Kind::Validator`](#kindvalidator)
@@ -85,8 +86,9 @@ unreleased| https://github.com/serradura/u-case/blob/main/README.md
85
86
 
86
87
  | u-case | branch | ruby | activemodel | u-attributes |
87
88
  | ---------------- | ------ | -------- | -------------- | -------------- |
88
- | unreleased | main | >= 2.7 | >= 6.0 | >= 2.7, < 4.0 |
89
- | 5.0.0 | v5.x | >= 2.7 | >= 6.0 | >= 2.7, < 4.0 |
89
+ | unreleased | main | >= 2.7 | >= 6.0 | >= 2.8, < 4.0 |
90
+ | 5.2.0 | v5.x | >= 2.7 | >= 6.0 | >= 2.8, < 4.0 |
91
+ | 5.1.0 | v5.x | >= 2.7 | >= 6.0 | >= 2.7, < 4.0 |
90
92
  | 4.5.1 | v4.x | >= 2.2.0 | >= 3.2, <= 8.1 | >= 2.7, < 3.0 |
91
93
 
92
94
  Esta biblioteca é testada (matriz de CI) contra:
@@ -187,8 +189,10 @@ Um `Micro::Case::Result` armazena os dados de output de um caso de uso. Esses s
187
189
  - `#type` retorna um Symbol que dá significado ao resultado, isso é útil para declarar diferentes tipos de falha e sucesso.
188
190
  - `#data` os dados do resultado (um `Hash`).
189
191
  - `#[]` e `#values_at` são atalhos para acessar as propriedades do `#data`.
190
- - `#key?` retorna `true` se a chave estiver present no `#data`.
191
- - `#value?` retorna `true` se o valor estiver present no `#data`.
192
+ - `#fetch` e `#fetch_values` são outras maneiras de acessar os valores contidos em `#data`, porém se alguma chave não existir, é levantado um `KeyError`.
193
+ - `#keys` retorna uma array com as chaves presentes no resultado.
194
+ - `#key?` retorna `true` se a chave estiver presente no `#data`.
195
+ - `#value?` retorna `true` se o valor estiver presente no `#data`.
192
196
  - `#slice` retorna um novo `Hash` que inclui apenas as chaves fornecidas. Se as chaves fornecidas não existirem, um `Hash` vazio será retornado.
193
197
  - `#on_success` or `#on_failure` são métodos de hooks que te auxiliam a definir o fluxo da aplicação.
194
198
  - `#then` este método permite aplicar novos casos de uso ao resultado atual se ele for sucesso. A ideia dessa feature é a criação de fluxos dinâmicos.
@@ -1067,6 +1071,43 @@ Como você pode ver, este hook tem o mesmo comportamento de `result.on_failure(:
1067
1071
 
1068
1072
  [⬆️ Voltar para o índice](#índice-)
1069
1073
 
1074
+ ### Validando atributos com `accept:` / `reject:`
1075
+
1076
+ 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!`.
1077
+
1078
+ ```ruby
1079
+ class CreateUser < Micro::Case
1080
+ attribute :name, accept: String
1081
+ attribute :email, accept: ->(value) { value.is_a?(String) && value.include?('@') }
1082
+ attribute :age, accept: Integer, allow_nil: true
1083
+
1084
+ def call!
1085
+ Success result: { user: User.create!(attributes) }
1086
+ end
1087
+ end
1088
+
1089
+ CreateUser.call(name: 'Bob', email: 'bob@example.com')
1090
+ # => #<Success type=:ok ...>
1091
+
1092
+ CreateUser.call(name: 42, email: 'not-an-email')
1093
+ # => #<Failure type=:invalid_attributes data={
1094
+ # errors: {
1095
+ # "name" => "expected to be a kind of String",
1096
+ # "email" => "is invalid"
1097
+ # }
1098
+ # }>
1099
+ ```
1100
+
1101
+ O tipo da falha segue a mesma configuração usada pela integração com `ActiveModel` — veja [`Micro::Case.config`](#microcaseconfig) e `set_activemodel_validation_errors_failure`.
1102
+
1103
+ Quando combinado com [`u-case/with_activemodel_validation`](#u-casewith_activemodel_validation---como-validar-os-atributos-do-caso-de-uso), a ordem de execução é:
1104
+
1105
+ 1. O `u-attributes` resolve o valor padrão de cada atributo.
1106
+ 2. O `u-attributes` executa as verificações de `accept:` / `reject:`.
1107
+ 3. O `u-case` executa as validações do `ActiveModel` **apenas se** todos os atributos forem aceitos.
1108
+
1109
+ [⬆️ Voltar para o índice](#índice-)
1110
+
1070
1111
  ### `u-case/with_activemodel_validation` - Como validar os atributos do caso de uso?
1071
1112
 
1072
1113
  **Requisitos:**
@@ -62,6 +62,18 @@ module Micro
62
62
  data.key?(key)
63
63
  end
64
64
 
65
+ def keys
66
+ data.keys
67
+ end
68
+
69
+ def fetch(*args, &block)
70
+ data.fetch(*args, &block)
71
+ end
72
+
73
+ def fetch_values(*keys, &block)
74
+ Utils::Hashes.fetch_values(data, keys, &block)
75
+ end
76
+
65
77
  def value?(value)
66
78
  data.value?(value)
67
79
  end
@@ -27,6 +27,14 @@ module Micro::Case::Utils
27
27
 
28
28
  hash.select { |key, _value| keys.include?(key) }
29
29
  end
30
+
31
+ def self.fetch_values(hash, keys, &block)
32
+ return hash.fetch_values(*keys, &block) if hash_respond_to?(hash, :fetch_values)
33
+
34
+ keys.each_with_object([]) do |key, values|
35
+ values << hash.fetch(key, &block)
36
+ end
37
+ end
30
38
  end
31
39
 
32
40
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Micro
4
4
  class Case
5
- VERSION = '5.0.0'.freeze
5
+ VERSION = '5.2.0'.freeze
6
6
  end
7
7
  end
@@ -19,7 +19,10 @@ module Micro
19
19
  private
20
20
 
21
21
  def __call_use_case
22
- return failure_by_validation_error(self) if !self.class.auto_validation_disabled? && errors.present?
22
+ unless self.class.auto_validation_disabled?
23
+ return failure_by_validation_error(self) if errors.present?
24
+ return __failure_from_attributes_errors if __attributes_errors_present?
25
+ end
23
26
 
24
27
  result = call!
25
28
 
data/lib/micro/case.rb CHANGED
@@ -18,6 +18,7 @@ module Micro
18
18
  require 'micro/cases'
19
19
 
20
20
  include Micro::Attributes
21
+ include Micro::Attributes::Features::Accept
21
22
 
22
23
  def self.call(input = Kind::Empty::HASH)
23
24
  result = __new__(Result.new, input).__call__
@@ -206,6 +207,8 @@ module Micro
206
207
  end
207
208
 
208
209
  def __call_use_case
210
+ return __failure_from_attributes_errors if __attributes_errors_present?
211
+
209
212
  result = call!
210
213
 
211
214
  return result if result.is_a?(Result)
@@ -213,6 +216,17 @@ module Micro
213
216
  raise Error::UnexpectedResult.new("#{self.class.name}#call!")
214
217
  end
215
218
 
219
+ def __attributes_errors_present?
220
+ attributes_errors?
221
+ end
222
+
223
+ def __failure_from_attributes_errors
224
+ Failure(
225
+ Config.instance.activemodel_validation_errors_failure,
226
+ result: { errors: attributes_errors }
227
+ )
228
+ end
229
+
216
230
  def __call_the_use_case_flow?
217
231
  self.class.__flow_get__
218
232
  end
data/u-case.gemspec CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.required_ruby_version = '>= 2.7.0'
27
27
 
28
28
  spec.add_runtime_dependency 'kind', '>= 5.6', '< 7.0'
29
- spec.add_runtime_dependency 'u-attributes', '>= 2.7', '< 4.0'
29
+ spec.add_runtime_dependency 'u-attributes', '>= 2.8', '< 4.0'
30
30
 
31
31
  spec.add_development_dependency 'appraisal', '~> 2.5'
32
32
  spec.add_development_dependency 'bundler'
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.0.0
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura
@@ -35,7 +35,7 @@ dependencies:
35
35
  requirements:
36
36
  - - ">="
37
37
  - !ruby/object:Gem::Version
38
- version: '2.7'
38
+ version: '2.8'
39
39
  - - "<"
40
40
  - !ruby/object:Gem::Version
41
41
  version: '4.0'
@@ -45,7 +45,7 @@ dependencies:
45
45
  requirements:
46
46
  - - ">="
47
47
  - !ruby/object:Gem::Version
48
- version: '2.7'
48
+ version: '2.8'
49
49
  - - "<"
50
50
  - !ruby/object:Gem::Version
51
51
  version: '4.0'