Browse Source

Custom map types with no methods converted to objectGoMapReflect (closes #47).

Dmitry Panov 8 years ago
parent
commit
4e76d88204
4 changed files with 78 additions and 2 deletions
  1. 7 1
      README.md
  2. 45 0
      object_gomap_reflect_test.go
  3. 25 0
      object_goslice_reflect_test.go
  4. 1 1
      runtime.go

+ 7 - 1
README.md

@@ -61,10 +61,16 @@ the appropriate Go types. If conversion is not possible, a TypeError is thrown.
 
 
 A slice type is converted into a generic reflect based host object that behaves similar to an unexpandable Array.
 A slice type is converted into a generic reflect based host object that behaves similar to an unexpandable Array.
 
 
+A map type with numeric or string keys and no methods is converted into a host object where properties are map keys.
+
+A map type with methods is converted into a host object where properties are method names,
+the map values are not accessible. This is to avoid ambiguity between m\["Property"\] and m.Property.
+
 Any other type is converted to a generic reflect based host object. Depending on the underlying type it behaves similar
 Any other type is converted to a generic reflect based host object. Depending on the underlying type it behaves similar
 to a Number, String, Boolean or Object.
 to a Number, String, Boolean or Object.
 
 
-Note that the underlying type is not lost, calling Export() returns the original Go value. This applies to all
+Note that these conversions wrap the original value which means any changes made inside JS
+are reflected on the value and calling Export() returns the original value. This applies to all
 reflect based types.
 reflect based types.
 
 
 Exporting Values from JS
 Exporting Values from JS

+ 45 - 0
object_gomap_reflect_test.go

@@ -119,3 +119,48 @@ func TestGoMapReflectProto(t *testing.T) {
 		t.Fatalf("Expected true, got %v", v)
 		t.Fatalf("Expected true, got %v", v)
 	}
 	}
 }
 }
+
+type gomapReflect_noMethods map[string]interface{}
+type gomapReflect_withMethods map[string]interface{}
+
+func (m gomapReflect_withMethods) Method() bool {
+	return true
+}
+
+func TestGoMapReflectNoMethods(t *testing.T) {
+	const SCRIPT = `
+	typeof m === "object" && m.hasOwnProperty("t") && m.t === 42;
+	`
+
+	vm := New()
+	m := make(gomapReflect_noMethods)
+	m["t"] = 42
+	vm.Set("m", m)
+	v, err := vm.RunString(SCRIPT)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !v.StrictEquals(valueTrue) {
+		t.Fatalf("Expected true, got %v", v)
+	}
+
+}
+
+func TestGoMapReflectWithMethods(t *testing.T) {
+	const SCRIPT = `
+	typeof m === "object" && !m.hasOwnProperty("t") && m.hasOwnProperty("Method") && m.Method();
+	`
+
+	vm := New()
+	m := make(gomapReflect_withMethods)
+	m["t"] = 42
+	vm.Set("m", m)
+	v, err := vm.RunString(SCRIPT)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !v.StrictEquals(valueTrue) {
+		t.Fatalf("Expected true, got %v", v)
+	}
+
+}

+ 25 - 0
object_goslice_reflect_test.go

@@ -87,3 +87,28 @@ func TestGoSliceReflectProto(t *testing.T) {
 		t.Fatalf("Unexpected result: '%s'", s)
 		t.Fatalf("Unexpected result: '%s'", s)
 	}
 	}
 }
 }
+
+type gosliceReflect_withMethods []interface{}
+
+func (s gosliceReflect_withMethods) Method() bool {
+	return true
+}
+
+func TestGoSliceReflectMethod(t *testing.T) {
+	const SCRIPT = `
+	typeof a === "object" && a[0] === 42 && a.Method() === true;
+	`
+
+	vm := New()
+	a := make(gosliceReflect_withMethods, 1)
+	a[0] = 42
+	vm.Set("a", a)
+	v, err := vm.RunString(SCRIPT)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !v.StrictEquals(valueTrue) {
+		t.Fatalf("Expected true, got %v", v)
+	}
+
+}

+ 1 - 1
runtime.go

@@ -1005,7 +1005,7 @@ func (r *Runtime) ToValue(i interface{}) Value {
 
 
 	switch value.Kind() {
 	switch value.Kind() {
 	case reflect.Map:
 	case reflect.Map:
-		if value.Type().Name() == "" {
+		if value.Type().NumMethod() == 0 {
 			switch value.Type().Key().Kind() {
 			switch value.Type().Key().Kind() {
 			case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
 			case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
 				reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
 				reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,