rubyluabridge_0.8.0.orig/.hg_archival.txt0000644000000000000000000000022212410064617016611 0ustar 00000000000000repo: 81856691e86a55792d9e880459857aaac3627b50 node: f66f1c3f4848e9dc394addd5521081a48662ea32 branch: default latesttag: 0.8 latesttagdistance: 1 rubyluabridge_0.8.0.orig/.hgtags0000644000000000000000000000013412410064617015003 0ustar 00000000000000992022b499cd50a4dd4a92500ba8a7b7bf9e1bc4 0.7.0 6502df66ade8dcdd1adb6605a9a82fc658b5e793 0.8 rubyluabridge_0.8.0.orig/.project0000644000000000000000000000534112410064617015201 0ustar 00000000000000 RubyLuaBridge org.eclipse.cdt.make.core.makeBuilder clean,full,incremental, org.eclipse.cdt.make.core.build.arguments org.eclipse.cdt.core.errorOutputParser org.eclipse.cdt.core.MakeErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser;org.eclipse.cdt.core.VCErrorParser; org.eclipse.cdt.make.core.environment org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.build.target.inc all org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.enabledIncrementalBuild true org.eclipse.cdt.make.core.build.location org.eclipse.cdt.make.core.build.command make org.eclipse.cdt.make.core.build.target.clean clean org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.make.core.build.target.auto all org.eclipse.cdt.make.core.stopOnError false org.eclipse.dltk.core.scriptbuilder org.eclipse.cdt.make.core.ScannerConfigBuilder org.eclipse.dltk.ruby.core.nature org.eclipse.cdt.core.cnature org.eclipse.cdt.make.core.makeNature org.eclipse.cdt.make.core.ScannerConfigNature rubyluabridge_0.8.0.orig/LICENSE0000644000000000000000000000275112410064617014541 0ustar 00000000000000RubyLuaBridge Licensed under the BSD License: Copyright (c) 2007, Evan Wies Copyright (c) 2014, Roberto C. Sanchez All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the neomantra nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY Evan Wies ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Evan Wies BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. rubyluabridge_0.8.0.orig/LUA_IN_RUBY0000644000000000000000000001553112410064617015327 0ustar 00000000000000= Using Lua in Ruby Ruby is different in Lua in that there is a single Ruby VM, whereas there can be many Lua states. A Lua virtual machine is wrapped in an instance of the Lua::State class. You can have multiple Lua::States. First, you need to require the RubyLuaBridge library and create a Lua::State. With this instance, you can run Lua code, load Lua libraries, and access Lua objects. require 'rubyluabridge' l = Lua::State.new # we're gonna do a lot with this guy Once you have a Lua::State, you can run Lua code using the Lua::State.eval. This method will return whatever value is returned by the passed code. It will also raise an exception on errors. l.eval "print('hello world')" # => nil l.eval "function give_me_one() return 1 end" # => nil l.eval("return give_me_one()") # => 1 Since Lua can return multiple values, Lua::State.eval_mult will return all values in an Array. require 'pp' pp l.eval_mult("return") # => [] pp l.eval_mult("return 1") # => [1.0] pp l.eval_mult("return 1, 2, 3") # => [1.0, 2.0, 3.0] Due to the dynamic natures of Ruby and Lua, you can easily query and set Lua values in a natural way. You can use square brackets [key], which is necessary if your key is not a string. Otherwise, string keys can also be accessed by invoking it like a method (see example below). Querying from the Lua::State will access the Lua global table. l.eval < 5 l.s # => "hello" l.a # => Lua::Table l.a[1] # => 1 l.h # => Lua::Table l.h['a'] # => "x" l.h.a # => "x" Similarly, you can use this style to set Lua variables. To make a new table, invoke _new_table_at_ on the object, specifying where you want it. Setting a Ruby Arrays or Hashes to a Lua variable will create and assign a new table with a shallow copy of the Ruby container. l.n = 5 # n = 5 l.new_table_at 't' # t = {} l.t.u = 4 # t.u = 4 l.t['u'] = 4 # t.u = 4 l.a = [1,2] # t.a = { 1, 2 } l.h = { 'a' => 'b' } # t.h = { a = 'b' } When RubyLuaBridge has to marshal a table to Ruby, it return a Lua::Table. The Lua::Table implements various iterators that take Ruby Blocks. There are two ways of looking at a Lua table. The first is as a hash, where it has keys of any type mapping to values of any type. The second is as an array, where it has integer keys from 1 to N, where N is the size of the array. The each_i* methods iterate the table as an array, whereas the each_* methods (without the i) iterate the table as a hash. In each case you can iterate of the keys, the values, or the pair [key, value]. Lua::Table#each is aliased to Lua::Table#each_pair and Lua::Table#each_index is aliased to Lua::Table#each_ikey. l.eval( "array = { 100, 200, 300, 400 }" ) l.array.each_ikey { |k| print "#{k} " } # 1 2 3 4 l.array.each_ivalue { |v| print "#{v} " } # 100.0 200.0 300.0 400.0 l.array.each_ipair { |k,v| print "#{k},#{v} " } # 1,100.0 2,200.0 3,300.0 4,400.0 l.eval( "hsh = { a = 100, b = 200, [1] = 300, [5] = 400 }" ) l.hsh.each_key { |k| print "#{k} " } # a 1.0 5.0 b l.hsh.each_value { |v| print "#{v} " } # 100.0 300.0 400.0 200.0 l.hsh.each_pair { |k,v| print "#{k},#{v} " } # a,100.0 1.0,300.0 5.0,400.0 b,200.0 l.hsh.each_ikey { |k| print "#{k} " } # 1 l.hsh.each_ivalue { |v| print "#{v} " } # 300.0 l.hsh.each_ipair { |k,v| print "#{k},#{v} " } # 1,300.0 You can also extract a Ruby Hash or Array that is a shallow-copy of the table. l.eval "a = {1,2} ; h = { a=3, b=4 }" l.a.to_array # => [1, 2] l.a.to_hash # => { 1 => 1, 2 => 2 } l.h.to_array # => [] l.a.to_hash # => { 'a' => 3, 'b' => 4 } Note that by default, all the Lua standard libraries are loaded into the Lua::State. You can control this by passing :loadlibs option to Lua::State.new, or invoking Lua::State.__loadlibs: l = Lua::State.new( :loadlibs => :none ) l = Lua::State.new( :loadlibs => [:base, :io, :debug] ) l.__loadlibs( :package ) l.__loadlibs( [:string, :math] ) Note that Ruby Array's start with index 0, whereas Lua array's start with index 1. Note for advanced Lua users: all of these accesses use the Lua object's metamethods. RubyLuaBridge has a comprehensive test suite (LuaInRuby_Test). Examine it to see various simple uses of this library. == Language Mismatchs There are two sticky issues when trying to express ideas with RubyLuaBridge. Lua uses a colon : syntax to define Lua's "methods", functions that have an implicit extra parameter self. Ruby methods always have this self parameter implicitly. RubyLuaBridge's will only pass the self parameter to a Lua function invocation if you end the method name with bang !. The bang was chosen because it vaguely resembles a colon : !. Note that in Lua, the colon is before the method name, but in RubyLuaBridge, the bang is after (but attached to) the method name. Another issue is that it there is an ambiguity whether an index is meant to be a property or a function call. This happens when there are no arguments, since Ruby's parentheses are optional. RubyLuaBridge always returns the object when there are no arguments, unless it's name is suffixed with an underscore _. With the underscore, RubyLuaBridge will invoke the object like a function. The underscore can be used with multiple arguments as well. Awkwardly, it will do this parameter-less behavior even when paretheses are present, so don't do that! The one exception to the no argument behavior is if the object is a Lua function, in which case it is dispatched. To get a reference to a function, rather than invoking it, use []. Examples of this notation, with their semantics shown in the more explicit Lua code: l.eval <l.coroutine.create(f) == Ruby to Lua Type Mapping *Ruby*:: *Lua* nil:: nil None:: nil True:: true False:: false Fixnum:: number Bignum:: number Float:: number String:: string Symbol:: string Hash:: new Lua::Table clone Array:: new Lua::Table clone everything else:: lightuserdata == Lua to Ruby Type Mapping *Lua*:: *Ruby* none:: nil nil:: nil true:: True false:: False number:: Float string:: String table:: Lua::Table lightuserdata:: Lua::RefObject function:: Lua::RefObject userdata:: Lua::RefObject thread:: Lua::RefObject == TODO * package as gem * stack trace in error callback * how to get some external lua_State there? * how to deal with .clone and .dup? * accessing Ruby from Lua == Credits The following persons have contributed to RubyLuaBridge: * Evan Wies (evan a neomantra d net) * Roberto C. Sanchez (roberto at connexer d com) RubyLuaBridge is inspired by, but not derived from: * Lunatic Python [http://labix.org/lunatic-python] * ruby-lua [http://raa.ruby-lang.org/project/ruby-lua] == License Licensed under the BSD License. It is free software, and may be redistributed under the terms specified in the accompanying LICENSE file, as follows: Copyright (c) 2007, Evan Wies. All rights reserved. Copyright (c) 2014, Roberto C. Sanchez. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the neomantra nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY Evan Wies ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Evan Wies BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. == Support Download the latest sources from {BitBucket}[http://bitbucket.org/neomantra/rubyluabridge] Please use the mailing list and issue tracking features as well. rubyluabridge_0.8.0.orig/RUBY_IN_LUA0000644000000000000000000000141512410064617015323 0ustar 00000000000000== Using Ruby in Lua ==NONE OF THIS IS IMPLEMENTED ==IF YOU HAVE SUGGESTIONS, TELL ME! Ruby is different in Lua in that there is a single Ruby VM, whereas there can be many Lua states. This is represented in Lua as an object in the global table named 'ruby'. The first thing you need to require the RubyLuaBridge library. With this object, you can run Ruby code, load Ruby libraries, and access Ruby objects. require 'rubyluabridge' print(ruby) # => userdata: 0x219083 With this +ruby+ object, you can get and set variables and invoke functions. ruby.NilClass -- ruby.a = 5 -- ruby.print -- ruby.eval("print 'hello world'" # => nil ruby.eval("1") # => 1 ruby.eval("'test'") # => "test" rubyluabridge_0.8.0.orig/Rakefile0000644000000000000000000000546212410064617015203 0ustar 00000000000000require 'rdoc/task' require 'rubygems/package_task' require 'rake/testtask' require 'rake/clean' require 'rubygems' # Specifies the default task to execute. This is often the "test" task # and we'll change things around as soon as we have some tests. task :default => [:rdoc] # The directory to generate +rdoc+ in. RDOC_DIR = "doc/html" # This global variable contains files that will be erased by the `clean` task. # The `clean` task itself is automatically generated by requiring `rake/clean`. CLEAN << RDOC_DIR # This is the task that generates the +rdoc+ documentation from the # source files. Instantiating Rake::RDocTask automatically generates a # task called `rdoc`. Rake::RDocTask.new("rdoc") do |rdoc| rdoc.main = "README" rdoc.rdoc_files.include( "README", "LICENSE", "RUBY_IN_LUA", "LUA_IN_RUBY", "rubyluabridge.cpp", "tests/*.rb" ) rdoc.rdoc_dir = RDOC_DIR rdoc.title = "RubyLuaBridge: A seamless bridge between Ruby and Lua." rdoc.options = ["--line-numbers"] rdoc.template = 'doc/jamis.rb' # Check: # `rdoc --help` for more rdoc options # the {rdoc documenation home}[http://www.ruby-doc.org/stdlib/libdoc/rdoc/rdoc/index.html] # or the documentation for the +Rake::RDocTask+ task[http://rake.rubyforge.org/classes/Rake/RDocTask.html] end # The GemPackageTask facilitates getting all your files collected # together into gem archives. You can also use it to generate tarball # and zip archives. PROJECT_NAME = "rubyluabridge" PKG_VERSION = "0.8.0" #Lua::BRIDGE_VERSION PKG_FILES = FileList['[A-Z]*', 'test/**/*'].to_a spec = Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY s.summary = "RubyLuaBridge: A seamless bridge between Ruby and Lua." s.name = PROJECT_NAME s.version = PKG_VERSION s.files = PKG_FILES s.requirements << "none" s.require_path = '' s.description = < true end rubyluabridge_0.8.0.orig/build/extconf_osx.sh0000755000000000000000000000032112410064617017520 0ustar 00000000000000#!/bin/bash # This is to build rubyluabridge on OSX # # requires: # brew install --with-complete --universal lua # ruby extconf.rb --with-lua-include=/usr/local/include --with-lua-lib=/usr/local/lib $@ rubyluabridge_0.8.0.orig/build/extconf_ubuntu.sh0000755000000000000000000000013312410064617020232 0ustar 00000000000000#!/bin/bash ruby extconf.rb --with-lua-include=/usr/include/lua5.1 --with-lualib=lua5.1 $@ rubyluabridge_0.8.0.orig/doc/jamis.rb0000644000000000000000000002613112410064617015727 0ustar 00000000000000module RDoc module Page FONTS = "\"Bitstream Vera Sans\", Verdana, Arial, Helvetica, sans-serif" STYLE = < pre { padding: 0.5em; border: 1px dotted black; background: #FFE; } CSS XHTML_PREAMBLE = %{ } HEADER = XHTML_PREAMBLE + < %title% ENDHEADER FILE_PAGE = <
File
%short_name%
Path: %full_path% IF:cvsurl  (CVS) ENDIF:cvsurl
Modified: %dtm_modified%

HTML ################################################################### CLASS_PAGE = < %classmod%
%full_name% IF:parent ENDIF:parent
In: START:infiles HREF:full_path_url:full_path: IF:cvsurl  (CVS) ENDIF:cvsurl END:infiles
Parent: IF:par_url ENDIF:par_url %parent% IF:par_url ENDIF:par_url
HTML ################################################################### METHOD_LIST = < IF:diagram
%diagram%
ENDIF:diagram IF:description
%description%
ENDIF:description IF:requires
Required Files
    START:requires
  • HREF:aref:name:
  • END:requires
ENDIF:requires IF:toc
Contents
ENDIF:toc IF:methods
Methods
    START:methods
  • HREF:aref:name:
  • END:methods
ENDIF:methods IF:includes
Included Modules
    START:includes
  • HREF:aref:name:
  • END:includes
ENDIF:includes START:sections IF:sectitle IF:seccomment
%seccomment%
ENDIF:seccomment ENDIF:sectitle IF:classlist
Classes and Modules
%classlist% ENDIF:classlist IF:constants
Constants
START:constants IF:desc ENDIF:desc END:constants
%name% = %value%
  %desc%
ENDIF:constants IF:attributes
Attributes
START:attributes END:attributes
IF:rw [%rw%] ENDIF:rw %name% %a_desc%
ENDIF:attributes IF:method_list START:method_list IF:methods
%type% %category% methods
START:methods
IF:callseq %callseq% ENDIF:callseq IFNOT:callseq %name%%params% ENDIF:callseq IF:codeurl [ source ] ENDIF:codeurl
IF:m_desc
%m_desc%
ENDIF:m_desc IF:aka
This method is also aliased as START:aka %name% END:aka
ENDIF:aka IF:sourcecode
%sourcecode%
ENDIF:sourcecode
END:methods ENDIF:methods END:method_list ENDIF:method_list END:sections HTML FOOTER = < ENDFOOTER BODY = HEADER + <
#{METHOD_LIST}
#{FOOTER} ENDBODY ########################## Source code ########################## SRC_PAGE = XHTML_PREAMBLE + < %title%
%code%
HTML ########################## Index ################################ FR_INDEX_BODY = <
START:entries %name%
END:entries
HTML CLASS_INDEX = FILE_INDEX METHOD_INDEX = FILE_INDEX INDEX = XHTML_PREAMBLE + < %title% IF:inline_source ENDIF:inline_source IFNOT:inline_source ENDIF:inline_source <body bgcolor="white"> Click <a href="html/index.html">here</a> for a non-frames version of this page. </body> HTML end end rubyluabridge_0.8.0.orig/extconf.rb0000755000000000000000000000150112410064617015522 0ustar 00000000000000 require 'mkmf' def fail( str ) STDERR << " extconf failed: #{str}\n" exit 1 end if enable_config('debug') $CFLAGS = '-O0 -g -Wall ' else $CFLAGS = '-O3 -Wall' end if enable_config('rlb-debug') $CFLAGS += '-DRLB_DEBUG ' end # link in C++ libraries $LIBS << " -lstdc++ -lc" nolua_msg = < extern "C" { #include #include #include } #include "rubyluabridge.h" #include "ruby/st.h" // Debug Scaffolding #ifdef RLB_DEBUG #define RLB_DEBUG_PRINT(fmt, ...) printf(fmt, __VA_ARGS__) #else #define RLB_DEBUG_PRINT(fmt, ...) #endif /*****************************************************************************/ // // Global Variables and Typedefs // /*****************************************************************************/ VALUE mLua; VALUE cLua_State; VALUE cLua_RefObject; VALUE cLua_Table; // derives from Lua::RefObject /// A place to stash error messages #define RUBYLUABRIDGE_ERROR_BUFFER_SIZE 4096 char gszErrorBuffer[RUBYLUABRIDGE_ERROR_BUFFER_SIZE]; /// WE DON"T DO THIS YET BUT PROBABLY WILL /// In general, I'm doing a little cheating. /// Since cLua_State is just a wrapper around a lua_State*, /// and always can always extract the lua_State /// meaning, take advantage the lua_State is ALWAYS there... /// /*****************************************************************************/ // // Library Infrastructure // /*****************************************************************************/ // Fwd: Ruby Hash iterator, inserting elements to a table static int _rhash_to_table_iter_func( VALUE rkey, VALUE rvalue, lua_State* L ); /// Copies the top of the stack to gszErrorBuffer, /// pops the top of the stack, and returns the address to gszErrorBuffer. /// This is useful for error handling functions. char* pop_error_to_buffer( lua_State* L ) { const char* szerr = lua_tostring( L, -1 ); strncpy( gszErrorBuffer, szerr, RUBYLUABRIDGE_ERROR_BUFFER_SIZE ); lua_pop(L, 1); return gszErrorBuffer; } /// return whether the value at a given index is "callable", /// meaning that we can try to invoke it like a method int is_callable( lua_State* L, int idx ) { // functions are callable if ( lua_type(L, idx) == LUA_TFUNCTION ) return 1; // check if it is supports the __call metamethod if ( !lua_getmetatable(L, idx) ) // no metatable? return 0; lua_pushstring( L, "__call" ); lua_rawget(L, -2); int callable = (lua_isnil(L, -1) == 0); lua_pop( L, 2 ); // remove metatable and metafield return callable; } /// return whether the value at a given index is "indexable", /// that means will doing a table-like lookup not crash int is_indexable( lua_State* L, int idx ) { // tables are obviously indexable if ( lua_type(L, idx) == LUA_TTABLE ) return 1; // check if it is supports the __index metamethod if ( !lua_getmetatable(L, idx) ) // no metatable? return 0; lua_pushstring( L, "__index" ); lua_rawget(L, -2); int indexable = (lua_isnil(L, -1) == 0); lua_pop( L, 2 ); // remove metatable and metafield return indexable; } /// return whether the value at a given index is "new_indexable", /// that means will doing a table-like lookup not crash int is_new_indexable( lua_State* L, int idx ) { // tables are obviously indexable if ( lua_type(L, idx) == LUA_TTABLE ) return 1; // check if it is supports the __index metamethod if ( !lua_getmetatable(L, idx) ) // no metatable? return 0; lua_pushstring( L, "__newindex" ); lua_rawget(L, -2); int new_indexable = (lua_isnil(L, -1) == 0); lua_pop( L, 2 ); // remove metatable and metafield return new_indexable; } /// marshals the given stack value to Ruby /// leaves the stack unchanged VALUE marshal_lua_to_ruby( VALUE Rstate, lua_State* L, int idx ) { int ltype = lua_type( L, idx ); switch ( ltype ) { // primitive types -> marshal directly case LUA_TNONE: case LUA_TNIL: return Qnil; case LUA_TBOOLEAN: return lua_toboolean(L,idx) ? Qtrue : Qfalse; case LUA_TNUMBER: return rb_float_new( lua_tonumber(L,idx) ); case LUA_TSTRING: { size_t len = 0; const char* str = lua_tolstring(L, idx, &len); return rb_str_new( str, len ); } // complex types // these are stored in Lua::RefObjects // except tables, which are stored in Lua::Table case LUA_TLIGHTUSERDATA: case LUA_TFUNCTION: case LUA_TUSERDATA: case LUA_TTHREAD: case LUA_TTABLE: { // make a Lua reference for this lua_pushvalue( L, idx ); int ref = luaL_ref( L, LUA_REGISTRYINDEX ); RLB_DEBUG_PRINT( "ref created: L:%p r:%d\n", L, ref); // create a new lua_Ref object holding it VALUE args[2] = { Rstate, INT2NUM(ref) }; VALUE res = rb_class_new_instance( 2, args, (ltype == LUA_TTABLE) ? cLua_Table : cLua_RefObject ); return res; } default: return Qnil; } } /// marshals the given Ruby value to Lua, leaving it on the top /// returns a non-zero error code on failure int marshal_ruby_to_lua_top( lua_State* L, VALUE val ) { int rtype = TYPE(val); switch ( rtype ) { case T_NONE: lua_pushnil( L ); break; case T_NIL: lua_pushnil( L ); break; case T_TRUE: lua_pushboolean( L, 1 ); break; case T_FALSE: lua_pushboolean( L, 0 ); break; case T_FIXNUM: lua_pushnumber( L, FIX2INT(val) ); break; case T_BIGNUM: lua_pushnumber( L, NUM2DBL(val) ); break; case T_FLOAT: lua_pushnumber( L, (lua_Number)RFLOAT_VALUE(val) ); break; case T_STRING: lua_pushlstring( L, RSTRING_PTR(val), RSTRING_LEN(val) ); break; case T_SYMBOL: lua_pushstring( L, rb_id2name( SYM2ID(val) ) ); break; // Hash becomes a table case T_HASH: { lua_newtable( L ); rb_hash_foreach( val, (int (*)(ANYARGS))_rhash_to_table_iter_func, VALUE(L) ); break; } // Array becomes a table-array. // note in Lua, the first index is 1, whereas in Ruby the first index is 0 case T_ARRAY: { long i; VALUE array = val; lua_newtable( L ); for ( i = 0; i < RARRAY_LEN(array); i++ ) { marshal_ruby_to_lua_top( L, RARRAY_PTR(array)[i] ); lua_rawseti( L, -2, i+1 ); // Lua is 1-based } break; } case T_OBJECT: { // if it's a Lua::RefObject, put it on the stack if ( rb_obj_is_kind_of(val, cLua_RefObject) == Qtrue ) { rlua_RefObject* pRefObject; Data_Get_Struct( val, rlua_RefObject, pRefObject ); if ( pRefObject->getState() != L ) { // TODO: handle this better rb_warning( "Marshalling Lua::RefObject between two different states. Pushing nil." ); break; } lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); break; } // else, flow through to default... } default: // just throw the Ruby object up as a light userdata lua_pushlightuserdata( L, (void*)val ); break; } return 0; } // dispatches method_missing // // assumes that the Lua object (RefObject) is on the top of the stack // leaves the stack clean and returns the corresponding value // // an = at the end of the key makes it an assignment // an ! at the end of the key makes it a method call with self // an _ at the end of the key forces it as a method call without self // nothing at the end of the key will make a function call, // unless there are no arguments in which case it simply returns obj[key] // VALUE rlua_method_missing_dispatch( lua_State* L, const char* key, VALUE Rstate, int argc, VALUE* argv ) { int keylen = strlen( key ); // if method ends "=", then it's an assignment if ( key[keylen-1] == '=' ) { assert( argc >= 2 ); lua_pushlstring( L, key, keylen-1 ); // strip off = marshal_ruby_to_lua_top( L, argv[1] ); lua_settable( L, -3 ); lua_pop( L, 1 ); return argv[1]; } // // otherwise read the index and return the value or invoke the function // // determine any special treatment and retrieve the value int pushself = (key[keylen-1] == '!'); int forcecall = (key[keylen-1] == '_'); // keylen-1 to strip ! or _ lua_pushlstring( L, key, (pushself || forcecall) ? keylen-1 : keylen ); lua_gettable( L, -2 ); // if there are no arguments (besides self) and the method doesn't ends with a special char // and it is not a function, then just return the indexed value. if ( !pushself && !forcecall && argc == 1 && (lua_type(L,-1) != LUA_TFUNCTION) ) { // marshal the result to Ruby VALUE result = marshal_lua_to_ruby( Rstate, L, -1 ); lua_pop( L, 2 ); return result; } // // otherwise, we're gonna pcall the indexed value // // make sure it is callable if ( !is_callable(L,-1) ) { int ltype = lua_type( L, -1 ); lua_pop( L, 2 ); rb_raise( rb_eRuntimeError, "Value is not callable (not a function and no __call metamethod), ltype: %d, key: %s", ltype, key ); } // push the arguments on the stack int args_bottom = lua_gettop(L) - 1; if ( pushself ) lua_pushvalue( L, -2 ); // push self as arg with method! int i; for ( i = 1; i < argc; ++i ) marshal_ruby_to_lua_top( L, argv[i] ); // pcall and handle errors int err = lua_pcall( L, (pushself ? argc : argc-1), LUA_MULTRET, 0 ); if ( err == LUA_ERRRUN ) { lua_remove( L, -2 ); rb_raise( rb_eRuntimeError, "%s", pop_error_to_buffer(L) ); } else if ( err == LUA_ERRMEM ) { lua_remove( L, -2 ); rb_raise( rb_eNoMemError, "%s", pop_error_to_buffer(L) ); } else if ( err == LUA_ERRERR ) { lua_remove( L, -2 ); rb_raise( rb_eFatal, "%s", pop_error_to_buffer(L) ); } // if there is one result, return that alone // otherwise put them in an Array int args_top = lua_gettop(L); int nres = args_top - args_bottom; if ( nres == 1 ) { // marshal the result to Ruby VALUE result = marshal_lua_to_ruby( Rstate, L, -1 ); lua_pop( L, 2 ); return result; } else { int li, ri; VALUE ary_result = rb_ary_new2( nres ); for ( li = args_bottom+1, ri = 0; li <= args_top; ++li, ++ri ) rb_ary_store( ary_result, ri, marshal_lua_to_ruby(Rstate, L, li) ); lua_pop( L, 1+nres ); return ary_result; } } /// Ruby Hash iterator, mapping pairs into a table static int _rhash_to_table_iter_func( VALUE rkey, VALUE rvalue, lua_State* L ) { marshal_ruby_to_lua_top( L, rkey ); marshal_ruby_to_lua_top( L, rvalue ); lua_settable( L, -3 ); return ST_CONTINUE; } // copied from: // http://www.lua.org/source/5.1/lbaselib.c.html#luaB_tostring static int rluaB_tostring(lua_State *L) { luaL_checkany(L, 1); if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ return 1; /* use its value */ switch (lua_type(L, 1)) { case LUA_TNUMBER: lua_pushstring(L, lua_tostring(L, 1)); break; case LUA_TSTRING: lua_pushvalue(L, 1); break; case LUA_TBOOLEAN: lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); break; case LUA_TNIL: lua_pushliteral(L, "nil"); break; default: lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); break; } return 1; } // mapping of Lua Standard Library names to their registration functions static const luaL_Reg rubylua_lualibs[] = { {"", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, {NULL, NULL} }; /// loads the specified standard Lua library void load_std_library_by_name( lua_State* L, const char* libname ) { // special-case: base const luaL_Reg* libreg = NULL; if ( !strcmp(libname, "base") ) libreg = &rubylua_lualibs[0]; // otherwise search for it else { for ( libreg = &rubylua_lualibs[1]; libreg->func; libreg++ ) if ( !strcmp(libname, libreg->name) ) break; } // register if found if ( libreg && libreg->func ) { lua_pushcfunction( L, libreg->func ); lua_pushstring( L, libreg->name ); lua_call( L, 1, 0 ); } } /***************************************************************************** Document-class: Lua::State The Ruby representation of a lua_State. *****************************************************************************/ // Forward declaration static VALUE rlua_State_loadlibs( VALUE self, VALUE libs ); /* call-seq: * Lua::State.new( options ) * * Creates a new Lua::State. * * _options_ is a hash of options. If no _options_ are specified, the default is { :loadlibs => :all }. * * loadlibs: * Invokes Lua::State.__loadlibs on the new Lua::State, passing the value of :loadlibs. * * Raises NoMemoryError if the state cannot be allocated, or ArgumentError if the value of :loadlibs * is invalid. */ static VALUE rlua_State_initialize( int argc, VALUE* argv, VALUE self ) { rlua_State* pRLState; Data_Get_Struct( self, rlua_State, pRLState ); // create new Lua state pRLState->Lstate.reset( luaL_newstate(), lua_close_deleter() ); if ( !pRLState->getState() ) rb_raise( rb_eNoMemError, "lua_State memory allocation failed" ); RLB_DEBUG_PRINT( "state init: ptr:%p L:%p\n", pRLState, pRLState->getState() ); // if there is no arguments (or nil first value), load all if ( argc == 0 || NIL_P(argv[0]) ) { luaL_openlibs( pRLState->getState() ); return self; } // otherwise, it has to be a hash Check_Type( argv[0], T_HASH ); // process "loadlibs" VALUE libs = rb_hash_aref( argv[0], ID2SYM(rb_intern("loadlibs")) ); rlua_State_loadlibs( self, libs ); // OK if nil return self; } /// free the lua_State, create with lua_State_alloc static void rlua_State_free( rlua_State* pRLState ) { RLB_DEBUG_PRINT( "state free : ptr:%p L:%p\n", pRLState, pRLState->getState() ); } /// allocate a new Lua::State /// this actually performs the luaL_newstate allocation static VALUE rlua_State_alloc( VALUE klass ) { rlua_State* pRLState = new rlua_State(); if ( !pRLState ) rb_raise( rb_eNoMemError, "Out of memory when allocating rlua_State" ); RLB_DEBUG_PRINT( "state malloc: ptr:%p\n", pRLState ); // wrap it inside a Ruby object VALUE obj = Data_Wrap_Struct( klass, NULL, rlua_State_free, pRLState ); return obj; } /* call-seq: * Lua::State.__state -> Lua::State * * Returns this Lua::State itself. * * Introduced for parallelism with Lua::RefObject.__state. */ static VALUE rlua_State_state( VALUE self ) { return self; } /* call-seq: * Lua::State.__top -> int * * Return the absolute position of the top of the lua_State's stack. * * This is mainly for debugging/testing purposes. */ static VALUE rlua_State_top( VALUE self ) { rlua_State* pRLState; Data_Get_Struct( self, rlua_State, pRLState ); int top = lua_gettop( pRLState->getState() ); return INT2NUM( top ); } /* call-seq: * Lua::State.__globals -> Lua::Table * * Returns the globals table of this Lua::State. * It is an instance of the Lua::Table class. */ static VALUE rlua_State_globals( VALUE self ) { rlua_State* pRLState; Data_Get_Struct( self, rlua_State, pRLState ); lua_State* L = pRLState->getState(); lua_pushvalue( L, LUA_GLOBALSINDEX ); VALUE result = marshal_lua_to_ruby( self, L, -1 ); lua_pop( L, 1 ); return result; } /* call-seq: * Lua::State.__registry -> Lua::Table * * Returns the registry table of this Lua::State. * It is an instance of the Lua::Table class. * * As the Lua Registry is intended for C extensions * and the Lua reference system, be careful modifying * values stored in this table. */ static VALUE rlua_State_registry( VALUE self ) { rlua_State* pRLState; Data_Get_Struct( self, rlua_State, pRLState ); lua_State* L = pRLState->getState(); lua_pushvalue( L, LUA_REGISTRYINDEX ); VALUE result = marshal_lua_to_ruby( self, L, -1 ); lua_pop( L, 1 ); return result; } /* call-seq: * Lua::State.__loadlib( libs ) * * Loads the specified Lua standard libraries into the Lua::State. * * If _libs_ is not specified, all libraries are loaded. Otherwise, if _libs_ is a symbol, that library * is loaded. Special symbols are :all, which loads all libraries, and :none which loads no libraries. * If _libs_ is an Array, all symbols in the Array are loaded (in the order specified); in this case, * :all and :none are ignored; an empty Array will load no libraries. If none of the above fits, * an ArgumentError is raised. * * Supported libraries are: * - base * - package * - table * - io * - os * - string * - math * - debug */ static VALUE rlua_State_loadlibs( VALUE self, VALUE libs ) { rlua_State* pRLState; Data_Get_Struct( self, rlua_State, pRLState ); lua_State* L = pRLState->getState(); // if it is empty or :all, load all // if it is a symbol, load that the lib it matches // if it is :none, load none // if it is an array, load all its symbols (:all is ignored here) // otherwise, load none if ( NIL_P(libs) ) { luaL_openlibs( L ); } else if ( TYPE(libs) == T_SYMBOL ) { const char* libname = rb_id2name( SYM2ID(libs) ); if ( !strcmp(libname, "all") ) luaL_openlibs( L ); else if ( !strcmp(libname, "none") ) {} // load none on :none else load_std_library_by_name( L, libname ); } else if ( TYPE(libs) == T_ARRAY ) { int i; for ( i = 0; i < RARRAY_LEN(libs); i++ ) { VALUE entry = RARRAY_PTR(libs)[i]; if ( TYPE(entry) == T_SYMBOL ) { const char* libname = rb_id2name( SYM2ID(entry) ); load_std_library_by_name( L, libname ); } } } else rb_raise( rb_eArgError, "loadlibs must be Nil, a Symbol, or an Array of symbols" ); return self; } /* call-seq: * Lua::State.eval -> result * * Evaluates the passed string in the Lua::State. * * Returns the first value returned by the evaluation. */ static VALUE rlua_State_eval( VALUE self, VALUE str ) { // verify and marshal Ruby args to C rlua_State* pRLState; Data_Get_Struct( self, rlua_State, pRLState ); SafeStringValue(str); lua_State* L = pRLState->getState(); // process the string to a chunk int err = luaL_loadbuffer( L, RSTRING_PTR(str), RSTRING_LEN(str), "Lua::State.eval" ); if ( err == LUA_ERRMEM ) rb_raise( rb_eNoMemError, "%s", pop_error_to_buffer(L) ); else if ( err == LUA_ERRSYNTAX ) rb_raise( rb_eSyntaxError, "%s", pop_error_to_buffer(L) ); // pcall the chunk, returning only a single argument // TODO: error handler with stack traceback // TODO: it would be nice to have it configurable whether to print the traceback // TODO: hmmm... the err handler could even be in Ruby? err = lua_pcall( L, 0, 1, 0 ); if ( err == LUA_ERRRUN ) rb_raise( rb_eRuntimeError, "%s", pop_error_to_buffer(L) ); else if ( err == LUA_ERRMEM ) rb_raise( rb_eNoMemError, "%s", pop_error_to_buffer(L) ); else if ( err == LUA_ERRERR ) rb_raise( rb_eFatal, "%s", pop_error_to_buffer(L) ); // marshal the result to Ruby VALUE result = marshal_lua_to_ruby( self, L, -1 ); lua_pop( L, 1 ); return result; } /* call-seq: * Lua::State.eval_mult -> Array * * Evaluates the passed string in the Lua::State. * * Returns the all the return values in a Ruby array (with the first result first). * If there are no results, an empty array is returned. */ static VALUE rlua_State_eval_mult( VALUE self, VALUE str ) { // verify and marshal Ruby args to C rlua_State* pRLState; Data_Get_Struct( self, rlua_State, pRLState ); SafeStringValue(str); lua_State* L = pRLState->getState(); int args_bottom = lua_gettop(L); // process the string to a chunk int err = luaL_loadbuffer( L, RSTRING_PTR(str), RSTRING_LEN(str), "Lua::State.eval" ); if ( err == LUA_ERRMEM ) rb_raise( rb_eNoMemError, "%s", pop_error_to_buffer(L) ); else if ( err == LUA_ERRSYNTAX ) rb_raise( rb_eSyntaxError, "%s", pop_error_to_buffer(L) ); // pcall the chunk, returning only a single argument // TODO: error handler with stack traceback // TODO: it would be nice to have it configurable whether to print the traceback // TODO: hmmm... the err handler could even be in Ruby? err = lua_pcall( L, 0, LUA_MULTRET, 0 ); if ( err == LUA_ERRRUN ) rb_raise( rb_eRuntimeError, "%s", pop_error_to_buffer(L) ); else if ( err == LUA_ERRMEM ) rb_raise( rb_eNoMemError, "%s", pop_error_to_buffer(L) ); else if ( err == LUA_ERRERR ) rb_raise( rb_eFatal, "%s", pop_error_to_buffer(L) ); // marshal the result to Ruby int args_top = lua_gettop(L); int nres = args_top - args_bottom; int li, ri; VALUE ary_res = rb_ary_new2( nres ); for ( li = args_bottom+1, ri = 0; li <= args_top; ++li, ++ri ) rb_ary_store( ary_res, ri, marshal_lua_to_ruby(self, L, li) ); lua_pop( L, nres ); return ary_res; } /* call-seq: * Lua::State.method_missing -> result * * This method is called by Ruby when it sees an Object can't handle a message. * We use it to dispatch to Lua, attempting a lookup of that value in the Lua::State's global table. * * If the method name has an '=' at the end, it is treated as an assignment, * in which case it assigns the first value. It returns that value for chaining. * * The first argument is the symbol of the message name, the rest are its args. */ VALUE rlua_State_method_missing( int argc, VALUE* argv, VALUE self ) { rlua_State* pRLstate; Data_Get_Struct( self, rlua_State, pRLstate ); lua_State* L = pRLstate->getState(); Check_Type( argv[0], T_SYMBOL ); ID methodid = SYM2ID( argv[0] ); const char* key = rb_id2name( methodid ); lua_pushvalue( L, LUA_GLOBALSINDEX ); return rlua_method_missing_dispatch( L, key, self, argc, argv ); } /* call-seq: * Lua::State[key] -> value * * Returns the value indexed at _key_ in the Lua::State's globals table. */ VALUE rlua_State_getindex( VALUE self, VALUE key ) { rlua_State* pRLstate; Data_Get_Struct( self, rlua_State, pRLstate ); lua_State* L = pRLstate->getState(); marshal_ruby_to_lua_top( L, key ); lua_gettable( L, LUA_GLOBALSINDEX ); // marshal the result to Ruby VALUE result = marshal_lua_to_ruby( self, L, -1 ); lua_pop( L, 1 ); return result; } /* call-seq: * Lua::State[key] = value -> value * * Assigns _value_ to be indexed at _key_ in the Lua::State's globals table. * Returns the value for chaining. */ VALUE rlua_State_setindex( VALUE self, VALUE key, VALUE val ) { rlua_State* pRLstate; Data_Get_Struct( self, rlua_State, pRLstate ); lua_State* L = pRLstate->getState(); marshal_ruby_to_lua_top( L, key ); marshal_ruby_to_lua_top( L, val ); lua_settable( L, LUA_GLOBALSINDEX ); return val; // return val for chaining } /* call-seq: * Lua::State.new_table_at key -> Lua::Table * * Creates a new table at the given key. Returns the new table. */ VALUE rlua_State_new_table_at( VALUE self, VALUE key ) { rlua_State* pRLstate; Data_Get_Struct( self, rlua_State, pRLstate ); lua_State* L = pRLstate->getState(); marshal_ruby_to_lua_top( L, key ); lua_newtable( L ); VALUE result = marshal_lua_to_ruby( self, L, -1 ); lua_settable( L, LUA_GLOBALSINDEX ); return result; } /* call-seq: * Lua::State.indexable? -> true * * Returns whether Lua:State is indexable (via __index), which it is. * This is to provide consistency with Lua::RefObject interface. */ VALUE rlua_State_is_indexable( VALUE self ) { return Qtrue; } /* call-seq: * Lua::State.new_indexable? -> true * * Returns whether Lua:State can create new indices (via __newindex), which it can. * This is to provide consistency with Lua::RefObject interface. */ VALUE rlua_State_is_new_indexable( VALUE self ) { return Qtrue; } /* call-seq: * Lua::State.callable? -> true * * Returns whether Lua:State is callable (like via __cal), which it is not.. * This is to provide consistency with Lua::RefObject interface. */ VALUE rlua_State_is_callable( VALUE self ) { return Qfalse; } /***************************************************************************** Document-class: Lua::RefObject The Ruby representation of non-primitive objects in Lua. *****************************************************************************/ /* call-seq: * Lua::RefObject.new -> result * * Initializes a new Lua::RefObject. * * THIS METHOD IS NOT INTENDED TO BE CALLED BY CLIENTS. * * TODO: Can we enforce the hiding of this? Only Lua module members should access it. */ static VALUE rlua_RefObject_initialize( VALUE self, VALUE Rstate, VALUE RluaRef ) { rlua_RefObject* pRef; Data_Get_Struct( self, rlua_RefObject, pRef ); RLB_DEBUG_PRINT( "ref init: self:%d Rstate:%p TYPE(Rstate):%d RluaRef:%d TYPE(RluaRef):%d luaRef:%d\n", (unsigned long)self, (unsigned long)Rstate, (unsigned long)TYPE(Rstate), (unsigned long)RluaRef, (unsigned long)TYPE(RluaRef), NUM2INT(RluaRef) ); pRef->Rstate = Rstate; pRef->Lref = NUM2INT(RluaRef); rlua_State* pRState; Data_Get_Struct( Rstate, rlua_State, pRState ); pRef->Lstate = pRState->Lstate; return self; } /// free the Lua::RefObject, created with lua_RefObject_alloc static void rlua_RefObject_free( rlua_RefObject* pRefObject ) { RLB_DEBUG_PRINT( "ref free: ptr:%p ref:%d L:%p\n", pRefObject, pRefObject->Lref, pRefObject->getState() ); assert( pRefObject != NULL ); luaL_unref( pRefObject->getState(), LUA_REGISTRYINDEX, pRefObject->Lref ); delete pRefObject; } /// allocate a new Lua::RefObject static VALUE rlua_RefObject_alloc( VALUE klass ) { rlua_RefObject* pRef = new rlua_RefObject(); if ( !pRef ) rb_raise( rb_eNoMemError, "Out of memory when allocating rlua_RefObject" ); // pRef->Lstate = NULL; pRef->Lref = LUA_NOREF; pRef->Rstate = Qnil; // wrap it inside a Ruby object //rlua_RefObject_mark VALUE obj = Data_Wrap_Struct( klass, NULL, rlua_RefObject_free, pRef ); return obj; } /* call-seq: * Lua::RefObject.__state -> Lua::State * * Returns the Lua::State this Lua::RefObject belongs to. */ static VALUE rlua_RefObject_state( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); return pRefObject->Rstate; } /* call-seq: * Lua::RefObject.method_missing -> result * * This method is called by Ruby when it sees an Object can't handle a message. * We use it to dispatch to Lua, attempting a lookup of that value in the Lua::RefObject. * * The first argument is the symbol of the message name, the rest are its args. * If the method name has an = at the end, it is treated as an assignment, * in which case it assigns the first value. It returns that value for chaining. * * If the method name has a '_' at the end, it is treated as an method invocation, * passing itself as a parameter. This is to emulate the ':' token used in Lua. */ VALUE rlua_RefObject_method_missing( int argc, VALUE* argv, VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); Check_Type( argv[0], T_SYMBOL ); ID methodid = SYM2ID( argv[0] ); const char* key = rb_id2name( methodid ); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); if ( !is_indexable(L, -1) ) { lua_pop(L, 1); rb_raise( rb_eRuntimeError, "Lua::RefObject not indexable, key='%s'", key ); } return rlua_method_missing_dispatch( L, key, pRefObject->Rstate, argc, argv ); } /* call-seq: * Lua::RefObject.__length -> int * * Returns the 'length' of the RefObject. * * According to the {Lua manual}[http://www.lua.org/manual/5.1/manual.html#lua_objlen]: * Returns the "length" of the value at the given acceptable index: * for strings, this is the string length; for tables, this is the result * of the length operator ('#'); for userdata, this is the size of the * block of memory allocated for the userdata; for other values, it is 0. */ VALUE rlua_RefObject_length( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); size_t len = lua_objlen(L, -1); lua_pop( L, 1 ); VALUE result = INT2NUM(len); return result; } /* call-seq: * Lua::RefObject.__type -> int * * Returns the type id of the underlying Lua object. */ VALUE rlua_RefObject_type( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); size_t len = lua_type(L, -1); lua_pop( L, 1 ); VALUE result = INT2NUM(len); return result; } /* call-seq: * Lua::RefObject.__metatable -> Lua::Table * * Returns the metatable of the underlying Lua object. * Return nil if it has no metatable. */ VALUE rlua_RefObject_getmetatable( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); if (lua_getmetatable(L, -1) == 0) lua_pushnil( L ); VALUE result = marshal_lua_to_ruby( pRefObject->Rstate, L, -1 ); lua_pop( L, 2 ); return result; } /* call-seq: * Lua::RefObject.__metatable= Lua::Table -> Lua::Table * * Sets the metatable for this Lua::RefObject. * Returns the passed metatable. */ VALUE rlua_RefObject_setmetatable( VALUE self, VALUE mtable ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); marshal_ruby_to_lua_top( L, mtable ); lua_setmetatable( L, -2 ); lua_pop( L, 1 ); return mtable; } /* call-seq: * Lua::RefObject.[key] -> value * * Returns the value indexed at _key_ in the RefObject. * * Raises RuntimeError if the RefObject is not indexable. */ VALUE rlua_RefObject_getindex( VALUE self, VALUE key ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); if ( !is_indexable(L, -1) ) { lua_pop( L, 1 ); rb_raise( rb_eRuntimeError, "(getindex) Lua::RefObject not indexable" ); } marshal_ruby_to_lua_top( L, key ); lua_gettable( L, -2 ); // marshal the result to Ruby VALUE result = marshal_lua_to_ruby( pRefObject->Rstate, L, -1 ); lua_pop( L, 2 ); return result; } /* call-seq: * Lua::RefObject.[key] = value -> value * * Assigns _value_ to be indexed at _key_ in the RefObject. * Returns the value for chaining. * * Raises RuntimeError if the RefObject is not indexable. */ VALUE rlua_RefObject_setindex( VALUE self, VALUE key, VALUE val ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); if ( !is_indexable(L, -1) ) { lua_pop( L, 1 ); rb_raise( rb_eRuntimeError, "(setindex) Lua::RefObject not indexable" ); } marshal_ruby_to_lua_top( L, key ); marshal_ruby_to_lua_top( L, val ); lua_settable( L, -3 ); lua_pop( L, 1 ); return val; // return val for chaining } /* call-seq: * Lua::RefObject.new_table_at key -> Lua::Table * * Creates a new table at the given key. Returns the new table. * * Raises RuntimeError if the RefObject is not indexable. */ VALUE rlua_RefObject_new_table_at( VALUE self, VALUE key ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); if ( !is_indexable(L, -1) ) { lua_pop( L, 1 ); rb_raise( rb_eRuntimeError, "(setindex) Lua::RefObject not indexable" ); } marshal_ruby_to_lua_top( L, key ); lua_newtable( L ); VALUE result = marshal_lua_to_ruby( pRefObject->Rstate, L, -1 ); lua_settable( L, -3 ); lua_pop( L, 1 ); return result; } /* call-seq: * Lua::RefObject.to_s -> string * * Invokes the Lua function {tostring}[http://www.lua.org/manual/5.1/manual.html#pdf-tostring] * on the object and returns the resulting string. */ VALUE rlua_RefObject_to_s( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); rluaB_tostring( L ); VALUE result = marshal_lua_to_ruby( pRefObject->Rstate, L, -1 ); lua_pop( L, 2 ); return result; } /* call-seq: * Lua::RefObject.indexable? -> true * * Returns whether Lua:State is indexable (via __index), which it is. * This is to provide consistency with Lua::RefObject interface. */ VALUE rlua_RefObject_is_indexable( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); VALUE result = is_indexable(L, -1) ? Qtrue : Qfalse; lua_pop( L, 1 ); return result; } /* call-seq: * Lua::RefObject.new_indexable? -> true * * Returns whether Lua:State can create new indices (via __newindex), which it can. * This is to provide consistency with Lua::RefObject interface. */ VALUE rlua_RefObject_is_new_indexable( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); VALUE result = is_new_indexable(L, -1) ? Qtrue : Qfalse; lua_pop( L, 1 ); return result; } /* call-seq: * Lua::State.indexable? -> true * * Returns whether Lua:State is callable (like via __cal), which it is not.. * This is to provide consistency with Lua::RefObject interface. */ VALUE rlua_RefObject_is_callable( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); VALUE result = is_callable(L, -1) ? Qtrue : Qfalse; lua_pop( L, 1 ); return result; } /***************************************************************************** Document-class: Lua::Table When Rua marshals a Lua table to Ruby, it instantiates it as a Lua::Table. This gives it some extra methods that aren't available to a regular Lua::RefObject. *****************************************************************************/ ///////////////////////////////// ///// LUA::TABLE CONVERSION /* call-seq: * Lua::Table.to_array -> Array * * Returns a Ruby Array of the (first, dense) integer keys in the Table. */ VALUE rlua_Table_to_array( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); int tablelen = lua_objlen( L, -1 ); VALUE array = rb_ary_new2( tablelen ); int i; for ( i = 1; i <= tablelen; ++i ) { lua_rawgeti( L, -1, i ); VALUE rvalue = marshal_lua_to_ruby( pRefObject->Rstate, L, -1 ); rb_ary_push( array, rvalue ); lua_pop( L, 1 ); } lua_pop( L, 1 ); return array; } /* call-seq: * Lua::Table.to_hash -> Hash * * Returns a Ruby Hash of all pairs in the table. */ VALUE rlua_Table_to_hash( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); VALUE hash = rb_hash_new(); // table is in the stack at index 't' lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); int table = lua_gettop( L ); lua_pushnil( L ); // first key while ( lua_next(L, table) != 0 ) { // uses 'key' (at index -2) and 'value' (at index -1) VALUE rvalue = marshal_lua_to_ruby( pRefObject->Rstate, L, -1 ); VALUE rkey = marshal_lua_to_ruby( pRefObject->Rstate, L, -2 ); rb_hash_aset( hash, rkey, rvalue ); // removes 'value'; keeps 'key' for next iteration lua_pop( L, 1 ); } lua_pop( L, 1 ); return hash; } ///////////////////////////////// ///// LUA::TABLE HASH ITERATION /* call-seq: * Lua::Table.each { |key,value| block } -> Lua::Table * Lua::Table.each_pair { |key,value| block } -> Lua::Table * * Calls _block_ once for each key in _table_, passing the key and value as parameters. * * This goes over all pairs in the table. */ VALUE rlua_Table_each_pair( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); // table is in the stack at index 't' lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); int table = lua_gettop( L ); lua_pushnil( L ); // first key while ( lua_next(L, table) != 0 ) { // uses 'key' (at index -2) and 'value' (at index -1) VALUE rvalue = marshal_lua_to_ruby( pRefObject->Rstate, L, -1 ); VALUE rkey = marshal_lua_to_ruby( pRefObject->Rstate, L, -2 ); rb_yield_values( 2, rkey, rvalue ); // removes 'value'; keeps 'key' for next iteration lua_pop( L, 1 ); } lua_pop( L, 1 ); return self; } /* call-seq: * Lua::Table.each_key { |key| block } -> Lua::Table * * Calls _block_ once for each key in _table_, passing the key to the block as a parameter. * * This goes over all pairs in the table. */ VALUE rlua_Table_each_key( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); // table is in the stack at index 't' lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); int table = lua_gettop( L ); lua_pushnil( L ); // first key while ( lua_next(L, table) != 0 ) { // uses 'key' (at index -2) and 'value' (at index -1) VALUE rkey = marshal_lua_to_ruby( pRefObject->Rstate, L, -2 ); rb_yield( rkey ); // removes 'value'; keeps 'key' for next iteration lua_pop( L, 1 ); } lua_pop( L, 1 ); return self; } /* call-seq: * Lua::Table.each_value { |value| block } -> Lua::Table * * Calls _block_ once for each key in _table_, passing the value to the block as a parameter. * * This goes over all pairs in the table. */ VALUE rlua_Table_each_value( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); // table is in the stack at index 't' lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); int table = lua_gettop( L ); lua_pushnil( L ); // first key while ( lua_next(L, table) != 0 ) { // uses 'key' (at index -2) and 'value' (at index -1) VALUE rvalue = marshal_lua_to_ruby( pRefObject->Rstate, L, -1 ); rb_yield( rvalue ); // removes 'value'; keeps 'key' for next iteration lua_pop( L, 1 ); } lua_pop( L, 1 ); return self; } ///////////////////////// ///// ARRAY ITERATION /* call-seq: * Lua::Table.each_ipair { |key,value| block } -> Lua::Table * * Calls _block_ once for each integer key in _table_, passing the key and value as parameters. * * This goes over all integer pairs in the table. Similar to ipairs(), this * only touches the first #table integers, thus treating the table like a dense array. */ VALUE rlua_Table_each_ipair( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); int tablelen = lua_objlen( L, -1 ); int i; for ( i = 1; i <= tablelen; ++i ) { lua_rawgeti( L, -1, i ); VALUE rvalue = marshal_lua_to_ruby( pRefObject->Rstate, L, -1 ); rb_yield_values( 2, INT2NUM(i), rvalue ); lua_pop( L, 1 ); } lua_pop( L, 1 ); return self; } /* call-seq: * Lua::Table.each_index { |key| block } -> Lua::Table * Lua::Table.each_ikey { |key| block } -> Lua::Table * * Calls _block_ once for each integer key in _table_, passing the key to the block as a parameter. * * This goes over all integer pairs in the table. Similar to ipairs(), this * only touches the first #table integers, thus treating the table like a dense array. */ VALUE rlua_Table_each_ikey( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); int tablelen = lua_objlen( L, -1 ); int i; for ( i = 1; i <= tablelen; ++i ) { lua_rawgeti( L, -1, i ); rb_yield( INT2NUM(i) ); lua_pop( L, 1 ); } lua_pop( L, 1 ); return self; } /* call-seq: * Lua::Table.each_ivalue { |value| block } -> Lua::Table * * Calls _block_ once for each integer key in _table_, passing the value to the block as a parameter. * * This goes over all integer pairs in the table. Similar to ipairs(), this * only touches the first #table integers, thus treating the table like a dense array. */ VALUE rlua_Table_each_ivalue( VALUE self ) { rlua_RefObject* pRefObject; Data_Get_Struct( self, rlua_RefObject, pRefObject ); lua_State* L = pRefObject->getState(); lua_rawgeti( L, LUA_REGISTRYINDEX, pRefObject->Lref ); int tablelen = lua_objlen( L, -1 ); int i; for ( i = 1; i <= tablelen; ++i ) { lua_rawgeti( L, -1, i ); VALUE rvalue = marshal_lua_to_ruby( pRefObject->Rstate, L, -1 ); rb_yield( rvalue ); lua_pop( L, 1 ); } lua_pop( L, 1 ); return self; } /*****************************************************************************/ // // Extension Initialization // /*****************************************************************************/ extern "C" { /* Document-module: Lua The module where all of the RubyLuaBridge components live. */ void Init_rubyluabridge() { // Lua module mLua = rb_define_module( "Lua" ); rb_define_const( mLua, "BRIDGE_VERSION", rb_str_new2( RUBYLUABRIDGE_VERSION ) ); rb_define_const( mLua, "BRIDGE_VERSION_NUM", INT2FIX( RUBYLUABRIDGE_VERSION_NUM ) ); rb_define_const( mLua, "LUA_VERSION", rb_str_new2( LUA_VERSION ) ); rb_define_const( mLua, "LUA_RELEASE", rb_str_new2( LUA_RELEASE ) ); rb_define_const( mLua, "TNONE", INT2FIX( LUA_TNONE ) ); rb_define_const( mLua, "TNIL", INT2FIX( LUA_TNIL ) ); rb_define_const( mLua, "TBOOLEAN", INT2FIX( LUA_TBOOLEAN ) ); rb_define_const( mLua, "TLIGHTUSERDATA", INT2FIX( LUA_TLIGHTUSERDATA ) ); rb_define_const( mLua, "TNUMBER", INT2FIX( LUA_TNUMBER ) ); rb_define_const( mLua, "TSTRING", INT2FIX( LUA_TSTRING ) ); rb_define_const( mLua, "TTABLE", INT2FIX( LUA_TTABLE ) ); rb_define_const( mLua, "TFUNCTION", INT2FIX( LUA_TFUNCTION ) ); rb_define_const( mLua, "TUSERDATA", INT2FIX( LUA_TUSERDATA ) ); rb_define_const( mLua, "TTHREAD", INT2FIX( LUA_TTHREAD ) ); // Lua::State class cLua_State = rb_define_class_under( mLua, "State", rb_cObject ); rb_define_alloc_func( cLua_State, rlua_State_alloc ); rb_define_method( cLua_State, "initialize", RUBY_METHOD_FUNC(rlua_State_initialize), -1 ); rb_define_method( cLua_State, "method_missing", RUBY_METHOD_FUNC(rlua_State_method_missing), -1 ); rb_define_method( cLua_State, "__state", RUBY_METHOD_FUNC(rlua_State_state), 0 ); rb_define_method( cLua_State, "__top", RUBY_METHOD_FUNC(rlua_State_top), 0 ); rb_define_method( cLua_State, "__globals", RUBY_METHOD_FUNC(rlua_State_globals), 0 ); rb_define_method( cLua_State, "__registry", RUBY_METHOD_FUNC(rlua_State_registry), 0 ); rb_define_method( cLua_State, "__loadlibs", RUBY_METHOD_FUNC(rlua_State_loadlibs), 1 ); rb_define_method( cLua_State, "new_table_at", RUBY_METHOD_FUNC(rlua_State_new_table_at), 1 ); rb_define_method( cLua_State, "[]", RUBY_METHOD_FUNC(rlua_State_getindex), 1 ); rb_define_method( cLua_State, "[]=", RUBY_METHOD_FUNC(rlua_State_setindex), 2 ); rb_define_method( cLua_State, "eval", RUBY_METHOD_FUNC(rlua_State_eval), 1 ); rb_define_method( cLua_State, "eval_mult", RUBY_METHOD_FUNC(rlua_State_eval_mult), 1 ); rb_define_method( cLua_State, "callable?", RUBY_METHOD_FUNC(rlua_State_is_callable), 0 ); rb_define_method( cLua_State, "indexable?", RUBY_METHOD_FUNC(rlua_State_is_indexable), 0 ); rb_define_method( cLua_State, "new_indexable?", RUBY_METHOD_FUNC(rlua_State_is_new_indexable), 0 ); // TODO: more methods! // rb_define_method( cLua_State, "execute", lua_State_eval, 1 ); // rb_define_method( cLua_State, "execute_mult", lua_State_eval_mult, 1 ); // Lua::RefObject class cLua_RefObject = rb_define_class_under( mLua, "RefObject", rb_cObject ); rb_define_alloc_func( cLua_RefObject, rlua_RefObject_alloc ); rb_define_method( cLua_RefObject, "initialize", RUBY_METHOD_FUNC(rlua_RefObject_initialize), 2 ); rb_define_method( cLua_RefObject, "method_missing", RUBY_METHOD_FUNC(rlua_RefObject_method_missing), -1 ); rb_define_method( cLua_RefObject, "__state", RUBY_METHOD_FUNC(rlua_RefObject_state), 0 ); rb_define_method( cLua_RefObject, "__length", RUBY_METHOD_FUNC(rlua_RefObject_length), 0 ); rb_define_method( cLua_RefObject, "__type", RUBY_METHOD_FUNC(rlua_RefObject_type), 0 ); rb_define_method( cLua_RefObject, "__metatable", RUBY_METHOD_FUNC(rlua_RefObject_getmetatable), 0 ); rb_define_method( cLua_RefObject, "__metatable=", RUBY_METHOD_FUNC(rlua_RefObject_setmetatable), 1 ); rb_define_method( cLua_RefObject, "[]", RUBY_METHOD_FUNC(rlua_RefObject_getindex), 1 ); rb_define_method( cLua_RefObject, "[]=", RUBY_METHOD_FUNC(rlua_RefObject_setindex), 2 ); rb_define_method( cLua_RefObject, "new_table_at", RUBY_METHOD_FUNC(rlua_RefObject_new_table_at), 1 ); rb_define_method( cLua_RefObject, "to_s", RUBY_METHOD_FUNC(rlua_RefObject_to_s), 0 ); rb_define_method( cLua_RefObject, "method_missing", RUBY_METHOD_FUNC(rlua_RefObject_method_missing), -1 ); rb_undef_method( cLua_RefObject, "type" ); rb_undef_method( cLua_RefObject, "id" ); rb_define_method( cLua_RefObject, "callable?", RUBY_METHOD_FUNC(rlua_RefObject_is_callable), 0 ); rb_define_method( cLua_RefObject, "indexable?", RUBY_METHOD_FUNC(rlua_RefObject_is_indexable), 0 ); rb_define_method( cLua_RefObject, "new_indexable?", RUBY_METHOD_FUNC(rlua_RefObject_is_new_indexable), 0 ); // Lua::Table class cLua_Table = rb_define_class_under( mLua, "Table", cLua_RefObject ); rb_define_method( cLua_Table, "to_array", RUBY_METHOD_FUNC(rlua_Table_to_array), 0 ); rb_define_method( cLua_Table, "to_hash", RUBY_METHOD_FUNC(rlua_Table_to_hash), 0 ); rb_define_method( cLua_Table, "each_ipair", RUBY_METHOD_FUNC(rlua_Table_each_ipair), 0 ); rb_define_method( cLua_Table, "each_ikey", RUBY_METHOD_FUNC(rlua_Table_each_ikey), 0 ); rb_define_method( cLua_Table, "each_ivalue", RUBY_METHOD_FUNC(rlua_Table_each_ivalue), 0 ); rb_define_method( cLua_Table, "each_pair", RUBY_METHOD_FUNC(rlua_Table_each_pair), 0 ); rb_define_method( cLua_Table, "each_key", RUBY_METHOD_FUNC(rlua_Table_each_key), 0 ); rb_define_method( cLua_Table, "each_value", RUBY_METHOD_FUNC(rlua_Table_each_value), 0 ); rb_define_alias( cLua_Table, "each", "each_pair" ); rb_define_alias( cLua_Table, "each_index", "each_ikey" ); } } // extern "C" rubyluabridge_0.8.0.orig/rubyluabridge.h0000644000000000000000000000552512410064617016547 0ustar 00000000000000/* * RubyLuaBridge * * Licensed under the BSD License: * * Copyright (c) 2007, Evan Wies * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of 'neomantra' nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Evan Wies ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Evan Wies BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef NEOMANTRA_RUBYLUABRIDGE_H_ #define NEOMANTRA_RUBYLUABRIDGE_H_ #include #include #include // Version Information #define RUBYLUABRIDGE_VERSION ("0.8") #define RUBYLUABRIDGE_VERSION_NUM (0x000800) // shared_ptr deleter which invokes lua_close struct lua_close_deleter { void operator()(lua_State* L) { lua_close(L); } }; /// Struct for our Ruby Lua::State. /// Manages the lifetime of a lua_State using a shared_ptr struct rlua_State { lua_State* getState() { return Lstate.get(); } boost::shared_ptr Lstate; /// The lua_State we are wrapping }; /// Struct for our Ruby Lua::Object. /// /// We use it to persist Lua object beyond its lifetime on the Lua stack. /// /// It uses Lua's "standard" reference system: /// http://www.lua.org/manual/5.1/manual.html#luaL_ref /// We follow the convention of using Lua's registry to store the references. struct rlua_RefObject { lua_State* getState() { return Lstate.get(); } boost::shared_ptr Lstate; /// The lua_State where the reference is held. int Lref; /// The reference id VALUE Rstate; /// The Ruby Lua::State where this ref came from }; #endif // NEOMANTRA_RUBYLUABRIDGE_H_ rubyluabridge_0.8.0.orig/tests/lua_in_ruby_test.rb0000755000000000000000000003755512410064617020607 0ustar 00000000000000#!/usr/bin/ruby -w require 'rubyluabridge' require 'stringio' require 'test/unit' class LuaInRuby_Test < Test::Unit::TestCase # test module-level entities def test_module assert_not_nil( Lua::BRIDGE_VERSION ) assert_not_nil( Lua::BRIDGE_VERSION_NUM ) assert_not_nil( Lua::LUA_VERSION ) assert_not_nil( Lua::LUA_RELEASE ) end # test construction of various entities def test_construction l = Lua::State.new assert_instance_of Lua::State, l assert_instance_of Lua::Table, l.__globals assert_instance_of Lua::Table, l.__registry assert_equal l, l.__state assert_equal l, l.__globals.__state assert_equal l, l.__registry.__state assert_luastack_clean l assert_raise TypeError do l_bad = Lua::State.new "aa" end end # test the basic types def test_basic_types l = Lua::State.new # eval, and basic marshaling assert_nil l.eval('return') assert_nil l.eval('return nil') assert_equal 1, l.eval('return 1') assert_equal 1.1, l.eval('return 1.1') assert_equal 'abc', l.eval('return "abc"') assert_equal true, l.eval('return true') assert_equal false, l.eval('return false') # multi-ret a = l.eval_mult( "return" ) assert_instance_of Array, a assert_equal [], a assert_equal 0, a.length a = l.eval_mult( "return 1" ) assert_instance_of Array, a assert_equal [1], a assert_equal 1, a.length a = l.eval_mult( "return 1, 2, 3, 4" ) assert_instance_of Array, a assert_equal [1,2,3,4], a assert_equal 4, a.length # type id l.eval < Hello from Lua!-> " l.eval( 'print "Hello from Lua!"' ) STDOUT << "you should see-> Hello again from Lua!-> " l.print "Hello again from Lua!" end assert_luastack_clean l # loading libraries ##################### l = Lua::State.new # all count = 0 ; l.__globals.each_key { |k| count += 1 } assert_equal 39, count assert_instance_of Lua::RefObject, l['ipairs'] # base library check assert_instance_of Lua::Table, l.package assert_instance_of Lua::Table, l.table assert_instance_of Lua::Table, l.io assert_instance_of Lua::Table, l.os assert_instance_of Lua::Table, l.string assert_instance_of Lua::Table, l.math assert_instance_of Lua::Table, l.debug l = Lua::State.new( :loadlibs => :all ) count = 0 ; l.__globals.each_key { |k| count += 1 } assert_equal 39, count assert_instance_of Lua::RefObject, l['ipairs'] # base library check assert_instance_of Lua::Table, l.package assert_instance_of Lua::Table, l.table assert_instance_of Lua::Table, l.io assert_instance_of Lua::Table, l.os assert_instance_of Lua::Table, l.string assert_instance_of Lua::Table, l.math assert_instance_of Lua::Table, l.debug l = Lua::State.new( :loadlibs => :none ) count = 0 ; l.__globals.each_key { |k| count += 1 } assert_equal 0, count l = Lua::State.new( :loadlibs => :base ) assert_instance_of Lua::RefObject, l['ipairs'] # base library check assert_equal nil, l.string l = Lua::State.new( :loadlibs => :package ) assert_instance_of Lua::Table, l.package assert_equal nil, l.string l = Lua::State.new( :loadlibs => :table ) assert_instance_of Lua::Table, l.table assert_equal nil, l.string l = Lua::State.new( :loadlibs => :io ) assert_instance_of Lua::Table, l.io assert_equal nil, l.string l = Lua::State.new( :loadlibs => :os ) assert_instance_of Lua::Table, l.os assert_equal nil, l.string l = Lua::State.new( :loadlibs => :string ) assert_instance_of Lua::Table, l.string assert_equal nil, l.io l = Lua::State.new( :loadlibs => :math ) assert_instance_of Lua::Table, l.math assert_equal nil, l.string l = Lua::State.new( :loadlibs => :debug ) assert_instance_of Lua::Table, l.debug assert_equal nil, l.string l = Lua::State.new( :loadlibs => [:base, :package, :io] ) assert_instance_of Lua::RefObject, l['ipairs'] # base library check assert_instance_of Lua::Table, l.package assert_instance_of Lua::Table, l.io end # test table creation from ruby def test_table_creation_from_ruby l = Lua::State.new l.eval( "a = {}") assert_instance_of Lua::Table, l.a s = "return {1,2,3}" assert_instance_of Lua::Table, l.eval(s) assert_equal 3, l.eval(s).__length assert_equal [1,2,3], l.eval(s).to_array b = l.new_table_at 'b' assert_instance_of Lua::Table, b assert_instance_of Lua::Table, l.b b = l.a.new_table_at 'b' assert_instance_of Lua::Table, b assert_instance_of Lua::Table, l.a.b l.c = [] assert_instance_of Lua::Table, l.c assert_equal 0, l.c.__length l.d = {} assert_instance_of Lua::Table, l.d assert_equal 0, l.d.__length e = [1,2,3,4] l.e = e assert_equal 1, l.e[1] assert_equal 2, l.e[2] assert_equal 3, l.e[3] assert_equal 4, l.e[4] assert_equal e, l.e.to_array assert_instance_of Lua::Table, l.e f = { 1=>1, 2=>2, 'a'=>3, 'b'=>4 } l.f = f assert_equal 1, l.f[1] assert_equal 2, l.f[2] assert_equal 3, l.f['a'] assert_equal 4, l.f['b'] assert_equal 2, l.f.__length assert_instance_of Lua::Table, l.f assert_luastack_clean l end # test table accesses def test_table_access l = Lua::State.new l.eval < 'x','b' => 'y'}, l.h2.to_hash) assert_luastack_clean l end # test table iteration def test_table_iteration l = Lua::State.new # array integer iteration l.eval( "array = { 100, 200, 300, 400 }" ) assert_instance_of Lua::Table, l.array n = 0 ; l.array.each_ipair { |k,v| n += 1 assert_pairs_match( k, v, 1, 100 ) assert_pairs_match( k, v, 2, 200 ) assert_pairs_match( k, v, 3, 300 ) assert_pairs_match( k, v, 4, 400 ) } assert_equal(4, n) n = 0 ; l.array.each_ikey { |k| n += 1 assert_pairs_match( n, k, 1, 1 ) assert_pairs_match( n, k, 2, 2 ) assert_pairs_match( n, k, 3, 3 ) assert_pairs_match( n, k, 4, 4 ) assert( n <= 4 ) } assert_equal(4, n) sumv = n = 0 ; l.array.each_ivalue { |v| n += 1 sumv += v assert_equal(v, n*100) } assert_equal(4, n) ; assert_equal(1000, sumv) # hash integer iteration l.eval( "hsh = { [1]=100, [2]=200, a=300, b=400, }" ) assert_instance_of Lua::Table, l.hsh n = 0 ; l.hsh.each_ipair { |k,v| n += 1 assert_pairs_match( k, v, 1, 100 ) assert_pairs_match( k, v, 2, 200 ) assert_pairs_match( k, v, 'a', 300 ) assert_pairs_match( k, v, 'b', 400 ) } assert_equal(2, n) sumk = n = 0 ; l.hsh.each_ikey { |k| n += 1 sumk += k } assert_equal(2, n) ; assert_equal(3, sumk) sumv = n = 0 ; l.hsh.each_ivalue { |v| n += 1 sumv += v assert_equal(v, n*100) } assert_equal(2, n) ; assert_equal(300, sumv) # array assoc iteration l.eval( "array = { 100, 200, 300, 400 }" ) assert_instance_of Lua::Table, l.array n = 0 ; l.array.each_pair { |k,v| n += 1 assert_pairs_match( k, v, 1, 100 ) assert_pairs_match( k, v, 2, 200 ) assert_pairs_match( k, v, 3, 300 ) assert_pairs_match( k, v, 4, 400 ) } assert_equal(4, n) sumk = n = 0 ; l.array.each_key { |k| n += 1 sumk += k assert_equal(k, n) } assert_equal(4, n) ; assert_equal(10, sumk) sumv = n = 0 ; l.array.each_ivalue { |v| n += 1 sumv += v assert_equal(v, n*100) } assert_equal(4, n) ; assert_equal(1000, sumv) # hash assoc iteration l.eval( "hsh = { [1]=100, [2]=200, a=300, b=400, }" ) assert_instance_of Lua::Table, l.array n = 0 ; l.hsh.each_pair { |k,v| n += 1 assert_pairs_match( k, v, 1, 100 ) assert_pairs_match( k, v, 2, 200 ) assert_pairs_match( k, v, 'a', 300 ) assert_pairs_match( k, v, 'b', 400 ) } assert_equal( n, 4) n = 0 ; l.hsh.each_key { |k| n += 1 assert_pairs_match( n, k, 1, 100 ) assert_pairs_match( n, k, 2, 200 ) assert_pairs_match( n, k, 3, 'a' ) assert_pairs_match( n, k, 4, 'b' ) } assert_equal( n, 4) n = sumv = 0 ; l.hsh.each_value { |v| n += 1 sumv += v } assert_equal(4, n) ; assert_equal( sumv, 1000) # done iteration tests assert_luastack_clean l end # test method dispatch def test_method_dispatch l = Lua::State.new l.eval <