github.com/anycable/anycable-go@v1.5.1/mrb/mrb.go (about) 1 //go:build (darwin && mrb) || (linux && mrb) 2 // +build darwin,mrb linux,mrb 3 4 package mrb 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "strings" 10 "sync" 11 12 nanoid "github.com/matoous/go-nanoid" 13 "github.com/mitchellh/go-mruby" 14 ) 15 16 // Supported returns true iff mruby scripting is available 17 func Supported() bool { 18 return true 19 } 20 21 // Engine represents one running mruby VM 22 type Engine struct { 23 VM *mruby.Mrb 24 mu sync.Mutex 25 } 26 27 var ( 28 defaultEngine *Engine 29 defaultEngineSync sync.Mutex 30 ) 31 32 // NewEngine builds new mruby VM and return new engine 33 func NewEngine() *Engine { 34 return &Engine{VM: mruby.NewMrb()} 35 } 36 37 // DefaultEngine returns a default mruby engine 38 func DefaultEngine() *Engine { 39 defaultEngineSync.Lock() 40 defer defaultEngineSync.Unlock() 41 42 if defaultEngine == nil { 43 defaultEngine = NewEngine() 44 } 45 46 return defaultEngine 47 } 48 49 func Version() (v string, err error) { 50 mrbv, err := DefaultEngine().Eval("MRUBY_DESCRIPTION") 51 if err != nil { 52 return 53 } 54 55 v = strings.TrimSpace(mrbv.String()) 56 return 57 } 58 59 // LoadFile loads, parses and eval Ruby file within a vm 60 func (engine *Engine) LoadFile(path string) error { 61 contents, err := ioutil.ReadFile(path) 62 63 if err != nil { 64 return err 65 } 66 67 return engine.LoadString(string(contents)) 68 } 69 70 // LoadString loads, parses and eval Ruby code within a vm 71 func (engine *Engine) LoadString(contents string) error { 72 engine.mu.Lock() 73 defer engine.mu.Unlock() 74 75 ctx := mruby.NewCompileContext(engine.VM) 76 defer ctx.Close() 77 78 filename, err := nanoid.Nanoid() 79 80 if err != nil { 81 return err 82 } 83 84 ctx.SetFilename(fmt.Sprintf("%s.rb", filename)) 85 86 parser := mruby.NewParser(engine.VM) 87 defer parser.Close() 88 89 if _, err = parser.Parse(contents, ctx); err != nil { 90 return err 91 } 92 93 parsed := parser.GenerateCode() 94 95 if _, err = engine.VM.Run(parsed, nil); err != nil { 96 return err 97 } 98 99 return nil 100 } 101 102 // Eval runs arbitrary code within a vm 103 func (engine *Engine) Eval(code string) (*mruby.MrbValue, error) { 104 return engine.VM.LoadString(code) 105 }