Browse Source

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

Dmitry Panov 5 năm trước cách đây
mục cha
commit
3cddd0f5c3
3 tập tin đã thay đổi với 112 bổ sung21 xóa
  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
 --------------------
-
 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
 ------------------------
-
 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.
 
+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
 -------------------------------------
 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[sym] === true; // true
  field2[sym] === undefined; // also true
+ `)
 
 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 = `
 	function f(param) {
 		return +param + 2;
@@ -563,18 +563,20 @@ func TestRuntime_ExportToFunc(t *testing.T) {
 	vm := New()
 	_, err := vm.RunString(SCRIPT)
 	if err != nil {
-		t.Fatal(err)
+		panic(err)
 	}
 
 	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 = `
 	function f(param) {
 		throw new Error("testing");
@@ -584,26 +586,39 @@ func TestRuntime_ExportToFuncThrow(t *testing.T) {
 	vm := New()
 	_, err := vm.RunString(SCRIPT)
 	if err != nil {
-		t.Fatal(err)
+		panic(err)
 	}
 
 	var fn func(string) (string, error)
 	err = vm.ExportTo(vm.Get("f"), &fn)
 	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) {
@@ -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) {
 	const SCRIPT = `
 	try {