bcdd-result 0.9.0 → 0.10.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 +4 -4
- data/.rubocop.yml +8 -0
- data/CHANGELOG.md +34 -11
- data/README.md +170 -5
- data/Steepfile +2 -2
- data/lib/bcdd/result/config/switchers/addons.rb +20 -0
- data/lib/bcdd/result/config/{constant_alias.rb → switchers/constant_aliases.rb} +4 -4
- data/lib/bcdd/result/config/switchers/features.rb +28 -0
- data/lib/bcdd/result/config/switchers/pattern_matching.rb +20 -0
- data/lib/bcdd/result/config.rb +8 -28
- data/lib/bcdd/result/context/failure.rb +1 -1
- data/lib/bcdd/result/context/success.rb +2 -2
- data/lib/bcdd/result/context.rb +12 -11
- data/lib/bcdd/result/transitions/tracking/disabled.rb +17 -0
- data/lib/bcdd/result/transitions/tracking/enabled.rb +80 -0
- data/lib/bcdd/result/transitions/tracking.rb +20 -0
- data/lib/bcdd/result/transitions/tree.rb +95 -0
- data/lib/bcdd/result/transitions.rb +30 -0
- data/lib/bcdd/result/version.rb +1 -1
- data/lib/bcdd/result.rb +35 -18
- data/sig/bcdd/result/config.rbs +100 -0
- data/sig/bcdd/result/context.rbs +102 -0
- data/sig/bcdd/result/contract.rbs +119 -0
- data/sig/bcdd/result/data.rbs +16 -0
- data/sig/bcdd/result/error.rbs +31 -0
- data/sig/bcdd/result/expectations.rbs +67 -0
- data/sig/bcdd/result/handler.rbs +47 -0
- data/sig/bcdd/result/mixin.rbs +37 -0
- data/sig/bcdd/result/transitions.rbs +89 -0
- data/sig/bcdd/result/version.rbs +5 -0
- data/sig/bcdd/result.rbs +6 -516
- metadata +22 -4
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class BCDD::Result
         | 
| 4 | 
            +
              module Transitions
         | 
| 5 | 
            +
                module Tracking
         | 
| 6 | 
            +
                  require_relative 'tracking/enabled'
         | 
| 7 | 
            +
                  require_relative 'tracking/disabled'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  EMPTY_ARRAY = [].freeze
         | 
| 10 | 
            +
                  EMPTY_HASH = {}.freeze
         | 
| 11 | 
            +
                  EMPTY_TREE = Tree.new(nil).freeze
         | 
| 12 | 
            +
                  VERSION = 1
         | 
| 13 | 
            +
                  EMPTY = { version: VERSION, records: EMPTY_ARRAY, metadata: { duration: 0, tree_map: EMPTY_ARRAY } }.freeze
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def self.instance
         | 
| 16 | 
            +
                    Config.instance.feature.enabled?(:transitions) ? Tracking::Enabled.new : Tracking::Disabled
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,95 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class BCDD::Result
         | 
| 4 | 
            +
              module Transitions
         | 
| 5 | 
            +
                class Tree
         | 
| 6 | 
            +
                  class Node
         | 
| 7 | 
            +
                    attr_reader :id, :value, :parent, :normalizer, :children
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    def initialize(value, parent:, id:, normalizer:)
         | 
| 10 | 
            +
                      @normalizer = normalizer
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                      @id = id
         | 
| 13 | 
            +
                      @value = normalizer.call(id, value)
         | 
| 14 | 
            +
                      @parent = parent
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                      @children = []
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    def insert(value, id:)
         | 
| 20 | 
            +
                      node = self.class.new(value, parent: self, id: id, normalizer: normalizer)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                      @children << node
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                      node
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    def root?
         | 
| 28 | 
            +
                      parent.nil?
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    def leaf?
         | 
| 32 | 
            +
                      children.empty?
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    def node?
         | 
| 36 | 
            +
                      !leaf?
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    def inspect
         | 
| 40 | 
            +
                      "#<#{self.class.name} id=#{id} children.size=#{children.size}>"
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  attr_reader :size, :root, :current
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def initialize(value, normalizer: ->(_id, val) { val })
         | 
| 47 | 
            +
                    @size = 0
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    @root = Node.new(value, parent: nil, id: @size, normalizer: normalizer)
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    @current = @root
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  def root_value
         | 
| 55 | 
            +
                    root.value
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  def parent_value
         | 
| 59 | 
            +
                    current.parent&.value || root_value
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  def current_value
         | 
| 63 | 
            +
                    current.value
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  def insert(value)
         | 
| 67 | 
            +
                    @size += 1
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                    current.insert(value, id: size)
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  def insert!(value)
         | 
| 73 | 
            +
                    @current = insert(value)
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  def move_up!(level = 1)
         | 
| 77 | 
            +
                    tap { level.times { @current = current.parent || root } }
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  def move_down!(level = 1, index: -1)
         | 
| 81 | 
            +
                    tap { level.times { current.children[index].then { |child| @current = child if child } } }
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  def move_to_root!
         | 
| 85 | 
            +
                    tap { @current = root }
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                  NestedIds = ->(node) { [node.id, node.children.map(&NestedIds)] }
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  def nested_ids
         | 
| 91 | 
            +
                    NestedIds[root]
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class BCDD::Result
         | 
| 4 | 
            +
              module Transitions
         | 
| 5 | 
            +
                require_relative 'transitions/tree'
         | 
| 6 | 
            +
                require_relative 'transitions/tracking'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                THREAD_VAR_NAME = :bcdd_result_transitions_tracking
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def self.tracking
         | 
| 11 | 
            +
                  Thread.current[THREAD_VAR_NAME] ||= Tracking.instance
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              def self.transitions(name: nil, desc: nil)
         | 
| 16 | 
            +
                Transitions.tracking.start(name: name, desc: desc)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                result = yield
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                result.is_a?(::BCDD::Result) or raise Error::UnexpectedOutcome.build(outcome: result, origin: :transitions)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                Transitions.tracking.finish(result: result)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                result
         | 
| 25 | 
            +
              rescue ::Exception => e
         | 
| 26 | 
            +
                Transitions.tracking.reset!
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                raise e
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
    
        data/lib/bcdd/result/version.rb
    CHANGED
    
    
    
        data/lib/bcdd/result.rb
    CHANGED
    
    | @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require_relative 'result/version'
         | 
| 4 | 
            +
            require_relative 'result/transitions'
         | 
| 4 5 | 
             
            require_relative 'result/error'
         | 
| 5 6 | 
             
            require_relative 'result/data'
         | 
| 6 7 | 
             
            require_relative 'result/handler'
         | 
| @@ -13,13 +14,13 @@ require_relative 'result/context' | |
| 13 14 | 
             
            require_relative 'result/config'
         | 
| 14 15 |  | 
| 15 16 | 
             
            class BCDD::Result
         | 
| 16 | 
            -
              attr_accessor :unknown
         | 
| 17 | 
            +
              attr_accessor :unknown, :transitions
         | 
| 17 18 |  | 
| 18 19 | 
             
              attr_reader :subject, :data, :type_checker, :halted
         | 
| 19 20 |  | 
| 20 21 | 
             
              protected :subject
         | 
| 21 22 |  | 
| 22 | 
            -
              private :unknown, :unknown=, :type_checker
         | 
| 23 | 
            +
              private :unknown, :unknown=, :type_checker, :transitions=
         | 
| 23 24 |  | 
| 24 25 | 
             
              def self.config
         | 
| 25 26 | 
             
                Config.instance
         | 
| @@ -40,6 +41,9 @@ class BCDD::Result | |
| 40 41 | 
             
                @data = data
         | 
| 41 42 |  | 
| 42 43 | 
             
                self.unknown = true
         | 
| 44 | 
            +
                self.transitions = Transitions::Tracking::EMPTY
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                Transitions.tracking.record(self)
         | 
| 43 47 | 
             
              end
         | 
| 44 48 |  | 
| 45 49 | 
             
              def halted?
         | 
| @@ -84,16 +88,12 @@ class BCDD::Result | |
| 84 88 | 
             
                tap { yield(value, type) if unknown }
         | 
| 85 89 | 
             
              end
         | 
| 86 90 |  | 
| 87 | 
            -
              def and_then(method_name = nil, context = nil)
         | 
| 91 | 
            +
              def and_then(method_name = nil, context = nil, &block)
         | 
| 88 92 | 
             
                return self if halted?
         | 
| 89 93 |  | 
| 90 | 
            -
                method_name &&  | 
| 91 | 
            -
             | 
| 92 | 
            -
                return call_subject_method(method_name, context) if method_name
         | 
| 93 | 
            -
             | 
| 94 | 
            -
                result = yield(value)
         | 
| 94 | 
            +
                method_name && block and raise ::ArgumentError, 'method_name and block are mutually exclusive'
         | 
| 95 95 |  | 
| 96 | 
            -
                 | 
| 96 | 
            +
                method_name ? call_and_then_subject_method(method_name, context) : call_and_then_block(block)
         | 
| 97 97 | 
             
              end
         | 
| 98 98 |  | 
| 99 99 | 
             
              def handle
         | 
| @@ -139,18 +139,35 @@ class BCDD::Result | |
| 139 139 | 
             
                block.call(value, type)
         | 
| 140 140 | 
             
              end
         | 
| 141 141 |  | 
| 142 | 
            -
              def  | 
| 142 | 
            +
              def call_and_then_subject_method(method_name, context_data)
         | 
| 143 143 | 
             
                method = subject.method(method_name)
         | 
| 144 144 |  | 
| 145 | 
            -
                 | 
| 146 | 
            -
                   | 
| 147 | 
            -
             | 
| 148 | 
            -
                   | 
| 149 | 
            -
             | 
| 150 | 
            -
             | 
| 151 | 
            -
             | 
| 145 | 
            +
                Transitions.tracking.record_and_then(method, context_data, subject) do
         | 
| 146 | 
            +
                  result = call_and_then_subject_method!(method, context_data)
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  ensure_result_object(result, origin: :method)
         | 
| 149 | 
            +
                end
         | 
| 150 | 
            +
              end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
              def call_and_then_subject_method!(method, context_data)
         | 
| 153 | 
            +
                case method.arity
         | 
| 154 | 
            +
                when 0 then subject.send(method.name)
         | 
| 155 | 
            +
                when 1 then subject.send(method.name, value)
         | 
| 156 | 
            +
                when 2 then subject.send(method.name, value, context_data)
         | 
| 157 | 
            +
                else raise Error::InvalidSubjectMethodArity.build(subject: subject, method: method, max_arity: 2)
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
              end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
              def call_and_then_block(block)
         | 
| 162 | 
            +
                Transitions.tracking.record_and_then(:block, nil, subject) do
         | 
| 163 | 
            +
                  result = call_and_then_block!(block)
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                  ensure_result_object(result, origin: :block)
         | 
| 166 | 
            +
                end
         | 
| 167 | 
            +
              end
         | 
| 152 168 |  | 
| 153 | 
            -
             | 
| 169 | 
            +
              def call_and_then_block!(block)
         | 
| 170 | 
            +
                block.call(value)
         | 
| 154 171 | 
             
              end
         | 
| 155 172 |  | 
| 156 173 | 
             
              def ensure_result_object(result, origin:)
         | 
| @@ -0,0 +1,100 @@ | |
| 1 | 
            +
            class BCDD::Result::Config
         | 
| 2 | 
            +
              include Singleton
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              ADDON: Hash[Symbol, Hash[Symbol, untyped]]
         | 
| 5 | 
            +
              FEATURE: Hash[Symbol, Hash[Symbol, untyped]]
         | 
| 6 | 
            +
              PATTERN_MATCHING: Hash[Symbol, Hash[Symbol, untyped]]
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              attr_reader addon: BCDD::Result::Config::Switcher
         | 
| 9 | 
            +
              attr_reader feature: BCDD::Result::Config::Switcher
         | 
| 10 | 
            +
              attr_reader constant_alias: BCDD::Result::Config::Switcher
         | 
| 11 | 
            +
              attr_reader pattern_matching: BCDD::Result::Config::Switcher
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              def self.instance: -> BCDD::Result::Config
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              def initialize: -> void
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              def freeze: -> BCDD::Result::Config
         | 
| 18 | 
            +
              def options: -> Hash[Symbol, BCDD::Result::Config::Switcher]
         | 
| 19 | 
            +
              def to_h: -> Hash[Symbol, Hash[Symbol | String, bool]]
         | 
| 20 | 
            +
            end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            module BCDD::Result::Config::Options
         | 
| 23 | 
            +
              def self.with_defaults: (
         | 
| 24 | 
            +
                Hash[Symbol, Hash[Symbol, bool]],
         | 
| 25 | 
            +
                Symbol
         | 
| 26 | 
            +
              ) -> Hash[Symbol, bool]
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              def self.select: (
         | 
| 29 | 
            +
                Hash[Symbol, Hash[Symbol, bool]],
         | 
| 30 | 
            +
                config: Symbol,
         | 
| 31 | 
            +
                from: Hash[Symbol, untyped]
         | 
| 32 | 
            +
              ) -> Hash[Symbol, untyped]
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def self.addon: (
         | 
| 35 | 
            +
                map: Hash[Symbol, Hash[Symbol, bool]],
         | 
| 36 | 
            +
                from: Hash[Symbol, Module]
         | 
| 37 | 
            +
              ) -> Hash[Symbol, Module]
         | 
| 38 | 
            +
            end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            class BCDD::Result::Config::Switcher
         | 
| 41 | 
            +
              private attr_reader _affects: Hash[Symbol | String, Array[String]]
         | 
| 42 | 
            +
              private attr_reader _options: Hash[Symbol | String, bool]
         | 
| 43 | 
            +
              private attr_reader listener: Proc
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              def initialize: (
         | 
| 46 | 
            +
                options: Hash[Symbol | String, Hash[Symbol, untyped]],
         | 
| 47 | 
            +
                ?listener: Proc
         | 
| 48 | 
            +
              ) -> void
         | 
| 49 | 
            +
             | 
| 50 | 
            +
              def freeze: -> BCDD::Result::Config::Switcher
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              def to_h: -> Hash[Symbol | String, bool]
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              def options: -> Hash[Symbol | String, Hash[Symbol, untyped]]
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              def enabled?: (Symbol | String) -> bool
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              def enable!: (*(Symbol | String)) -> Hash[Symbol | String, Hash[Symbol, untyped]]
         | 
| 59 | 
            +
             | 
| 60 | 
            +
              def disable!: (*(Symbol | String)) -> Hash[Symbol | String, Hash[Symbol, untyped]]
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              private
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              def set_many: (Array[Symbol | String], to: bool) -> Hash[Symbol | String, Hash[Symbol, untyped]]
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              def set_one: (Symbol | String, bool) -> void
         | 
| 67 | 
            +
             | 
| 68 | 
            +
              def require_option!: (Array[Symbol | String]) -> void
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              def validate_option!: (Symbol | String) -> void
         | 
| 71 | 
            +
             | 
| 72 | 
            +
              def available_options_message: -> String
         | 
| 73 | 
            +
            end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            module BCDD::Result::Config::Addons
         | 
| 76 | 
            +
              OPTIONS: Hash[String, Hash[Symbol, untyped]]
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              def self.switcher: -> BCDD::Result::Config::Switcher
         | 
| 79 | 
            +
            end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
            module BCDD::Result::Config::ConstantAliases
         | 
| 82 | 
            +
              MAPPING: Hash[String, Hash[Symbol, untyped]]
         | 
| 83 | 
            +
              OPTIONS: Hash[String, Hash[Symbol, untyped]]
         | 
| 84 | 
            +
              Listener: Proc
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              def self.switcher: -> BCDD::Result::Config::Switcher
         | 
| 87 | 
            +
            end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            module BCDD::Result::Config::Features
         | 
| 90 | 
            +
              OPTIONS: Hash[String, Hash[Symbol, untyped]]
         | 
| 91 | 
            +
              Listener: Proc
         | 
| 92 | 
            +
             | 
| 93 | 
            +
              def self.switcher: -> BCDD::Result::Config::Switcher
         | 
| 94 | 
            +
            end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
            module BCDD::Result::Config::PatternMatching
         | 
| 97 | 
            +
              OPTIONS: Hash[String, Hash[Symbol, untyped]]
         | 
| 98 | 
            +
             | 
| 99 | 
            +
              def self.switcher: -> BCDD::Result::Config::Switcher
         | 
| 100 | 
            +
            end
         | 
| @@ -0,0 +1,102 @@ | |
| 1 | 
            +
            class BCDD::Result::Context < BCDD::Result
         | 
| 2 | 
            +
              EXPECTED_OUTCOME: String
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              SubjectMethodArity: ^(Method) -> Integer
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              attr_reader acc: Hash[Symbol, untyped]
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def initialize: (
         | 
| 9 | 
            +
                type: Symbol,
         | 
| 10 | 
            +
                value: untyped,
         | 
| 11 | 
            +
                ?subject: untyped,
         | 
| 12 | 
            +
                ?expectations: BCDD::Result::Contract::Evaluator,
         | 
| 13 | 
            +
                ?halted: bool
         | 
| 14 | 
            +
              ) -> void
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def and_then: (?Symbol, **untyped) ?{ (Hash[Symbol, untyped]) -> untyped } -> BCDD::Result::Context
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              private
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def call_and_then_subject_method: (Symbol, Hash[Symbol, untyped]) -> BCDD::Result::Context
         | 
| 21 | 
            +
              def ensure_result_object: (untyped, origin: Symbol) -> BCDD::Result::Context
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def raise_unexpected_outcome_error: (BCDD::Result::Context | untyped, Symbol) -> void
         | 
| 24 | 
            +
            end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            class BCDD::Result::Context
         | 
| 27 | 
            +
              class Success < BCDD::Result::Context
         | 
| 28 | 
            +
                include BCDD::Result::Success::Methods
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def and_expose: (Symbol, Array[Symbol], halted: bool) -> BCDD::Result::Context::Success
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def self.Success: (Symbol, **untyped) -> BCDD::Result::Context::Success
         | 
| 34 | 
            +
            end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            class BCDD::Result::Context
         | 
| 37 | 
            +
              class Failure < BCDD::Result::Context
         | 
| 38 | 
            +
                include BCDD::Result::Failure::Methods
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def and_expose: (Symbol, Array[Symbol], **untyped) -> BCDD::Result::Context::Failure
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              def self.Failure: (Symbol, **untyped) -> BCDD::Result::Context::Failure
         | 
| 44 | 
            +
            end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            class BCDD::Result::Context
         | 
| 47 | 
            +
              module Mixin
         | 
| 48 | 
            +
                Factory: singleton(BCDD::Result::Mixin::Factory)
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                module Methods
         | 
| 51 | 
            +
                  def Success: (Symbol, **untyped) -> BCDD::Result::Context::Success
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  def Failure: (Symbol, **untyped) -> BCDD::Result::Context::Failure
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  private
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  def _ResultAs: (singleton(BCDD::Result::Context), Symbol, untyped, ?halted: bool) -> untyped
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                module Addons
         | 
| 61 | 
            +
                  module Continuable
         | 
| 62 | 
            +
                    include BCDD::Result::Context::Mixin::Methods
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                    private
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                    def Continue: (**untyped) -> BCDD::Result::Context::Success
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  OPTIONS: Hash[Symbol, Module]
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  def self.options: (Hash[Symbol, Hash[Symbol, bool]]) -> Hash[Symbol, Module]
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
              def self.mixin_module: -> singleton(BCDD::Result::Context::Mixin)
         | 
| 76 | 
            +
             | 
| 77 | 
            +
              def self.result_factory: -> singleton(BCDD::Result::Context)
         | 
| 78 | 
            +
            end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
            class BCDD::Result::Context::Expectations < BCDD::Result::Expectations
         | 
| 81 | 
            +
              def self.mixin_module: -> singleton(BCDD::Result::Context::Expectations::Mixin)
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              def self.result_factory_without_expectations: -> singleton(BCDD::Result)
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              def Success: (Symbol, **untyped) -> BCDD::Result::Context::Success
         | 
| 86 | 
            +
              def Failure: (Symbol, **untyped) -> BCDD::Result::Context::Failure
         | 
| 87 | 
            +
            end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            module BCDD::Result::Context::Expectations::Mixin
         | 
| 90 | 
            +
              Methods: singleton(BCDD::Result::Expectations::Mixin::Methods)
         | 
| 91 | 
            +
              Factory: singleton(BCDD::Result::Expectations::Mixin::Factory)
         | 
| 92 | 
            +
             | 
| 93 | 
            +
              module Addons
         | 
| 94 | 
            +
                module Continuable
         | 
| 95 | 
            +
                  private def Continue: (**untyped) -> BCDD::Result::Context::Success
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                OPTIONS: Hash[Symbol, Module]
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                def self.options: (Hash[Symbol, Hash[Symbol, bool]]) -> Hash[Symbol, Module]
         | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
            end
         | 
| @@ -0,0 +1,119 @@ | |
| 1 | 
            +
            module BCDD::Result::Contract
         | 
| 2 | 
            +
              NONE: BCDD::Result::Contract::Evaluator
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              def self.evaluate: (
         | 
| 5 | 
            +
                BCDD::Result::Data,
         | 
| 6 | 
            +
                BCDD::Result::Contract::Evaluator
         | 
| 7 | 
            +
              ) -> BCDD::Result::Contract::TypeChecker
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              ToEnsure: ^(Hash[Symbol, untyped] | Array[Symbol], Hash[Symbol, Hash[Symbol, bool]])
         | 
| 10 | 
            +
                -> BCDD::Result::Contract::Interface
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def self.new: (
         | 
| 13 | 
            +
                success: Hash[Symbol, untyped] | Array[Symbol],
         | 
| 14 | 
            +
                failure: Hash[Symbol, untyped] | Array[Symbol],
         | 
| 15 | 
            +
                config: Hash[Symbol, Hash[Symbol, bool]]
         | 
| 16 | 
            +
              ) -> BCDD::Result::Contract::Evaluator
         | 
| 17 | 
            +
            end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            module BCDD::Result::Contract
         | 
| 20 | 
            +
              class TypeChecker
         | 
| 21 | 
            +
                attr_reader result_type: Symbol
         | 
| 22 | 
            +
                attr_reader expectations: BCDD::Result::Contract::Evaluator
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def initialize: (
         | 
| 25 | 
            +
                  Symbol,
         | 
| 26 | 
            +
                  expectations: BCDD::Result::Contract::Evaluator
         | 
| 27 | 
            +
                ) -> void
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def allow?: (Array[Symbol]) -> bool
         | 
| 30 | 
            +
                def allow_success?: (Array[Symbol]) -> bool
         | 
| 31 | 
            +
                def allow_failure?: (Array[Symbol]) -> bool
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                private
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def validate: (
         | 
| 36 | 
            +
                  Array[Symbol],
         | 
| 37 | 
            +
                  expected: BCDD::Result::Contract::Interface,
         | 
| 38 | 
            +
                  allow_empty: bool
         | 
| 39 | 
            +
                ) -> bool
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            class BCDD::Result::Contract::Error < BCDD::Result::Error
         | 
| 44 | 
            +
              class UnexpectedType < BCDD::Result::Contract::Error
         | 
| 45 | 
            +
                def self.build: (type: Symbol, allowed_types: Set[Symbol])
         | 
| 46 | 
            +
                    -> BCDD::Result::Contract::Error::UnexpectedType
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              class UnexpectedValue < BCDD::Result::Contract::Error
         | 
| 50 | 
            +
                def self.build: (type: Symbol, value: untyped, ?cause: Exception)
         | 
| 51 | 
            +
                  -> BCDD::Result::Contract::Error::UnexpectedValue
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
            end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            module BCDD::Result::Contract
         | 
| 56 | 
            +
              module Interface
         | 
| 57 | 
            +
                def ==: (BCDD::Result::Contract::Interface) -> bool
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                def allowed_types: -> Set[Symbol]
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def type?: (Symbol) -> bool
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def type!: (Symbol) -> Symbol
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                def type_and_value!: (BCDD::Result::Data) -> void
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                def !=: (untyped) -> bool
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
            end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            module BCDD::Result::Contract
         | 
| 72 | 
            +
              module Disabled
         | 
| 73 | 
            +
                extend Interface
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                EMPTY_SET: Set[Symbol]
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
            end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            module BCDD::Result::Contract
         | 
| 80 | 
            +
              class ForTypes
         | 
| 81 | 
            +
                include Interface
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                def initialize: (Array[Symbol]) -> void
         | 
| 84 | 
            +
              end
         | 
| 85 | 
            +
            end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            module BCDD::Result::Contract
         | 
| 88 | 
            +
              class ForTypesAndValues
         | 
| 89 | 
            +
                include Interface
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                def initialize: (
         | 
| 92 | 
            +
                  Hash[Symbol, untyped],
         | 
| 93 | 
            +
                  Hash[Symbol, Hash[Symbol, bool]]
         | 
| 94 | 
            +
                ) -> void
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                private
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                def nil_as_valid_value_checking?: -> bool
         | 
| 99 | 
            +
              end
         | 
| 100 | 
            +
            end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            module BCDD::Result::Contract
         | 
| 103 | 
            +
              class Evaluator
         | 
| 104 | 
            +
                include Interface
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                attr_reader allowed_types: Set[Symbol]
         | 
| 107 | 
            +
                attr_reader success: BCDD::Result::Contract::Interface
         | 
| 108 | 
            +
                attr_reader failure: BCDD::Result::Contract::Interface
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                def initialize: (
         | 
| 111 | 
            +
                  BCDD::Result::Contract::Interface,
         | 
| 112 | 
            +
                  BCDD::Result::Contract::Interface
         | 
| 113 | 
            +
                ) -> void
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                private
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                def for: (BCDD::Result::Data) -> BCDD::Result::Contract::Interface
         | 
| 118 | 
            +
              end
         | 
| 119 | 
            +
            end
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            class BCDD::Result
         | 
| 2 | 
            +
              class Data
         | 
| 3 | 
            +
                attr_reader kind: Symbol
         | 
| 4 | 
            +
                attr_reader type: Symbol
         | 
| 5 | 
            +
                attr_reader value: untyped
         | 
| 6 | 
            +
                attr_reader to_h: Hash[Symbol, untyped]
         | 
| 7 | 
            +
                attr_reader to_a: [Symbol, Symbol, untyped]
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def initialize: (Symbol, Symbol, untyped) -> void
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def inspect: -> String
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                alias to_ary to_a
         | 
| 14 | 
            +
                alias to_hash to_h
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            class BCDD::Result
         | 
| 2 | 
            +
              class Error < StandardError
         | 
| 3 | 
            +
                def self.build: (**untyped) -> BCDD::Result::Error
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                class NotImplemented < BCDD::Result::Error
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                class MissingTypeArgument < BCDD::Result::Error
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                class UnexpectedOutcome < BCDD::Result::Error
         | 
| 12 | 
            +
                  def self.build: (outcome: untyped, origin: Symbol, ?expected: String)
         | 
| 13 | 
            +
                      -> BCDD::Result::Error::UnexpectedOutcome
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                class InvalidResultSubject < BCDD::Result::Error
         | 
| 17 | 
            +
                  def self.build: (given_result: BCDD::Result, expected_subject: untyped)
         | 
| 18 | 
            +
                      -> BCDD::Result::Error::InvalidResultSubject
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                class InvalidSubjectMethodArity < BCDD::Result::Error
         | 
| 22 | 
            +
                  def self.build: (subject: untyped, method: Method, max_arity: Integer)
         | 
| 23 | 
            +
                    -> BCDD::Result::Error::InvalidSubjectMethodArity
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                class UnhandledTypes < BCDD::Result::Error
         | 
| 27 | 
            +
                  def self.build: (types: Set[Symbol])
         | 
| 28 | 
            +
                    -> BCDD::Result::Error::UnhandledTypes
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
            end
         | 
| @@ -0,0 +1,67 @@ | |
| 1 | 
            +
            class BCDD::Result::Expectations
         | 
| 2 | 
            +
              def self.mixin: (
         | 
| 3 | 
            +
                ?config: Hash[Symbol, Hash[Symbol, bool]],
         | 
| 4 | 
            +
                ?success: Hash[Symbol, untyped] | Array[Symbol],
         | 
| 5 | 
            +
                ?failure: Hash[Symbol, untyped] | Array[Symbol]
         | 
| 6 | 
            +
              ) -> Module
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def self.mixin!: (
         | 
| 9 | 
            +
                ?config: Hash[Symbol, Hash[Symbol, bool]],
         | 
| 10 | 
            +
                ?success: Hash[Symbol, untyped] | Array[Symbol],
         | 
| 11 | 
            +
                ?failure: Hash[Symbol, untyped] | Array[Symbol]
         | 
| 12 | 
            +
              ) -> Module
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def self.mixin_module: -> singleton(BCDD::Result::Expectations::Mixin)
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def self.result_factory_without_expectations: -> singleton(BCDD::Result)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def self.new: (
         | 
| 19 | 
            +
                ?subject: untyped,
         | 
| 20 | 
            +
                ?contract: BCDD::Result::Contract::Evaluator,
         | 
| 21 | 
            +
                ?halted: bool,
         | 
| 22 | 
            +
                **untyped
         | 
| 23 | 
            +
              ) -> (BCDD::Result::Expectations | untyped)
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def initialize: (
         | 
| 26 | 
            +
                ?subject: untyped,
         | 
| 27 | 
            +
                ?contract: BCDD::Result::Contract::Evaluator,
         | 
| 28 | 
            +
                ?halted: bool,
         | 
| 29 | 
            +
                **untyped
         | 
| 30 | 
            +
              ) -> void
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              def Success: (Symbol, ?untyped) -> BCDD::Result::Success
         | 
| 33 | 
            +
              def Failure: (Symbol, ?untyped) -> BCDD::Result::Failure
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              def with: (subject: untyped) -> BCDD::Result::Expectations
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              private
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              def _ResultAs: (singleton(BCDD::Result), Symbol, untyped) -> untyped
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              attr_reader subject: untyped
         | 
| 42 | 
            +
              attr_reader contract: BCDD::Result::Contract::Evaluator
         | 
| 43 | 
            +
              attr_reader halted: bool
         | 
| 44 | 
            +
            end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            module BCDD::Result::Expectations::Mixin
         | 
| 47 | 
            +
              module Factory
         | 
| 48 | 
            +
                def self.module!: -> Module
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              module Methods
         | 
| 52 | 
            +
                BASE: String
         | 
| 53 | 
            +
                FACTORY: String
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                def self.to_eval: (Hash[Symbol, untyped]) -> String
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              module Addons
         | 
| 59 | 
            +
                module Continuable
         | 
| 60 | 
            +
                  private def Continue: (untyped) -> BCDD::Result::Success
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                OPTIONS: Hash[Symbol, Module]
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                def self.options: (Hash[Symbol, Hash[Symbol, bool]]) -> Hash[Symbol, Module]
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
            end
         |