lib/speculation/spec_impl/hash_spec.rb in speculation-0.1.0 vs lib/speculation/spec_impl/hash_spec.rb in speculation-0.2.0
- old
+ new
@@ -1,12 +1,10 @@
# frozen_string_literal: true
module Speculation
- using Speculation::NamespacedSymbols.refine(self)
- using Conj
-
# @private
class HashSpec < SpecImpl
+ include NamespacedSymbols
S = Speculation
attr_reader :id
def initialize(req, opt, req_un, opt_un)
@@ -17,31 +15,32 @@
@opt_un = opt_un
req_keys = req.flat_map(&method(:extract_keys))
req_un_specs = req_un.flat_map(&method(:extract_keys))
- unless (req_keys + req_un_specs + opt + opt_un).all? { |s| s.is_a?(Symbol) && s.namespace }
+ all_keys = req_keys + req_un_specs + opt + opt_un
+ unless all_keys.all? { |s| s.is_a?(Symbol) && NamespacedSymbols.namespace(s) }
raise "all keys must be namespaced Symbols"
end
req_specs = req_keys + req_un_specs
req_keys += req_un_specs.map(&method(:unqualify_key))
pred_exprs = [Utils.method(:hash?)]
- pred_exprs.push(->(v) { parse_req(req, v, :itself.to_proc) == true }) if req.any?
- pred_exprs.push(->(v) { parse_req(req_un, v, method(:unqualify_key)) == true }) if req_un.any?
+ pred_exprs.push(->(v) { parse_req(req, v, Utils.method(:itself)).empty? }) if req.any?
+ pred_exprs.push(->(v) { parse_req(req_un, v, method(:unqualify_key)).empty? }) if req_un.any?
@req_keys = req_keys
@req_specs = req_specs
@opt_keys = opt + opt_un.map(&method(:unqualify_key))
@opt_specs = opt + opt_un
@keys_pred = ->(v) { pred_exprs.all? { |p| p.call(v) } }
@key_to_spec_map = Hash[req_keys.concat(@opt_keys).zip(req_specs.concat(@opt_specs))]
end
def conform(value)
- return :invalid.ns unless @keys_pred.call(value)
+ return ns(S, :invalid) unless @keys_pred.call(value)
reg = S.registry
ret = value
value.each do |key, v|
@@ -51,11 +50,11 @@
next unless spec
conformed_value = S.conform(spec, v)
if S.invalid?(conformed_value)
- return :invalid.ns
+ return ns(S, :invalid)
else
unless conformed_value.equal?(v)
ret = ret.merge(key => conformed_value)
end
end
@@ -64,42 +63,39 @@
ret
end
def explain(path, via, inn, value)
unless Utils.hash?(value)
- return [{ :path => path, :pred => :hash?, :val => value, :via => via, :in => inn }]
+ return [{ :path => path, :pred => [Utils.method(:hash?), [value]], :val => value, :via => via, :in => inn }]
end
problems = []
if @req.any?
- valid_or_failure = parse_req(@req, value, :itself.to_proc)
+ failures = parse_req(@req, value, Utils.method(:itself))
- unless valid_or_failure == true
- valid_or_failure.each do |failure_sexp|
- pred = sexp_to_rb(failure_sexp)
- problems << { :path => path, :pred => pred, :val => value, :via => via, :in => inn }
- end
+ failures.each do |failure_sexp|
+ # eww
+ pred = [Utils.method(:key?), [sexp_to_rb(failure_sexp)]]
+ problems << { :path => path, :pred => pred, :val => value, :via => via, :in => inn }
end
end
if @req_un.any?
- valid_or_failure = parse_req(@req_un, value, method(:unqualify_key))
+ failures = parse_req(@req_un, value, method(:unqualify_key))
- unless valid_or_failure == true
- valid_or_failure.each do |failure_sexp|
- pred = sexp_to_rb(failure_sexp)
- problems << { :path => path, :pred => pred, :val => value, :via => via, :in => inn }
- end
+ failures.each do |failure_sexp|
+ pred = [Utils.method(:key?), [sexp_to_rb(failure_sexp)]]
+ problems << { :path => path, :pred => pred, :val => value, :via => via, :in => inn }
end
end
problems += value.flat_map { |(k, v)|
next unless S.registry.key?(@key_to_spec_map[k])
unless S.pvalid?(@key_to_spec_map.fetch(k), v)
- S.explain1(@key_to_spec_map.fetch(k), path.conj(k), via, inn.conj(k), v)
+ S.explain1(@key_to_spec_map.fetch(k), Utils.conj(path, k), via, Utils.conj(inn, k), v)
end
}
problems.compact
end
@@ -113,25 +109,25 @@
rmap = S.inck(rmap, @id)
reqs = @req_keys.zip(@req_specs).
reduce({}) { |m, (k, s)|
- m.merge(k => S.gensub(s, overrides, path.conj(k), rmap))
+ m.merge(k => S.gensub(s, overrides, Utils.conj(path, k), rmap))
}
opts = @opt_keys.zip(@opt_specs).
reduce({}) { |m, (k, s)|
if S.recur_limit?(rmap, @id, path, k)
m
else
- m.merge(k => Gen.delay { S.gensub(s, overrides, path.conj(k), rmap) })
+ m.merge(k => Gen.delay { S.gensub(s, overrides, Utils.conj(path, k), rmap) })
end
}
->(rantly) do
count = rantly.range(0, opts.count)
- opts = opts.to_a.shuffle.take(count).to_h
+ opts = Hash[opts.to_a.shuffle.take(count)]
reqs.merge(opts).each_with_object({}) { |(k, spec_gen), h|
h[k] = spec_gen.call(rantly)
}
end
@@ -146,21 +142,21 @@
rb_string << "(" unless level.zero?
keys.each_with_index do |key, i|
unless i.zero?
- rb_string << " #{op.name} "
+ rb_string << " #{NamespacedSymbols.name(op)} "
end
- rb_string << sexp_to_rb(key, level + 1)
+ rb_string << sexp_to_rb(key, level + 1).to_s
end
rb_string << ")" unless level.zero?
rb_string
else
- ":#{sexp}"
+ sexp
end
end
def extract_keys(symbol_or_arr)
if symbol_or_arr.is_a?(Array)
@@ -169,45 +165,41 @@
symbol_or_arr
end
end
def unqualify_key(x)
- x.name.to_sym
+ NamespacedSymbols.name(x).to_sym
end
def parse_req(ks, v, f)
key, *ks = ks
ret = if key.is_a?(Array)
op, *kks = key
case op
- when :or.ns
- if kks.one? { |k| parse_req([k], v, f) == true }
- true
+ when ns(S, :or)
+ if kks.one? { |k| parse_req([k], v, f).empty? }
+ []
else
[key]
end
- when :and.ns
- if kks.all? { |k| parse_req([k], v, f) == true }
- true
+ when ns(S, :and)
+ if kks.all? { |k| parse_req([k], v, f).empty? }
+ []
else
[key]
end
else
raise "Expected or, and, got #{op}"
end
elsif v.key?(f.call(key))
- true
+ []
else
[key]
end
if ks.any?
- if ret == true
- parse_req(ks, v, f)
- else
- ret + parse_req(ks, v, f)
- end
+ ret + parse_req(ks, v, f)
else
ret
end
end
end