use_cases 0.2.5

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 (44) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/main.yml +23 -0
  3. data/.gitignore +12 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +19 -0
  6. data/.rubocop_todo.yml +28 -0
  7. data/CHANGELOG.md +20 -0
  8. data/CODE_OF_CONDUCT.md +84 -0
  9. data/Gemfile +20 -0
  10. data/Gemfile.lock +129 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +265 -0
  13. data/Rakefile +22 -0
  14. data/bin/console +15 -0
  15. data/bin/setup +8 -0
  16. data/lib/use_case.rb +57 -0
  17. data/lib/use_cases/authorize.rb +20 -0
  18. data/lib/use_cases/base.rb +8 -0
  19. data/lib/use_cases/dsl.rb +35 -0
  20. data/lib/use_cases/errors.rb +9 -0
  21. data/lib/use_cases/module_optins.rb +43 -0
  22. data/lib/use_cases/notifications.rb +51 -0
  23. data/lib/use_cases/params.rb +15 -0
  24. data/lib/use_cases/prepare.rb +19 -0
  25. data/lib/use_cases/rspec/matchers.rb +31 -0
  26. data/lib/use_cases/stack.rb +51 -0
  27. data/lib/use_cases/stack_runner.rb +60 -0
  28. data/lib/use_cases/step_active_job_adapter.rb +34 -0
  29. data/lib/use_cases/step_adapters/abstract.rb +99 -0
  30. data/lib/use_cases/step_adapters/authorize.rb +22 -0
  31. data/lib/use_cases/step_adapters/check.rb +22 -0
  32. data/lib/use_cases/step_adapters/enqueue.rb +18 -0
  33. data/lib/use_cases/step_adapters/map.rb +18 -0
  34. data/lib/use_cases/step_adapters/step.rb +18 -0
  35. data/lib/use_cases/step_adapters/tee.rb +20 -0
  36. data/lib/use_cases/step_adapters/try.rb +20 -0
  37. data/lib/use_cases/step_adapters.rb +25 -0
  38. data/lib/use_cases/step_result.rb +55 -0
  39. data/lib/use_cases/transaction.rb +25 -0
  40. data/lib/use_cases/validate.rb +104 -0
  41. data/lib/use_cases/version.rb +5 -0
  42. data/lib/use_cases.rb +7 -0
  43. data/use_cases.gemspec +42 -0
  44. metadata +200 -0
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "use_cases/step_adapters/step"
4
+ require "use_cases/step_adapters/map"
5
+ require "use_cases/step_adapters/tee"
6
+ require "use_cases/step_adapters/try"
7
+ require "use_cases/step_adapters/check"
8
+ require "use_cases/step_adapters/enqueue"
9
+ require "use_cases/step_active_job_adapter"
10
+
11
+ module UseCases
12
+ module StepAdapters
13
+ def self.included(base)
14
+ base.class_eval do
15
+ register_adapter StepAdapters::Step
16
+ register_adapter StepAdapters::Tee
17
+ register_adapter StepAdapters::Try
18
+ register_adapter StepAdapters::Map
19
+ register_adapter StepAdapters::Check
20
+
21
+ register_adapter StepAdapters::Enqueue if defined? ActiveJob
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UseCases
4
+ class StepResult < Dry::Monads::Result
5
+ attr_reader :step, :result
6
+
7
+ def initialize(step, result)
8
+ super()
9
+ @step = step
10
+ @result = result
11
+ end
12
+
13
+ def value
14
+ return result if result_not_monad?
15
+ return nil if result_empty?
16
+
17
+ result.success? ? result.value! : result
18
+ end
19
+ alias value! value
20
+
21
+ def success?
22
+ !failure?
23
+ end
24
+
25
+ def failure?
26
+ value.is_a?(Dry::Monads::Result::Failure)
27
+ end
28
+
29
+ def failure
30
+ failure? && value.failure
31
+ end
32
+
33
+ def success
34
+ success? && value
35
+ end
36
+
37
+ def nil?
38
+ value.nil?
39
+ end
40
+
41
+ def to_result
42
+ value.to_result if failure?
43
+
44
+ result
45
+ end
46
+
47
+ def result_empty?
48
+ result.success? && result.value! == Dry::Monads::Unit
49
+ end
50
+
51
+ def result_not_monad?
52
+ !result.is_a?(Dry::Monads::Result)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UseCases
4
+ module Transaction
5
+ class TransactionHandlerUndefined < StandardError; end
6
+
7
+ class TransactionHandlerInvalid < StandardError; end
8
+
9
+ def self.included(base)
10
+ base.prepend DoCallPatch
11
+ end
12
+
13
+ module DoCallPatch
14
+ def do_call(*args)
15
+ unless respond_to?(:transaction_handler)
16
+ raise TransactionHandlerUndefined, "when using *transactional*, make sure to include a transaction handler in your dependencies."
17
+ end
18
+
19
+ raise TransactionHandlerInvalid, "Make sure your transaction_handler implements #transaction." unless transaction_handler.respond_to?(:transaction)
20
+
21
+ transaction_handler.transaction { super }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/validation/contract"
4
+
5
+ module UseCases
6
+ module Validate
7
+ class NoValidationError < StandardError; end
8
+
9
+ def self.included(base)
10
+ base.class_eval do
11
+ extend DSL
12
+ extend ClassMethods
13
+ prepend CallPatch
14
+ end
15
+ end
16
+
17
+ module CallPatch
18
+ def call(*args)
19
+ unless stack.include_step?(:validate)
20
+ raise NoValidationError,
21
+ "Make sure to define params validations by using *params*" \
22
+ "*schema*, *json*, *rule* or *option* macros in your use case."
23
+ end
24
+
25
+ super
26
+ end
27
+ end
28
+
29
+ module DSL
30
+ def params(*args, &blk)
31
+ _setup_validation
32
+
33
+ _contract_class.params(*args, &blk)
34
+ end
35
+
36
+ def schema(*args, &blk)
37
+ _setup_validation
38
+
39
+ _contract_class.schema(*args, &blk)
40
+ end
41
+
42
+ def rule(*args, &blk)
43
+ _setup_validation
44
+
45
+ _contract_class.rule(*args, &blk)
46
+ end
47
+
48
+ def json(*args, &blk)
49
+ _setup_validation
50
+
51
+ _contract_class.json(*args, &blk)
52
+ end
53
+
54
+ def option(*args, &blk)
55
+ _contract_class.option(*args, &blk)
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def validate(params, current_user)
62
+ return Failure([:validation_error, "*params* must be a hash."]) unless params.respond_to?(:merge)
63
+
64
+ validation = contract.call(params.merge(current_user: current_user))
65
+
66
+ validation.success? ? Success(validation.to_h) : Failure([:validation_error, validation.errors.to_h])
67
+ end
68
+
69
+ def contract
70
+ return self.class._contract_class.new if self.class._contract_class_defined?
71
+ end
72
+
73
+ module ClassMethods
74
+ def _setup_validation
75
+ _define_contract_class unless _contract_class_defined?
76
+ _define_validation_step unless _validation_step_defined?
77
+ end
78
+
79
+ def _define_validation_step
80
+ step :validate
81
+ end
82
+
83
+ def _contract_class
84
+ self::Contract
85
+ end
86
+
87
+ def _define_contract_class
88
+ const_set(:Contract, Class.new(Dry::Validation::Contract))
89
+ end
90
+
91
+ def _contract_class_name
92
+ "#{name}::Contract"
93
+ end
94
+
95
+ def _contract_class_defined?
96
+ Object.const_defined? _contract_class_name
97
+ end
98
+
99
+ def _validation_step_defined?
100
+ __steps__.map(&:name).include?(:validate)
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UseCases
4
+ VERSION = "0.2.5"
5
+ end
data/lib/use_cases.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "use_case"
4
+ require_relative "use_cases/version"
5
+ require_relative "use_cases/base"
6
+
7
+ module UseCases; end
data/use_cases.gemspec ADDED
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/use_cases/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "use_cases"
7
+ spec.version = UseCases::VERSION
8
+ spec.authors = ["Ring Twice"]
9
+ spec.email = ["guilherme@listminut.com"]
10
+
11
+ spec.summary = "Use Cases"
12
+ spec.description = "A DSL to encapsulate your domain logic."
13
+ spec.homepage = "https://github.com/listminut/use_cases"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 2.6.8"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/listminut/use_cases"
19
+ spec.metadata["changelog_uri"] = "https://github.com/listminut/use_cases/CHANGELOG.md"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ # For more information and examples about making a new gem, checkout our
31
+ # guide at: https://bundler.io/guides/creating_gem.html
32
+
33
+ spec.add_dependency "activesupport"
34
+ spec.add_dependency "dry-events"
35
+ spec.add_dependency "dry-matcher"
36
+ spec.add_dependency "dry-monads"
37
+ spec.add_dependency "dry-validation"
38
+
39
+ spec.add_development_dependency "rake"
40
+ spec.add_development_dependency "rspec"
41
+ spec.add_development_dependency "rubocop"
42
+ end
metadata ADDED
@@ -0,0 +1,200 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: use_cases
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.5
5
+ platform: ruby
6
+ authors:
7
+ - Ring Twice
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-10-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dry-events
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dry-matcher
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: dry-monads
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: dry-validation
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: A DSL to encapsulate your domain logic.
126
+ email:
127
+ - guilherme@listminut.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".github/workflows/main.yml"
133
+ - ".gitignore"
134
+ - ".rspec"
135
+ - ".rubocop.yml"
136
+ - ".rubocop_todo.yml"
137
+ - CHANGELOG.md
138
+ - CODE_OF_CONDUCT.md
139
+ - Gemfile
140
+ - Gemfile.lock
141
+ - LICENSE.txt
142
+ - README.md
143
+ - Rakefile
144
+ - bin/console
145
+ - bin/setup
146
+ - lib/use_case.rb
147
+ - lib/use_cases.rb
148
+ - lib/use_cases/authorize.rb
149
+ - lib/use_cases/base.rb
150
+ - lib/use_cases/dsl.rb
151
+ - lib/use_cases/errors.rb
152
+ - lib/use_cases/module_optins.rb
153
+ - lib/use_cases/notifications.rb
154
+ - lib/use_cases/params.rb
155
+ - lib/use_cases/prepare.rb
156
+ - lib/use_cases/rspec/matchers.rb
157
+ - lib/use_cases/stack.rb
158
+ - lib/use_cases/stack_runner.rb
159
+ - lib/use_cases/step_active_job_adapter.rb
160
+ - lib/use_cases/step_adapters.rb
161
+ - lib/use_cases/step_adapters/abstract.rb
162
+ - lib/use_cases/step_adapters/authorize.rb
163
+ - lib/use_cases/step_adapters/check.rb
164
+ - lib/use_cases/step_adapters/enqueue.rb
165
+ - lib/use_cases/step_adapters/map.rb
166
+ - lib/use_cases/step_adapters/step.rb
167
+ - lib/use_cases/step_adapters/tee.rb
168
+ - lib/use_cases/step_adapters/try.rb
169
+ - lib/use_cases/step_result.rb
170
+ - lib/use_cases/transaction.rb
171
+ - lib/use_cases/validate.rb
172
+ - lib/use_cases/version.rb
173
+ - use_cases.gemspec
174
+ homepage: https://github.com/listminut/use_cases
175
+ licenses:
176
+ - MIT
177
+ metadata:
178
+ homepage_uri: https://github.com/listminut/use_cases
179
+ source_code_uri: https://github.com/listminut/use_cases
180
+ changelog_uri: https://github.com/listminut/use_cases/CHANGELOG.md
181
+ post_install_message:
182
+ rdoc_options: []
183
+ require_paths:
184
+ - lib
185
+ required_ruby_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ version: 2.6.8
190
+ required_rubygems_version: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ requirements: []
196
+ rubygems_version: 3.0.3.1
197
+ signing_key:
198
+ specification_version: 4
199
+ summary: Use Cases
200
+ test_files: []