Documentation
¶
Overview ¶
datalark makes IPLD data legible to, and constructable in, starlark.
Given an IPLD Schema (and optionally, a list of types to focus on), datalark can generate a set of starlark constructor functions for those types. These functions should generally DWIM ("do what I mean"): for structs, they accept kwargs corresponding to the field names, etc. Some functions get clever: for example, for structs with stringy representations (stringjoin, etc), the representation form can be used as an argument to the constructor instead of the kwargs form, and the construction will "DWIM" with that information and parse it in the appropriate way.
Standard datamodel data is also always legible, and a set of functions for creating it can also be obtained from the datalark package.
All IPLD data exposed to starlark always acts as if it is "frozen", in starlark parlance. This should be unsurprising, since IPLD is already oriented around immutability.
datalark can be used on natural golang structs by combining it with the go-ipld-prime/node/bindnode package. This may make it an interesting alternative to github.com/starlight-go/starlight (although admittedly more complicated; it's probably only worth it if you also already value some of the features of IPLD Schemas).
Future objectives for this package include the ability to provide a function to starlark which will accept an IPLD Schema document and a type name as parameters, and will return a constructor for that type. (Not yet implemented.)
Example (Hello) ¶
// Prepare things needed by a starlark interpreter. (This is Starlark boilerplate!)
thread := &starlark.Thread{
Name: "thethreadname",
Print: func(thread *starlark.Thread, msg string) {
fmt.Printf("%s\n", msg)
},
}
// Use datalark to make IPLD value constructors available to Starlark!
globals := starlark.StringDict{}
globals["datalark"] = datalark.ObjOfConstructorsForPrimitives()
// Now here's our demo script:
script := testutil.Dedent(`
print(datalark.String("yo"))
`)
// Invoke the starlark interpreter!
_, err := starlark.ExecFile(thread, "thefilename.star", script, globals)
if err != nil {
panic(err)
}
Output: string{"yo"}
Example (HelloGlobals) ¶
// In this example, we do similar things to the other examples,
// except we put our functions directly into the global namespace.
// You may wish to do this to make it even easier to use
// (but remember to weigh it against cluttering the namespace your users will experience!).
// Prepare things needed by a starlark interpreter. (This is Starlark boilerplate!)
thread := &starlark.Thread{
Name: "thethreadname",
Print: func(thread *starlark.Thread, msg string) {
fmt.Printf("%s\n", msg)
},
}
// Use datalark to make IPLD value constructors available to Starlark!
// Note the use of 'InjectGlobals' here -- this puts things into scope without any namespace,
// as opposed to what we did in other examples, which let you choose a name in the globals to put everything under.
globals := starlark.StringDict{}
datalark.InjectGlobals(globals, datalark.ObjOfConstructorsForPrimitives())
// Now here's our demo script:
script := testutil.Dedent(`
print(String("yo")) # look, no 'datalark.' prefix!
`)
// Invoke the starlark interpreter!
_, err := starlark.ExecFile(thread, "thefilename.star", script, globals)
if err != nil {
panic(err)
}
Output: string{"yo"}
Example (HelloTypes) ¶
// In this example we'll use an IPLD Schema!
ts := schema.MustTypeSystem(
schema.SpawnString("String"),
schema.SpawnStruct("FooBar", []schema.StructField{
schema.SpawnStructField("foo", "String", false, false),
schema.SpawnStructField("bar", "String", false, false),
}, nil),
)
// And we'll bind it to this golang native type:
type FooBar struct{ Foo, Bar string }
// Prepare things needed by a starlark interpreter. (This is Starlark boilerplate!)
thread := &starlark.Thread{
Name: "thethreadname",
Print: func(thread *starlark.Thread, msg string) {
fmt.Printf("%s\n", msg)
},
}
// Use datalark to make IPLD value constructors available to Starlark!
globals := starlark.StringDict{}
globals["datalark"] = datalark.ObjOfConstructorsForPrimitives()
globals["mytypes"] = datalark.ObjOfConstructorsForPrototypes(
bindnode.Prototype((*FooBar)(nil), ts.TypeByName("FooBar")),
)
// Now here's our demo script:
script := testutil.Dedent(`
print(mytypes.FooBar)
print(mytypes.FooBar(foo="helloooo", bar="world!"))
`)
// Invoke the starlark interpreter!
_, err := starlark.ExecFile(thread, "thefilename.star", script, globals)
if err != nil {
panic(err)
}
Output: <built-in function datalark.Prototype<FooBar>> struct<FooBar>{ foo: string<String>{"helloooo"} bar: string<String>{"world!"} }
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func InjectGlobals ¶
func InjectGlobals(globals starlark.StringDict, obj *datalarkengine.Object)
InjectGlobals mutates a starlark.StringDict to contain the values in the given Object.
Use this if you want to add things to your global starlark environment without a namespacing element. (If you want things *with* a namespacing element, it's sufficient to just put the Object in the StringDict under whatever key you like.)
This is meant to be used with objects like those from ObjOfConstructorsForPrimitives and ObjOfConstructorsForPrototypes. It will panic if keys that aren't starlark.String are encountered, if iterators error, etc.
func ObjOfConstructorsForPrimitives ¶
func ObjOfConstructorsForPrimitives() *datalarkengine.Object
ObjOfConstructorsForPrimitives returns an Object containing constructor functions for all the IPLD Data Model kinds -- strings, maps, etc -- as those names, in TitleCase.
An "Object" is like a starlark.Dict but you can also access its members using dotted notation. It's a convenient namespacing helper. You can either add it as a value to the globals starlark.StringDict and use the key you add it to as a namespace; or, you can use the InjectGlobals function to make all the functions available as globals without namespacing.
func ObjOfConstructorsForPrototypes ¶
func ObjOfConstructorsForPrototypes(prototypes ...schema.TypedPrototype) *datalarkengine.Object
ObjOfConstructorsForPrototypes returns an Object containing constructor functions for IPLD typed nodes, based on the list of schema.TypedPrototype you provide, and using the names of each of those prototype's types as the keys.
An "Object" is like a starlark.Dict but you can also access its members using dotted notation. It's a convenient namespacing helper. You can either add it as a value to the globals starlark.StringDict and use the key you add it to as a namespace; or, you can use the InjectGlobals function to make all the functions available as globals without namespacing.
The reason this function takes `schema.TypedPrototype` as an argument, rather than `schema.Type`, is because prototypes contain information about how to actually construct values. (A `schema.Type` value only describes the shape of data, but doesn't say how we want to work with it in memory, so it's not enough information to create constructor functions out of.)
Types ¶
This section is empty.