bcdd-result 0.6.0 → 0.8.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +31 -11
  3. data/CHANGELOG.md +148 -0
  4. data/README.md +849 -242
  5. data/Rakefile +9 -3
  6. data/Steepfile +1 -1
  7. data/lib/bcdd/result/config/constant_alias.rb +33 -0
  8. data/lib/bcdd/result/config/options.rb +26 -0
  9. data/lib/bcdd/result/config/switcher.rb +82 -0
  10. data/lib/bcdd/result/config.rb +71 -0
  11. data/lib/bcdd/result/context/expectations/mixin.rb +23 -0
  12. data/lib/bcdd/result/context/expectations.rb +25 -0
  13. data/lib/bcdd/result/context/failure.rb +9 -0
  14. data/lib/bcdd/result/context/mixin.rb +41 -0
  15. data/lib/bcdd/result/context/success.rb +15 -0
  16. data/lib/bcdd/result/context.rb +74 -0
  17. data/lib/bcdd/result/{expectations/contract → contract}/disabled.rb +2 -2
  18. data/lib/bcdd/result/{expectations → contract}/error.rb +5 -3
  19. data/lib/bcdd/result/{expectations/contract → contract}/evaluator.rb +2 -2
  20. data/lib/bcdd/result/{expectations/contract → contract}/for_types.rb +2 -2
  21. data/lib/bcdd/result/contract/for_types_and_values.rb +44 -0
  22. data/lib/bcdd/result/contract/interface.rb +21 -0
  23. data/lib/bcdd/result/{expectations → contract}/type_checker.rb +1 -1
  24. data/lib/bcdd/result/contract.rb +33 -0
  25. data/lib/bcdd/result/error.rb +7 -9
  26. data/lib/bcdd/result/expectations/mixin.rb +19 -12
  27. data/lib/bcdd/result/expectations.rb +51 -36
  28. data/lib/bcdd/result/failure/methods.rb +21 -0
  29. data/lib/bcdd/result/failure.rb +2 -16
  30. data/lib/bcdd/result/mixin.rb +26 -8
  31. data/lib/bcdd/result/success/methods.rb +21 -0
  32. data/lib/bcdd/result/success.rb +2 -16
  33. data/lib/bcdd/result/version.rb +1 -1
  34. data/lib/bcdd/result.rb +17 -4
  35. data/lib/bcdd-result.rb +3 -0
  36. data/sig/bcdd/result.rbs +340 -88
  37. metadata +27 -16
  38. data/lib/bcdd/result/expectations/contract/for_types_and_values.rb +0 -37
  39. data/lib/bcdd/result/expectations/contract/interface.rb +0 -21
  40. data/lib/bcdd/result/expectations/contract.rb +0 -25
  41. data/lib/result.rb +0 -5
@@ -1,37 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class BCDD::Result::Expectations
4
- module Mixin
3
+ class BCDD::Result
4
+ module Expectations::Mixin
5
+ module Factory
6
+ def self.module!
7
+ ::Module.new do
8
+ def self.included(base); base.const_set(:ResultExpectationsMixin, self); end
9
+ def self.extended(base); base.const_set(:ResultExpectationsMixin, self); end
10
+ end
11
+ end
12
+ end
13
+
5
14
  METHODS = <<~RUBY
6
15
  def Success(...)
7
- __expected::Success(...)
16
+ _Result.Success(...)
8
17
  end
9
18
 
10
19
  def Failure(...)
11
- __expected::Failure(...)
20
+ _Result.Failure(...)
12
21
  end
13
22
 
14
23
  private
15
24
 
16
- def __expected
17
- @__expected ||= Expected.with(subject: self)
25
+ def _Result
26
+ @_Result ||= Result.with(subject: self)
18
27
  end
19
28
  RUBY
20
29
 
21
30
  module Addons
22
31
  module Continuable
23
32
  private def Continue(value)
24
- ::BCDD::Result::Success.new(type: :continued, value: value, subject: self)
33
+ Success.new(type: :continued, value: value, subject: self)
25
34
  end
26
35
  end
27
36
 
28
- OPTIONS = { Continue: Continuable }.freeze
37
+ OPTIONS = { continue: Continuable }.freeze
29
38
 
30
- def self.options(names)
31
- Array(names).filter_map { |name| OPTIONS[name] }
39
+ def self.options(config_flags)
40
+ Config::Options.addon(map: config_flags, from: OPTIONS)
32
41
  end
33
42
  end
34
43
  end
35
-
36
- private_constant :Mixin
37
44
  end
@@ -1,50 +1,65 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class BCDD::Result::Expectations
4
- require_relative 'expectations/mixin'
5
- require_relative 'expectations/error'
6
- require_relative 'expectations/contract'
7
- require_relative 'expectations/type_checker'
8
-
9
- def self.mixin(success: nil, failure: nil, with: nil)
10
- addons = Mixin::Addons.options(with)
11
-
12
- mod = Module.new
13
- mod.const_set(:Expected, new(success: success, failure: failure).freeze)
14
- mod.module_eval(Mixin::METHODS)
15
- mod.send(:include, *addons) unless addons.empty?
16
- mod
17
- end
3
+ class BCDD::Result
4
+ class Expectations
5
+ require_relative 'expectations/mixin'
18
6
 
19
- def self.evaluate(data, expectations)
20
- expectations ||= Contract::NONE
7
+ def self.mixin(**options)
8
+ return mixin!(**options) if Config.instance.feature.enabled?(:expectations)
21
9
 
22
- expectations.type_and_value!(data)
10
+ result_factory_without_expectations.mixin(**options.slice(:config))
11
+ end
23
12
 
24
- TypeChecker.new(data.type, expectations: expectations)
25
- end
13
+ def self.mixin!(success: nil, failure: nil, config: nil)
14
+ addons = mixin_module::Addons.options(config)
26
15
 
27
- def initialize(subject: nil, success: nil, failure: nil, contract: nil)
28
- @subject = subject
16
+ mod = mixin_module::Factory.module!
17
+ mod.const_set(:Result, new(success: success, failure: failure, config: config).freeze)
18
+ mod.module_eval(mixin_module::METHODS)
19
+ mod.send(:include, *addons) unless addons.empty?
20
+ mod
21
+ end
29
22
 
30
- @contract = contract if contract.is_a?(Contract::Evaluator)
23
+ def self.mixin_module
24
+ Mixin
25
+ end
31
26
 
32
- @contract ||= Contract.new(success: success, failure: failure).freeze
33
- end
27
+ def self.result_factory_without_expectations
28
+ ::BCDD::Result
29
+ end
34
30
 
35
- def Success(type, value = nil)
36
- ::BCDD::Result::Success.new(type: type, value: value, subject: subject, expectations: contract)
37
- end
31
+ def self.new(...)
32
+ return result_factory_without_expectations unless Config.instance.feature.enabled?(:expectations)
38
33
 
39
- def Failure(type, value = nil)
40
- ::BCDD::Result::Failure.new(type: type, value: value, subject: subject, expectations: contract)
41
- end
34
+ instance = allocate
35
+ instance.send(:initialize, ...)
36
+ instance
37
+ end
42
38
 
43
- def with(subject:)
44
- self.class.new(subject: subject, contract: contract)
45
- end
39
+ private_class_method :mixin!, :mixin_module, :result_factory_without_expectations
40
+
41
+ def initialize(subject: nil, success: nil, failure: nil, contract: nil, config: nil)
42
+ @subject = subject
46
43
 
47
- private
44
+ @contract = contract if contract.is_a?(Contract::Evaluator)
48
45
 
49
- attr_reader :subject, :contract
46
+ @contract ||= Contract.new(success: success, failure: failure, config: config).freeze
47
+ end
48
+
49
+ def Success(type, value = nil)
50
+ Success.new(type: type, value: value, subject: subject, expectations: contract)
51
+ end
52
+
53
+ def Failure(type, value = nil)
54
+ Failure.new(type: type, value: value, subject: subject, expectations: contract)
55
+ end
56
+
57
+ def with(subject:)
58
+ self.class.new(subject: subject, contract: contract)
59
+ end
60
+
61
+ private
62
+
63
+ attr_reader :subject, :contract
64
+ end
50
65
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDD::Result::Failure::Methods
4
+ def success?(_type = nil)
5
+ false
6
+ end
7
+
8
+ def failure?(type = nil)
9
+ type.nil? || type_checker.allow_failure?([type])
10
+ end
11
+
12
+ def value_or
13
+ yield(value)
14
+ end
15
+
16
+ private
17
+
18
+ def name
19
+ :failure
20
+ end
21
+ end
@@ -2,23 +2,9 @@
2
2
 
3
3
  class BCDD::Result
4
4
  class Failure < self
5
- def success?(_type = nil)
6
- false
7
- end
5
+ require_relative 'failure/methods'
8
6
 
9
- def failure?(type = nil)
10
- type.nil? || type_checker.allow_failure?([type])
11
- end
12
-
13
- def value_or
14
- yield
15
- end
16
-
17
- private
18
-
19
- def name
20
- :failure
21
- end
7
+ include Methods
22
8
  end
23
9
 
24
10
  def self.Failure(type, value = nil)
@@ -2,6 +2,15 @@
2
2
 
3
3
  class BCDD::Result
4
4
  module Mixin
5
+ module Factory
6
+ def self.module!
7
+ ::Module.new do
8
+ def self.included(base); base.const_set(:ResultMixin, self); end
9
+ def self.extended(base); base.const_set(:ResultMixin, self); end
10
+ end
11
+ end
12
+ end
13
+
5
14
  module Methods
6
15
  def Success(type, value = nil)
7
16
  Success.new(type: type, value: value, subject: self)
@@ -19,22 +28,31 @@ class BCDD::Result
19
28
  end
20
29
  end
21
30
 
22
- OPTIONS = { Continue: Continuable }.freeze
31
+ OPTIONS = { continue: Continuable }.freeze
23
32
 
24
- def self.options(names)
25
- Array(names).filter_map { |name| OPTIONS[name] }
33
+ def self.options(config_flags)
34
+ Config::Options.addon(map: config_flags, from: OPTIONS)
26
35
  end
27
36
  end
28
37
  end
29
38
 
30
- def self.mixin(with: nil)
31
- addons = Mixin::Addons.options(with)
39
+ def self.mixin(config: nil)
40
+ addons = mixin_module::Addons.options(config)
32
41
 
33
- mod = Module.new
34
- mod.send(:include, Mixin::Methods)
42
+ mod = mixin_module::Factory.module!
43
+ mod.send(:include, mixin_module::Methods)
44
+ mod.const_set(:Result, result_factory)
35
45
  mod.send(:include, *addons) unless addons.empty?
36
46
  mod
37
47
  end
38
48
 
39
- private_constant :Mixin
49
+ def self.mixin_module
50
+ Mixin
51
+ end
52
+
53
+ def self.result_factory
54
+ ::BCDD::Result
55
+ end
56
+
57
+ private_class_method :mixin_module, :result_factory
40
58
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDD::Result::Success::Methods
4
+ def success?(type = nil)
5
+ type.nil? || type_checker.allow_success?([type])
6
+ end
7
+
8
+ def failure?(_type = nil)
9
+ false
10
+ end
11
+
12
+ def value_or
13
+ value
14
+ end
15
+
16
+ private
17
+
18
+ def name
19
+ :success
20
+ end
21
+ end
@@ -2,23 +2,9 @@
2
2
 
3
3
  class BCDD::Result
4
4
  class Success < self
5
- def success?(type = nil)
6
- type.nil? || type_checker.allow_success?([type])
7
- end
5
+ require_relative 'success/methods'
8
6
 
9
- def failure?(_type = nil)
10
- false
11
- end
12
-
13
- def value_or
14
- value
15
- end
16
-
17
- private
18
-
19
- def name
20
- :success
21
- end
7
+ include Methods
22
8
  end
23
9
 
24
10
  def self.Success(type, value = nil)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module BCDD
4
4
  class Result
5
- VERSION = '0.6.0'
5
+ VERSION = '0.8.0'
6
6
  end
7
7
  end
data/lib/bcdd/result.rb CHANGED
@@ -3,11 +3,14 @@
3
3
  require_relative 'result/version'
4
4
  require_relative 'result/error'
5
5
  require_relative 'result/data'
6
+ require_relative 'result/config'
6
7
  require_relative 'result/handler'
7
8
  require_relative 'result/failure'
8
9
  require_relative 'result/success'
9
10
  require_relative 'result/mixin'
11
+ require_relative 'result/contract'
10
12
  require_relative 'result/expectations'
13
+ require_relative 'result/context'
11
14
 
12
15
  class BCDD::Result
13
16
  attr_accessor :unknown
@@ -18,10 +21,20 @@ class BCDD::Result
18
21
 
19
22
  private :unknown, :unknown=, :type_checker
20
23
 
24
+ def self.config
25
+ Config.instance
26
+ end
27
+
28
+ def self.configuration
29
+ yield(config)
30
+
31
+ config.freeze
32
+ end
33
+
21
34
  def initialize(type:, value:, subject: nil, expectations: nil)
22
35
  data = Data.new(name, type, value)
23
36
 
24
- @type_checker = Expectations.evaluate(data, expectations)
37
+ @type_checker = Contract.evaluate(data, expectations)
25
38
  @subject = subject
26
39
  @data = data
27
40
 
@@ -69,7 +82,7 @@ class BCDD::Result
69
82
  def and_then(method_name = nil, context = nil)
70
83
  return self if failure?
71
84
 
72
- method_name && block_given? and raise ArgumentError, 'method_name and block are mutually exclusive'
85
+ method_name && block_given? and raise ::ArgumentError, 'method_name and block are mutually exclusive'
73
86
 
74
87
  return call_subject_method(method_name, context) if method_name
75
88
 
@@ -129,7 +142,7 @@ class BCDD::Result
129
142
  when 0 then subject.send(method_name)
130
143
  when 1 then subject.send(method_name, value)
131
144
  when 2 then subject.send(method_name, value, context)
132
- else raise Error::WrongSubjectMethodArity.build(subject: subject, method: method)
145
+ else raise Error::InvalidSubjectMethodArity.build(subject: subject, method: method, max_arity: 2)
133
146
  end
134
147
 
135
148
  ensure_result_object(result, origin: :method)
@@ -140,6 +153,6 @@ class BCDD::Result
140
153
 
141
154
  return result if result.subject.equal?(subject)
142
155
 
143
- raise Error::WrongResultSubject.build(given_result: result, expected_subject: subject)
156
+ raise Error::InvalidResultSubject.build(given_result: result, expected_subject: subject)
144
157
  end
145
158
  end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bcdd/result'