Ruby Interface of Erlang

K

KDr2

[Note: parts of this message were removed to make it a legal post.]

Hello, erveyone,I just start a new project called erlix,the ruby interface
for erlang,at http://code.google.com/p/erlix ,you may need it.

Erlix can help you communicating with the erlang-node, you can write
distributed programs with ruby and erlang easily.

Just read its api docs if you need it.
 
K

KDr2

[Note: parts of this message were removed to make it a legal post.]

1.Erlectricity interact with Erlang through the ports system. If you are an
Erlang programmer,you will feel confused about it:
Where are my Erlang-Terms? How to match two Terms? How to make my
ruby-process an erlang-node? so i start the project erlix.
2.erlix is based on the erl_interface, all its api is the same as
erl_interface:

irb(main):001:0> require "erlix"
=> true
irb(main):002:0>
list=ErlixList.new([ErlixAtom.new("erlatom"),ErlixInt.new(2),ErlixFloat.new(3.0)])
=> #<ErlixList:0xb7c738e8>
irb(main):003:0> list.puts
[erlatom,2,3.000000]
=> nil
irb(main):004:0> list.match("[A,2,B]")
=> true
irb(main):005:0> list.match("[A,3,B]")
=> false
irb(main):006:0> b=list.mget("[Atom,_,_]","Atom")
=> erlatom
irb(main):007:0> b.class
=> ErlixAtom
irb(main):008:0> ObjectSpace.each_object(Class).inject([]){|a,i|a<< i if
i.ancestors.any?{|k|k==ErlixTerm};a}
=> [ErlixBinary, ErlixTuple, ErlixList, ErlixAtom, ErlixRef, ErlixPid,
ErlixFloat, ErlixUInt, ErlixInt]
irb(main):009:0>

And... use erlix, you can make you ruby-process an Erlang-Node(read the test
code in the src-package) hehe

:)
 
K

KDr2

[Note: parts of this message were removed to make it a legal post.]

I release erlix-v0.3 today:

bugfix:

IO block bug in
ErlixConnection?<http://code.google.com/p/erlix/w/edit/ErlixConnection>#erecv


feature:

1. ErlixList?
<http://code.google.com/p/erlix/w/edit/ErlixList>#new("string")

2. ErlixConnection?<http://code.google.com/p/erlix/w/edit/ErlixConnection>#close

3. ErlixConnection?<http://code.google.com/p/erlix/w/edit/ErlixConnection>#closed?

4. ErlixConnection?<http://code.google.com/p/erlix/w/edit/ErlixConnection>
#rpc("module","function",ErlixTermList?<http://code.google.com/p/erlix/w/edit/ErlixTermList>)

5. ErlixConnection?<http://code.google.com/p/erlix/w/edit/ErlixConnection>#peer


see the section Erlix RPC on
http://code.google.com/p/erlix/wiki/ErlixTutorial


1.Erlectricity interact with Erlang through the ports system. If you are an
Erlang programmer,you will feel confused about it:
Where are my Erlang-Terms? How to match two Terms? How to make my
ruby-process an erlang-node? so i start the project erlix.
2.erlix is based on the erl_interface, all its api is the same as
erl_interface:

irb(main):001:0> require "erlix"
=> true
irb(main):002:0>

list=ErlixList.new([ErlixAtom.new("erlatom"),ErlixInt.new(2),ErlixFloat.new(3.0)])
=> #<ErlixList:0xb7c738e8>
irb(main):003:0> list.puts
[erlatom,2,3.000000]
=> nil
irb(main):004:0> list.match("[A,2,B]")
=> true
irb(main):005:0> list.match("[A,3,B]")
=> false
irb(main):006:0> b=list.mget("[Atom,_,_]","Atom")
=> erlatom
irb(main):007:0> b.class
=> ErlixAtom
irb(main):008:0> ObjectSpace.each_object(Class).inject([]){|a,i|a<< i if
i.ancestors.any?{|k|k==ErlixTerm};a}
=> [ErlixBinary, ErlixTuple, ErlixList, ErlixAtom, ErlixRef, ErlixPid,
ErlixFloat, ErlixUInt, ErlixInt]
irb(main):009:0>

And... use erlix, you can make you ruby-process an Erlang-Node(read the
test
code in the src-package) hehe

:)




Erlectricity
 
B

Brian Candler

KDr2 said:

Just a thought: if you were to move all these constants into an Erlix
module (e.g. Erlix::Tuple, Erlix::Int etc) then you could 'include
Erlix' and save a lot of typing. The only conflict I can see would be
Float, and you can always use ::Float to get the Ruby one should you
need it.

The separate namespace can also be useful when creating objects
dynamically:
type = "Tuple"
obj = Erlix.const_get(type).new

You could also consider module functions as a shortcut for constructors.

module Erlix
# Fake implementation
class Tuple
def initialize(*x)
@data = *x
end
end
class Int
def initialize(x)
@data = x
end
end

# Module functions
def Tuple(*x)
Tuple.new(*x)
end
module_function :Tuple
def Int(*x)
Int.new(*x)
end
module_function :Int
# etc
end

include Erlix
puts Tuple(Tuple(Int(1)), Int(2)).inspect

Regards,

Brian.
 
K

KDr2

[Note: parts of this message were removed to make it a legal post.]

Thank you for your advise :) They are very useful for me.
 
B

Brian Candler

BTW, I haven't been able to get it to build yet - it's stuck looking for
-lei

$ ruby configure.rb
--with-ei-dir=/usr/lib/erlang/lib/erl_interface-3.5.7
*** ./extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers. Check the mkmf.log file for more
details. You may need configuration options.

Provided configuration options:
--with-opt-dir
--without-opt-dir
--with-opt-include
--without-opt-include=${opt-dir}/include
--with-opt-lib
--without-opt-lib=${opt-dir}/lib
--with-make-prog
--without-make-prog
--srcdir=.
--curdir
--ruby=/usr/local/bin/ruby
--with-ei-dir
--with-ei-include
--without-ei-include=${ei-dir}/include
--with-ei-lib
--without-ei-lib=${ei-dir}/lib
--with-eilib
--without-eilib
checking for erl_init() in -lei... no
error: erl_interface not found!
$ ls /usr/lib/erlang/lib/erl_interface-3.5.7/
bin doc include info lib src
$

I've tried various values for --with-eir without success. This is under
Ubuntu Hardy but with erlang 12.b.3 from Intrepid. (Works fine with
CouchDB, for example).

On a different point, I noticed the following in the C source:

//check: all elements' must be ErlixTerm
for(i=0;i<RARRAY(array)->len;i++){
VALUE e=RARRAY(array)->ptr;
if(!IS_ETERM(e)){
rb_raise(rb_eTypeError,"all tuple's elements must be ErlixTerm!");
}
}

I think it could be useful if some automatic conversions were done here.
e.g. Fixnum converted to Erlix[::]Int automatically, String to a List,
maybe Array to Tuple. However maybe they're done elsewhere - as I say,
I've not been able to run it yet.

Regards,

Brian.
 
B

Brian Candler

Brian said:
BTW, I haven't been able to get it to build yet - it's stuck looking for
-lei

I found the problem. In configure.rb I had to add "-pthread" to
--with-ldflags. Without that, mkmf.log was showing the following errors:

"gcc -o conftest -I. -I/usr/local/lib/ruby/1.8/i686-linux -I./src
-I/usr/lib/erlang/lib/erl_interface-3.5.7/include -g -O2 conftest.c
-L'.' -L'/usr/local/lib' -Wl,-R'/usr/local/lib'
-L'/usr/lib/erlang/lib/erl_interface-3.5.7/lib'
-Wl,-R'/usr/lib/erlang/lib/erl_interface-3.5.7/lib' -lei -lerl_interface
-lruby-static -lei -ldl -lcrypt -lm -lc"
/usr/lib/erlang/lib/erl_interface-3.5.7/lib/libei.a(ei_pthreads.o): In
function `__erl_errno_place':
(.text+0x4c): undefined reference to `pthread_once'
/usr/lib/erlang/lib/erl_interface-3.5.7/lib/libei.a(ei_pthreads.o): In
function `__erl_errno_place':
(.text+0x7a): undefined reference to `pthread_getspecific'
/usr/lib/erlang/lib/erl_interface-3.5.7/lib/libei.a(ei_pthreads.o): In
function `__erl_errno_place':
(.text+0xa4): undefined reference to `pthread_setspecific'
/usr/lib/erlang/lib/erl_interface-3.5.7/lib/libei.a(ei_pthreads.o): In
function `__erl_errno_place':
(.text+0xb6): undefined reference to `pthread_getspecific'
/usr/lib/erlang/lib/erl_interface-3.5.7/lib/libei.a(ei_pthreads.o): In
function `erl_errno_key_alloc':
(.text+0x136): undefined reference to `pthread_key_create'
/usr/lib/erlang/lib/erl_interface-3.5.7/lib/libei.a(ei_pthreads.o): In
function `ei_m_trylock':
(.text+0x189): undefined reference to `pthread_mutex_trylock'
collect2: ld returned 1 exit status

However, even after successful compilation, it still didn't work due to
a runtime linker error on "__erl_errno":

irb(main):001:0> require 'erlix'
LoadError: /usr/local/lib/ruby/site_ruby/1.8/i686-linux/erlix.so:
undefined symbol: __erl_errno -
/usr/local/lib/ruby/site_ruby/1.8/i686-linux/erlix.so
from /usr/local/lib/ruby/site_ruby/1.8/i686-linux/erlix.so
from (irb):1

After poking around header files, I decided that the way to fix this
was:

$ make clean
$ make CPPFLAGS=-D_REENTRANT

And it happily builds and runs the sample now. I don't know how
configure.rb should decide for itself whether -D_REENTRANT is needed or
not.

A few more suggestions:

(1) For converting objects to strings, you should implement a "to_s"
method, not "puts". Current behaviour is rather un-rubylike:

irb(main):008:0> t=ErlixTuple.new([a1,f,b,a2,i])
=> #<ErlixTuple:0xb7d78d74>
irb(main):009:0> t
=> #<ErlixTuple:0xb7d78d74>
irb(main):010:0> t.puts ## unexpected
{atom1,17.000000,#Bin,atom2,101}
=> nil
irb(main):011:0> t.to_s
=> "#<ErlixTuple:0xb7d78d74>" ## unexpected

This would also allow you to interpolate terms into strings, e.g.

puts "The response was #{t}"

(2) It would be helpful if ErlixTurple took a variable number of
arguments, instead of a single array. That would let you write

ErlixTuple.new(a1,f,b,a2,i)

This wouldn't prevent you from using an array if you like, because Ruby
provides a 'splat' operator:

arr = [a1,f,b,a2,i]
ErlixTuple.new(*arr)

Anyway, keep up the good work - this is looking promising!

Regards,

Brian.
 
K

KDr2

[Note: parts of this message were removed to make it a legal post.]

Thank you, I just hava done little update :
http://github.com/KDr2/erlix/tree/master#fn1

I will go on and on ...

Brian said:
BTW, I haven't been able to get it to build yet - it's stuck looking for
-lei

I found the problem. In configure.rb I had to add "-pthread" to
--with-ldflags. Without that, mkmf.log was showing the following errors:

"gcc -o conftest -I. -I/usr/local/lib/ruby/1.8/i686-linux -I./src
-I/usr/lib/erlang/lib/erl_interface-3.5.7/include -g -O2 conftest.c
-L'.' -L'/usr/local/lib' -Wl,-R'/usr/local/lib'
-L'/usr/lib/erlang/lib/erl_interface-3.5.7/lib'
-Wl,-R'/usr/lib/erlang/lib/erl_interface-3.5.7/lib' -lei -lerl_interface
-lruby-static -lei -ldl -lcrypt -lm -lc"
/usr/lib/erlang/lib/erl_interface-3.5.7/lib/libei.a(ei_pthreads.o): In
function `__erl_errno_place':
(.text+0x4c): undefined reference to `pthread_once'
/usr/lib/erlang/lib/erl_interface-3.5.7/lib/libei.a(ei_pthreads.o): In
function `__erl_errno_place':
(.text+0x7a): undefined reference to `pthread_getspecific'
/usr/lib/erlang/lib/erl_interface-3.5.7/lib/libei.a(ei_pthreads.o): In
function `__erl_errno_place':
(.text+0xa4): undefined reference to `pthread_setspecific'
/usr/lib/erlang/lib/erl_interface-3.5.7/lib/libei.a(ei_pthreads.o): In
function `__erl_errno_place':
(.text+0xb6): undefined reference to `pthread_getspecific'
/usr/lib/erlang/lib/erl_interface-3.5.7/lib/libei.a(ei_pthreads.o): In
function `erl_errno_key_alloc':
(.text+0x136): undefined reference to `pthread_key_create'
/usr/lib/erlang/lib/erl_interface-3.5.7/lib/libei.a(ei_pthreads.o): In
function `ei_m_trylock':
(.text+0x189): undefined reference to `pthread_mutex_trylock'
collect2: ld returned 1 exit status

However, even after successful compilation, it still didn't work due to
a runtime linker error on "__erl_errno":

irb(main):001:0> require 'erlix'
LoadError: /usr/local/lib/ruby/site_ruby/1.8/i686-linux/erlix.so:
undefined symbol: __erl_errno -
/usr/local/lib/ruby/site_ruby/1.8/i686-linux/erlix.so
from /usr/local/lib/ruby/site_ruby/1.8/i686-linux/erlix.so
from (irb):1

After poking around header files, I decided that the way to fix this
was:

$ make clean
$ make CPPFLAGS=-D_REENTRANT

And it happily builds and runs the sample now. I don't know how
configure.rb should decide for itself whether -D_REENTRANT is needed or
not.

A few more suggestions:

(1) For converting objects to strings, you should implement a "to_s"
method, not "puts". Current behaviour is rather un-rubylike:

irb(main):008:0> t=ErlixTuple.new([a1,f,b,a2,i])
=> #<ErlixTuple:0xb7d78d74>
irb(main):009:0> t
=> #<ErlixTuple:0xb7d78d74>
irb(main):010:0> t.puts ## unexpected
{atom1,17.000000,#Bin,atom2,101}
=> nil
irb(main):011:0> t.to_s
=> "#<ErlixTuple:0xb7d78d74>" ## unexpected

This would also allow you to interpolate terms into strings, e.g.

puts "The response was #{t}"

(2) It would be helpful if ErlixTurple took a variable number of
arguments, instead of a single array. That would let you write

ErlixTuple.new(a1,f,b,a2,i)

This wouldn't prevent you from using an array if you like, because Ruby
provides a 'splat' operator:

arr = [a1,f,b,a2,i]
ErlixTuple.new(*arr)

Anyway, keep up the good work - this is looking promising!

Regards,

Brian.
 
B

Brian Candler

KDr2 said:
Thank you, I just hava done little update :
http://github.com/KDr2/erlix/tree/master#fn1

Interesting.

However I think it would be better to turn a ruby string into an erlang
list, rather than an atom, for two reasons:

(1) It more closely matches what happens in Erlang

1> Foo = "abc".
"abc"
2> hd(Foo).
97

(2) I'm not an Erlang expert, but I think I read that Erlang has the
same atom-exhaustion problem that Ruby has with symbols: namely that
once an atom has been allocated it cannot be freed. So it is not a good
idea to keep calling list_to_atom on random strings provided by
untrusted users.

I'd still expect Ruby symbols to be mapped to atoms, of course.

Regards,

Brian.
 
K

KDr2

You're right, String should be converted to List, thanks again=EF=BC=81

Interesting.

However I think it would be better to turn a ruby string into an erlang
list, rather than an atom, for two reasons:

(1) It more closely matches what happens in Erlang

1> Foo =3D "abc".
"abc"
2> hd(Foo).
97

(2) I'm not an Erlang expert, but I think I read that Erlang has the
same atom-exhaustion problem that Ruby has with symbols: namely that
once an atom has been allocated it cannot be freed. So it is not a good
idea to keep calling list_to_atom on random strings provided by
untrusted users.

I'd still expect Ruby symbols to be mapped to atoms, of course.

Regards,

Brian.


--=20
Best Regards,
-- KDr2, at x-macro.com.
 
K

KDr2

I made some update today, and Erlix supports Ruby1.9.x now.

There're also some other changes:
1. All classes (Term/Int/List/Tuple/Atom/...) are under the Erlix module now
2. new init method for Tuple/List:
Erlix::List.new
Erlix::List.new(1,2,3)
Erlix::List.new([1,2,3])

You can install it with gem or from the source, see docs at https://github.com/KDr2/erlix .

This is an alpha version(0.5.0a). If you are interesting in this, please install and do some test, find bugs and send to me, Many Thanks.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top