1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
require 'pl.compat' -- require this one before loading strict
local strict = require 'pl.strict'
local test = require 'pl.test'
local app = require 'pl.app'
-- in strict mode, you must assign to a global first, even if just nil.
test.assertraise(function()
print(x)
print 'ok?'
end,"variable 'x' is not declared")
-- can assign to globals in main (or from C extensions) but not anywhere else!
test.assertraise(function()
Boo = 3
end,"assign to undeclared global 'Boo'")
Boo = true
Boo2 = nil
-- once declared, you can assign to globals from anywhere
(function() Boo = 42; Boo2 = 6*7 end)()
--- a module may use strict.module() to generate a simularly strict environment
-- (see lua/mymod.lua)
app.require_here 'lua'
local M = require 'mymod'
--- these are fine
M.answer()
M.question()
-- spelling mistakes become errors...
test.assertraise(function()
print(M.Answer())
end,"variable 'Answer' is not declared in 'mymod'")
--- for the extra paranoid, you can choose to make all global tables strict...
strict.make_all_strict(_G)
test.assertraise(function()
print(math.sine(1.2))
end,"variable 'sine' is not declared in 'math'")
-- module
do
local testmodule = {
hello = function() return "supremacy" end
}
-- make strict and allow extra field "world"
strict.module("my_test", testmodule, { world = true })
test.asserteq(testmodule.hello(), "supremacy")
test.assertraise(function()
print(testmodule.not_allowed_key)
end, "variable 'not_allowed_key' is not declared in 'my_test'")
test.asserteq(testmodule.world, nil)
testmodule.world = "supremacy"
test.asserteq(testmodule.world, "supremacy")
-- table with a __newindex method
local mod1 = strict.module("mod1", setmetatable(
{
hello = "world",
}, {
__newindex = function(self, key, value)
if key == "Lua" then
rawset(self, key, value)
end
end,
}
))
test.asserteq(mod1.hello, "world")
mod1.Lua = "hello world"
test.asserteq(mod1.Lua, "hello world")
test.assertraise(function()
print(mod1.not_allowed_key)
end, "variable 'not_allowed_key' is not declared in 'mod1'")
-- table with a __index method
local mod1 = strict.module("mod1", setmetatable(
{
hello = "world",
}, {
__index = function(self, key)
if key == "Lua" then
return "rocks"
end
end,
}
))
test.asserteq(mod1.hello, "world")
test.asserteq(mod1.Lua, "rocks")
test.assertraise(function()
print(mod1.not_allowed_key)
end, "variable 'not_allowed_key' is not declared in 'mod1'")
-- table with a __index table
local mod1 = strict.module("mod1", setmetatable(
{
hello = "world",
}, {
__index = {
Lua = "rocks!"
}
}
))
test.asserteq(mod1.hello, "world")
test.asserteq(mod1.Lua, "rocks!")
test.assertraise(function()
print(mod1.not_allowed_key)
end, "variable 'not_allowed_key' is not declared in 'mod1'")
end
do
-- closed_module
-- what does this do? this does not seem a usefull function???
local testmodule = {
hello = function() return "supremacy" end
}
local M = strict.closed_module(testmodule, "my_test")
-- read acces to original is granted, but not to the new one
test.asserteq(testmodule.hello(), "supremacy")
test.assertraise(function()
print(M.hello())
end, "variable 'hello' is not declared in 'my_test'")
-- write access to both is granted
testmodule.world = "domination"
M.world = "domination"
-- read acces to set field in original is granted, but not set
test.asserteq(testmodule.world, nil)
test.asserteq(M.world, "domination")
end
|