rufus-lua 1.1.0 → 1.1.1
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 +17 -0
- data/CREDITS.txt +7 -2
- data/LICENSE.txt +1 -1
- data/README.md +263 -0
- data/Rakefile +82 -0
- data/lib/rufus/lua.rb +4 -1
- data/lib/rufus/lua/error.rb +86 -0
- data/lib/rufus/lua/lib.rb +34 -14
- data/lib/rufus/lua/objects.rb +11 -12
- data/lib/rufus/lua/state.rb +74 -55
- data/lib/rufus/lua/utils.rb +3 -3
- data/lib/rufus/lua/version.rb +32 -0
- data/rufus-lua.gemspec +36 -0
- data/spec/coroutines_spec.rb +90 -0
- data/spec/eval_spec.rb +125 -0
- data/spec/functions_spec.rb +119 -0
- data/spec/gc_spec.rb +41 -0
- data/spec/lib_spec.rb +32 -0
- data/spec/rfunctions_spec.rb +282 -0
- data/spec/spec_base.rb +10 -0
- data/spec/state_spec.rb +106 -0
- data/spec/string_spec.rb +46 -0
- data/spec/tables_spec.rb +165 -0
- data/spec/utils_spec.rb +36 -0
- data/test/bm0.rb +41 -0
- data/test/bm_fiber.rb +78 -0
- data/test/bm_gc_stop.rb +43 -0
- data/test/gc0.rb +19 -0
- data/test/t.rb +19 -0
- metadata +105 -56
- data/README.rdoc +0 -210
data/spec/lib_spec.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-lua
|
4
|
+
#
|
5
|
+
# Thu Jun 19 20:29:06 JST 2014
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'spec_base'
|
9
|
+
|
10
|
+
|
11
|
+
describe Rufus::Lua::Lib do
|
12
|
+
|
13
|
+
describe '.path' do
|
14
|
+
|
15
|
+
it 'returns the Lua lib being used' do
|
16
|
+
|
17
|
+
path =
|
18
|
+
Array(
|
19
|
+
Dir.glob('/usr/lib/liblua*.so') +
|
20
|
+
Dir.glob('/usr/lib/*/liblua*.so') +
|
21
|
+
Dir.glob('/usr/local/lib/liblua*.so') +
|
22
|
+
Dir.glob('/opt/local/lib/liblua*.so') +
|
23
|
+
Dir.glob('/usr/lib/liblua*.dylib') +
|
24
|
+
Dir.glob('/usr/local/lib/liblua*.dylib') +
|
25
|
+
Dir.glob('/opt/local/lib/liblua*.dylib')
|
26
|
+
).first
|
27
|
+
|
28
|
+
expect(Rufus::Lua::Lib.path).to eq path
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,282 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-lua
|
4
|
+
#
|
5
|
+
# Wed Mar 18 17:53:06 JST 2009
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'spec_base'
|
9
|
+
|
10
|
+
|
11
|
+
describe Rufus::Lua::State do
|
12
|
+
|
13
|
+
before do
|
14
|
+
@s = Rufus::Lua::State.new
|
15
|
+
end
|
16
|
+
after do
|
17
|
+
@s.close
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#function' do
|
21
|
+
|
22
|
+
it 'raises when no block is given' do
|
23
|
+
|
24
|
+
expect(lambda {
|
25
|
+
@s.function 'no_block'
|
26
|
+
}).to raise_error(RuntimeError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'works without arguments' do
|
30
|
+
|
31
|
+
blinked = false
|
32
|
+
|
33
|
+
@s.function 'blink' do
|
34
|
+
blinked = true
|
35
|
+
end
|
36
|
+
|
37
|
+
@s.eval('blink()')
|
38
|
+
|
39
|
+
expect(blinked).to eq true
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'works with arguments' do
|
43
|
+
|
44
|
+
message = nil
|
45
|
+
|
46
|
+
@s.function :greet do |msg|
|
47
|
+
message = msg
|
48
|
+
end
|
49
|
+
|
50
|
+
@s.eval("greet('obandegozaimasu')")
|
51
|
+
|
52
|
+
expect(message).to eq 'obandegozaimasu'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'binds functions inside of Lua tables' do
|
56
|
+
|
57
|
+
@s.eval('lib = {}')
|
58
|
+
@s.function 'lib.myfunc' do |x|
|
59
|
+
x + 2
|
60
|
+
end
|
61
|
+
|
62
|
+
expect(@s.eval("return lib.myfunc(3)")).to eq 5.0
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'creates the top Lua table if not present' do
|
66
|
+
|
67
|
+
@s.function 'lib.myfunc' do |x|
|
68
|
+
x + 2
|
69
|
+
end
|
70
|
+
|
71
|
+
expect(@s.eval("return lib.myfunc(3)")).to eq 5.0
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'only creates the top table (not intermediary tables)' do
|
75
|
+
|
76
|
+
expect(lambda {
|
77
|
+
@s.function('lib.toto.myfunc') { |x| x + 2 }
|
78
|
+
}).to raise_error(ArgumentError)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'calling a Ruby function from Lua' do
|
83
|
+
|
84
|
+
it 'may return a single value' do
|
85
|
+
|
86
|
+
@s.function :greet do
|
87
|
+
'hello !'
|
88
|
+
end
|
89
|
+
|
90
|
+
expect(@s.eval('return greet()')).to eq 'hello !'
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'may return multiple values' do
|
94
|
+
|
95
|
+
@s.function :compute do
|
96
|
+
[ 'a', true, 1 ]
|
97
|
+
end
|
98
|
+
|
99
|
+
expect(@s.eval('return compute()').to_a).to eq [ 'a', true, 1.0 ]
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'may return tables' do
|
103
|
+
|
104
|
+
@s.function :compute do
|
105
|
+
{ 'a' => 'alpha', 'z' => 'zebra' }
|
106
|
+
end
|
107
|
+
|
108
|
+
expect(@s.eval('return compute()').to_h).to eq(
|
109
|
+
{ 'a' => 'alpha', 'z' => 'zebra' })
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'may return tables (with nested arrays)' do
|
113
|
+
|
114
|
+
@s.function :compute do
|
115
|
+
{ 'a' => 'alpha', 'z' => [ 1, 2, 3 ] }
|
116
|
+
end
|
117
|
+
|
118
|
+
expect(@s.eval('return compute()').to_h['z'].to_a).to eq [ 1.0, 2.0, 3.0 ]
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'accepts hashes as arguments' do
|
122
|
+
|
123
|
+
@s.function :to_json do |h|
|
124
|
+
"{" + h.collect { |k, v| "#{k}:\"#{v}\"" }.join(",") + "}"
|
125
|
+
end
|
126
|
+
|
127
|
+
expect(@s.eval(
|
128
|
+
"return to_json({ a = 'ALPHA', b = 'BRAVO' })"
|
129
|
+
)).to eq(
|
130
|
+
'{a:"ALPHA",b:"BRAVO"}'
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'accepts arrays as arguments' do
|
135
|
+
|
136
|
+
@s.function :do_join do |a|
|
137
|
+
a.to_a.join(', ')
|
138
|
+
end
|
139
|
+
|
140
|
+
expect(@s.eval(
|
141
|
+
"return do_join({ 'alice', 'bob', 'charly' })"
|
142
|
+
)).to eq(
|
143
|
+
'alice, bob, charly'
|
144
|
+
)
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'raise exceptions (Ruby -> Lua -> Ruby and back)' do
|
148
|
+
|
149
|
+
@s.function :do_fail do
|
150
|
+
raise "fail!"
|
151
|
+
end
|
152
|
+
|
153
|
+
expect(lambda {
|
154
|
+
@s.eval("return do_fail()")
|
155
|
+
}).to raise_error(RuntimeError)
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'counts the animals correctly' do
|
159
|
+
|
160
|
+
@s.function 'key_up' do |table|
|
161
|
+
table.inject({}) do |h, (k, v)|
|
162
|
+
h[k.to_s.upcase] = v; h
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
expect(@s.eval(%{
|
167
|
+
local table = {}
|
168
|
+
table['CoW'] = 2
|
169
|
+
table['pigs'] = 3
|
170
|
+
table['DUCKS'] = 'none'
|
171
|
+
return key_up(table)
|
172
|
+
}).to_h).to eq(
|
173
|
+
{ 'COW' => 2.0, 'DUCKS' => 'none', 'PIGS' => 3.0 }
|
174
|
+
)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'returns Ruby arrays as Lua tables' do
|
178
|
+
|
179
|
+
@s.function :get_data do |msg|
|
180
|
+
%w[ one two three ]
|
181
|
+
end
|
182
|
+
|
183
|
+
@s.eval('data = get_data()')
|
184
|
+
|
185
|
+
expect(@s['data'].to_a).to eq %w[ one two three ]
|
186
|
+
expect(@s.eval('return type(data)')).to eq('table')
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'return properly indexed Lua tables' do
|
190
|
+
|
191
|
+
@s.function :get_data do |msg|
|
192
|
+
%w[ one two three ]
|
193
|
+
end
|
194
|
+
|
195
|
+
@s.eval('data = get_data()')
|
196
|
+
|
197
|
+
expect(@s.eval('return data[0]')).to eq nil
|
198
|
+
expect(@s.eval('return data[1]')).to eq 'one'
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'accepts more than 1 arg and order the args correctly' do
|
202
|
+
|
203
|
+
@s.function 'myfunc' do |a, b, c|
|
204
|
+
"#{a}_#{b}_#{c}"
|
205
|
+
end
|
206
|
+
|
207
|
+
expect(@s.eval("return myfunc(1, 2, 3)")).to eq '1.0_2.0_3.0'
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'accepts optional arguments' do
|
211
|
+
|
212
|
+
@s.function 'myfunc' do |a, b, c|
|
213
|
+
"#{a}_#{b}_#{c}"
|
214
|
+
end
|
215
|
+
|
216
|
+
expect(@s.eval("return myfunc(1)")).to eq '1.0__'
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'is ok when there are too many args' do
|
220
|
+
|
221
|
+
@s.function 'myfunc' do |a, b|
|
222
|
+
"#{a}_#{b}"
|
223
|
+
end
|
224
|
+
|
225
|
+
expect(@s.eval("return myfunc(1, 2, 3)")).to eq '1.0_2.0'
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'passes Float arguments correctly' do
|
229
|
+
|
230
|
+
@s.function 'myfunc' do |a|
|
231
|
+
"#{a.class} #{a}"
|
232
|
+
end
|
233
|
+
|
234
|
+
expect(@s.eval("return myfunc(3.14)")).to eq 'Float 3.14'
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'preserves arguments' do
|
238
|
+
|
239
|
+
@s.function 'check_types' do |t, s, f, h, a|
|
240
|
+
|
241
|
+
#p [ t, s, f, h, a ]
|
242
|
+
|
243
|
+
(t.is_a?(TrueClass) &&
|
244
|
+
s.is_a?(String) &&
|
245
|
+
f.is_a?(Float) &&
|
246
|
+
h.is_a?(Rufus::Lua::Table) &&
|
247
|
+
a.is_a?(Rufus::Lua::Table))
|
248
|
+
end
|
249
|
+
|
250
|
+
expect(@s.eval(
|
251
|
+
"return check_types(true, 'foobar', 3.13, {a='ay',b='bee'}, {'one','two','three'})"
|
252
|
+
)).to eq true
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'honours to_ruby=true' do
|
256
|
+
|
257
|
+
@s.function 'check_types', :to_ruby => true do |t, s, f, h, a|
|
258
|
+
|
259
|
+
#p [ t, s, f, h, a ]
|
260
|
+
|
261
|
+
(t.is_a?(TrueClass) &&
|
262
|
+
s.is_a?(String) &&
|
263
|
+
f.is_a?(Float) &&
|
264
|
+
h.is_a?(Hash) &&
|
265
|
+
a.is_a?(Array))
|
266
|
+
end
|
267
|
+
|
268
|
+
expect(@s.eval(
|
269
|
+
"return check_types(true, 'foobar', 3.13, {a='ay',b='bee'}, {'one','two','three'})"
|
270
|
+
)).to eq true
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'protects callbacks from GC' do
|
274
|
+
|
275
|
+
@s.function 'myfunc' do |a|
|
276
|
+
end
|
277
|
+
|
278
|
+
expect(@s.instance_variable_get(:@callbacks).size).to eq 1
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
data/spec/spec_base.rb
ADDED
data/spec/state_spec.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-lua
|
4
|
+
#
|
5
|
+
# Mon Mar 16 23:38:00 JST 2009
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'spec_base'
|
9
|
+
|
10
|
+
|
11
|
+
describe Rufus::Lua::State do
|
12
|
+
|
13
|
+
describe '#new' do
|
14
|
+
|
15
|
+
it 'loads all libs by default' do
|
16
|
+
|
17
|
+
@s = Rufus::Lua::State.new
|
18
|
+
expect(@s.eval('return os;')).not_to be nil
|
19
|
+
@s.close
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'loads no libs when told so' do
|
23
|
+
|
24
|
+
@s = Rufus::Lua::State.new(false)
|
25
|
+
expect(@s.eval('return os;')).to be nil
|
26
|
+
@s.close
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'loads only specific libs when told so' do
|
30
|
+
|
31
|
+
@s = Rufus::Lua::State.new([ :os, :math ])
|
32
|
+
expect(@s.eval('return io;')).to be nil
|
33
|
+
expect(@s.eval('return os;')).not_to be nil
|
34
|
+
@s.close
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#close' do
|
39
|
+
|
40
|
+
it 'does not crash when closing an already closed State' do
|
41
|
+
|
42
|
+
@s = Rufus::Lua::State.new
|
43
|
+
@s.close
|
44
|
+
|
45
|
+
expect(lambda { @s.close }).to raise_error(RuntimeError)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#[]' do
|
50
|
+
|
51
|
+
before do
|
52
|
+
@s = Rufus::Lua::State.new
|
53
|
+
end
|
54
|
+
after do
|
55
|
+
@s.close
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'return nils for unbound variables' do
|
59
|
+
|
60
|
+
expect(@s['a']).to be nil
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'accepts setting values directly' do
|
64
|
+
|
65
|
+
@s['a'] = 1
|
66
|
+
@s['a'] == 1
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'accepts setting array values directly' do
|
70
|
+
|
71
|
+
@s['a'] = [ true, false, %w[ alpha bravo charly ] ]
|
72
|
+
|
73
|
+
expect(@s['a'].to_a[0]).to be true
|
74
|
+
expect(@s['a'].to_a[2].to_a).to eq %w[ alpha bravo charly ]
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'accepts setting hash values directly' do
|
78
|
+
|
79
|
+
@s['a'] = { 'a' => 'alpha', 'b' => 'bravo' }
|
80
|
+
|
81
|
+
expect(@s['a'].to_h).to eq({ 'a' => 'alpha', 'b' => 'bravo' })
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'gh-6 panic: unprotected error' do
|
86
|
+
|
87
|
+
it 'does not happen when loading io alone' do
|
88
|
+
|
89
|
+
state = Rufus::Lua::State.new(%w[ io ])
|
90
|
+
|
91
|
+
expect(state.eval('return io;')).not_to be nil
|
92
|
+
expect(state.eval('return math;')).to be nil
|
93
|
+
state.close
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'does not happen' do
|
97
|
+
|
98
|
+
state = Rufus::Lua::State.new(%w[ base table string math package ])
|
99
|
+
|
100
|
+
expect(state.eval('return table;')).not_to be nil
|
101
|
+
expect(state.eval('return math;')).not_to be nil
|
102
|
+
state.close
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
data/spec/string_spec.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-lua
|
4
|
+
#
|
5
|
+
# Sat Jun 21 11:04:02 JST 2014
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'spec_base'
|
9
|
+
|
10
|
+
# adapted from https://github.com/jmettraux/rufus-lua/issues/14
|
11
|
+
|
12
|
+
|
13
|
+
describe 'lua strings' do
|
14
|
+
|
15
|
+
context 'and \0 bytes' do
|
16
|
+
|
17
|
+
before :each do
|
18
|
+
@s = Rufus::Lua::State.new
|
19
|
+
end
|
20
|
+
after :each do
|
21
|
+
@s.close
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'are not truncated when returned to Ruby' do
|
25
|
+
|
26
|
+
s = @s.eval('return string.char(1, 0, 0, 2, 0, 0)')
|
27
|
+
|
28
|
+
expect(s.bytes.to_a).to eq([ 1, 0, 0, 2, 0, 0 ])
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'are not truncated when passed from Ruby to Lua and back' do
|
32
|
+
|
33
|
+
s = [ 65, 66, 0, 67, 0, 0, 68, 0 ].pack('c*')
|
34
|
+
|
35
|
+
f = @s.eval(%{
|
36
|
+
f = function(s)
|
37
|
+
return { s = s, l = string.len(s) }
|
38
|
+
end
|
39
|
+
return f
|
40
|
+
})
|
41
|
+
|
42
|
+
expect(f.call(s).to_h).to eq({ 's' => s, 'l' => 8.0 })
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|