Class: Rufus::Lua::State

Inherits:
Object
  • Object
show all
Includes:
StateMixin
Defined in:
lib/rufus/lua/state.rb

Overview

A Lua state, wraps a Lua runtime.

require 'rufus/lua'
s = Rufus::Lua::State.new
s.eval "a = 1 + 2"

p s['a'] # => 3.0

Constant Summary

Constants included from StateMixin

Rufus::Lua::StateMixin::LUA_ENVIRONINDEX, Rufus::Lua::StateMixin::LUA_GCCOLLECT, Rufus::Lua::StateMixin::LUA_GCCOUNT, Rufus::Lua::StateMixin::LUA_GCCOUNTB, Rufus::Lua::StateMixin::LUA_GCRESTART, Rufus::Lua::StateMixin::LUA_GCSETPAUSE, Rufus::Lua::StateMixin::LUA_GCSETSTEPMUL, Rufus::Lua::StateMixin::LUA_GCSTEP, Rufus::Lua::StateMixin::LUA_GCSTOP, Rufus::Lua::StateMixin::LUA_GLOBALSINDEX, Rufus::Lua::StateMixin::LUA_MULTRET, Rufus::Lua::StateMixin::LUA_NOREF, Rufus::Lua::StateMixin::LUA_REFNIL, Rufus::Lua::StateMixin::LUA_REGISTRYINDEX, Rufus::Lua::StateMixin::SIMPLE_TYPES, Rufus::Lua::StateMixin::TBOOLEAN, Rufus::Lua::StateMixin::TFUNCTION, Rufus::Lua::StateMixin::TLIGHTUSERDATA, Rufus::Lua::StateMixin::TNIL, Rufus::Lua::StateMixin::TNONE, Rufus::Lua::StateMixin::TNUMBER, Rufus::Lua::StateMixin::TSTRING, Rufus::Lua::StateMixin::TTABLE, Rufus::Lua::StateMixin::TTHREAD, Rufus::Lua::StateMixin::TUSERDATA

Instance Method Summary collapse

Constructor Details

#initialize(include_libs = true) ⇒ State

Instantiates a Lua state (runtime).

Accepts an ‘include_libs’ optional arg. When set to true (the default, all the base Lua libs are loaded in the runtime.

This optional arg can be set to false, when no libs should be present, or to an array of libs to load in order to prepare the state.

The list may include ‘base’, ‘package’, ‘table’, ‘string’, ‘math’, ‘io’, ‘os’ and ‘debug’.



373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
# File 'lib/rufus/lua/state.rb', line 373

def initialize(include_libs=true)

  @pointer = Lib.luaL_newstate

  open_libraries(include_libs)

  #
  # preparing library methods cache

  class << @pointer
    attr_reader :__lib_method_cache
  end
  @pointer.instance_variable_set(:@__lib_method_cache, {})

  #
  # an array for preserving callback (Ruby functions) from Ruby
  # garbage collection (Scott).

  @callbacks = []
end

Instance Method Details

#[](k) ⇒ Object

Returns a value set at the ‘global’ level in the state.

state.eval('a = 1 + 2')
puts state['a'] # => "3.0"


406
407
408
409
# File 'lib/rufus/lua/state.rb', line 406

def [](k)

  k.index('.') ?  self.eval("return #{k}") : get_global(k)
end

#[]=(k, v) ⇒ Object

Allows for setting a Lua varible immediately.

state['var'] = [ 1, 2, 3 ]
puts state['var'].to_a[0] # => 1


416
417
418
419
420
# File 'lib/rufus/lua/state.rb', line 416

def []=(k, v)

  #puts; puts("#{k} = #{Rufus::Lua.to_lua_s(v)}")
  self.eval("#{k} = #{Rufus::Lua.to_lua_s(v)}")
end

#closeObject

Closes the state.

It’s probably a good idea (mem leaks) to close a Lua state once you’re done with it.



539
540
541
542
543
544
# File 'lib/rufus/lua/state.rb', line 539

def close

  raise "State already closed" unless @pointer
  Lib.lua_close(@pointer)
  @pointer = nil
end

#eval(s, binding = nil, filename = nil, lineno = nil) ⇒ Object

Evaluates a piece (string) of Lua code within the state.



396
397
398
399
# File 'lib/rufus/lua/state.rb', line 396

def eval(s, binding=nil, filename=nil, lineno=nil)

  loadstring_and_call(s, binding, filename, lineno)
end

#function(name, opts = {}, &block) ⇒ Object

Binds a Ruby function (callback) in the top environment of Lua

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
  end
end

p s.eval(%{
  local table = {}
  table['CoW'] = 2
  table['pigs'] = 3
  table['DUCKS'] = 'none'
  return key_up(table)
}).to_h
  # => { 'COW' => 2.0, 'DUCKS => 'none', 'PIGS' => 3.0 }

s.close

:to_ruby => true

Without this option set to true, Lua tables passed to the wrapped Ruby code are instances of Rufus::Lua::Table. With this option set, rufus-lua will call #to_ruby on any parameter that responds to it (And Rufus::Lua::Table does).

s = Rufus::Lua::State.new

s.function 'is_array', :to_ruby => true do |table|
  table.is_a?(Array)
end

s.eval(return is_array({ 1, 2 }))
  # => true
s.eval(return is_array({ 'a' = 'b' }))
  # => false


463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
# File 'lib/rufus/lua/state.rb', line 463

def function(name, opts={}, &block)

  raise 'please pass a block for the body of the function' unless block

  to_ruby = opts[:to_ruby]

  callback = Proc.new do |state|

    args = []

    loop do

      break if stack_top == 0 # never touch stack[0] !!

      arg = stack_fetch
      break if arg.class == Rufus::Lua::Function

      args.unshift(arg)

      stack_unstack unless args.first.is_a?(Rufus::Lua::Table)
    end

    while args.size < block.arity
      args << nil
    end

    args = args.collect { |a| a.respond_to?(:to_ruby) ? a.to_ruby : a } \
      if to_ruby

    result = block.call(*args)

    stack_push(result)

    1
  end

  @callbacks << callback
    # preserving the callback from garbage collection

  name = name.to_s

  name, index = if ri = name.rindex('.')
    #
    # bind in the given table

    table_name = name[0..ri-1]

    t = self.eval("return #{table_name}") rescue nil

    raise ArgumentError.new(
      "won't create automatically nested tables"
    ) if (not t) and table_name.index('.')

    t = self.eval("#{table_name} = {}; return #{table_name}") \
      unless t

    t.send(:load_onto_stack)

    [ name[ri+1..-1], -2 ]

  else
    #
    # bind function at the global level

    [ name, LUA_GLOBALSINDEX ]
  end

  Lib.lua_pushcclosure(@pointer, callback, 0)
  Lib.lua_setfield(@pointer, index, name)
end

#gc_collect!Object

Runs garbage collection



556
557
558
559
560
# File 'lib/rufus/lua/state.rb', line 556

def gc_collect!

  raise "State got closed, cannot proceed" unless @pointer
  Lib.lua_gc(@pointer, LUA_GCCOLLECT, 0)
end

#gc_countObject

Returns current amount of memory in KB in use by Lua



548
549
550
551
552
# File 'lib/rufus/lua/state.rb', line 548

def gc_count

  raise "State got closed, cannot proceed" unless @pointer
  Lib.lua_gc(@pointer, LUA_GCCOUNT, 0)
end

#gc_resumeObject

Restart garbage collection for this state



572
573
574
575
576
# File 'lib/rufus/lua/state.rb', line 572

def gc_resume

  raise "State got closed, cannot proceed" unless @pointer
  Lib.lua_gc(@pointer, LUA_GCRESTART, 0)
end

#gc_stopObject

Stop garbage collection for this state



564
565
566
567
568
# File 'lib/rufus/lua/state.rb', line 564

def gc_stop

  raise "State got closed, cannot proceed" unless @pointer
  Lib.lua_gc(@pointer, LUA_GCSTOP, 0)
end

#open_libraries(libs) ⇒ Object



602
603
604
605
606
607
608
609
# File 'lib/rufus/lua/state.rb', line 602

def open_libraries(libs)

  if libs == true
    Lib.luaL_openlibs(@pointer)
  elsif libs.is_a?(Array)
    libs.each { |l| open_library(l) }
  end
end

#open_library(libname) ⇒ Object

#open_library(libname) - load a lua library via lua_call().

This is needed because is the Lua 5.1 Reference Manual Section 5 (www.lua.org/manual/5.1/manual.html#5) it says:

“The luaopen_* functions (to open libraries) cannot be called directly, like a regular C function. They must be called through Lua, like a Lua function.”

“..you must call them like any other Lua C function, e.g., by using lua_call.”

(by Matthew Nielsen - github.com/xunker)



592
593
594
595
596
597
598
599
600
# File 'lib/rufus/lua/state.rb', line 592

def open_library(libname)

  Lib.lua_pushcclosure(
    @pointer, lambda { |ptr| Lib.send("luaopen_#{libname}", @pointer) }, 0)
  Lib.lua_pushstring(
    @pointer, (libname.to_s == "base" ? "" : libname.to_s))
  Lib.lua_call(
    @pointer, 1, 0)
end