Go Libraries
Create reusable Go libraries with functions, constants, and sub-libraries.
Native Library API
Basic Library
import (
"context"
"github.com/paularlott/scriptling/object"
)
var MyLibrary = object.NewLibrary("mylib",
// Functions
map[string]*object.Builtin{
"connect": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
host, _ := args[0].AsString()
port, _ := args[1].AsInt()
fmt.Printf("Connecting to %s:%d\n", host, port)
return &object.Boolean{Value: true}
},
HelpText: "connect(host, port) - Connect to a host and port",
},
"disconnect": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
fmt.Println("Disconnecting...")
return &object.Boolean{Value: false}
},
HelpText: "disconnect() - Disconnect from current connection",
},
},
// Constants
map[string]object.Object{
"MAX_CONNECTIONS": &object.Integer{Value: 100},
"VERSION": &object.String{Value: "1.0.0"},
"DEBUG": &object.Boolean{Value: true},
},
// Description
"My custom library with connection utilities",
)
// Register the library
func main() {
p := scriptling.New()
p.RegisterLibrary(MyLibrary)
}Use from Scriptling:
import mylib
connected = mylib.connect("localhost", 8080)
print(f"Max connections: {mylib.MAX_CONNECTIONS}")
print(f"Version: {mylib.VERSION}")Library with Sub-Libraries
var DatabaseLibrary = object.NewLibrary("database",
map[string]*object.Builtin{
"connect": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
// Connection logic
return &object.Boolean{Value: true}
},
HelpText: "connect(host, port) - Connect to database",
},
},
map[string]object.Object{
"DEFAULT_PORT": &object.Integer{Value: 5432},
},
"Database connectivity library",
)
// Add sub-libraries
var QueryLibrary = object.NewLibrary("query",
map[string]*object.Builtin{
"select": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
table, _ := args[0].AsString()
// SELECT logic
return &object.List{Elements: []object.Object{}}
},
HelpText: "select(table) - Select all rows from table",
},
"insert": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
table, _ := args[0].AsString()
data, _ := args[1].AsDict()
// INSERT logic
return &object.Integer{Value: 1}
},
HelpText: "insert(table, data) - Insert row into table",
},
},
nil,
"Query operations",
)
func main() {
p := scriptling.New()
// Register main library
p.RegisterLibrary(DatabaseLibrary)
// Register as sub-library
p.RegisterSubLibrary("database", "query", QueryLibrary)
}Use from Scriptling:
import database
db = database.connect("localhost", 5432)
rows = database.query.select("users")
database.query.insert("users", {"name": "Alice"})On-Demand Library Loading
Load libraries only when they’re first imported:
func main() {
p := scriptling.New()
// Set callback for lazy loading
p.SetOnDemandLibraryCallback(func(p *scriptling.Scriptling, name string) bool {
switch name {
case "heavylib":
// Only load when first imported
p.RegisterLibrary(createHeavyLibrary())
return true
case "ai":
p.RegisterLibrary(createAILibrary())
return true
case "mcp":
p.RegisterLibrary(createMCPLibrary())
return true
}
return false // Library not found
})
// Library will be loaded when first referenced
p.Eval(`
import heavylib # Triggers callback, loads library
result = heavylib.process(data)
`)
}Factory Pattern for Stateful Libraries
Libraries that need to create objects with state:
// Factory function that creates instances
var ConnectionLibrary = object.NewLibrary("connection",
map[string]*object.Builtin{
"create": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
host, _ := args[0].AsString()
port, _ := kwargs.GetInt("port", 8080)
// Create a new connection object (as dict with methods)
conn := &object.Dict{Pairs: map[string]object.Object{
"host": &object.String{Value: host},
"port": object.NewInteger(int64(port)),
"connected": object.False,
}}
return conn
},
HelpText: "create(host, port=8080) - Create a new connection",
},
},
nil,
"Connection factory library",
)Complete Library Example
package mylib
import (
"context"
"fmt"
"github.com/paularlott/scriptling/object"
)
// Create a comprehensive library
func CreateMathLibrary() *object.Library {
return object.NewLibrary("mymath",
map[string]*object.Builtin{
// Basic operations
"add": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
a, _ := args[0].AsFloat()
b, _ := args[1].AsFloat()
return object.NewFloat(a + b)
},
HelpText: "add(a, b) - Add two numbers",
},
"subtract": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
a, _ := args[0].AsFloat()
b, _ := args[1].AsFloat()
return object.NewFloat(a - b)
},
HelpText: "subtract(a, b) - Subtract b from a",
},
"multiply": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
a, _ := args[0].AsFloat()
b, _ := args[1].AsFloat()
return object.NewFloat(a * b)
},
HelpText: "multiply(a, b) - Multiply two numbers",
},
"divide": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
a, _ := args[0].AsFloat()
b, _ := args[1].AsFloat()
if b == 0 {
return &object.Error{Message: "division by zero"}
}
return object.NewFloat(a / b)
},
HelpText: "divide(a, b) - Divide a by b",
},
// Advanced operations
"power": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
base, _ := args[0].AsFloat()
exp, _ := args[1].AsFloat()
return object.NewFloat(math.Pow(base, exp))
},
HelpText: "power(base, exp) - Raise base to power",
},
"sqrt": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
x, _ := args[0].AsFloat()
return object.NewFloat(math.Sqrt(x))
},
HelpText: "sqrt(x) - Square root of x",
},
// Statistical functions
"mean": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
list, _ := args[0].AsList()
if len(list) == 0 {
return object.NewFloat(0)
}
sum := 0.0
for _, item := range list {
val, _ := item.AsFloat()
sum += val
}
return object.NewFloat(sum / float64(len(list)))
},
HelpText: "mean(numbers) - Calculate arithmetic mean",
},
"sum": {
Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
list, _ := args[0].AsList()
sum := 0.0
for _, item := range list {
val, _ := item.AsFloat()
sum += val
}
return object.NewFloat(sum)
},
HelpText: "sum(numbers) - Sum all numbers in list",
},
},
map[string]object.Object{
"PI": object.NewFloat(3.14159265359),
"E": object.NewFloat(2.71828182846),
"PHI": object.NewFloat(1.61803398875), // Golden ratio
"VERSION": &object.String{Value: "1.0.0"},
},
"Extended math library with statistical functions",
)
}
// Usage
func main() {
p := scriptling.New()
p.RegisterLibrary(CreateMathLibrary())
p.Eval(`
import mymath
result = mymath.add(10, 20)
pi = mymath.PI
average = mymath.mean([1, 2, 3, 4, 5])
`)
}Registering Script Libraries
You can also register libraries written in Scriptling:
p.RegisterScriptLibrary("helpers", `
def format_name(first, last):
return first + " " + last
def capitalize(text):
return text[0].upper() + text[1:]
DEFAULT_GREETING = "Hello"
`)
p.Eval(`
import helpers
name = helpers.format_name("john", "doe")
greeting = helpers.capitalize(helpers.DEFAULT_GREETING)
`)Best Practices
- Group related functions - Put related functions in the same library
- Use sub-libraries - Organize large libraries into sub-modules
- Provide help text - Make functions discoverable
- Export constants - Share configuration values
- Use lazy loading - Load heavy libraries on demand
- Handle errors gracefully - Return meaningful error messages
// Good: Organized library with help text
var GoodLibrary = object.NewLibrary("goodlib",
map[string]*object.Builtin{
"process": {
Fn: processFunc,
HelpText: `process(data, options={}) - Process data
Parameters:
data - Input data
options - Configuration options
Returns:
Processed result`,
},
},
map[string]object.Object{
"VERSION": &object.String{Value: "1.0.0"},
},
"A well-documented library",
)