class Typecheck::SignatureCompiler

Public Instance Methods

call(signature, method) click to toggle source
# File lib/typecheck.rb, line 10
def call(signature, method)
  unchecked_method = "#{method}_unchecked"
  check_args, check_out = parse_sig(signature)
  ->(*args) do
    check_args.(*args)
    __send__(unchecked_method, *args).tap do |result|
      check_out.(result)
    end
  end
end
check_array(type, array) click to toggle source
# File lib/typecheck.rb, line 78
def check_array(type, array)
  array.all? {|element| check_class(type, element) }
end
check_class(klz, value) click to toggle source
# File lib/typecheck.rb, line 87
def check_class(klz, value)
  value.is_a? klz
end
check_respond_to(method, value) click to toggle source
# File lib/typecheck.rb, line 69
def check_respond_to(method, value)
  value.respond_to?(method)
end
parse_sig(sig) click to toggle source
# File lib/typecheck.rb, line 21
def parse_sig(sig)
  in_t, out_t = sig.split('->').map(&:strip)
  in_ts = in_t.split(',')

  in_checks = in_ts.map(&method(:parse_type_list))
  out_check = parse_type_list(out_t)

  args_checker = ->(*args) {
    args.each.with_index do |arg, idx|
      in_checks[idx].(arg)
    end
  }
  [args_checker, out_check]
end
parse_type(subtype, check_or_raise) click to toggle source
# File lib/typecheck.rb, line 56
def parse_type(subtype, check_or_raise)
  pred_and subtype.split(';').map(&:strip).map { |type|
    case type
    when /#(.*)/
      method("#{check_or_raise}_respond_to").to_proc.curry.(type[1..-1])
    when /\[(.*)\]/
      method("#{check_or_raise}_array").to_proc.curry.(eval(type[1..-2]))
    else
      method("#{check_or_raise}_class").to_proc.curry.(eval(type))
    end
  }
end
parse_type_list(choices) click to toggle source
# File lib/typecheck.rb, line 44
def parse_type_list(choices)
  types = choices.split('|')
  pred_or [
    pred_or(types.map {|choice|
        parse_type(choice, :check)
      }),
    pred_or(types.map {|choice|
        parse_type(choice, :raise)
      })
  ]
end
pred_and(preds) click to toggle source
# File lib/typecheck.rb, line 40
def pred_and(preds)
  ->(value) { preds.all?{|pred| pred.(value) } }
end
pred_or(preds) click to toggle source
# File lib/typecheck.rb, line 36
def pred_or(preds)
  ->(value) { preds.any?{|pred| pred.(value) } }
end
raise_array(type, array) click to toggle source
# File lib/typecheck.rb, line 82
def raise_array(type, array)
  raise TypeError, "Bad type: expected #{array} to only contain #{type}" unless check_array(type, array)
  true
end
raise_class(klz, value) click to toggle source
# File lib/typecheck.rb, line 91
def raise_class(klz, value)
  raise TypeError, "Bad type: #{value.inspect}, expected #{klz}" unless check_class(klz, value)
  true
end
raise_respond_to(method, value) click to toggle source
# File lib/typecheck.rb, line 73
def raise_respond_to(method, value)
  raise TypeError, "Expected #{value.inspect}, to respond_to #{method}" unless check_respond_to(method, value)
  true
end