u-case 2.3.0 → 3.0.0.rc1

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.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Micro
4
4
  class Case
5
- VERSION = '2.3.0'.freeze
5
+ VERSION = '3.0.0.rc1'.freeze
6
6
  end
7
7
  end
@@ -7,7 +7,7 @@ module Micro
7
7
  include Micro::Attributes::Features::ActiveModelValidations
8
8
 
9
9
  def self.auto_validation_disabled?
10
- @disable_auto_validation
10
+ return @disable_auto_validation if defined?(@disable_auto_validation)
11
11
  end
12
12
 
13
13
  def self.disable_auto_validation
@@ -22,18 +22,20 @@ module Micro
22
22
 
23
23
  private
24
24
 
25
- def __call
26
- return __call_use_case_flow if __call_use_case_flow?
27
-
25
+ def __call_use_case
28
26
  return failure_by_validation_error(self) if !self.class.auto_validation_disabled? && invalid?
29
27
 
30
- __call_use_case
28
+ result = call!
29
+
30
+ return result if result.is_a?(Result)
31
+
32
+ raise Error::UnexpectedResult.new(self.class)
31
33
  end
32
34
 
33
35
  def failure_by_validation_error(object)
34
36
  errors = object.respond_to?(:errors) ? object.errors : object
35
37
 
36
- Failure(:validation_error) { { errors: errors } }
38
+ Failure :validation_error, result: { errors: errors }
37
39
  end
38
40
  end
39
41
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'micro/cases/flow'
4
+ require 'micro/cases/safe/flow'
5
+
6
+ module Micro
7
+ module Cases
8
+ def self.flow(args)
9
+ Flow.build(args)
10
+ end
11
+
12
+ def self.safe_flow(args)
13
+ Safe::Flow.build(args)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro
4
+ module Cases
5
+ class Flow
6
+ class InvalidUseCases < ArgumentError
7
+ def initialize; super('argument must be a collection of `Micro::Case` classes'.freeze); end
8
+ end
9
+
10
+ attr_reader :use_cases
11
+
12
+ def self.map_use_cases(arg)
13
+ return arg.use_cases if arg.is_a?(Flow)
14
+
15
+ Array(arg)
16
+ end
17
+
18
+ def self.build(args)
19
+ use_cases = Array(args).flat_map { |arg| map_use_cases(arg) }
20
+
21
+ raise InvalidUseCases if use_cases.any? { |klass| !(klass < ::Micro::Case) }
22
+
23
+ new(use_cases)
24
+ end
25
+
26
+ def initialize(use_cases)
27
+ @use_cases = use_cases
28
+ @first_use_case = use_cases[0]
29
+ @next_use_cases = use_cases[1..-1]
30
+ end
31
+
32
+ def call(arg = {})
33
+ memo = arg.is_a?(Hash) ? arg.dup : {}
34
+
35
+ first_result = first_use_case_result(arg)
36
+
37
+ return first_result if @next_use_cases.empty?
38
+
39
+ next_use_cases_result(first_result, memo)
40
+ end
41
+
42
+ def to_proc
43
+ Proc.new { |arg| call(arg) }
44
+ end
45
+
46
+ private
47
+
48
+ def is_a_result?(arg)
49
+ arg.is_a?(Case::Result)
50
+ end
51
+
52
+ def arg_to_call?(arg)
53
+ return true if arg.is_a?(::Micro::Case) || arg.is_a?(Flow)
54
+ return true if arg.is_a?(Class) && arg < ::Micro::Case
55
+ return false
56
+ end
57
+
58
+ def call_arg(arg)
59
+ output = arg.call
60
+
61
+ is_a_result?(output) ? output.value : output
62
+ end
63
+
64
+ def first_use_case_input(arg)
65
+ return call_arg(arg) if arg_to_call?(arg)
66
+ return arg.value if is_a_result?(arg)
67
+
68
+ arg
69
+ end
70
+
71
+ def first_use_case_result(arg)
72
+ input = first_use_case_input(arg)
73
+
74
+ result = Case::Result.new
75
+
76
+ @first_use_case.__call_and_set_transition__(result, input)
77
+ end
78
+
79
+ def next_use_case_result(use_case, result, input)
80
+ use_case.__new__(result, input).call
81
+ end
82
+
83
+ def next_use_cases_result(first_result, memo)
84
+ @next_use_cases.reduce(first_result) do |result, use_case|
85
+ break result if result.failure?
86
+
87
+ memo.merge!(result.value)
88
+
89
+ result.__set_transitions_accessible_attributes__(memo)
90
+
91
+ next_use_case_result(use_case, result, memo)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro
4
+ module Cases
5
+ module Safe
6
+ class Flow < Cases::Flow
7
+ private def next_use_case_result(use_case, result, input)
8
+ instance = use_case.__new__(result, input)
9
+ instance.call
10
+ rescue => exception
11
+ raise exception if Case::Error.by_wrong_usage?(exception)
12
+
13
+ result.__set__(false, exception, :exception, instance)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kind/active_model/validation'
4
+
5
+ require 'micro/case/with_activemodel_validation'
@@ -1,3 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'micro/case/with_validation'
3
+ warn 'Deprecation: "u-case/with_validation" will be deprecated in the next major release.' \
4
+ 'Please use "u-case/with_activemodel_validation" instead of it.'
5
+
6
+ require 'u-case/with_activemodel_validation'
@@ -14,20 +14,8 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = 'https://github.com/serradura/u-case'
15
15
  spec.license = 'MIT'
16
16
 
17
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
- # to allow pushing to a single host or delete this section to allow pushing to any host.
19
- if spec.respond_to?(:metadata)
20
- # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
21
-
22
- # spec.metadata["homepage_uri"] = spec.homepage
23
- # spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
24
- # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
25
- else
26
- raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
27
- end
17
+ raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.' unless spec.respond_to?(:metadata)
28
18
 
29
- # Specify which files should be added to the gem when it is released.
30
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
31
19
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
32
20
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|assets|benchmarks|comparisons|examples)/}) }
33
21
  end
@@ -37,8 +25,9 @@ Gem::Specification.new do |spec|
37
25
 
38
26
  spec.required_ruby_version = '>= 2.2.0'
39
27
 
28
+ spec.add_runtime_dependency 'kind', '~> 3.0'
40
29
  spec.add_runtime_dependency 'u-attributes', '~> 1.1'
41
30
 
42
31
  spec.add_development_dependency 'bundler'
43
- spec.add_development_dependency 'rake', '~> 10.0'
32
+ spec.add_development_dependency 'rake', '~> 13.0'
44
33
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: u-case
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 3.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-12-18 00:00:00.000000000 Z
11
+ date: 2020-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: kind
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: u-attributes
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,14 +58,14 @@ dependencies:
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '10.0'
61
+ version: '13.0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '10.0'
68
+ version: '13.0'
55
69
  description: Create simple and powerful use cases as objects.
56
70
  email:
57
71
  - rodrigo.serradura@gmail.com
@@ -72,15 +86,17 @@ files:
72
86
  - bin/setup
73
87
  - lib/micro/case.rb
74
88
  - lib/micro/case/error.rb
75
- - lib/micro/case/flow.rb
76
- - lib/micro/case/flow/reducer.rb
77
89
  - lib/micro/case/result.rb
78
90
  - lib/micro/case/safe.rb
79
- - lib/micro/case/safe/flow.rb
80
91
  - lib/micro/case/strict.rb
92
+ - lib/micro/case/utils.rb
81
93
  - lib/micro/case/version.rb
82
- - lib/micro/case/with_validation.rb
94
+ - lib/micro/case/with_activemodel_validation.rb
95
+ - lib/micro/cases.rb
96
+ - lib/micro/cases/flow.rb
97
+ - lib/micro/cases/safe/flow.rb
83
98
  - lib/u-case.rb
99
+ - lib/u-case/with_activemodel_validation.rb
84
100
  - lib/u-case/with_validation.rb
85
101
  - test.sh
86
102
  - u-case.gemspec
@@ -99,9 +115,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
115
  version: 2.2.0
100
116
  required_rubygems_version: !ruby/object:Gem::Requirement
101
117
  requirements:
102
- - - ">="
118
+ - - ">"
103
119
  - !ruby/object:Gem::Version
104
- version: '0'
120
+ version: 1.3.1
105
121
  requirements: []
106
122
  rubygems_version: 3.0.6
107
123
  signing_key:
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Micro
4
- class Case
5
- module Flow
6
- module ClassMethods
7
- def __flow__
8
- @__flow
9
- end
10
-
11
- def flow(*args)
12
- @__flow = flow_reducer.build(args)
13
- end
14
-
15
- def call(options = {})
16
- new(options).call
17
- end
18
- end
19
-
20
- CONSTRUCTOR = <<-RUBY
21
- def initialize(options)
22
- @options = options
23
-
24
- flow = self.class.__flow__
25
-
26
- raise Error::UndefinedFlow unless flow
27
- end
28
- RUBY
29
-
30
- private_constant :ClassMethods, :CONSTRUCTOR
31
-
32
- # Deprecated: Classes with flows are now defined via `Micro::Case` inheritance
33
- def self.included(base)
34
- warn 'Deprecation: Micro::Case::Flow mixin is being deprecated, please use `Micro::Case` inheritance instead.'
35
-
36
- def base.flow_reducer; Reducer; end
37
-
38
- base.extend(ClassMethods)
39
-
40
- base.class_eval(CONSTRUCTOR)
41
- end
42
-
43
- def call
44
- self.class.__flow__.call(@options)
45
- end
46
- end
47
- end
48
- end
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Micro
4
- class Case
5
- module Flow
6
- class Reducer
7
- attr_reader :use_cases
8
-
9
- def self.map_use_cases(arg)
10
- return arg.use_cases if arg.is_a?(Reducer)
11
- return arg.__flow__.use_cases if arg.is_a?(Class) && arg < ::Micro::Case::Flow
12
-
13
- Array(arg)
14
- end
15
-
16
- def self.build(args)
17
- use_cases = Array(args).flat_map { |arg| map_use_cases(arg) }
18
-
19
- raise Error::InvalidUseCases if use_cases.any? { |klass| !(klass < ::Micro::Case) }
20
-
21
- new(use_cases)
22
- end
23
-
24
- def initialize(use_cases)
25
- @use_cases = use_cases
26
- end
27
-
28
- def call(arg = {})
29
- memo = arg.is_a?(Hash) ? arg.dup : {}
30
-
31
- @use_cases.reduce(initial_result(arg)) do |result, use_case|
32
- break result if result.failure?
33
-
34
- value = result.value
35
- input = value.is_a?(Hash) ? memo.tap { |data| data.merge!(value) } : value
36
-
37
- use_case_result(use_case, result, input)
38
- end
39
- end
40
-
41
- def >>(arg)
42
- self.class.build(use_cases + self.class.map_use_cases(arg))
43
- end
44
-
45
- def &(arg)
46
- raise NoMethodError, "undefined method `&' for #{self.inspect}. Please, use the method `>>' to avoid this error."
47
- end
48
-
49
- def to_proc
50
- Proc.new { |arg| call(arg) }
51
- end
52
-
53
- private
54
-
55
- def use_case_result(use_case, result, input)
56
- use_case.__new__(result, input).call
57
- end
58
-
59
- def initial_result(arg)
60
- return arg.call if arg_to_call?(arg)
61
- return arg if arg.is_a?(Micro::Case::Result)
62
-
63
- result = ::Micro::Case::Result.new
64
- result.__set__(true, arg, :ok, nil)
65
- end
66
-
67
- def arg_to_call?(arg)
68
- return true if arg.is_a?(::Micro::Case) || arg.is_a?(Reducer)
69
- return true if arg.is_a?(Class) && (arg < ::Micro::Case || arg < ::Micro::Case::Flow)
70
- return false
71
- end
72
- end
73
- end
74
- end
75
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Micro
4
- class Case
5
- class Safe
6
- module Flow
7
- def self.included(base)
8
- base.send(:include, ::Micro::Case::Flow)
9
-
10
- def base.flow_reducer; Reducer; end
11
- end
12
-
13
- class Reducer < ::Micro::Case::Flow::Reducer
14
- alias_method :&, :>>
15
-
16
- def >>(arg)
17
- raise NoMethodError, "undefined method `>>' for #{self.inspect}. Please, use the method `&' to avoid this error."
18
- end
19
-
20
- private
21
-
22
- def use_case_result(use_case, result, input)
23
- begin
24
- instance = use_case.__new__(result, input)
25
- instance.call
26
- rescue => exception
27
- raise exception if Error::ByWrongUsage.check(exception)
28
-
29
- result.__set__(false, exception, :exception, instance)
30
- end
31
- end
32
- end
33
- end
34
-
35
- def self.Flow(args)
36
- Flow::Reducer.build(Array(args))
37
- end
38
-
39
- def self.__flow_reducer
40
- Flow::Reducer
41
- end
42
- end
43
- end
44
- end