lib/speculation/spec_impl/every_spec.rb in speculation-0.1.0 vs lib/speculation/spec_impl/every_spec.rb in speculation-0.2.0

- old
+ new

@@ -1,12 +1,10 @@ # frozen_string_literal: true module Speculation - using NamespacedSymbols.refine(self) - using Conj - # @private class EverySpec < SpecImpl + include NamespacedSymbols S = Speculation def initialize(predicate, options) @predicate = predicate @options = options @@ -22,57 +20,57 @@ coll.count.between?(min, max) end) end - @collection_predicate = ->(coll) { collection_predicates.all? { |f| f === coll } } + @collection_predicate = ->(coll) { collection_predicates.all? { |f| f.respond_to?(:call) ? f.call(coll) : f === coll } } @delayed_spec = Concurrent::Delay.new { S.send(:specize, predicate) } - @kfn = options.fetch(:kfn.ns, ->(i, _v) { i }) + @kfn = options.fetch(ns(S, :kfn), ->(i, _v) { i }) @conform_keys, @conform_all, @kind, @gen_into, @gen_max, @distinct, @count, @min_count, @max_count = - options.values_at(:conform_keys, :conform_all.ns, :kind, :into, :gen_max, :distinct, :count, :min_count, :max_count) + options.values_at(:conform_keys, ns(S, :conform_all), :kind, :into, :gen_max, :distinct, :count, :min_count, :max_count) @gen_max ||= 20 @conform_into = @gen_into # returns a tuple of [init add complete] fns @cfns = ->(x) do if Utils.array?(x) && (!@conform_into || Utils.array?(@conform_into)) - [:itself.to_proc, + [Utils.method(:itself), ->(ret, i, v, cv) { v.equal?(cv) ? ret : ret.tap { |r| r[i] = cv } }, - :itself.to_proc] + Utils.method(:itself)] elsif Utils.hash?(x) && ((@kind && !@conform_into) || Utils.hash?(@conform_into)) - [@conform_keys ? Utils.method(:empty) : :itself.to_proc, + [@conform_keys ? Utils.method(:empty) : Utils.method(:itself), ->(ret, _i, v, cv) { if v.equal?(cv) && !@conform_keys ret else ret.merge((@conform_keys ? cv : v).first => cv.last) end }, - :itself.to_proc] + Utils.method(:itself)] else [->(init) { Utils.empty(@conform_into || init) }, - ->(ret, _i, _v, cv) { ret.conj(cv) }, - :itself.to_proc] + ->(ret, _i, _v, cv) { Utils.conj(ret, cv) }, + Utils.method(:itself)] end end end def conform(value) - return :invalid.ns unless @collection_predicate.call(value) + return ns(S, :invalid) unless @collection_predicate.call(value) - spec = @delayed_spec.value + spec = @delayed_spec.value! if @conform_all init, add, complete = @cfns.call(value) return_value = init.call(value) value.each_with_index do |val, index| conformed_value = spec.conform(val) if S.invalid?(conformed_value) - return :invalid.ns + return ns(S, :invalid) else return_value = add.call(return_value, index, val, conformed_value) end end @@ -81,28 +79,28 @@ # OPTIMIZE: check if value is indexed (array, hash etc.) vs not indexed (list, custom enumerable) limit = S.coll_check_limit value.each_with_index do |item, index| return value if index == limit - return :invalid.ns unless S.valid?(spec, item) + return ns(S, :invalid) unless S.valid?(spec, item) end value end end def explain(path, via, inn, value) probs = collection_problems(value, @kind, @distinct, @count, @min_count, @max_count, path, via, inn) return probs if probs - spec = @delayed_spec.value + spec = @delayed_spec.value! probs = value.lazy.each_with_index.flat_map { |v, i| k = @kfn.call(i, v) unless S.valid?(spec, v) - S.explain1(@predicate, path, via, inn.conj(k), v) + S.explain1(@predicate, path, via, Utils.conj(inn, k), v) end } probs = @conform_all ? probs.to_a : probs.take(S.coll_error_limit) probs.compact @@ -156,21 +154,23 @@ unless S.pvalid?(pred, x) return S.explain1(pred, path, via, inn, x) end - if count && count != x.count - return [{ :path => path, :pred => "count == x.count", :val => x, :via => via, :in => inn }] + if count && !Utils.count_eq?(x, count) + return [{ :path => path, :pred => [Utils.method(:count_eq?), [x, count]], :val => x, :via => via, :in => inn }] end if min_count || max_count - if x.count.between?(min_count || 0, max_count || Float::Infinity) - return [{ :path => path, :pred => "count.between?(min_count || 0, max_count || Float::Infinity)", :val => x, :via => via, :in => inn }] + min_count ||= 0 + max_count ||= Float::INFINITY + unless Utils.count_between?(x, min_count, max_count) + return [{ :path => path, :pred => [Utils.method(:count_between?), [x, min_count, max_count]], :val => x, :via => via, :in => inn }] end end - if distinct && !x.empty? && Utils.distinct?(x) - [{ :path => path, :pred => "distinct?", :val => x, :via => via, :in => inn }] + if distinct && !x.empty? && !Utils.distinct?(x) + [{ :path => path, :pred => [Utils.method(:distinct?), [x]], :val => x, :via => via, :in => inn }] end end end end