I am working on a quick and dirty Ruby bridge library, that I hope will yield a huge performance gain with template interpolation in the language-puppet library. Right now, it is capable of:
Initializing a Ruby interpreter from libruby
Calling Ruby methods and functions
Registering methods or functions that will be called from Ruby code
Converting data between the two Worlds (right now the most complex instance is the JSON one, which means that many complex Ruby types can’t be converted, but it is more than enough for passing data)
Embedding native Haskell values that can be passed around in Ruby to the Haskell-provided external functions (I will use this for passing the Puppet catalog state around)
There are still a few things to do before releasing it :
Making compilation a bit less dependant on the system. This will probably require quite a few flags in the cabal definition …
Hunting for memory leaks. I am not sure how to do this with the GHC Runtime in the middle, and I do hope that ruby_finalize frees everything that is managed by the Ruby runtime. After all, restarting processes seems to be the only working garbage collection method for Ruby daemons …
Writing stubs for the Puppet library methods that might be needed by templates. I would like to be able to support custom types and functions directly written in Ruby instead of Lua, but this will probably turn into a nightmare …
{-# LANGUAGE OverloadedStrings, OverloadedStrings #-}moduleMainwhereimportForeign.Ruby.BindingsimportData.AesonimportData.Attoparsec.Number-- this is an external function that will be executed from the Ruby interpreter-- the first parameter to the function is probably some reference to some top object-- my knowledge of ruby is close to nonexistent, so I can't say for sure ...extfunc::RValue->RValue->IORValueextfunc_v=do-- deserialize the Ruby value into some JSON Valueonv<-fromRubyv::IO(MaybeValue)-- and display itprintonv-- now let's create a JSON object containing all kind of data typesletnv=object[("bigint",Number(I16518656116889898998656112323135664684684)),("int",Number(I12)),("double",Number(D0.123)),("null","Null"),("string",String"string"),("true",BoolTrue),("false",BoolFalse),("array",toJSON([1,2,3,4,5]::[Int])),("object",object[("k",String"v")])]-- turn it into Ruby values, and return thistoRubynv-- this is the function that is called if everything was loaded properlynextThings::IO()nextThings=do-- turn the extfunc function into something that can be called by the Ruby interpretermyfunc<-mkRegistered2extfunc-- and bind it to the global 'hsfunction' functionrb_define_global_function"hsfunction"myfunc1-- now call a method in the Ruby interpretero<-safeMethodCall"MyClass""testfunc"[]caseoofRightv->(fromRubyv::IO(MaybeValue))>>=printLeftr->putStrLnrmain::IO()main=do-- initialize stuffruby_initruby_init_loadpath-- and load "test.rb"s<-rb_load_protect"test.rb"0ifs==0thennextThingselseshowError>>=putStrLn
And here is the ruby program, that calls our external function :