tengo之用户自定义module

1,085 阅读1分钟

概述

Tengo is a small, dynamic, fast, secure script language for Go.

作为一款编译和运行都在go编写的本地堆栈vm上完成的脚本语言,tengo对比其他脚本语言具有更快速和更安全的特点。本文主要介绍如何在tengo中导入并使用自定义module。

1.定义一个module

用户自定义module,一般需要实现Importable接口。

// Importable interface represents importable module instance.
type Importable interface {
	// Import should return either an Object or module source code ([]byte).
	Import(moduleName string) (interface{}, error)
}

//我们的实现如下:
// MyModule is an importable module that's written in Go.
type MyModule struct {
	Attrs map[string]tengo.Object
}

// Import returns an immutable map for the module.
func (m *MyModule) Import(moduleName string) (interface{}, error) {
	return m.AsImmutableMap(moduleName), nil
}
// AsImmutableMap converts builtin module into an immutable map.
func (m *MyModule) AsImmutableMap(moduleName string) *tengo.ImmutableMap {
	attrs := make(map[string]tengo.Object, len(m.Attrs))
	for k, v := range m.Attrs {
		attrs[k] = v.Copy()
	}
	attrs["__module_name__"] = &tengo.String{Value: moduleName}
	return &tengo.ImmutableMap{Value: attrs}
}

然后,我们需要用我们实现的Importable接口类,即MyModule,声明一个map[string]tengo.Object结构。

package tengo_module

import (
	"github.com/d5/tengo/v2"
)


//我们的库里新增了一个用户自定义函数,名字为hello。
var JoyboiiModule = &MyModule {
	Attrs: map[string]tengo.Object{
		"hello": &tengo.UserFunction{Name: "hello", Value: hello},
	},
}

//完成参数校验、错误处理等工作,最终完成我们需要的工作。
func hello(args ...tengo.Object) (ret tengo.Object, err error) {
	if len(args) != 1 {
		return nil, tengo.ErrWrongNumArguments
	} else if f1, ok := tengo.ToString(args[0]); !ok {
		return nil, tengo.ErrInvalidArgumentType{
			Name:     "one",
			Expected: "string",
			Found:    args[0].TypeName(),
		}
	} else {
		return &tengo.String{Value:"hello, " + f1}, nil
	}
}




2.验证效果

package main

import (
	"draft/tengo_module"
	"fmt"
	"github.com/d5/tengo/v2"
	"github.com/d5/tengo/v2/stdlib"
)

var src = `
  fmt := import("fmt")
	joyboii := import("joyboii")
	res := joyboii.hello("joyboii")
	fmt.println("tengo_module res: ", res)
`

func main() {
	script := tengo.NewScript([]byte(src))
  //拓展我们自己的module
	modules := stdlib.GetModuleMap(stdlib.AllModuleNames()...)
	modules.Add("joyboii",tengo_module.JoyboiiModule)
	script.SetImports(modules)
  //编译并运行
	compiled, err := script.Compile()
	if err != nil {
		fmt.Println(err)
		return
	}
	err = compiled.Run()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("go res:", compiled.Get("res"))
}

最终输出结果为:

tengo_module res: hello, joyboii
go res: hello, joyboii

官方资料