rufus-lua 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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