rufus-lua 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG.txt ADDED
@@ -0,0 +1,8 @@
1
+
2
+ = rufus-lua CHANGELOG.txt
3
+
4
+
5
+ == rufus-lua - 0.1.0 released 2009/03/16
6
+
7
+ - initial release
8
+
data/CREDITS.txt ADDED
@@ -0,0 +1,21 @@
1
+
2
+ = CREDITS.txt rufus-lua gem
3
+
4
+
5
+ == authors
6
+
7
+ John Mettraux http://jmettraux.wordpress.com
8
+ Alain Hoang http://blogs.law.harvard.edu/hoanga/
9
+
10
+
11
+ == inspiration
12
+
13
+ http://rubyluabridge.rubyforge.org/
14
+
15
+
16
+ == finally
17
+
18
+ many thanks to the authors of ruby-ffi
19
+
20
+ http://kenai.com/projects/ruby-ffi
21
+
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+
2
+ Copyright (c) 2009, John Mettraux, jmettraux@gmail.com
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+
data/README.txt ADDED
@@ -0,0 +1,141 @@
1
+
2
+ = rufus-lua
3
+
4
+ Lua embedded in Ruby, via Ruby FFI
5
+
6
+ Tested with Ruby 1.8.6, Ruby 1.9.1p0 and JRuby 1.1.6
7
+
8
+
9
+ == Lua
10
+
11
+ from
12
+
13
+ http://www.lua.org/
14
+ http://www.lua.org/about.html
15
+
16
+ """
17
+ Lua is a powerful, fast, lightweight, embeddable scripting language.
18
+
19
+ 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.
20
+ """
21
+
22
+
23
+ == other Ruby and Lua bridges / connectors
24
+
25
+
26
+ http://rubyluabridge.rubyforge.org/
27
+ http://raa.ruby-lang.org/project/ruby-lua
28
+
29
+
30
+ == using rufus-lua
31
+
32
+ If you don't have liblua.dylib on your system, scroll until "compiling liblua.dylib" to learn how to get it.
33
+
34
+ sudo gem install rufus-lua
35
+
36
+ then
37
+
38
+ require 'rubygems'
39
+ require 'rufus/lua'
40
+
41
+ s = Rufus::Lua::State.new
42
+
43
+ puts s.eval("return table.concat({ 'hello', 'from', 'Lua' }, ' ')")
44
+ #
45
+ # => "Hello from Lua"
46
+
47
+ s.close
48
+
49
+ rufus-lua's rdoc is at http://rufus.rubyforge.org/rufus-lua/
50
+
51
+
52
+ == compiling liblua.dylib
53
+
54
+ original instructions by Adrian Perez at :
55
+
56
+ http://lua-users.org/lists/lua-l/2006-09/msg00894.html
57
+
58
+ get the source at
59
+
60
+ http://www.lua.org/ftp/lua-5.1.4.tar.gz
61
+
62
+ then
63
+
64
+ tar xzvf lua-5.1.4.tar.gz
65
+ cd lua-5.1.4
66
+
67
+ modify the file src/Makefile as per http://lua-users.org/lists/lua-l/2006-09/msg00894.html
68
+
69
+ make
70
+ make masocx # or make linux ...
71
+ make -C src src liblua.dylib
72
+
73
+ sudo cp src/liblua.dylib /usr/local/lib/
74
+
75
+
76
+ == build dependencies
77
+
78
+ You need to add the github gems to your gem sources
79
+ gem sources -a http://gems.github.com
80
+
81
+ The following gems are needed to run the specs
82
+ mislav-hanna
83
+ install bacon
84
+
85
+
86
+ == dependencies
87
+
88
+ the ruby gem 'ffi'
89
+
90
+
91
+ == mailing list
92
+
93
+ On the rufus-ruby list :
94
+
95
+ http://groups.google.com/group/rufus-ruby
96
+
97
+
98
+ == issue tracker
99
+
100
+ http://rubyforge.org/tracker/?atid=18584&group_id=4812&func=browse
101
+
102
+
103
+ == irc
104
+
105
+ irc.freenode.net #ruote
106
+
107
+
108
+ == source
109
+
110
+ http://github.com/jmettraux/rufus-lua
111
+
112
+ git clone git://github.com/jmettraux/rufus-lua.git
113
+
114
+
115
+ == credits
116
+
117
+ many thanks to the authors of Ruby FFI, and of Lua
118
+
119
+ http://kenai.com/projects/ruby-ffi/
120
+ http://lua.org/
121
+
122
+
123
+ == authors
124
+
125
+ John Mettraux, jmettraux@gmail.com, http://jmettraux.wordpress.com
126
+ Alain Hoang, http://blogs.law.harvard.edu/hoanga/
127
+
128
+
129
+ == the rest of Rufus
130
+
131
+ http://rufus.rubyforge.org
132
+
133
+
134
+ == license
135
+
136
+ MIT
137
+
138
+ Lua itself is licensed under the MIT license as well :
139
+
140
+ http://www.lua.org/license.html
141
+
data/TODO.txt ADDED
@@ -0,0 +1,19 @@
1
+
2
+ [o] spec table.free()
3
+ [o] function.call()
4
+ [o] Table#[]
5
+ [o] Table + Enumerable (not necessarily)
6
+
7
+ [x] State#stack_ready() maybe : NO !
8
+
9
+ [o] better protection for State methods (into lib ?)
10
+
11
+ [o] fix coroutine & co / memoization (make it better later)
12
+ [o] fib.lua, use local, bench ! (2 times faster almost)
13
+
14
+ [ ] add GC control methods (Alain)
15
+ [ ] Add method to disable GC
16
+ [ ] Add method to enable GC
17
+ [ ] Look at parameters in Lua GC that can be tweaked
18
+ [ ] Add method to tune GC parameters
19
+
data/lib/rufus-lua.rb ADDED
@@ -0,0 +1,3 @@
1
+
2
+ require 'rufus/lua'
3
+
data/lib/rufus/lua.rb ADDED
@@ -0,0 +1,30 @@
1
+ #--
2
+ # Copyright (c) 2009, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+ require 'rufus/lua/lib'
26
+
27
+ require 'rufus/lua/state'
28
+ require 'rufus/lua/utils'
29
+ require 'rufus/lua/objects'
30
+
@@ -0,0 +1,97 @@
1
+ #--
2
+ # Copyright (c) 2009, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+
26
+ #require 'rubygems' # done by the 'client' code
27
+ require 'ffi'
28
+
29
+
30
+ module Rufus
31
+ module Lua
32
+
33
+ module Lib
34
+ extend FFI::Library
35
+
36
+ #
37
+ # locate dylib
38
+
39
+ paths = Array(ENV['LUA_LIB'] || %w{
40
+ /opt/local/lib/liblua.dylib
41
+ /usr/local/lib/liblua.dylib
42
+ /usr/local/lib/liblua.so
43
+ })
44
+
45
+ path = paths.find { |path| File.exist?(path) }
46
+
47
+ raise(
48
+ "didn't find the lua dylib on your system, " +
49
+ "see http://rufus.rubyforge.org/rufus-lua/ to learn how to get it"
50
+ ) unless path
51
+
52
+ ffi_lib(path)
53
+
54
+ #
55
+ # attach functions
56
+
57
+ attach_function :strlen, [ :string ], :int
58
+
59
+ attach_function :lua_close, [ :pointer ], :void
60
+
61
+ attach_function :luaL_openlibs, [ :pointer ], :void
62
+
63
+ attach_function :lua_pcall, [ :pointer, :int, :int, :int ], :int
64
+ #attach_function :lua_resume, [ :pointer, :int ], :int
65
+
66
+ attach_function :lua_toboolean, [ :pointer, :int ], :int
67
+ attach_function :lua_tonumber, [ :pointer, :int ], :float
68
+ attach_function :lua_tolstring, [ :pointer, :int, :pointer ], :string
69
+
70
+ attach_function :lua_type, [ :pointer, :int ], :int
71
+ attach_function :lua_typename, [ :pointer, :int ], :string
72
+
73
+ attach_function :lua_gettop, [ :pointer ], :int
74
+ attach_function :lua_settop, [ :pointer, :int ], :void
75
+
76
+ attach_function :lua_objlen, [ :pointer, :int ], :int
77
+ attach_function :lua_getfield, [ :pointer, :int, :string ], :pointer
78
+ attach_function :lua_gettable, [ :pointer, :int ], :void
79
+
80
+ attach_function :lua_next, [ :pointer, :int ], :int
81
+
82
+ attach_function :lua_pushnil, [ :pointer ], :pointer
83
+ attach_function :lua_pushboolean, [ :pointer, :int ], :pointer
84
+ attach_function :lua_pushinteger, [ :pointer, :int ], :pointer
85
+ attach_function :lua_pushnumber, [ :pointer, :float ], :pointer
86
+ attach_function :lua_pushstring, [ :pointer, :string ], :pointer
87
+
88
+ attach_function :lua_rawgeti, [ :pointer, :int, :int ], :void
89
+
90
+ attach_function :luaL_newstate, [], :pointer
91
+ attach_function :luaL_loadbuffer, [ :pointer, :string, :int, :string ], :int
92
+ attach_function :luaL_ref, [ :pointer, :int ], :int
93
+ attach_function :luaL_unref, [ :pointer, :int, :int ], :void
94
+ end
95
+ end
96
+ end
97
+
@@ -0,0 +1,246 @@
1
+ #--
2
+ # Copyright (c) 2009, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+
26
+ module Rufus::Lua
27
+
28
+ #
29
+ # The parent class for Table, Function and Coroutine. Simply holds
30
+ # a reference to the object in the Lua registry.
31
+ #
32
+ class Ref
33
+ include StateMixin
34
+
35
+ #
36
+ # The reference in the Lua registry.
37
+ # (You shouldn't care about this value)
38
+ #
39
+ attr_reader :ref
40
+
41
+ def initialize (pointer)
42
+ @pointer = pointer
43
+ @ref = Lib.luaL_ref(@pointer, LUA_REGISTRYINDEX)
44
+ end
45
+
46
+ #
47
+ # Frees the reference to this object
48
+ # (Problably a good idea if you want Lua's GC to get rid of it later).
49
+ #
50
+ def free
51
+ Lib.luaL_unref(@pointer, LUA_REGISTRYINDEX, @ref)
52
+ @ref = nil
53
+ end
54
+
55
+ protected
56
+
57
+ #
58
+ # Brings the referenced object on top of the stack (will probably
59
+ # then take part in a method call).
60
+ #
61
+ def load_onto_stack
62
+
63
+ raise LuaError.new(
64
+ "#{self.class} got freed, cannot re-access it directly"
65
+ ) unless @ref
66
+
67
+ stack_load_ref(@ref)
68
+ end
69
+ end
70
+
71
+ #
72
+ # A Lua function.
73
+ #
74
+ # require 'rubygems'
75
+ # require 'rufus/lua'
76
+ #
77
+ # s = Rufus::Lua::State.new
78
+ #
79
+ # f = s.eval(%{
80
+ # return function (x)
81
+ # return 2 * x
82
+ # end
83
+ # })
84
+ #
85
+ # f.call(2) # => 4.0
86
+ #
87
+ class Function < Ref
88
+
89
+ #
90
+ # Calls the Lua function.
91
+ #
92
+ def call (*args)
93
+
94
+ bottom = stack_top
95
+
96
+ load_onto_stack
97
+ # load function on stack
98
+
99
+ args.each { |arg| stack_push(arg) }
100
+ # push arguments on stack
101
+
102
+ pcall(bottom, args.length)
103
+ end
104
+ end
105
+
106
+ #
107
+ # (coming soon)
108
+ #
109
+ class Coroutine < Ref
110
+
111
+ #
112
+ # Resumes the coroutine
113
+ #
114
+ def resume (*args)
115
+
116
+ bottom = stack_top
117
+
118
+ fetch_library_method('coroutine.resume').load_onto_stack
119
+
120
+ load_onto_stack
121
+ args.each { |arg| stack_push(arg) }
122
+
123
+ pcall(bottom, args.length + 1)
124
+ end
125
+
126
+ #
127
+ # Returns the string status of the coroutine :
128
+ # suspended/running/dead/normal
129
+ #
130
+ def status
131
+
132
+ bottom = stack_top
133
+
134
+ fetch_library_method('coroutine.status').load_onto_stack
135
+ load_onto_stack
136
+
137
+ pcall(bottom, 1)
138
+ end
139
+ end
140
+
141
+ #
142
+ # A Lua table.
143
+ #
144
+ # For now, the only thing you can do with it is cast it into a Hash or
145
+ # an Array (will raise an exception if casting to an Array is not possible).
146
+ #
147
+ # Note that direct manipulation of the Lua table (inside Lua) is not possible
148
+ # (as of now).
149
+ #
150
+ class Table < Ref
151
+ include Enumerable
152
+
153
+ #
154
+ # The classical 'each'.
155
+ #
156
+ # Note it cheats by first turning the table into a Ruby Hash and calling
157
+ # the each of that Hash instance (this way, the stack isn't involved
158
+ # in the iteration).
159
+ #
160
+ def each
161
+
162
+ return unless block_given?
163
+ self.to_h.each { |k, v| yield(k, v) }
164
+ end
165
+
166
+ #
167
+ # Returns the array of keys of this Table.
168
+ #
169
+ def keys
170
+
171
+ self.to_h.keys
172
+ end
173
+
174
+ #
175
+ # Returns the array of values in this Table.
176
+ #
177
+ def values
178
+
179
+ self.to_h.values
180
+ end
181
+
182
+ #
183
+ # Returns the value behind the key, or else nil.
184
+ #
185
+ def [] (k)
186
+
187
+ load_onto_stack # table
188
+ stack_push(k) # key
189
+ Lib.lua_gettable(@pointer, -2) # fetch val for key at top and table at -2
190
+ stack_pop
191
+ end
192
+
193
+ #--
194
+ # TODO : implement (maybe)
195
+ #
196
+ #def []= (k, v)
197
+ # raise 'not yet !'
198
+ #end
199
+ #++
200
+
201
+ #
202
+ # Returns a Ruby Hash instance representing this Lua table.
203
+ #
204
+ def to_h
205
+
206
+ load_onto_stack
207
+
208
+ table_pos = stack_top
209
+
210
+ Lib.lua_pushnil(@pointer)
211
+
212
+ h = {}
213
+
214
+ while Lib.lua_next(@pointer, table_pos) != 0 do
215
+
216
+ value = stack_fetch(-1)
217
+ key = stack_fetch(-2)
218
+
219
+ stack_unstack # leave key on top
220
+
221
+ h[key] = value
222
+ end
223
+
224
+ h
225
+ end
226
+
227
+ #
228
+ # Returns a Ruby Array instance representing this Lua table.
229
+ #
230
+ # Will raise an error if the 'rendering' is not possible.
231
+ #
232
+ def to_a
233
+
234
+ h = self.to_h
235
+
236
+ keys = h.keys.sort
237
+
238
+ keys.find { |k| not [ Float ].include?(k.class) } &&
239
+ raise("cannot turn hash into array, some keys are not numbers")
240
+
241
+ keys.inject([]) { |a, k| a << h[k]; a }
242
+ end
243
+
244
+ end
245
+ end
246
+
@@ -0,0 +1,367 @@
1
+ #--
2
+ # Copyright (c) 2009, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+
26
+ module Rufus::Lua
27
+
28
+ #
29
+ # An error class for this gem/library.
30
+ #
31
+ class LuaError < RuntimeError; end
32
+
33
+ #
34
+ # Rufus::Lua::Lib contains all the raw C API Lua methods. The methods
35
+ # here are shared by all the rufus-lua classes that have to deal with
36
+ # a Lua state. They are protected since they aren't meant to be called
37
+ # directly.
38
+ #
39
+ # The entry point of rufus-lua is Rufus::Lua::State, look there.
40
+ #
41
+ module StateMixin
42
+
43
+ LUA_GLOBALSINDEX = -10002
44
+ LUA_ENVIRONINDEX = -10001
45
+ LUA_REGISTRYINDEX = -10000
46
+ LUA_NOREF = -2
47
+ LUA_REFNIL = -1
48
+
49
+ TNONE = -1
50
+ TNIL = 0
51
+ TBOOLEAN = 1
52
+ TLIGHTUSERDATA = 2
53
+ TNUMBER = 3
54
+ TSTRING = 4
55
+ TTABLE = 5
56
+ TFUNCTION = 6
57
+ TUSERDATA = 7
58
+ TTHREAD = 8
59
+
60
+ LUA_MULTRET = -1
61
+
62
+ protected
63
+
64
+ #
65
+ # This method is used to fetch/cache references to library methods like
66
+ # 'math.sin' or 'coroutine.resume'.
67
+ # The caching is done at the Lua state level (ie, all Lua objects available
68
+ # via the state share the cache.
69
+ #
70
+ # (Not sure yet about this yet)
71
+ #
72
+ def fetch_library_method (s)
73
+
74
+ if m = @pointer.__lib_method_cache[s]
75
+ m
76
+ else
77
+ @pointer.__lib_method_cache[s] = loadstring_and_call("return #{s}")
78
+ end
79
+ end
80
+
81
+ #
82
+ # This method holds the 'eval' mechanism.
83
+ #
84
+ def loadstring_and_call (s)
85
+
86
+ bottom = stack_top
87
+
88
+ err = Lib.luaL_loadbuffer(@pointer, s, Lib.strlen(s), 'line')
89
+ raise_if_error('eval:compile', err)
90
+
91
+ pcall(bottom, 0) # arg_count is set to 0
92
+ end
93
+
94
+ #
95
+ # Returns a string representation of the state's stack.
96
+ #
97
+ def stack_to_s
98
+
99
+ # warning : don't touch at stack[0]
100
+
101
+ s = (1..stack_top).inject([]) { |a, i|
102
+ type, tname = stack_type_at(i)
103
+ a << "#{i} : #{tname} (#{type})"
104
+ a
105
+ }.reverse.join("\n")
106
+ s += "\n" if s.length > 0
107
+ s
108
+ end
109
+
110
+ #
111
+ # Outputs the stack to the stdout
112
+ #
113
+ def print_stack (msg=nil)
114
+
115
+ puts "\n=stack= #{msg ? "(#{msg})" : ""}"
116
+ puts "top : #{stack_top}"
117
+ print stack_to_s
118
+ puts "= ="
119
+ end
120
+
121
+ #
122
+ # Returns the offset (int) of the top element of the stack.
123
+ #
124
+ def stack_top
125
+
126
+ Lib.lua_gettop(@pointer)
127
+ end
128
+
129
+ #
130
+ # Returns a pair type (int) and type name (string) of the element on top
131
+ # of the Lua state's stack. There is an optional pos paramter to peek
132
+ # at other elements of the stack.
133
+ #
134
+ def stack_type_at (pos=-1)
135
+
136
+ type = Lib.lua_type(@pointer, pos)
137
+ tname = Lib.lua_typename(@pointer, type)
138
+
139
+ [ type, tname ]
140
+ end
141
+
142
+ #
143
+ # Fetches the top value on the stack (or the one specified by the optional
144
+ # pos parameter), but does not 'pop' it.
145
+ #
146
+ def stack_fetch (pos=-1)
147
+
148
+ type, tname = stack_type_at(pos)
149
+
150
+ case type
151
+
152
+ when TNIL then nil
153
+
154
+ when TSTRING then Lib.lua_tolstring(@pointer, pos, nil)
155
+ when TBOOLEAN then (Lib.lua_toboolean(@pointer, pos) == 1)
156
+ when TNUMBER then Lib.lua_tonumber(@pointer, pos)
157
+
158
+ when TTABLE then Table.new(@pointer)
159
+ when TFUNCTION then Function.new(@pointer)
160
+ when TTHREAD then Coroutine.new(@pointer)
161
+
162
+ else tname
163
+ end
164
+ end
165
+
166
+ #
167
+ # Pops the top value of lua state's stack and returns it.
168
+ #
169
+ def stack_pop
170
+
171
+ r = stack_fetch
172
+ stack_unstack
173
+ r
174
+ end
175
+
176
+ #
177
+ # Makes sure the stack loses its top element (but doesn't return it).
178
+ #
179
+ def stack_unstack
180
+
181
+ new_top = stack_top - 1
182
+ new_top = 0 if new_top < 0
183
+ Lib.lua_settop(@pointer, new_top)
184
+ end
185
+
186
+ #
187
+ # Given a Ruby instance, will attempt to push it on the Lua stack.
188
+ #
189
+ def stack_push (o)
190
+
191
+ case o
192
+
193
+ when NilClass then Lib.lua_pushnil(@pointer)
194
+
195
+ when TrueClass then Lib.lua_pushboolean(@pointer, 1)
196
+ when FalseClass then Lib.lua_pushboolean(@pointer, 1)
197
+
198
+ when Fixnum then Lib.lua_pushinteger(@pointer, o)
199
+ when Float then Lib.lua_pushnumber(@pointer, o)
200
+
201
+ when String then Lib.lua_pushstring(@pointer, o)
202
+
203
+ #when Hash then ...
204
+ #when Array then ...
205
+
206
+ else raise(
207
+ ArgumentError.new(
208
+ "don't know how to pass Ruby instance of #{o.class} to Lua"))
209
+ end
210
+ end
211
+
212
+ #
213
+ # Loads a Lua global value on top of the stack
214
+ #
215
+ def stack_load_global (name)
216
+
217
+ Lib.lua_getfield(@pointer, LUA_GLOBALSINDEX, name)
218
+ end
219
+
220
+ #
221
+ # Loads the Lua object registered with the given ref on top of the stack
222
+ #
223
+ def stack_load_ref (ref)
224
+
225
+ Lib.lua_rawgeti(@pointer, LUA_REGISTRYINDEX, @ref)
226
+ end
227
+
228
+ #
229
+ # Returns the result of a function call or a coroutine.resume().
230
+ #
231
+ def return_result (stack_bottom)
232
+
233
+ count = stack_top - stack_bottom
234
+
235
+ return nil if count == 0
236
+ return stack_pop if count == 1
237
+
238
+ (1..count).collect { |pos| stack_pop }.reverse
239
+ end
240
+
241
+ #
242
+ # Assumes the Lua stack is loaded with a ref to a method and arg_count
243
+ # arguments (on top of the method), will then call that Lua method and
244
+ # return a result.
245
+ #
246
+ # Will raise an error in case of failure.
247
+ #
248
+ def pcall (stack_bottom, arg_count)
249
+
250
+ #err = Lib.lua_pcall(@pointer, 0, 1, 0)
251
+ # when there's only 1 return value, use LUA_MULTRET (-1) the
252
+ # rest of the time
253
+
254
+ err = Lib.lua_pcall(@pointer, arg_count, LUA_MULTRET, 0)
255
+ raise_if_error('eval:pcall', err)
256
+
257
+ return_result(stack_bottom)
258
+ end
259
+
260
+ #--
261
+ # Resumes a coroutine (that has been placed, under its arguments,
262
+ # on top of the stack).
263
+ #
264
+ #def do_resume (stack_bottom, arg_count)
265
+ # err = Lib.lua_resume(@pointer, arg_count)
266
+ # raise_if_error('eval:resume', err)
267
+ # return_result(stack_bottom)
268
+ #end
269
+ #++
270
+
271
+ #
272
+ # This method will raise an error with err > 0, else it will immediately
273
+ # return.
274
+ #
275
+ def raise_if_error (where, err)
276
+
277
+ return if err < 1
278
+
279
+ # TODO :
280
+ #
281
+ # LUA_ERRRUN: a runtime error.
282
+ # LUA_ERRMEM: memory allocation error. For such errors, Lua does not call
283
+ # the error handler function.
284
+ # LUA_ERRERR: error while running the error handler function.
285
+
286
+ s = Lib.lua_tolstring(@pointer, -1, nil)
287
+ Lib.lua_settop(@pointer, -2)
288
+
289
+ raise LuaError.new("#{where} : '#{s}' (#{err})")
290
+ end
291
+
292
+ #
293
+ # Given the name of a Lua global variable, will return its value (or nil
294
+ # if there is nothing bound under that name).
295
+ #
296
+ def get_global (name)
297
+
298
+ stack_load_global(name)
299
+ stack_pop
300
+ end
301
+ end
302
+
303
+ #
304
+ # A Lua state, wraps a Lua runtime.
305
+ #
306
+ # require 'rufus/lua'
307
+ # s = Rufus::Lua::State.new
308
+ # s.eval "a = 1 + 2"
309
+ #
310
+ # p s['a'] # => 3.0
311
+ #
312
+ class State
313
+ include StateMixin
314
+
315
+ #
316
+ # Instantiates a Lua state (runtime).
317
+ #
318
+ # Accepts an 'include_libs' optional arg. When set to true (the default,
319
+ # all the base Lua libs are loaded in the runtime.
320
+ #
321
+ def initialize (include_libs=true)
322
+
323
+ @pointer = Lib.luaL_newstate
324
+
325
+ Lib.luaL_openlibs(@pointer) if include_libs
326
+
327
+ #
328
+ # preparing library methods cache
329
+
330
+ class << @pointer
331
+ attr_reader :__lib_method_cache
332
+ end
333
+ @pointer.instance_variable_set(:@__lib_method_cache, {})
334
+ end
335
+
336
+ #
337
+ # Evaluates a piece (string) of Lua code within the state.
338
+ #
339
+ def eval (s)
340
+
341
+ loadstring_and_call(s)
342
+ end
343
+
344
+ #
345
+ # Returns a value set at the 'global' level in the state.
346
+ #
347
+ # state.eval('a = 1 + 2')
348
+ # puts state['a'] # => "3.0"
349
+ #
350
+ def [] (k)
351
+
352
+ k.index('.') ? self.eval("return #{k}") : get_global(k)
353
+ end
354
+
355
+ #
356
+ # Closes the state.
357
+ #
358
+ # It's probably a good idea (mem leaks) to close a Lua state once you're
359
+ # done with it.
360
+ #
361
+ def close
362
+
363
+ Lib.lua_close(@pointer)
364
+ end
365
+ end
366
+ end
367
+
@@ -0,0 +1,78 @@
1
+ #--
2
+ # Copyright (c) 2009, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+
26
+ module Rufus::Lua
27
+
28
+ #--
29
+ # always make sure that the methods here are usable without the need
30
+ # to load liblua.dylib
31
+ #++
32
+
33
+ #
34
+ # Turns a Ruby instance into a Lua parseable string representation.
35
+ #
36
+ # Will raise an ArgumentError as soon as something else than a simple
37
+ # Ruby type (or Hash/Array) is passed.
38
+ #
39
+ # Rufus::Lua.to_lua_s({ 'a' => 'A', 'b' => 2})
40
+ # #
41
+ # # => '{ "a": "A", "b": 2 }'
42
+ #
43
+ def self.to_lua_s (o)
44
+
45
+ case o
46
+
47
+ when String then o.inspect
48
+ when Fixnum then o.to_s
49
+ when Float then o.to_s
50
+ when TrueClass then o.to_s
51
+ when FalseClass then o.to_s
52
+
53
+ when Hash then to_lua_table_s(o)
54
+ when Array then to_lua_table_s(o)
55
+
56
+ else raise(
57
+ ArgumentError.new(
58
+ "don't how to turning into a Lua string representation "+
59
+ "Ruby instances of class '#{o.class}'"))
60
+ end
61
+ end
62
+
63
+ #
64
+ # Turns a Ruby Array or Hash instance into a Lua parseable string
65
+ # representation.
66
+ #
67
+ def self.to_lua_table_s (o)
68
+
69
+ s = if o.is_a?(Array)
70
+ o.collect { |e| to_lua_s(e) }
71
+ else
72
+ o.collect { |k, v| "#{to_lua_s(k)}: #{to_lua_s(v)}" }
73
+ end
74
+
75
+ "{ #{s.join(', ')} }"
76
+ end
77
+ end
78
+
data/spec/spec.rb ADDED
@@ -0,0 +1,9 @@
1
+
2
+ #
3
+ # specifying rufus-lua
4
+ #
5
+ # Wed Mar 11 16:09:11 JST 2009
6
+ #
7
+
8
+ Dir["#{File.dirname(__FILE__)}/*_spec.rb"].each { |path| load(path) }
9
+
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rufus-lua
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - John Mettraux
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-16 00:00:00 +09:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ffi
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email: jmettraux@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.txt
33
+ - CHANGELOG.txt
34
+ - CREDITS.txt
35
+ - LICENSE.txt
36
+ files:
37
+ - lib/rufus/lua/lib.rb
38
+ - lib/rufus/lua/objects.rb
39
+ - lib/rufus/lua/state.rb
40
+ - lib/rufus/lua/utils.rb
41
+ - lib/rufus/lua.rb
42
+ - lib/rufus-lua.rb
43
+ - CHANGELOG.txt
44
+ - CREDITS.txt
45
+ - LICENSE.txt
46
+ - README.txt
47
+ - TODO.txt
48
+ has_rdoc: true
49
+ homepage: http://rufus.rubyforge.org/
50
+ post_install_message:
51
+ rdoc_options: []
52
+
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements:
68
+ - ffi
69
+ rubyforge_project: rufus
70
+ rubygems_version: 1.3.1
71
+ signing_key:
72
+ specification_version: 2
73
+ summary: ruby-ffi based bridge from Ruby to Lua
74
+ test_files:
75
+ - spec/spec.rb