class JS::Proxy

def [](index)

def [](index)
  val = native[index]
  wrap_result(val)
end

def []=(k, v)

def []=(k, v)
  native[k] = v
  wrap_result(native)
end

def each

def each
  return enum_for(:each) unless respond_to?(:length)
  length = self.length
  (0...length).each do |i|
    yield self[i]
  end
end

def existing_property?(property)

def existing_property?(property)
  `#{property} in #{to_n}`
end

def initialize(native)

def initialize(native)
  @native = Native(native)
end

def length

def length
  native.length
end

def method_missing(name, *args, &block)

def method_missing(name, *args, &block)
  js_name = to_js_name(name)
  unless existing_property?(js_name) || js_name.end_with?("=")
    raise NoMethodError, "undefined method `#{name}` for #{self}"
  end
  if js_name.end_with?("=")
    prop = js_name[0..-2]
    native[prop] = args.first
  else
    val = native[js_name]
    if `typeof val === 'function'`
      js_args = args.dup
      if block
        js_callback = %x{
          function() {
            let args = Array.prototype.slice.call(arguments);
            return #{block.call(self.class.new(`this`), *args)};
          }
        }
        js_args << js_callback
      end
      result = `val.apply(#{to_n}, #{js_args.to_n})`
      wrap_result(result)
    elsif `typeof val === 'object' && val !== null`
      wrap_result(val)
    else
      val
    end
  end
end

def respond_to_missing?(name, include_private = false)

def respond_to_missing?(name, include_private = false)
  true
end

def to_js_name(name)

def to_js_name(name)
  name.to_s.split('_').map.with_index do |part, index|
    if IRREGULARS.include? part.gsub("=", "").downcase
      part.upcase
    else
      index.zero? ? part : part.capitalize
    end
  end.join
end

def to_n

def to_n
  native.to_n
end

def to_rb_name(name)

def to_rb_name(name)
  name
    .to_s
    .gsub(/([A-Z]+)/) { "_#{$1.downcase}" }
    .sub(/^_/, '')
end

def to_str

def to_str
  `#{to_n}.toString()`
end