rufus-lua
Lua embedded in Ruby, via Ruby FFI.
(Lua 5.1.x only, no luajit out of the box).
Lua
http://www.lua.org/about.html says :
Lua is a powerful, fast, lightweight, embeddable scripting language.
Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics. Lua is dynamically typed, runs by interpreting bytecode for a register-based virtual machine, and has automatic memory management with incremental garbage collection, making it ideal for configuration, scripting, and rapid prototyping.
other Ruby and Lua bridges / connectors
- https://github.com/glejeune/ruby-lua by Gregoire Lejeune
- http://rubyluabridge.rubyforge.org/ by Evan Wies
- https://github.com/whitequark/rlua by Peter Zotov
getting Lua on your system
Debian GNU/Linux
On Debian GNU/Linux, I do
sudo apt-get install liblua5.1-0
If your system's package manager doesn't have some version (5.1.x) of Lua around, jump to compiling liblua.dylib below or look at the LuaBinaries solution for GNU/Linux.
Rufus-lua will look for library in a list of know places.
If it doesn't find the Lua dynamic library or if it picks the wrong one, it's OK to set the LUA_LIB
environment variable. For example:
LUA_LIB=~/mystuff/lualib.5.1.4.so ruby myluacode.rb
or
export LUA_LIB=~/mystuff/lualib.5.1.4.so
# ...
ruby myluacode.rb
OSX
As of 2018-10-19, this Homebrew command will install Lua and its .dylib on OSX:
brew install lua@5.1
Windows
On Windows try using rufus-lua-win gem.
using rufus-lua
gem install rufus-lua
or add to your Gemfile:
gem 'rufus-lua'
then
require 'rufus-lua'
s = Rufus::Lua::State.new
puts s.eval("return table.concat({ 'hello', 'from', 'Lua' }, ' ')")
#
# => "Hello from Lua"
s.close
binding Ruby code as Lua functions
require 'rufus-lua'
s = Rufus::Lua::State.new
s.function 'key_up' do |table|
table.inject({}) do |h, (k, v)|
h[k.to_s.upcase] = v
h
end
end
p s.eval(%{
local table = { CoW = 2, pigs = 3, DUCKS = 'none' }
return key_up(table) -- calling Ruby from Lua...
}).to_h
# => { 'COW' => 2.0, 'DUCKS => 'none', 'PIGS' => 3.0 }
s.close
It's OK to bind a function inside of a table (library):
require 'rufus-lua'
s = Rufus::Lua::State.new
s.eval("rubies = {}")
s.function 'rubies.add' do |x, y|
x + y
end
p s.eval("return rubies.add(1, 2)")
# => 3.0
s.close
You can omit the table definition (only 1 level allowed here though):
require 'rufus-lua'
s = Rufus::Lua::State.new
s.function 'rubies.add' do |x, y|
x + y
end
p s.eval("return rubies.add(1, 2)")
# => 3.0
s.close
The specs contain more examples:
https://github.com/jmettraux/rufus-lua/tree/master/spec/
eval(code[, binding[, filename[, lineno ]]])
The examples so far have shown Rufus::Lua::State#eval
being used with a single argument, a piece of code.
But this rufus-lua eval mimics the Ruby eval
and lets one specify binding, filename and lineno.
(TODO) Binding hasn't yet been implemented. It'll probaby be with setfenv
but nothing sure yet. Stick a nil
to it for now.
The string of Lua code may come from wild places, it may help to flag it with an arbitrary filename and a lineno.
require 'rufus-lua'
lua = Rufus::Lua::State.new
lua.eval('print("hello")', nil, 'myluastuff/hello.lua', 77)
set_error_handler
set_error_handler
gives a little bit of control on how error messages are prepared when errors occur in the Lua interpreter.
Here are set of examples for each of the possible error handler kind: Lua code, Ruby block, :traceback
.
require 'rufus-lua'
lua = Rufus::Lua::State.new
#
# no error handler
begin
lua.eval('error("ouch!")')
rescue => e
puts(e)
end
# --> eval:pcall : '[string "line"]:1: ouch!' (2 LUA_ERRRUN)
#
# Lua error handler
lua.set_error_handler(%{
function (msg)
return 'something went wrong: ' .. string.gmatch(msg, ": (.+)$")()
end
})
begin
lua.eval('error("ouch!")')
rescue => e
puts(e)
end
# --> eval:pcall : 'something went wrong: ouch!' (2 LUA_ERRRUN)
#
# Ruby block error handler
lua.set_error_handler do |msg|
([ msg.split.last ] * 3).join(' ')
end
begin
lua.eval('error("ouch!")')
rescue => e
puts(e)
end
# --> eval:pcall : 'ouch! ouch! ouch!' (2 LUA_ERRRUN)
#
# prepackaged :traceback handler
lua.set_error_handler(:traceback)
begin
lua.eval('error("ouch!")')
rescue => e
puts(e)
end
# -->
# eval:pcall : '[string "line"]:1: ouch!
# stack traceback:
# [C]: in function 'error'
# [string "line"]:1: in main chunk' (2 LUA_ERRRUN)
#
# unset the error handler
lua.set_error_handler(nil)
begin
lua.eval('error("ouch!")')
rescue => e
puts(e)
end
# --> eval:pcall : '[string "line"]:1: ouch!' (2 LUA_ERRRUN)
# (back to default)
compiling liblua.dylib (OSX)
original instructions by Adrian Perez at:
http://lua-users.org/lists/lua-l/2006-09/msg00894.html
get the source at:
http://www.lua.org/ftp/lua-5.1.4.tar.gz
then
tar xzvf lua-5.1.4.tar.gz
cd lua-5.1.4
Modify the file src/Makefile
as per http://lua-users.org/lists/lua-l/2006-09/msg00894.html
It's mostly about adding that rule to the src/Makefile
:
liblua51.dylib: $(CORE_O) $(LIB_O)
$(CC) -dynamiclib -o $@ $^ $(LIBS)
Here's how to build the library file and deploy it:
make
make macosx
make -C src liblua51.dylib
sudo cp src/liblua51.dylib /usr/local/lib/
sudo make macosx install
I tend to copy the lib with
sudo cp src/liblua.dylib /usr/local/lib/liblua.5.1.4.dylib
# instead of
#sudo cp src/liblua.dylib /usr/local/lib/
lua binaries (GNU/Linux)
Hat tip to Micka33 for pointing to LuaBinaries in issue #34
tested with
ruby 1.9.1p0, jruby 1.2.0 jruby 1.1.6 has an issue with errors raised inside of Ruby functions (callbacks)
ruby-ffi 0.4.0 and 0.5.0
I run the specs with
bundle install # first time only
bundle exec rspec
dependencies
the ruby gem 'ffi'
issue tracker
http://github.com/jmettraux/rufus-lua/issues
source
http://github.com/jmettraux/rufus-lua
git clone git://github.com/jmettraux/rufus-lua.git
authors and credits
see CREDITS.txt
license
MIT
Lua itself is licensed under the MIT license as well :