class Jet::Contract

Constants

FLATTEN_ERROR_TYPES
MAJOR
MINOR
TINY
VERSION

Attributes

checks[R]
types[R]

Public Class Methods

build(*args, &blk) click to toggle source
# File lib/jet/contract.rb, line 19
def build(*args, &blk)
  raise ArgumentError, "no block given" unless block_given?
  Builder.new.tap { |b| b.instance_eval(&blk) }.call(*args)
end
checks!(checks) click to toggle source
# File lib/jet/contract.rb, line 24
def checks!(checks)
  validate_registry!("checks", checks, Check, :eql)
end
checks=(checks) click to toggle source
# File lib/jet/contract.rb, line 28
def checks=(checks)
  @checks = checks!(checks)
end
new(attributes, keys_in: [String, Symbol], keys_out: :to_sym, **) click to toggle source
# File lib/jet/contract.rb, line 57
def initialize(attributes, keys_in: [String, Symbol], keys_out: :to_sym, **)
  @attributes = Jet.type_check_hash!("`attributes`", attributes, Attribute)
                   .transform_keys(&:to_s)

  @opts = { keys_in: _keys_in(keys_in), keys_out: _keys_out(keys_out) }
end
types!(types) click to toggle source
# File lib/jet/contract.rb, line 32
def types!(types)
  case types
  when :http
    Type::HTTP
  when :json
    Type::JSON
  when :strict
    Type::Strict
  else
    validate_registry!("types", types, Type, :string)
  end
end
types=(types) click to toggle source
# File lib/jet/contract.rb, line 45
def types=(types)
  @types = types!(types)
end
version() click to toggle source
# File lib/jet/contract/version.rb, line 10
def self.version
  VERSION
end

Private Class Methods

validate_registry!(name, registry, type, key) click to toggle source
# File lib/jet/contract.rb, line 51
def validate_registry!(name, registry, type, key)
  return registry if registry.respond_to?(:[]) && registry[key].is_a?(type)
  raise ArgumentError, "`#{name}` must be a registry of #{type}"
end

Public Instance Methods

[](key) click to toggle source
# File lib/jet/contract.rb, line 69
def [](key)
  @attributes[key]
end
attributes() click to toggle source
# File lib/jet/contract.rb, line 73
def attributes
  @attributes.dup
end
call(input, **) click to toggle source
# File lib/jet/contract.rb, line 64
def call(input, **)
  results = check_attributes(filter_keys(input.to_h))
  failure(results, input) || success(results)
end
opts() click to toggle source
# File lib/jet/contract.rb, line 77
def opts
  @opts.dup
end
rebuild(*args) click to toggle source
# File lib/jet/contract.rb, line 81
def rebuild(*args)
  to_builder.(*args)
end
to_builder() click to toggle source
# File lib/jet/contract.rb, line 85
def to_builder
  Builder.new(@attributes.transform_values(&:to_builder))
end
with(*other_contracts, **opts) click to toggle source
# File lib/jet/contract.rb, line 89
def with(*other_contracts, **opts)
  Jet.type_check_each!("`other_contracts`", other_contracts, Contract)

  self.class.new(
    other_contracts.each_with_object(attributes) { |c, atts| atts.merge!(c.attributes) },
    **self.opts.merge(opts)
  )
end

Private Instance Methods

_keys_in(classes) click to toggle source
# File lib/jet/contract.rb, line 100
def _keys_in(classes)
  Array(classes).map do |c|
    next String if c == :string
    next Symbol if c == :symbol
    Jet.type_check!(":keys_in element #{c}", Class, Module)
    c
  end.uniq
end
_keys_out(key_type) click to toggle source
# File lib/jet/contract.rb, line 109
def _keys_out(key_type)
  if [Symbol, :symbol, :to_sym].include?(key_type)
    :to_sym
  elsif [String, :string, :to_s].include?(key_type)
    :to_s
  else
    raise ArgumentError, ":keys_out must equal either :symbol or :string"
  end
end
check_attributes(input) click to toggle source
# File lib/jet/contract.rb, line 119
def check_attributes(input)
  @attributes.each_with_object({}) do |(k, att), h|
    if input.key?(k)
      h[k] = att.(input[k], k.to_sym)
    else
      next if att.optional?
      h[k] = Result.failure(:key_missing_failure, at: k.to_sym)
    end
  end
end
failure(results, input) click to toggle source
# File lib/jet/contract.rb, line 130
def failure(results, input)
  return unless results.values.any?(&:failure?)
  Result.failure(
    :contract_validation_failure,
    errors: flatten_errors(results.values),
    input: input
  )
end
filter_keys(input) click to toggle source
# File lib/jet/contract.rb, line 139
def filter_keys(input)
  input.select { |k, _| @opts[:keys_in].any? { |t| k.is_a?(t) } }
       .transform_keys(&:to_s)
       .select { |k, _| attributes.keys.include?(k) }
end
flatten_errors(results) click to toggle source
# File lib/jet/contract.rb, line 145
def flatten_errors(results)
  results.select(&:failure?).each_with_object([]) do |r, errs|
    next errs.concat(flatten_errors(r.errors)) if FLATTEN_ERROR_TYPES.include?(r.output)
    errs << r
  end
end
success(results) click to toggle source
# File lib/jet/contract.rb, line 152
def success(results)
  results
    .each_with_object({}) { |(k, r), h| h[k.send(opts[:keys_out])] = r.output }
    .yield_self { |output| Result.success(output) }
end