class Plumb::Schema

def self.wrap(sch = nil, &block)

def self.wrap(sch = nil, &block)
  raise ArgumentError, 'expected a block or a schema' if sch.nil? && !block_given?
  if sch
    raise ArgumentError, 'expected a Composable' unless sch.is_a?(Composable)
    return sch
  end
  new(&block)
end

def &(other)

def &(other)
  self.class.new(_hash & other._hash)
end

def +(other)

def +(other)
  self.class.new(_hash + other._hash)
end

def after(callable = nil, &block)

def after(callable = nil, &block)
  @after >>= callable || block
  self
end

def before(callable = nil, &block)

def before(callable = nil, &block)
  @before >>= callable || block
  self
end

def call(result)

def call(result)
  @pipeline.call(result)
end

def field(key, type = nil, &block)

def field(key, type = nil, &block)
  key = Key.new(key.to_sym)
  @fields[key] = Field.new(key, type, &block)
end

def field?(key, type = nil, &block)

def field?(key, type = nil, &block)
  key = Key.new(key.to_sym, optional: true)
  @fields[key] = Field.new(key, type, &block)
end

def finish

def finish
ine = @before.freeze >> @_hash.freeze >> @after.freeze

def initialize(hash = Types::Hash, &block)

def initialize(hash = Types::Hash, &block)
  @pipeline = Types::Any
  @before = Types::Any
  @after = Types::Any
  @_hash = hash
  @fields = @_hash._schema.each.with_object(SymbolAccessHash.new({})) do |(k, v), memo|
    memo[k] = Field.new(k, v)
  end
  setup(&block) if block_given?
  finish
end

def inspect

def inspect
  "#{self.class}#{fields.keys.inspect}"
end

def merge(other = nil, &block)

def merge(other = nil, &block)
  other = self.class.wrap(other, &block)
  self + other
end

def setup(&block)

def setup(&block)
lock.arity

d self

ance_eval(&block)
e ::ArgumentError, "#{self.class} expects a block with 0 or 1 argument, but got #{block.arity}"
 = Types::Hash.schema(@fields.transform_values(&:_type))

def to_json_schema

def to_json_schema
  _hash.to_json_schema(root: true)
end