class Syntropy::ModuleLoader

def initialize(root, env)

def initialize(root, env)
  @root = root
  @env = env
  @loaded = {} # maps ref to code
  @fn_map = {} # maps filename to ref
end

def invalidate(fn)

def invalidate(fn)
  ref = @fn_map[fn]
  return if !ref
  @loaded.delete(ref)
  @fn_map.delete(fn)
end

def load(ref)

def load(ref)
  @loaded[ref] ||= load_module(ref)
end

def load_module(ref)

def load_module(ref)
  fn = File.expand_path(File.join(@root, "#{ref}.rb"))
  @fn_map[fn] = ref
  raise "File not found #{fn}" if !File.file?(fn)
  mod_body = IO.read(fn)
  mod_ctx = Class.new(Syntropy::Module)
  mod_ctx.prepare(loader: self, env: @env)
  mod_ctx.module_eval(mod_body, fn, 1)
  export_value = mod_ctx.__export_value__
  wrap_module(mod_ctx, export_value)
end

def wrap_module(mod_ctx, export_value)

def wrap_module(mod_ctx, export_value)
  case export_value
  when nil
    raise 'No export found'
  when Symbol
    o = mod_ctx.new(@env)
    # TODO: verify export_value denotes a valid method
    ->(req) { o.send(export_value, req) }
  when String
    ->(req) { req.respond(export_value) }
  when Proc
    export_value
  else
    export_value.new(@env)
  end
end