class ExecJS::JohnsonRuntime::Context

def array?(value)

def array?(value)
  array_test.call(value)
end

def array_test

def array_test
  @array_test ||= @runtime.evaluate("(function(a) {return a instanceof [].constructor})")
end

def call(properties, *args)

def call(properties, *args)
  unbox @runtime.evaluate(properties).call(*args)
rescue Johnson::Error => e
  if syntax_error?(e)
    raise RuntimeError, e.message
  else
    raise ProgramError, e.message
  end
end

def eval(source, options = {})

def eval(source, options = {})
  source = encode(source)
  if /\S/ =~ source
    unbox @runtime.evaluate("(#{source})")
  end
rescue Johnson::Error => e
  if syntax_error?(e)
    raise RuntimeError, e.message
  else
    raise ProgramError, e.message
  end
end

def exec(source, options = {})

def exec(source, options = {})
  source = encode(source)
  if /\S/ =~ source
    eval "(function(){#{source}})()", options
  end
end

def function?(value)

def function?(value)
  value.respond_to?(:function?) && value.function?
end

def initialize(runtime, source = "")

def initialize(runtime, source = "")
  source = encode(source)
  @runtime = Johnson::Runtime.new
  @runtime.evaluate(source)
end

def object?(value)

def object?(value)
  value.respond_to?(:inject)
end

def string?(value)

def string?(value)
  value.is_a?(String)
end

def syntax_error?(error)

def syntax_error?(error)
  error.message =~ /^syntax error at /
end

def unbox(value)

def unbox(value)
  case
  when function?(value)
    nil
  when string?(value)
    value.respond_to?(:force_encoding) ?
      value.force_encoding('UTF-8') :
      value
  when array?(value)
    value.map { |v| unbox(v) }
  when object?(value)
    value.inject({}) do |vs, (k, v)|
      vs[k] = unbox(v) unless function?(v)
      vs
    end
  else
    value
  end
end