Browse Source

Added documentation about calling JS functions from Go. See #71.

Dmitry Panov 5 years ago
parent
commit
3cddd0f5c3
3 changed files with 112 additions and 21 deletions
  1. 54 2
      README.md
  2. 1 0
      runtime.go
  3. 57 19
      runtime_test.go

+ 54 - 2
README.md

@@ -103,16 +103,68 @@ if num := v.Export().(int64); num != 4 {
 
 
 Passing Values to JS
 Passing Values to JS
 --------------------
 --------------------
-
 Any Go value can be passed to JS using Runtime.ToValue() method. See the method's [documentation](https://godoc.org/github.com/dop251/goja#Runtime.ToValue) for more details.
 Any Go value can be passed to JS using Runtime.ToValue() method. See the method's [documentation](https://godoc.org/github.com/dop251/goja#Runtime.ToValue) for more details.
 
 
 Exporting Values from JS
 Exporting Values from JS
 ------------------------
 ------------------------
-
 A JS value can be exported into its default Go representation using Value.Export() method.
 A JS value can be exported into its default Go representation using Value.Export() method.
 
 
 Alternatively it can be exported into a specific Go variable using Runtime.ExportTo() method.
 Alternatively it can be exported into a specific Go variable using Runtime.ExportTo() method.
 
 
+Calling JS functions from Go
+----------------------------
+There are 2 approaches:
+
+- Using [AssertFunction()](https://godoc.org/github.com/dop251/goja#AssertFunction):
+```go
+vm := New()
+_, err := vm.RunString(`
+function sum(a, b) {
+    return a+b;
+}
+`)
+if err != nil {
+    panic(err)
+}
+sum, ok := AssertFunction(vm.Get("sum"))
+if !ok {
+    panic("Not a function")
+}
+
+res, err := sum(Undefined(), vm.ToValue(40), vm.ToValue(2))
+if err != nil {
+    panic(err)
+}
+fmt.Println(res)
+// Output: 42
+```
+- Using [Runtime.ExportTo()](https://godoc.org/github.com/dop251/goja#Runtime.ExportTo):
+```go
+const SCRIPT = `
+function f(param) {
+    return +param + 2;
+}
+`
+
+vm := New()
+_, err := vm.RunString(SCRIPT)
+if err != nil {
+    panic(err)
+}
+
+var fn func(string) string
+err = vm.ExportTo(vm.Get("f"), &fn)
+if err != nil {
+    panic(err)
+}
+
+fmt.Println(fn("40")) // note, _this_ value in the function will be undefined.
+// Output: 42
+```
+
+The first one is more low level and allows specifying _this_ value, whereas the second one makes the function look like
+a normal Go function.
+
 Mapping struct field and method names
 Mapping struct field and method names
 -------------------------------------
 -------------------------------------
 By default, the names are passed through as is which means they are capitalised. This does not match
 By default, the names are passed through as is which means they are capitalised. This does not match

+ 1 - 0
runtime.go

@@ -1240,6 +1240,7 @@ Note that because a wrapper is created every time a property is accessed it may
  field1 === field2; // true, because the equality operation compares the wrapped values, not the wrappers
  field1 === field2; // true, because the equality operation compares the wrapped values, not the wrappers
  field1[sym] === true; // true
  field1[sym] === true; // true
  field2[sym] === undefined; // also true
  field2[sym] === undefined; // also true
+ `)
 
 
 The same applies to values from maps and slices as well.
 The same applies to values from maps and slices as well.
 
 

+ 57 - 19
runtime_test.go

@@ -553,7 +553,7 @@ func TestRuntime_ExportToTime(t *testing.T) {
 	}
 	}
 }
 }
 
 
-func TestRuntime_ExportToFunc(t *testing.T) {
+func ExampleRuntime_ExportTo_func() {
 	const SCRIPT = `
 	const SCRIPT = `
 	function f(param) {
 	function f(param) {
 		return +param + 2;
 		return +param + 2;
@@ -563,18 +563,20 @@ func TestRuntime_ExportToFunc(t *testing.T) {
 	vm := New()
 	vm := New()
 	_, err := vm.RunString(SCRIPT)
 	_, err := vm.RunString(SCRIPT)
 	if err != nil {
 	if err != nil {
-		t.Fatal(err)
+		panic(err)
 	}
 	}
 
 
 	var fn func(string) string
 	var fn func(string) string
-	vm.ExportTo(vm.Get("f"), &fn)
-
-	if res := fn("40"); res != "42" {
-		t.Fatalf("Unexpected value: %q", res)
+	err = vm.ExportTo(vm.Get("f"), &fn)
+	if err != nil {
+		panic(err)
 	}
 	}
+
+	fmt.Println(fn("40")) // note, _this_ value in the function will be undefined.
+	// Output: 42
 }
 }
 
 
-func TestRuntime_ExportToFuncThrow(t *testing.T) {
+func ExampleRuntime_ExportTo_funcThrow() {
 	const SCRIPT = `
 	const SCRIPT = `
 	function f(param) {
 	function f(param) {
 		throw new Error("testing");
 		throw new Error("testing");
@@ -584,26 +586,39 @@ func TestRuntime_ExportToFuncThrow(t *testing.T) {
 	vm := New()
 	vm := New()
 	_, err := vm.RunString(SCRIPT)
 	_, err := vm.RunString(SCRIPT)
 	if err != nil {
 	if err != nil {
-		t.Fatal(err)
+		panic(err)
 	}
 	}
 
 
 	var fn func(string) (string, error)
 	var fn func(string) (string, error)
 	err = vm.ExportTo(vm.Get("f"), &fn)
 	err = vm.ExportTo(vm.Get("f"), &fn)
 	if err != nil {
 	if err != nil {
-		t.Fatal(err)
+		panic(err)
 	}
 	}
+	_, err = fn("")
 
 
-	if _, err := fn("40"); err != nil {
-		if ex, ok := err.(*Exception); ok {
-			if msg := ex.Error(); msg != "Error: testing at f (<eval>:3:9(4))" {
-				t.Fatalf("Msg: %q", msg)
-			}
-		} else {
-			t.Fatalf("Error is not *Exception (%T): %v", err, err)
-		}
-	} else {
-		t.Fatal("Expected error")
+	fmt.Println(err)
+	// Output: Error: testing at f (<eval>:3:9(4))
+}
+
+func ExampleRuntime_ExportTo_funcVariadic() {
+	const SCRIPT = `
+	function f() {
+		return Array.prototype.join.call(arguments, ",");
 	}
 	}
+	`
+	vm := New()
+	_, err := vm.RunString(SCRIPT)
+	if err != nil {
+		panic(err)
+	}
+
+	var fn func(args ...interface{}) string
+	err = vm.ExportTo(vm.Get("f"), &fn)
+	if err != nil {
+		panic(err)
+	}
+	fmt.Println(fn("a", "b", 42))
+	// Output: a,b,42
 }
 }
 
 
 func TestRuntime_ExportToFuncFail(t *testing.T) {
 func TestRuntime_ExportToFuncFail(t *testing.T) {
@@ -683,6 +698,29 @@ func TestRuntime_ExportToObject(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func ExampleAssertFunction() {
+	vm := New()
+	_, err := vm.RunString(`
+	function sum(a, b) {
+		return a+b;
+	}
+	`)
+	if err != nil {
+		panic(err)
+	}
+	sum, ok := AssertFunction(vm.Get("sum"))
+	if !ok {
+		panic("Not a function")
+	}
+
+	res, err := sum(Undefined(), vm.ToValue(40), vm.ToValue(2))
+	if err != nil {
+		panic(err)
+	}
+	fmt.Println(res)
+	// Output: 42
+}
+
 func TestGoFuncError(t *testing.T) {
 func TestGoFuncError(t *testing.T) {
 	const SCRIPT = `
 	const SCRIPT = `
 	try {
 	try {