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

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

      to_ruby = opts[:to_ruby]

      callback =
        Proc.new do |state|

          s = CallbackState.new(state)
          args = []

          loop do

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

            arg = s.stack_fetch

            args.unshift(arg)

            s.stack_unstack unless args.first.is_a?(Rufus::Lua::Ref)
          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

          s.stack_push(block.call(*args))

          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
def function(name, opts={}, &block)

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

      to_ruby = opts[:to_ruby]

      callback =
        Proc.new do |state|

          s = CallbackState.new(state)
          args = []

          loop do

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

            arg = s.stack_fetch

            args.unshift(arg)

            s.stack_unstack unless args.first.is_a?(Rufus::Lua::Ref)
          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

          s.stack_push(block.call(*args))

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