mwotton-hubris 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/README.markdown +117 -0
- data/Rakefile +31 -0
- data/bin/jhc_builder +17 -0
- data/lib/Mapper.hs +93 -0
- data/lib/RubyMap.chs +49 -0
- data/lib/extconf.rb +3 -0
- data/lib/hubris.rb +70 -0
- data/lib/rshim.c +11 -0
- data/lib/rshim.h +65 -0
- data/sample/Makefile +6 -0
- data/sample/Test.hs +28 -0
- data/sample/hsload.rb +9 -0
- data/spec/hubris_spec.rb +25 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- data/tasks/rspec.rake +21 -0
- metadata +73 -0
data/History.txt
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
# Hubris
|
2
|
+
|
3
|
+
## Description
|
4
|
+
|
5
|
+
This is a quick and dirty way to call Haskell functions from ruby.
|
6
|
+
|
7
|
+
Hubris will wash your car, lie to your boss, and salvage your love life.
|
8
|
+
If you are very, very lucky, it might also let you get some uber-fast
|
9
|
+
functional goodness into your ruby programs through the back door.
|
10
|
+
|
11
|
+
## Synopsis
|
12
|
+
|
13
|
+
Eventually, we'll integrate with RubyInline or something similar,
|
14
|
+
so we can write inline Haskell. Until that happy day:
|
15
|
+
|
16
|
+
* write a haskell file (say sample/foo.hs) with some ccall exports declared
|
17
|
+
* call "jhc_builder.sh foo.hs". This will build "libfoo.so".
|
18
|
+
* write a ruby file similar to sample/hsload.rb in order to call the functions from ruby
|
19
|
+
|
20
|
+
If all else fails, mail mwotton@gmail.com with tales of woe.
|
21
|
+
|
22
|
+
## Requirements
|
23
|
+
|
24
|
+
|
25
|
+
* jhc (John's Haskell Compiler)
|
26
|
+
* gcc (oh, come on. don't tell me you don't have it)
|
27
|
+
* ruby 1.8.6 or higher
|
28
|
+
* Mac OSX or Linux
|
29
|
+
* bash
|
30
|
+
|
31
|
+
## Install
|
32
|
+
|
33
|
+
- Install the Hubris gem from RubyForge
|
34
|
+
|
35
|
+
<pre>
|
36
|
+
sudo gem install hubris
|
37
|
+
</pre>
|
38
|
+
|
39
|
+
- Or live on the bleeding edge and install the latest from Github
|
40
|
+
|
41
|
+
<pre>
|
42
|
+
gem source --add http://gems.github.com
|
43
|
+
sudo gem install mwotton-hubris
|
44
|
+
</pre>
|
45
|
+
|
46
|
+
- Get the [Haskell Platform][haskell_platform] and install this for your platform (now we have GHC for building JHC)
|
47
|
+
|
48
|
+
- Install Darcs (so we can access the JHC repository)
|
49
|
+
|
50
|
+
<pre>
|
51
|
+
sudo cabal update
|
52
|
+
sudo cabal install --global darcs
|
53
|
+
</pre>
|
54
|
+
|
55
|
+
Don't worry too much about any warnings that you may see while this builds.
|
56
|
+
|
57
|
+
- Install [JHC][jhc] (the instructions there are slightly out of date so use the following instead). Before you start get a cup of tea, and get comfy. This may take a while...
|
58
|
+
|
59
|
+
<pre>
|
60
|
+
darcs get --partial http://repetae.net/repos/jhc
|
61
|
+
cd jhc/src
|
62
|
+
darcs get --partial http://repetae.net/repos/Doc
|
63
|
+
cd ../lib
|
64
|
+
darcs get --partial http://darcs.haskell.org/packages/haskell98
|
65
|
+
darcs get --partial http://darcs.haskell.org/packages/containers
|
66
|
+
</pre>
|
67
|
+
|
68
|
+
- Copy the jhc binary in the root jhc directory to somewhere in your $PATH
|
69
|
+
|
70
|
+
## Troubleshooting installation
|
71
|
+
|
72
|
+
JHC doesn't have a heap of mac users, so there were a few problems I had in installing.
|
73
|
+
|
74
|
+
in ./src/data/rts/jhc_rts_header.h:
|
75
|
+
|
76
|
+
-#include <endian.h>
|
77
|
+
+#include <sys/types.h>
|
78
|
+
+#include <sys/param.h>
|
79
|
+
|
80
|
+
make libs doesn't always seem to work off the bat. so long as jhc builds, it's probably ok
|
81
|
+
for the moment - copy the jhc binary in the root jhc directory to somewhere in your $PATH.
|
82
|
+
|
83
|
+
## Contributors
|
84
|
+
|
85
|
+
|
86
|
+
* Mark Wotton
|
87
|
+
* James Britt
|
88
|
+
* Josh Price
|
89
|
+
|
90
|
+
## License
|
91
|
+
|
92
|
+
(The MIT License)
|
93
|
+
|
94
|
+
Copyright (c) 2009 Mark Wotton
|
95
|
+
|
96
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
97
|
+
a copy of this software and associated documentation files (the
|
98
|
+
'Software'), to deal in the Software without restriction, including
|
99
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
100
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
101
|
+
permit persons to whom the Software is furnished to do so, subject to
|
102
|
+
the following conditions:
|
103
|
+
|
104
|
+
The above copyright notice and this permission notice shall be
|
105
|
+
included in all copies or substantial portions of the Software.
|
106
|
+
|
107
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
108
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
109
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
110
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
111
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
112
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
113
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
114
|
+
|
115
|
+
|
116
|
+
[haskell_platform]: http://hackage.haskell.org/platform/
|
117
|
+
[jhc]: http://repetae.net/computer/jhc/
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# TODO - want other tests/tasks run by default? Add them to the list
|
2
|
+
|
3
|
+
# remove_task :default
|
4
|
+
|
5
|
+
# task :default => [:spec, :features]
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
gem 'hoe', '>= 2.1.0'
|
9
|
+
require 'hoe'
|
10
|
+
require 'fileutils'
|
11
|
+
require './lib/hubris'
|
12
|
+
|
13
|
+
Hoe.plugin :newgem
|
14
|
+
# Hoe.plugin :website
|
15
|
+
# Hoe.plugin :cucumberfeatures
|
16
|
+
|
17
|
+
# Generate all the Rake tasks
|
18
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
19
|
+
$hoe = Hoe.spec 'hubris' do
|
20
|
+
self.developer 'Mark Wotton', 'mwotton@gmail.com'
|
21
|
+
self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
|
22
|
+
self.rubyforge_name = "hubris"
|
23
|
+
self.summary = 'tool to help build .so files from haskell code for use in Ruby via dl'
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'newgem/tasks'
|
27
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
28
|
+
|
29
|
+
# TODO - want other tests/tasks run by default? Add them to the list
|
30
|
+
# remove_task :default
|
31
|
+
# task :default => [:spec, :features]
|
data/bin/jhc_builder
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
# $1 is our source haskell
|
4
|
+
rm -rf tmp.old
|
5
|
+
mv tmp tmp.old
|
6
|
+
mkdir tmp
|
7
|
+
tmp="tmp/$1"
|
8
|
+
cat $1 >> $tmp
|
9
|
+
echo "main :: IO ()" >> $tmp
|
10
|
+
echo "main = return ()" >> $tmp
|
11
|
+
|
12
|
+
cd tmp
|
13
|
+
jhc "$1"
|
14
|
+
sed -i 's/^main(/disregard_main(/' hs.out_code.c
|
15
|
+
gcc '-std=gnu99' -D_GNU_SOURCE '-falign-functions=4' -ffast-math -Wshadow -Wextra -Wall -Wno-unused-parameter -o libdynhs.so \
|
16
|
+
hs.out_code.c -DNDEBUG -O3 -fPIC -shared
|
17
|
+
mv libdynhs.so ..
|
data/lib/Mapper.hs
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
{-# LANGUAGE FlexibleInstances, ForeignFunctionInterface #-}
|
2
|
+
{-# INCLUDE <ruby.h> #-}
|
3
|
+
|
4
|
+
module Mapper where
|
5
|
+
import qualified Data.ByteString.Char8 as B -- do we need Unicode?
|
6
|
+
import Data.Array.CArray as CArray
|
7
|
+
import Data.Word
|
8
|
+
import Foreign.C.String
|
9
|
+
import Foreign.Ptr
|
10
|
+
import Foreign.Storable
|
11
|
+
import RubyMap
|
12
|
+
import System.IO.Unsafe
|
13
|
+
newtype RString = RString CString
|
14
|
+
newtype RSymbol = RSymbol Word
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
class Rubyable a where
|
19
|
+
toRuby :: a -> RValue
|
20
|
+
fromRuby :: RValue -> a
|
21
|
+
|
22
|
+
instance Rubyable Int where
|
23
|
+
toRuby a = T_FIXNUM a
|
24
|
+
fromRuby (T_FIXNUM a) = a
|
25
|
+
|
26
|
+
instance Rubyable Integer where
|
27
|
+
toRuby a = T_ a
|
28
|
+
fromRuby (T_FIXNUM a) = a
|
29
|
+
|
30
|
+
instance Rubyable Bool where
|
31
|
+
toRuby False = T_FALSE
|
32
|
+
toRuby True = T_TRUE
|
33
|
+
fromRuby T_FALSE = False
|
34
|
+
fromRuby T_TRUE = True
|
35
|
+
|
36
|
+
instance Rubyable (CArray Word RValue) where
|
37
|
+
toRuby arr = T_ARRAY arr
|
38
|
+
fromRuby (T_ARRAY arr) = arr
|
39
|
+
|
40
|
+
instance Rubyable a => Rubyable [a] where
|
41
|
+
toRuby l = unsafePerformIO $ do
|
42
|
+
arr <- rb_ary_new2 (length l)
|
43
|
+
mapM_ (\(i,x) -> rb_ary_store i arr x) l
|
44
|
+
return $ T_ARRAY arr
|
45
|
+
fromRuby (T_ARRAY arr) = map fromRuby $ CArray.elems arr
|
46
|
+
|
47
|
+
instance Rubyable RString where
|
48
|
+
toRuby (RString cstr) = T_STRING cstr
|
49
|
+
fromRuby (T_STRING cstr) = RString cstr
|
50
|
+
|
51
|
+
instance Rubyable RSymbol where
|
52
|
+
toRuby (RSymbol index) = T_SYMBOL index
|
53
|
+
fromRuby (T_SYMBOL index) = RSymbol index
|
54
|
+
|
55
|
+
|
56
|
+
-- -- | T_REGEXP
|
57
|
+
-- -- the array needs to be managed by ruby
|
58
|
+
-- | T_ARRAY (CArray Word RValue)
|
59
|
+
-- | T_FIXNUM Int --fixme, probably
|
60
|
+
-- -- the hash needs to be managed by ruby
|
61
|
+
-- | T_HASH Int -- definitely FIXME - native ruby hashes, or going to translitrate?
|
62
|
+
-- -- | T_STRUCT
|
63
|
+
-- | T_BIGNUM Integer
|
64
|
+
-- -- | T_FILE
|
65
|
+
-- | T_TRUE
|
66
|
+
-- | T_FALSE
|
67
|
+
-- -- | T_DATA
|
68
|
+
-- | T_SYMBOL Word -- interned string
|
69
|
+
|
70
|
+
instance Storable RValue where
|
71
|
+
sizeOf _ = 8 -- urgh, fixme. it's just a pointer, basically.
|
72
|
+
alignment _ = 8
|
73
|
+
|
74
|
+
-- so here's the problem - TYPE(...) is a macro, so we can't call it from haskell.
|
75
|
+
-- peek ptr = case toEnum $ rb_type ptr of
|
76
|
+
-- RT_FLOAT -> T_FLOAT (rb_num2dbl ptr)
|
77
|
+
-- RT_STRING -> T_STRING (rb_str_to_str ptr)
|
78
|
+
|
79
|
+
-- otherwise -> undefined
|
80
|
+
|
81
|
+
|
82
|
+
-- undefined -- insert definition of loadruby
|
83
|
+
-- poke ptr a = undefined
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
loadRuby :: Ptr RValue -> IO RValue
|
90
|
+
loadRuby ptr = undefined
|
91
|
+
|
92
|
+
dumpRuby :: RValue -> IO (Ptr RValue)
|
93
|
+
dumpRuby rval = undefined
|
data/lib/RubyMap.chs
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
{-# LANGUAGE ForeignFunctionInterface #-}
|
2
|
+
{-# LANGUAGE TypeSynonymInstances #-}
|
3
|
+
module RubyMap where
|
4
|
+
#include "rshim.h"
|
5
|
+
#include <ruby.h>
|
6
|
+
|
7
|
+
-- import Data.Array.CArray as CArray
|
8
|
+
import Data.Word
|
9
|
+
import Foreign.Ptr
|
10
|
+
import Foreign.C.Types
|
11
|
+
import Foreign.C.String
|
12
|
+
|
13
|
+
{# context lib="rshim" #}
|
14
|
+
{# enum RubyType {} deriving (Eq) #} -- maybe Ord?
|
15
|
+
|
16
|
+
-- can we have a type for Value, plz?
|
17
|
+
type Value = Ptr () -- fixme
|
18
|
+
|
19
|
+
-- we're being a bit filthy here - the interface is all macros, so we're digging in to find what it actually is
|
20
|
+
foreign import ccall unsafe "rshim.h rtype" rb_type :: Value -> CInt
|
21
|
+
-- FIXME jhc doesn't like importing floating point numbers, for some reason.
|
22
|
+
-- foreign import ccall unsafe "ruby.h rb_num2dbl" rb_num2dbl :: Value -> CDouble
|
23
|
+
foreign import ccall unsafe "ruby.h rb_str_to_str" rb_str_to_str :: Value -> CString
|
24
|
+
foreign import ccall unsafe "ruby.h rb_ary_new2" rb_ary_new :: Int -> IO Value
|
25
|
+
foreign import ccall unsafe "ruby.h rb_ary_store" rb_ary_store :: Value -> Int -> Value -> IO ()
|
26
|
+
|
27
|
+
|
28
|
+
-- all values in here need to be allocated and tracked by ruby.
|
29
|
+
-- ByteStrings... hm. Probably better to keep them as C-side ruby strings.
|
30
|
+
-- better come back and expand this later
|
31
|
+
data RValue = T_NIL
|
32
|
+
-- | T_OBJECT
|
33
|
+
-- | T_CLASS
|
34
|
+
-- | T_MODULE
|
35
|
+
| T_FLOAT Double
|
36
|
+
| T_STRING CString
|
37
|
+
-- | T_REGEXP
|
38
|
+
-- the array needs to be managed by ruby
|
39
|
+
-- | T_ARRAY (CArray Word RValue)
|
40
|
+
| T_FIXNUM Int --fixme, probably
|
41
|
+
-- the hash needs to be managed by ruby
|
42
|
+
| T_HASH Int -- definitely FIXME - native ruby hashes, or going to translitrate?
|
43
|
+
-- | T_STRUCT
|
44
|
+
| T_BIGNUM Integer
|
45
|
+
-- | T_FILE
|
46
|
+
| T_TRUE
|
47
|
+
| T_FALSE
|
48
|
+
-- | T_DATA
|
49
|
+
| T_SYMBOL Word -- interned string
|
data/lib/extconf.rb
ADDED
data/lib/hubris.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'dl/import'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
module Hubris
|
5
|
+
VERSION = '0.0.1'
|
6
|
+
class Hubris
|
7
|
+
extend DL::Importer # Importable in 1.8, FIXME
|
8
|
+
|
9
|
+
def initialize(haskell_str)
|
10
|
+
build_jhc(haskell_str)
|
11
|
+
end
|
12
|
+
|
13
|
+
def noisy(str)
|
14
|
+
print "Noisy: #{str}\n"
|
15
|
+
system(str)
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_jhc(haskell_str)
|
19
|
+
file=Tempfile.new("TempHs.hs")
|
20
|
+
# cheap way: assert type sigs binding to RValue. Might be able to do better after,
|
21
|
+
# but this'll do for the moment
|
22
|
+
file.print(<<EOF
|
23
|
+
import RubyMap
|
24
|
+
import Mapper
|
25
|
+
main :: IO ()
|
26
|
+
main = return ()
|
27
|
+
EOF
|
28
|
+
)
|
29
|
+
file.print(haskell_str)
|
30
|
+
# TODO add foreign export calls immediately for each toplevel func
|
31
|
+
# cheap hacky way: first word on each line, nub it to get rid of
|
32
|
+
# function types.
|
33
|
+
# tricky bit: generating interface for each
|
34
|
+
functions={}
|
35
|
+
haskell_str.each_line do |line|
|
36
|
+
# if line ~= /^[^ ]/ then
|
37
|
+
functions[line.split(/ /)[0]]=1
|
38
|
+
end
|
39
|
+
functions.keys.each do |fname|
|
40
|
+
file.print "#{fname} :: RValue -> IO RValue\n"
|
41
|
+
# end
|
42
|
+
end
|
43
|
+
|
44
|
+
file.flush
|
45
|
+
# this is so dumb
|
46
|
+
system("cat #{file.path}; cp #{file.path} #{file.path}.hs")
|
47
|
+
if(0!=noisy("jhc #{file.path}.hs -ilib")) then
|
48
|
+
raise SyntaxError, "JHC build failed"
|
49
|
+
end
|
50
|
+
# output goes to hs_out.code.c
|
51
|
+
# don't need to grep out main any more
|
52
|
+
# FIXME unique name for dynamic lib
|
53
|
+
lib = Tempfile.new("libDyn.so")
|
54
|
+
if(0!=noisy("gcc '-std=gnu99' -D_GNU_SOURCE -D'-falign-functions=4' '-D_JHC_STANDALONE=0' -ffast-math -Wshadow -Wextra -Wall -Wno-unused-parameter -o libdynhs.so \
|
55
|
+
-DNDEBUG -D_JHC_STANDALONE=0 -O3 -fPIC -shared #{file.dirname}/hs.out_code.c -o {lib.name}")) then
|
56
|
+
raise SyntaxError, "C build failed"
|
57
|
+
end
|
58
|
+
dlload lib.name
|
59
|
+
# get all the headers from ... somewhere
|
60
|
+
headers = []
|
61
|
+
headers.each do |header|
|
62
|
+
extern header
|
63
|
+
end
|
64
|
+
extern "hs_init"
|
65
|
+
hs_init
|
66
|
+
# TODO load all the object headers into the lib
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
data/lib/rshim.c
ADDED
data/lib/rshim.h
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
#ifndef __rshim_h__
|
2
|
+
#define __rshim_h__
|
3
|
+
#define HAVE_STRUCT_TIMESPEC 1
|
4
|
+
// this is about as filthy as it looks, but c2hs chokes otherwise.
|
5
|
+
|
6
|
+
#include <ruby.h>
|
7
|
+
|
8
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
9
|
+
|
10
|
+
#include <ruby/encoding.h>
|
11
|
+
|
12
|
+
#define ENCODED_STR_NEW2(str, encoding) \
|
13
|
+
({ \
|
14
|
+
VALUE _string = rb_str_new2((const char *)str); \
|
15
|
+
int _enc = rb_enc_find_index(encoding); \
|
16
|
+
rb_enc_associate_index(_string, _enc); \
|
17
|
+
_string; \
|
18
|
+
})
|
19
|
+
|
20
|
+
#else
|
21
|
+
|
22
|
+
#define ENCODED_STR_NEW2(str, encoding) \
|
23
|
+
rb_str_new2((const char *)str)
|
24
|
+
|
25
|
+
#endif
|
26
|
+
|
27
|
+
// did this really have to be a macro? BAD MATZ
|
28
|
+
unsigned int rtype(VALUE obj);
|
29
|
+
|
30
|
+
|
31
|
+
// argh, and again
|
32
|
+
enum RubyType {
|
33
|
+
RT_NONE = T_NONE,
|
34
|
+
|
35
|
+
RT_NIL = T_NIL ,
|
36
|
+
RT_OBJECT = T_OBJECT ,
|
37
|
+
RT_CLASS = T_CLASS ,
|
38
|
+
RT_ICLASS = T_ICLASS ,
|
39
|
+
RT_MODULE = T_MODULE ,
|
40
|
+
RT_FLOAT = T_FLOAT ,
|
41
|
+
RT_STRING = T_STRING ,
|
42
|
+
RT_REGEXP = T_REGEXP ,
|
43
|
+
RT_ARRAY = T_ARRAY ,
|
44
|
+
RT_FIXNUM = T_FIXNUM ,
|
45
|
+
RT_HASH = T_HASH ,
|
46
|
+
RT_STRUCT = T_STRUCT ,
|
47
|
+
RT_BIGNUM = T_BIGNUM ,
|
48
|
+
RT_FILE = T_FILE ,
|
49
|
+
|
50
|
+
RT_TRUE = T_TRUE ,
|
51
|
+
RT_FALSE = T_FALSE ,
|
52
|
+
RT_DATA = T_DATA ,
|
53
|
+
RT_MATCH = T_MATCH ,
|
54
|
+
RT_SYMBOL = T_SYMBOL ,
|
55
|
+
|
56
|
+
// t_BLKTAG = T_BLKTAG , // this one is broken in ruby 1.9
|
57
|
+
|
58
|
+
RT_UNDEF = T_UNDEF ,
|
59
|
+
// t_VARMAP = T_VARMAP , // this one is broken in ruby 1.9
|
60
|
+
// t_SCOPE = T_SCOPE , // this one is broken in ruby 1.9
|
61
|
+
RT_NODE = T_NODE ,
|
62
|
+
|
63
|
+
RT_MASK = T_MASK ,
|
64
|
+
};
|
65
|
+
#endif
|
data/sample/Makefile
ADDED
data/sample/Test.hs
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
{-# LANGUAGE ForeignFunctionInterface #-}
|
2
|
+
|
3
|
+
-- module Test where
|
4
|
+
|
5
|
+
import Foreign.C.Types
|
6
|
+
-- import Data.Map
|
7
|
+
import Maybe
|
8
|
+
|
9
|
+
-- main = putStrLn "11"
|
10
|
+
|
11
|
+
fibonacci :: Int -> Int
|
12
|
+
fibonacci n = fibs !! n
|
13
|
+
where fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
|
14
|
+
|
15
|
+
-- local_map = Data.Map.fromList [(1,2), (3,4)]
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
-- lookup_hs ::CInt -> CInt
|
20
|
+
-- lookup_hs = fromIntegral . Maybe.fromJust . ((flip Data.Map.lookup) local_map) . fromIntegral
|
21
|
+
-- foreign export ccall lookup_hs :: CInt -> CInt
|
22
|
+
|
23
|
+
fibonacci_hs :: CInt -> CInt
|
24
|
+
fibonacci_hs = fromIntegral . fibonacci . fromIntegral
|
25
|
+
|
26
|
+
foreign export ccall fibonacci_hs :: CInt -> CInt
|
27
|
+
|
28
|
+
-- main = putStrLn "foo"
|
data/sample/hsload.rb
ADDED
data/spec/hubris_spec.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
# Time to add your specs!
|
4
|
+
# http://rspec.info/
|
5
|
+
describe "Hubris" do
|
6
|
+
|
7
|
+
it "can whine like a little baby when you pass it bad haskell" do
|
8
|
+
lambda {Hubris::Hubris.new("broken _ = return (1 + \"a string\")")}.should raise_error(SyntaxError)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "can sing like a golden bird when you treat it right, aw yeah" do
|
12
|
+
lambda {Hubris::Hubris.new("working _ = return (toRuby $ 1 + 2)")}.should_not raise_error
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can double an int in Haskell-land" do
|
16
|
+
haskell = Hubris::Hubris.new(<<EOF
|
17
|
+
-- partial function, will probably crash and burn
|
18
|
+
double i = let j = fromRuby i in return (toRuby $ j + j)
|
19
|
+
EOF
|
20
|
+
)
|
21
|
+
haskell.double(1).should eql(2)
|
22
|
+
haskell.double("foo").should raise_error(RuntimeError)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/spec/spec_helper.rb
ADDED
data/tasks/rspec.rake
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
begin
|
2
|
+
require 'spec'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
5
|
+
require 'spec'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'spec/rake/spectask'
|
9
|
+
rescue LoadError
|
10
|
+
puts <<-EOS
|
11
|
+
To use rspec for testing you must install rspec gem:
|
12
|
+
gem install rspec
|
13
|
+
EOS
|
14
|
+
exit(0)
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Run the specs under spec/models"
|
18
|
+
Spec::Rake::SpecTask.new do |t|
|
19
|
+
t.spec_opts = ['--options', "spec/spec.opts"]
|
20
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mwotton-hubris
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mark Wotton
|
8
|
+
- James Britt
|
9
|
+
- Josh Price
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
|
14
|
+
date: 2009-08-16 00:00:00 -07:00
|
15
|
+
default_executable:
|
16
|
+
dependencies: []
|
17
|
+
|
18
|
+
description: A Ruby Haskell bridge
|
19
|
+
email: mwotton@gmail.com
|
20
|
+
executables: []
|
21
|
+
|
22
|
+
extensions: []
|
23
|
+
|
24
|
+
extra_rdoc_files:
|
25
|
+
- README.markdown
|
26
|
+
files:
|
27
|
+
- bin/jhc_builder
|
28
|
+
- History.txt
|
29
|
+
- lib/extconf.rb
|
30
|
+
- lib/hubris.rb
|
31
|
+
- lib/Mapper.hs
|
32
|
+
- lib/rshim.c
|
33
|
+
- lib/rshim.h
|
34
|
+
- lib/RubyMap.chs
|
35
|
+
- Rakefile
|
36
|
+
- README.markdown
|
37
|
+
- sample/hsload.rb
|
38
|
+
- sample/Makefile
|
39
|
+
- sample/Test.hs
|
40
|
+
- spec/hubris_spec.rb
|
41
|
+
- spec/spec.opts
|
42
|
+
- spec/spec_helper.rb
|
43
|
+
- tasks/rspec.rake
|
44
|
+
has_rdoc: false
|
45
|
+
homepage: http://github.com/mwotton/hubris
|
46
|
+
licenses:
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options:
|
49
|
+
- --inline-source
|
50
|
+
- --charset=UTF-8
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project: hubris
|
68
|
+
rubygems_version: 1.3.5
|
69
|
+
signing_key:
|
70
|
+
specification_version: 2
|
71
|
+
summary: Hubris is a Ruby Haskell bridge allowing you to call Haskell functions from your Ruby code.
|
72
|
+
test_files: []
|
73
|
+
|