instructor

package module
v0.1.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 23, 2016 License: Apache-2.0 Imports: 9 Imported by: 0

README

Instructor

GoDoc

It's like rails c for go applications, except not nearly as good

What is it?

It's a way to build a sidecar binary that you can configure with access to objects in your applications or services. This includes loading data from a database or another remote location, and invoking methods and properties on those objects interactively.

If what you want to is to glue together a little bootstrap code, so you can hop into a REPL-like environment and inspect data in your go app via structs, methods, and properties, Instructor might be for you.

What isn't it?

It's not a full fledged go environment - there are many things you cannot do. Even basic things, like declaring new instances in a "normal" way, or basic addition, or even declaring pointers!

While all that sounds limiting, and it is, there are ways to use Instructor and account for those issues as well, albeit with some upfront work via configuration.

Additionally, as I encounter more use cases, I focus on them for development. So the list of features it doesn't support is essentially the set of features that weren't immediately pressing while developing it

Wait, so this isn't actually a REPL?

Nah, it isn't.

It's more of a sidecar utility you can bolt on to an existing application, and use to do some basic interactions with your applications data in an interactive environment.

Kind of like a REPL. But I actually called Instructor that, i'd be rightfully torn to pieces.

Yea, but how fast is it? I'm very particular about code that doesn't perform well

Well, that's a real shame. Cus this isn't meant to be fast. It certainly isn't "slow", but the code is likely to change wildly at any time, so until I'm happy with an approach, my intention is to focus more on features, and move to any performance issues once the internals are stable.

Instructor makes heavy use of interface{} and the reflect package, so there will generally be some unavoidable performance hit at scale for the things it does.

But ideally, the primary use case of someone looking to use Instructor is for convenience, not performance.

Wow, looking at the code, it is clear you have no idea how to write an interpreter

I sure don't! Part of the fun was trying to make it work.

Why not use yacc / bison / etc?

It's more fun to learn this way

Any roadmap?

  • Lots of code cleanup and improvements
  • Find a better solution than my hackneyed "find" method for seeding objects into the environment. Ideally, you could just "make"/"do" whatever you want, but that's pie in the sky stuff.
  • Variable substitution when calling methods
  • Setting Properties on objects

How do I integrate it into my app?

Currently, the recommended way to integrate into an existing app is create a sub-binary to act as your CLI / REPL. Common patterns for this might include:

my_app/cmd/repl/repl.go my_app/tools/repl/repl.go

Inside of repl.go, you might have some code like the following

package main

import (
	"github.com/StabbyCutyou/instructor"
	"github.com/you/yourapp/models"
	"github.com/you/youapp/services"
)

var structFinder services.MyStructService

type Flooper struct {
  floops int
}

func main() {
  // Configure access to your database
  // ...
  // Do any additional config so you can boot into a facsimile of your app
  // ex: load any needed files, configure any needed global state, etc etc
  structFinder = services.NewMyStructService()
  // Create an instructor
  i := instructor.New()
  // Register a lookup method for MyStructs
  i.RegisterFinder("MyStruct", findMyStruct)
  i.RegisterConverter("Flooper", convertFloopers)

  // This will block until done
  if err := i.REPL(); err != nil {
    log.Fatal(err)
  }
}

func findMyStruct(string id)(interface{}, error) {
  i, err := strconv.Atoi(id)
  if err != nil {
    return structFinder.Find(id)
  }
  return nil, err
}

func convertFloopers(string s) (interface{}) {
  b := []byte(s)
  f := Flooper{}
  if err := json.Unmarshal(b, &f); err != nil {
    fmt.Println(s)
    fmt.Println(err)
    return f, err
  }
  return f, nil
}

How do I use it?

Once you have it integrated as a sidecar via a tool or cmd binary, you would simply invoke the binary. This will drop you into an interactive prompt, where you can perform things like the following:

  • type: quit to exit
  • type: help to get a list of commands
  • type: o = find(MyStruct, "MyID")
    • To use the find helper, you'll need to use RegisterFinder, as demonstrated in the sample code above
  • type: o.Property
  • type: o.SimpleFunc()
  • type: o.ComplexFunc(50, true)
  • type: o.NestedProperty.ArrayOrSlice[2].MathFunc(600.84)
  • So far, those are the following param types supported:
  • int
  • uint
  • float64
  • string
  • rune
  • bool
  • Pointer types of the above are technically supported, but you can't make literals of them yet - this is coming shortly
  • Additionally, you can define a "Custom Converter" for any type you want, so long as you can find a way to marshall it from string.
  • In the example above, you could pass a "Flooper" to a method by using the following string
  • {"floops": 5}
  • See lexer_test.go for an example

License

Apache v2 - See LICENSE

Documentation

Overview

Package instructor is

Index

Constants

View Source
const (
	INVALID      = iota // 0
	ASSIGNMENT          // 1
	METHODCALL          // 2
	PROPERTYCALL        // 3
	INSPECT             // 4
	LOOKUP              // 5
	LITERAL             // 6
)
View Source
const Version = "0.1.9"

Version is the current semver for this tool

Variables

This section is empty.

Functions

This section is empty.

Types

type Converter

type Converter func(string) (interface{}, error)

Converter is a function type that is used to convert a string to an associated type You'd wrap whatever logic you needed, including something like just JSON Unmarshalling to turn a string representation of a value into a concrete instance of it's type. Four come out of the box for you: string, bool, int, and float64

type Finder

type Finder func(string) (interface{}, error)

Finder is a function type that is used to load an object, serialized into a struct from the integrating-applications list of structs

type Instructor

type Instructor struct {
	// contains filtered or unexported fields
}

Instructor is an instance of the object which will allow you to inspect structs

func New

func New() *Instructor

New returns a new Instructor

func (*Instructor) REPL

func (i *Instructor) REPL() error

REPL will enter the read eval print loop, blocking the main thread until it exits

func (*Instructor) RegisterConverter

func (i *Instructor) RegisterConverter(name string, c Converter)

RegisterConverter is for registering one of your custom converters to convert cli arguments to typed values

func (*Instructor) RegisterFinder

func (i *Instructor) RegisterFinder(name string, f Finder)

RegisterFinder is for registering one of your custom finders to look up your structs

type Token added in v0.1.0

type Token int

Token represents a lexical token.

const (
	ILLEGAL Token = iota // 0
	EOF                  // 1: end of input
	WS                   // 2: spaces/tabs
)

Low level tokens - things looked for sepcifically by name in the interpreter

const (
	ASSIGN Token = 100 + iota // 100: assginment operator, =
	PERIOD                    // 101: .
	SQUOTE                    // 102: '
	DQUOTE                    // 103: "
	COMMA                     // 104: ,
	LPAREN                    // 105: (
	RPAREN                    // 106: )
	TICK                      // 107: `
	LBRACK                    // 108: [
	RBRACK                    // 109: ]
)

Operational tokens - things looked for by name, but are more meaningful

const (
	WORD Token = 200 + iota // 200: Placeholder, should be unused
	FIND                    // 201: built in helper for locating structs, hacky
	ADD                     // 202: Addition operator
	SUB                     // 203: Subtraction operator
	DIV                     // 204: Division operator
	MULT                    // 205: Multiplication operator
	MOD                     // 206: Modulo operator
)

Reserved words - special operators and functions, pre-defined by the "runtime"

const (
	VARIABLE Token = 300 + iota // 300: Any literal value that isn't a reserved word - any string not starting with single/double/tick quotes
	FIELD                       // 301: Any string not starting with a single/double/stick quotes but preceeded by a period
)

Field and variable tokens

const (
	STRING Token = 400 + iota // 302: Any literal string value
	INT                       // 303: Any literal number without a decimal
	FLOAT                     // 304: Any literal number with a decimal
	RUNE                      // 305: Any literal rune value
	BOOL                      // 306: The keywords true or false
)

Literal value tokens

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL