u-case 3.0.0 → 4.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.
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro
4
+ class Case
5
+ class Result
6
+ class Wrapper
7
+ def initialize(result)
8
+ @__is_unknown = true
9
+
10
+ @result = result
11
+ end
12
+
13
+ def failure(type = nil)
14
+ return if @result.success?
15
+
16
+ if result_type?(type)
17
+ @__is_unknown = false
18
+
19
+ yield(@result)
20
+ end
21
+ end
22
+
23
+ def success(type = nil)
24
+ return if @result.failure?
25
+
26
+ if result_type?(type)
27
+ @__is_unknown = false
28
+
29
+ yield(@result)
30
+ end
31
+ end
32
+
33
+ def unknown
34
+ return yield(@result) if @__is_unknown
35
+ end
36
+
37
+ private
38
+
39
+ def result_type?(type)
40
+ type.nil? || @result.type == type
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -3,12 +3,12 @@
3
3
  module Micro
4
4
  class Case
5
5
  class Safe < ::Micro::Case
6
- def self.__flow_builder
6
+ def self.__flow_builder__
7
7
  Cases::Safe::Flow
8
8
  end
9
9
 
10
10
  def __call__
11
- call
11
+ __call_the_use_case_or_its_flow
12
12
  rescue => exception
13
13
  raise exception if Error.by_wrong_usage?(exception)
14
14
 
@@ -3,10 +3,10 @@
3
3
  module Micro
4
4
  class Case
5
5
  class Strict < ::Micro::Case
6
- include Micro::Attributes::Features::StrictInitialize
6
+ include Micro::Attributes::Features::Initialize::Strict
7
7
 
8
8
  class Safe < ::Micro::Case::Safe
9
- include Micro::Attributes::Features::StrictInitialize
9
+ include Micro::Attributes::Features::Initialize::Strict
10
10
  end
11
11
  end
12
12
  end
@@ -3,24 +3,34 @@
3
3
  module Micro
4
4
  class Case
5
5
  module Utils
6
- def self.symbolize_hash_keys(hash)
7
- if Kind::Of::Hash(hash).respond_to?(:transform_keys)
8
- hash.transform_keys { |key| key.to_sym rescue key }
9
- else
6
+
7
+ module Hashes
8
+ def self.respond_to?(hash, method)
9
+ Kind.of(Hash, hash).respond_to?(method)
10
+ end
11
+
12
+ def self.symbolize_keys(hash)
13
+ return hash.transform_keys { |key| key.to_sym rescue key } if respond_to?(hash, :transform_keys)
14
+
10
15
  hash.each_with_object({}) do |(k, v), memo|
11
16
  key = k.to_sym rescue k
12
-
13
17
  memo[key] = v
14
18
  end
15
19
  end
16
- end
17
- def self.slice_hash(hash, keys)
18
- if Kind::Of::Hash(hash).respond_to?(:slice)
19
- hash.slice(*keys)
20
- else
20
+
21
+ def self.stringify_keys(hash)
22
+ return hash.transform_keys(&:to_s) if respond_to?(hash, :transform_keys)
23
+
24
+ hash.each_with_object({}) { |(k, v), memo| memo[k.to_s] = v }
25
+ end
26
+
27
+ def self.slice(hash, keys)
28
+ return hash.slice(*keys) if respond_to?(hash, :slice)
29
+
21
30
  hash.select { |key, _value| keys.include?(key) }
22
31
  end
23
32
  end
33
+
24
34
  end
25
35
  end
26
36
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Micro
4
4
  class Case
5
- VERSION = '3.0.0'.freeze
5
+ VERSION = '4.2.0'.freeze
6
6
  end
7
7
  end
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'micro/cases/utils'
4
+ require 'micro/cases/error'
3
5
  require 'micro/cases/flow'
4
6
  require 'micro/cases/safe/flow'
7
+ require 'micro/cases/map'
5
8
 
6
9
  module Micro
7
10
  module Cases
@@ -12,5 +15,9 @@ module Micro
12
15
  def self.safe_flow(args)
13
16
  Safe::Flow.build(args)
14
17
  end
18
+
19
+ def self.map(args)
20
+ Map.build(args)
21
+ end
15
22
  end
16
23
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro
4
+ module Cases
5
+
6
+ module Error
7
+ class InvalidUseCases < ArgumentError
8
+ def initialize; super('argument must be a collection of `Micro::Case` classes'.freeze); end
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -3,20 +3,15 @@
3
3
  module Micro
4
4
  module Cases
5
5
  class Flow
6
- class InvalidUseCases < ArgumentError
7
- def initialize; super('argument must be a collection of `Micro::Case` classes'.freeze); end
8
- end
6
+ IsAUseCaseWithDefaults = -> arg { arg.is_a?(Array) && Micro.case?(arg[0]) && arg[1].is_a?(Hash) }
7
+ IsAValidUseCase = -> use_case { Micro.case?(use_case) || IsAUseCaseWithDefaults[use_case] }
9
8
 
10
9
  attr_reader :use_cases
11
10
 
12
- def self.map_use_cases(arg)
13
- arg.is_a?(Flow) ? arg.use_cases : Array(arg)
14
- end
15
-
16
11
  def self.build(args)
17
- use_cases = Array(args).flat_map { |arg| map_use_cases(arg) }
12
+ use_cases = Utils.map_use_cases(args)
18
13
 
19
- raise InvalidUseCases if use_cases.any? { |klass| !(klass < ::Micro::Case) }
14
+ raise Error::InvalidUseCases if use_cases.none?(&IsAValidUseCase)
20
15
 
21
16
  new(use_cases)
22
17
  end
@@ -27,8 +22,12 @@ module Micro
27
22
  @first = @next_ones.shift
28
23
  end
29
24
 
25
+ def inspect
26
+ '<(%s) use_cases=%s>' % [self.class, @use_cases]
27
+ end
28
+
30
29
  def call!(input:, result:)
31
- first_result = __case_use_case(@first, result, input)
30
+ first_result = __call_use_case(@first, result, input)
32
31
 
33
32
  return first_result if @next_ones.empty?
34
33
 
@@ -36,7 +35,11 @@ module Micro
36
35
  end
37
36
 
38
37
  def call(input = Kind::Empty::HASH)
39
- call!(input: input, result: Case::Result.new)
38
+ result = call!(input: input, result: Case::Result.new)
39
+
40
+ return result unless block_given?
41
+
42
+ yield ::Micro::Case::Result::Wrapper.new(result)
40
43
  end
41
44
 
42
45
  alias __call__ call
@@ -49,30 +52,42 @@ module Micro
49
52
  can_yield_self = respond_to?(:yield_self)
50
53
 
51
54
  if block
52
- raise Error::InvalidInvocationOfTheThenMethod.new(self.class.name) if use_case
55
+ raise_invalid_invocation_of_the_then_method if use_case
53
56
  raise NotImplementedError if !can_yield_self
54
57
 
55
58
  yield_self(&block)
56
59
  else
57
60
  return yield_self if !use_case && can_yield_self
58
61
 
62
+ raise_invalid_invocation_of_the_then_method unless ::Micro.case_or_flow?(use_case)
63
+
59
64
  self.call.then(use_case)
60
65
  end
61
66
  end
62
67
 
63
68
  private
64
69
 
65
- def __case_use_case(use_case, result, input)
66
- use_case.__new__(result, input).__call__
70
+ def raise_invalid_invocation_of_the_then_method
71
+ raise Case::Error::InvalidInvocationOfTheThenMethod.new("#{self.class.name}#")
72
+ end
73
+
74
+ def __call_use_case(use_case, result, input)
75
+ __build_use_case(use_case, result, input).__call__
67
76
  end
68
77
 
69
78
  def __call_next_use_cases(first_result)
70
79
  @next_ones.reduce(first_result) do |result, use_case|
71
80
  break result if result.failure?
72
81
 
73
- __case_use_case(use_case, result, result.data)
82
+ __call_use_case(use_case, result, result.data)
74
83
  end
75
84
  end
85
+
86
+ def __build_use_case(use_case, result, input)
87
+ return use_case.__new__(result, input) unless use_case.is_a?(Array)
88
+
89
+ use_case[0].__new__(result, input.merge(use_case[1]))
90
+ end
76
91
  end
77
92
  end
78
93
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro
4
+ module Cases
5
+ class Map
6
+ IsAUseCaseOrFlowWithDefaults = -> arg { arg.is_a?(Array) && Micro.case_or_flow?(arg[0]) && arg[1].is_a?(Hash) }
7
+ IsAUseCaseOrFlow = -> arg { Micro.case_or_flow?(arg) || IsAUseCaseOrFlowWithDefaults[arg] }
8
+ HasValidArgs = -> (args) { Kind.of(Array, args).all?(&IsAUseCaseOrFlow) }
9
+
10
+ attr_reader :use_cases
11
+
12
+ def self.build(args)
13
+ raise Error::InvalidUseCases unless HasValidArgs[args]
14
+
15
+ new(args)
16
+ end
17
+
18
+ def initialize(use_cases)
19
+ @use_cases = use_cases
20
+ end
21
+
22
+ GetUseCaseResult = -> (hash) do
23
+ -> (use_case) do
24
+ return use_case.call(hash) unless use_case.is_a?(Array)
25
+
26
+ use_case[0].call(hash.merge(use_case[1]))
27
+ end
28
+ end
29
+
30
+ def call(arg = {})
31
+ hash = Kind.of(Hash, arg)
32
+
33
+ use_cases.map(&GetUseCaseResult[hash])
34
+ end
35
+
36
+ private_constant :HasValidArgs, :IsAUseCaseOrFlow, :IsAUseCaseOrFlowWithDefaults, :GetUseCaseResult
37
+ end
38
+ end
39
+ end
@@ -4,8 +4,8 @@ module Micro
4
4
  module Cases
5
5
  module Safe
6
6
  class Flow < Cases::Flow
7
- private def __case_use_case(use_case, result, input)
8
- instance = use_case.__new__(result, input)
7
+ private def __call_use_case(use_case, result, input)
8
+ instance = __build_use_case(use_case, result, input)
9
9
  instance.__call__
10
10
  rescue => exception
11
11
  raise exception if Case::Error.by_wrong_usage?(exception)
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro
4
+ module Cases
5
+
6
+ module Utils
7
+ def self.map_use_cases(args)
8
+ collection = args.is_a?(Array) && args.size == 1 ? args[0] : args
9
+
10
+ Array(collection).each_with_object([]) do |arg, memo|
11
+ if arg.is_a?(Flow)
12
+ arg.use_cases.each { |use_case| memo << use_case }
13
+ else
14
+ memo << arg
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ['Rodrigo Serradura']
10
10
  spec.email = ['rodrigo.serradura@gmail.com']
11
11
 
12
- spec.summary = %q{Create simple and powerful use cases as Ruby objects.}
13
- spec.description = %q{Create simple and powerful use cases as Ruby objects.}
12
+ spec.summary = %q{Represent use cases in a simple and powerful way while writing modular, expressive and sequentially logical code.}
13
+ spec.description = %q{Represent use cases in a simple and powerful way while writing modular, expressive and sequentially logical code.}
14
14
  spec.homepage = 'https://github.com/serradura/u-case'
15
15
  spec.license = 'MIT'
16
16
 
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.required_ruby_version = '>= 2.2.0'
27
27
 
28
28
  spec.add_runtime_dependency 'kind', '>= 3.0', '< 5.0'
29
- spec.add_runtime_dependency 'u-attributes', '~> 1.1'
29
+ spec.add_runtime_dependency 'u-attributes', '~> 2.0'
30
30
 
31
31
  spec.add_development_dependency 'bundler'
32
32
  spec.add_development_dependency 'rake', '~> 13.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: u-case
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-15 00:00:00.000000000 Z
11
+ date: 2020-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kind
@@ -36,14 +36,14 @@ dependencies:
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '1.1'
39
+ version: '2.0'
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '1.1'
46
+ version: '2.0'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: bundler
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -72,7 +72,8 @@ dependencies:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: '13.0'
75
- description: Create simple and powerful use cases as Ruby objects.
75
+ description: Represent use cases in a simple and powerful way while writing modular,
76
+ expressive and sequentially logical code.
76
77
  email:
77
78
  - rodrigo.serradura@gmail.com
78
79
  executables: []
@@ -95,14 +96,19 @@ files:
95
96
  - lib/micro/case/config.rb
96
97
  - lib/micro/case/error.rb
97
98
  - lib/micro/case/result.rb
99
+ - lib/micro/case/result/transitions.rb
100
+ - lib/micro/case/result/wrapper.rb
98
101
  - lib/micro/case/safe.rb
99
102
  - lib/micro/case/strict.rb
100
103
  - lib/micro/case/utils.rb
101
104
  - lib/micro/case/version.rb
102
105
  - lib/micro/case/with_activemodel_validation.rb
103
106
  - lib/micro/cases.rb
107
+ - lib/micro/cases/error.rb
104
108
  - lib/micro/cases/flow.rb
109
+ - lib/micro/cases/map.rb
105
110
  - lib/micro/cases/safe/flow.rb
111
+ - lib/micro/cases/utils.rb
106
112
  - lib/u-case.rb
107
113
  - lib/u-case/with_activemodel_validation.rb
108
114
  - test.sh
@@ -129,5 +135,6 @@ requirements: []
129
135
  rubygems_version: 3.0.6
130
136
  signing_key:
131
137
  specification_version: 4
132
- summary: Create simple and powerful use cases as Ruby objects.
138
+ summary: Represent use cases in a simple and powerful way while writing modular, expressive
139
+ and sequentially logical code.
133
140
  test_files: []