Sha256: 931dd06d559961948b3f6fc63b8942e2272cf1b23612c2156a2fcce3e0747560

Contents?: true

Size: 1.63 KB

Versions: 1

Compression:

Stored size: 1.63 KB

Contents

# frozen_string_literal: true

# This is a Ruby translation of clojure.spec:
#   https://github.com/clojure/clojure/blob/master/src/clj/clojure/spec.clj
# All credit belongs with Rich Hickey and contributors for their original work.

module Speculation
  # @private
  class OrSpec < Spec
    include NamespacedSymbols
    S = Speculation

    attr_reader :id

    def initialize(named_specs, gen = nil)
      @id = SecureRandom.uuid
      @named_specs = named_specs
      @keys = named_specs.keys
      @preds = preds = named_specs.values
      @gen = gen

      @delayed_specs = Concurrent::Delay.new do
        preds.map { |spec| S.send(:specize, spec) }
      end
    end

    def conform(value)
      @delayed_specs.value!.each_with_index do |spec, index|
        conformed = spec.conform(value)

        unless S.invalid?(conformed)
          return [@keys[index], conformed]
        end
      end

      S::INVALID
    end

    def explain(path, via, inn, value)
      return if S.pvalid?(self, value)

      @keys.zip(@preds).flat_map do |(key, pred)|
        next if S.pvalid?(pred, value)
        S.explain1(pred, Utils.conj(path, key), via, inn, value)
      end
    end

    def with_gen(gen)
      self.class.new(@named_specs, gen)
    end

    def gen(overrides, path, rmap)
      return @gen if @gen

      gs = @keys.zip(@preds).
        map { |(k, p)|
          rmap = S.inck(rmap, @id)

          unless S.recur_limit?(rmap, @id, path, k)
            Gen.delay { S.gensub(p, overrides, Utils.conj(path, k), rmap) }
          end
        }.
        compact

      unless gs.empty?
        ->(rantly) { rantly.branch(*gs) }
      end
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
speculation-0.4.0 lib/speculation/spec/or_spec.rb