Sha256: ff74d7a14080907df661d50368fa3ac13ed23509c7c33146a284f5b54490a1ad

Contents?: true

Size: 1.98 KB

Versions: 1

Compression:

Stored size: 1.98 KB

Contents

module BloodContracts
  module Core
    class Pipe < Refined
      class << self
        attr_reader :steps, :names, :finalized

        def new(*args)
          return super(*args) if finalized
          if args.last.is_a?(Hash)
            names = args.pop.delete(:names)
          end
          names ||= []

          raise ArgumentError unless args.all?(Class)
          pipe = Class.new(Pipe) { def inspect; super; end }
          pipe.instance_variable_set(:@steps, args)
          pipe.instance_variable_set(:@names, names)
          pipe.instance_variable_set(:@finalized, true)
          pipe
        end

        def and_then(other_type)
          raise ArgumentError unless Class === other_type
          pipe = Class.new(Pipe) { def inspect; super; end }
          pipe.instance_variable_set(:@steps, args)
          pipe.instance_variable_set(:@names, kwargs[:names].to_a)
          pipe.instance_variable_set(:@finalized, true)
          pipe
        end
        alias :> :and_then
      end

      def match
        super do
          index = 0
          self.class.steps.reduce(value) do |next_value, step|
            unpacked_value = unpack_refined(next_value)
            match = step.match(unpacked_value)

            share_context_with(match) do |context|
              context[:steps][step_name(index)] = unpacked_value
              index += 1
            end

            break match if match.invalid?
            next refine_value(yield(match)) if block_given?
            match
          end
        end
      end

      private

      def step_name(index)
        self.class.names[index] || index
      end

      def steps_with_names
        steps = if self.class.names.empty?
                  self.class.steps.map(&:to_s)
                else
                  self.class.steps.zip(self.class.names).map { |k, n| "#{k}(#{n})" }
                end
      end

      def inspect
        "#<pipe #{self.class.name} = #{steps_with_names.join(' > ')} (value=#{@value})>"
      end
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
blood_contracts-core-0.2.1 lib/blood_contracts/core/pipe.rb