class Spruz::Bijection

def self.[](*pairs)

def self.[](*pairs)
  pairs.size % 2 == 0 or
    raise ArgumentError, "odd number of arguments for #{self}"
  new.fill do |obj|
    (pairs.size / 2).times do |i|
      j = 2 * i
      key = pairs[j]
      value = pairs[j + 1]
      obj.key?(key) and raise ArgumentError, "duplicate key #{key.inspect} for #{self}"
      obj.inverted.key?(value) and raise ArgumentError, "duplicate value #{value.inspect} for #{self}"
      obj[pairs[j]] = pairs[j + 1]
    end
  end
end

def []=(key, value)

def []=(key, value)
  key?(key) and return
  super
  @inverted[value] = key
end

def fill

def fill
  if empty?
    yield self
    freeze
  end
  self
end

def freeze

def freeze
  r = super
  unless @inverted.frozen?
    @inverted.freeze
  end
  r
end

def initialize(inverted = Bijection.new(self))

def initialize(inverted = Bijection.new(self))
  @inverted = inverted
end