资源说明:Ruby Interface of Erlang
h2. Erlix Tutorial h3. Changelog h4. 20090430 update * features: ** Type auto-convert[1] ** [] singleton method for ErlixTuple and ErlixList[2] ** add ErlixTerm.to_s, remove ErlixTerm.puts h4. erlix-v0.3 changelog: * bugfix: ** IO block bug in ErlixConnection#erecv * feature: ** ErlixList#new("string") ** ErlixConnection#close ** ErlixConnection#closed? ** ErlixConnection#rpc("module","function",ErlixTermList) ** ErlixConnection#peer h3. Intsall erlix On Linux/Unix only,need erlang installed.h3. Play with the ErlixTerm ErlixTerm is a Module, represents the erlang-term, It is mixed into some particular classes,like ErlixAtom,ErlixInt,ErlixList... Now we will play with these classes in irb, First,open irb,and require the erlix lib:unzip erlix-version.zip cd erlix-version ruby configure.rb make make installFind all ErlixTerm's subclasses:kdr2@kdr2-pc:~$ irb irb(main):001:0> require "erlix" => true irb(main):002:0>We see,there are 9 ErlixTerm classes we hava implemented: # ErlixBinary # ErlixTuple # ErlixList # ErlixAtom # ErlixRef # ErlixPid # ErlixFloat # ErlixUInt # ErlixInt Here we go on:irb(main):002: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):003:0>Some Ruby-Type var can be auto-converted to particular Erlang-Type: |Ruby-Type | -> | Erlang-Type | |FixNum | -> | ErlixInt | |Float | -> | ErlixFloat | |String | -> | ErlixList | |Symbol | -> | ErlixAtom | See belowirb(main):003:0> a1=ErlixAtom.new("atom1") => atom1 irb(main):004:0> a2=ErlixAtom.new("atom2") => atom2 irb(main):005:0> f=ErlixFloat.new(17.0) => 17.000000 irb(main):006:0> b=ErlixBinary.new("data\0data") => #Bin irb(main):007:0> b.data => "data\000data" irb(main):008:0> i=ErlixInt.new(101) => 101 irb(main):009:0> t=ErlixTuple.new([a1,f,b,a2,i]) => {atom1,17.000000,#Bin,atom2,101} irb(main):010:0> list=ErlixList.new([a1,i,t]) => [atom1,101,{atom1,17.000000,#Bin,atom2,101}] irb(main):011:0> t[2] => 17.000000 irb(main):012:0> t[2].class => ErlixFloat irb(main):013:0> t[3].class => ErlixBinary irb(main):014:0> t.nth(3)==t[3] => true irb(main):015:0> list.head => atom1 irb(main):016:0> list.tail =>[101,{atom1,17.000000,#Bin,atom2,101}] irb(main):017:0> list2=list.cons(b) => [#Bin,atom1,101,{atom1,17.000000,#Bin,atom2,101}]Use singleton method [] to create ErlixTuple/ErlixListirb(main):016:0> c=ErlixList.new(["string-to-list",1,:symbol_to_atom,1.00]) => ["string-to-list",1,symbol_to_atom,1.000000] irb(main):017:0> c.head.class => ErlixList irb(main):019:0>And we can use @match@ to test a ErlixTerm's format, use @mget@ to get a particular ErlixTerm inside a ErlixTerm:irb(main):019:0> c=ErlixList["string-to-list",1,:symbol_to_atom,1.00] => ["string-to-list",1,symbol_to_atom,1.000000] irb(main):020:0> t=ErlixTuple["string-to-list",1,:symbol_to_atom,1.00] => {"string-to-list",1,symbol_to_atom,1.000000} irb(main):021:0> t[1] => "string-to-list" irb(main):022:0> t[3] => symbol_to_atom irb(main):023:0> sl=%w[abc def xyz] => ["abc", "def", "xyz"] irb(main):024:0> ErlixTuple[*sl] => {"abc","def","xyz"}h3. Play with the Real-Erlang-Node First write a erlang module for our test:irb(main):023:0> list2 => [#Bin,atom1,101,{atom1,17.000000,#Bin,atom2,101}] irb(main):024:0> list2.match("[B,Atom,101,Tuple]") => true irb(main):025:0> list2.match("[nomatch,B,Atom,101,Tuple]") => false irb(main):027:0> t2=list2.mget("[B,Atom,101,Tuple]","Tuple") => {atom1,17.000000,#Bin,atom2,101}Then we satrt an Erlang-Node to run the test module,you must give the erlang-node a short name or name:-module(test). -compile(export_all). loop()-> %% receive msg,the msg's format is {FromPid,Msg} %% the FromPid is a pid in our ruby program, %% we use "FromPid ! Msg" to echo the Msg back receive {FromPid,Msg} -> io:format("From:[~w], MSG From Ruby:[~w] ~n",[FromPid,Msg]), FromPid ! Msg, loop() end. run()-> Pid=spawn(fun loop/0), %% Associates the name "my_pid" with Pid %% so that our ruby code can find this pid and send message to it! register(my_pid,Pid).My hostname is "kdr2-pc", with the option "-sname foo",the erlang-node name is "foo@kdr2-pc". The time we write ruby code with erlix now:kdr2@kdr2-pc:~/work/erlix/test$ erl -sname foo Erlang (BEAM) emulator version 5.6.5 [source] [smp:2] [async-threads:0] [kernel-poll:false] Eshell V5.6.5 (abort with ^G) (foo@kdr2-pc)1> c(test). {ok,test} (foo@kdr2-pc)2> test:run(). true (foo@kdr2-pc)3>Run the test code:#!/usr/bin/ruby # -*- coding: utf-8 -*- require "erlix" # init ErlixNode, # the first argument is the short-name of the ErlixNode # the second argument is the erlang cookie, use nil it's will read ~/.erlang.cookie # after init, my ErlixNode's name is inited to "ruby@kdr2-pc" ErlixNode.init("ruby",nil) # connect to the real Erlang-Node: c=ErlixConnection.new("foo@kdr2-pc") puts "connect ok" # create a new Pid with the connection # we will use this Pid as the FromPid p=ErlixPid.new(c) # make a ErlixTuple {Pid,test_atom} and send it to the real erlang-node c.esend("my_pid",ErlixTuple.new([p,ErlixAtom.new("test_atom")])) puts "send ok" # start a new thread to receive the msg from the real erlang-node puts "receiving" t=Thread.new{ while true do #in erlix-v0.2,erecv make all threads blocked,v0.3 fixed this m=c.erecv puts m.mtype puts m.message puts m.class puts m.from puts m.to end } t.joinThe output of erlang:kdr2@kdr2-pc:~/work/erlix$ ruby test/erlix_test.rb connect ok send ok receiving ERL_SEND test_atom ErlixMessage nil <3.6.3> ...**Note** : the class ErlixMessage: The method ErlixConnection#erecv return an instance of ErlixMessage, ErlixMessage represents the struct ErlMessge in erl_interface,it has several fields: # type # msg # from # to You can call @ErlixMessage#mtype@,@ErlixMessage#message@,@ErlixMessage#from@,@ErlixMessage#to@ to get them. There's the description of ErlMessage from the erl_connect manual:(foo@kdr2-pc)2> test:run(). true From:[<6027.3.6>], MSG From Ruby:[test_atom] (foo@kdr2-pc)3>h3. Erlix RPCThis function receives the message into the specified buffer, and decodes into the (ErlMessage *) emsg. fd is an open descriptor to an Erlang connection. bufp is a buffer large enough to hold the expected message. bufsize indicates the size of bufp. emsg is a pointer to an ErlMessage structure, into which the message will be decoded. ErlMessage is defined as follows: typedef struct { int type; ETERM *msg; ETERM *to; ETERM *from; char to_name[MAXREGLEN]; } ErlMessage; Note: The definition of ErlMessage has changed since earlier versions of Erl_Interface. type identifies the type of message, one of ERL_SEND, ERL_REG_SEND, ERL_LINK, ERL_UNLINK and ERL_EXIT. If type contains ERL_SEND this indicates that an ordinary send operation has taken place, and emsg->to contains the Pid of the recipient. If type contains ERL_REG_SEND then a registered send operation took place, and emsg->from contains the Pid of the sender. In both cases, the actual message will be in emsg->msg. If type contains one of ERL_LINK or ERL_UNLINK, then emsg->to and emsg->from contain the pids of the sender and receipient of the link or unlink. emsg->msg is not used in these cases. If type contains ERL_EXIT, then this indicates that a link has been broken. In this case, emsg->to and emsg->from contain the pids of the linked processes, and emsg->msg contains the reason for the exit.**Note** : Before you make a @ErlixConnection#rpc@ call, @ErlixConnection#erecv@ and @ErlixConnection#esend@ calls must be stopped(There may be an thread runing and blocking on erecv call,you can make rpc-thead and erecv-thread as two mutual exclusive threads). After the ErlixConnection#rpc returned @ErlixConnection#erecv@ and @ErlixConnection#esend@ can be called again. **EOF**c=ErlixConnection.new("foo@kdr2-pc") #rpc call fmt=ErlixList.new("abc~n") tmp=ErlixList.new(nil) args=ErlixList.new([fmt,tmp]) ret=c.rpc("io","format",args) puts ret; puts ret.class
本源码包内暂不包含可直接显示的源代码文件,请下载源码包。
English
