packages feed

hruby 0.3.7 → 0.3.8

raw patch · 8 files changed

+75/−35 lines, 8 files

Files

Foreign/Ruby.hs view
@@ -14,6 +14,7 @@   , loadFile   , Foreign.Ruby.Safe.embedHaskellValue   , Foreign.Ruby.Safe.safeMethodCall+  , Foreign.Ruby.Safe.safeFunCall   , makeSafe   , RubyError(..)   -- * Converting to and from Ruby values
Foreign/Ruby/Bindings.hsc view
@@ -14,18 +14,16 @@ -- | The Ruby ID type, mostly used for symbols. type RID = CULong -data ShimDispatch = ShimDispatch String String [RValue]+data ShimDispatch = ShimDispatch RValue RID [RValue] instance Storable ShimDispatch where     sizeOf _ = (#size struct s_dispatch)     alignment = sizeOf-    peek ptr = do a <- peekCString ((#ptr struct s_dispatch, classname) ptr)-                  b <- peekCString ((#ptr struct s_dispatch, methodname) ptr)+    peek ptr = do a <- peek ((#ptr struct s_dispatch, receiver) ptr)+                  b <- peek ((#ptr struct s_dispatch, methodid) ptr)                   return (ShimDispatch a b [])     poke ptr (ShimDispatch c m vals) = do-        cs <- newCString c-        cm <- newCString m-        (#poke struct s_dispatch, classname) ptr cs-        (#poke struct s_dispatch, methodname) ptr cm+        (#poke struct s_dispatch, receiver) ptr c+        (#poke struct s_dispatch, methodid) ptr m         (#poke struct s_dispatch, nbargs) ptr (length vals)         let arrayblock = (#ptr struct s_dispatch, args) ptr         pokeArray arrayblock vals@@ -113,6 +111,7 @@ foreign import ccall   safe "rb_define_global_function" c_rb_define_global_function :: CString -> FunPtr a -> Int -> IO () foreign import ccall unsafe "rb_const_get"              rb_const_get                :: RValue -> RID -> IO RValue foreign import ccall   safe "&safeCall"                 safeCallback                :: FunPtr (RValue -> IO RValue)+foreign import ccall   safe "&getRubyCObject"           getRubyCObjectCallback      :: FunPtr (RValue -> IO RValue) foreign import ccall   safe "rb_protect"                c_rb_protect                :: FunPtr (RValue -> IO RValue) -> RValue -> Ptr Int -> IO RValue foreign import ccall unsafe "rb_string_value_cstr"      c_rb_string_value_cstr      :: Ptr RValue -> IO CString foreign import ccall unsafe "rb_ary_new"                rb_ary_new                  :: IO RValue
Foreign/Ruby/Helpers.hs view
@@ -4,6 +4,7 @@ import Foreign.Ruby.Bindings  import Foreign+import Foreign.C (withCString) import Data.Aeson import Control.Monad import qualified Data.Text as T@@ -190,26 +191,49 @@ defineGlobalClass :: String -> IO RValue defineGlobalClass s = peek rb_cObject >>= rb_define_class s --- | Runs a Ruby method, capturing errors.-safeMethodCall :: String -- ^ Class name.+-- | Gets a Ruby class, capturing errors.+safeGetClass :: String -> IO (Either (String, RValue) RValue)+safeGetClass s =+  withCString s $ \cs ->+  with 0 $ \pstatus -> do+    o <- c_rb_protect getRubyCObjectCallback (castPtr cs) pstatus+    status <- peek pstatus+    if status == 0+      then pure $ Right o+      else do+        err <- showErrorStack+        pure $ Left (err, o)++-- | Runs a Ruby singleton method, capturing errors.+safeMethodCall :: String -- ^ Name of a class or a module.                -> String -- ^ Method name.                -> [RValue] -- ^ Arguments. Please note that the maximum number of arguments is 16.                -> IO (Either (String, RValue) RValue) -- ^ Returns either an error message / value couple, or the value returned by the function.-safeMethodCall classname methodname args =-    if length args > 16-        then return (Left ("too many arguments", rbNil))-        else do-            dispatch <- new (ShimDispatch classname methodname args)-            pstatus <- new 0-            o <- c_rb_protect safeCallback (castPtr dispatch) pstatus-            status <- peek pstatus-            free dispatch-            free pstatus-            if status == 0-                then return (Right o)-                else do-                    err <- showErrorStack-                    return (Left (err,o))+safeMethodCall classname methodname args = do+  erecv <- safeGetClass classname+  case erecv of+    Right recv -> safeFunCall recv methodname args+    Left err -> pure $ Left err++-- | Runs a Ruby method, capturing errors.+safeFunCall+  :: RValue -- ^ Receiver.+  -> String -- ^ Method name.+  -> [RValue] -- ^ Arguments. Please note that the maximum number of arguments is 16.+  -> IO (Either (String, RValue) RValue) -- ^ Returns either an error message / value couple, or the value returned by the function.+safeFunCall recv methodname args+  | length args > 16 = pure $ Left ("too many arguments", rbNil)+  | otherwise =+      rb_intern methodname >>= \methodid ->+      with (ShimDispatch recv methodid args) $ \dispatch ->+      with 0 $ \pstatus -> do+        o <- c_rb_protect safeCallback (castPtr dispatch) pstatus+        status <- peek pstatus+        if status == 0+          then pure $ Right o+          else do+            err <- showErrorStack+            pure $ Left (err, o)  -- | Gives a (multiline) error friendly string representation of the last -- error.
Foreign/Ruby/Safe.hs view
@@ -15,6 +15,7 @@     , loadFile     , embedHaskellValue     , safeMethodCall+    , safeFunCall     , makeSafe     , fromRuby     , toRuby@@ -115,7 +116,7 @@ embedHaskellValue :: RubyInterpreter -> a -> IO (Either RubyError RValue) embedHaskellValue int v = makeSafe int $ FR.embedHaskellValue v --- | A safe version of the corresponding "Foreign.Ruby" function.+-- | A safe version of the corresponding "Foreign.Ruby.Helper" function. safeMethodCall :: RubyInterpreter                -> String                -> String@@ -123,6 +124,19 @@                -> IO (Either RubyError RValue) safeMethodCall int className methodName args = do     o <- makeSafe int $ FR.safeMethodCall className methodName args+    case o of+        Left x -> return (Left x)+        Right (Right v) -> return (Right v)+        Right (Left (s,v)) -> return (Left (WithOutput s v))++-- | A safe version of the corresponding "Foreign.Ruby.Helper" function.+safeFunCall :: RubyInterpreter+            -> RValue+            -> String+            -> [RValue]+            -> IO (Either RubyError RValue)+safeFunCall int receiver methodName args = do+    o <- makeSafe int $ FR.safeFunCall receiver methodName args     case o of         Left x -> return (Left x)         Right (Right v) -> return (Right v)
cbits/shim.c view
@@ -29,13 +29,14 @@ VALUE safeCall(VALUE args) { 	struct s_dispatch * d = (struct s_dispatch *) args;-	VALUE myclass = rb_const_get(rb_cObject, rb_intern(d->classname));-	VALUE o = rb_funcall2(myclass, rb_intern(d->methodname), d->nbargs, d->args);-	free(d->methodname);-	free(d->classname);-	return o;+	return rb_funcall2(d->receiver, d->methodid, d->nbargs, d->args); } +VALUE getRubyCObject(VALUE name)+{+	return rb_const_get(rb_cObject, rb_intern((const char*) name));+}+ long arrayLength(VALUE r) { 	return RARRAY_LEN(r);@@ -64,4 +65,3 @@ double num2dbl(VALUE v) { 	NUM2DBL(v); }-
cbits/shim.h view
@@ -6,8 +6,8 @@ void ruby_initialization(void);  struct s_dispatch {-	char * classname;-	char * methodname;+	VALUE receiver;+	ID methodid; 	int nbargs; 	VALUE args[16]; };
hruby.cabal view
@@ -1,6 +1,6 @@ cabal-version:       >= 1.10 name:                hruby-version:             0.3.7+version:             0.3.8 synopsis:            Embed a Ruby intepreter in your Haskell program ! description:         This doesn't work with Ruby 1.9. Everything you need should be in Foreign.Ruby.Safe. license:             BSD3
test/roundtrip.hs view
@@ -3,6 +3,7 @@ import Foreign.Ruby import Data.Aeson import Control.Monad+import System.Exit (exitFailure) import Test.QuickCheck import Test.QuickCheck.Monadic import qualified Data.Text as T@@ -54,4 +55,5 @@ main :: IO () main = withRubyInterpreter $ \i -> do     loadFile i "./test/test.rb" >>= either (error . show) return-    quickCheckWith (stdArgs { maxSuccess = 1000 } ) (roundTrip i)+    result <- quickCheckWithResult (stdArgs { maxSuccess = 1000 } ) (roundTrip i)+    unless (isSuccess result) exitFailure