lenix 1.3.3 → 1.3.4
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.
- package/lua/LICENSE +21 -0
- package/lua/src/_dev/firstAttempt.lua +202 -0
- package/lua/src/_dev/secondAttempt.lua +166 -0
- package/lua/src/_dev/tests.lua +298 -0
- package/lua/src/index.lua +322 -0
- package/lua/src/lenix-0.1.0-1.rockspec +25 -0
- package/package.json +3 -3
- package/lint/src/lint-preset.json +0 -370
- package/lint/src/lint.mts +0 -322
- package/lint/src/tsconfig.json +0 -10
package/lua/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lenix
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
local class<const> = function (fields)
|
|
2
|
+
local defined<const> = {}
|
|
3
|
+
local private<const> = fields.private or {}
|
|
4
|
+
local getter<const> = fields.get or {}
|
|
5
|
+
local setter<const> = fields.set or {}
|
|
6
|
+
local accessor<const> = fields.accessor or {}
|
|
7
|
+
local privates<const> = { static = {}, instance = {} }
|
|
8
|
+
local setProperties<const> = { static = {}, instance = {} }
|
|
9
|
+
local getProperties<const> = { static = {}, instance = {} }
|
|
10
|
+
|
|
11
|
+
local isVariableEligible<const> = function (variable, valueType, value)
|
|
12
|
+
if defined[variable] then
|
|
13
|
+
print(("`%s` is already defined"):format(variable))
|
|
14
|
+
return
|
|
15
|
+
elseif type(value) ~= valueType and valueType ~= "any" then
|
|
16
|
+
print(("type mismatch for `%s`, expected `%s`, got `%s`"):format(variable, valueType, type(value)))
|
|
17
|
+
return
|
|
18
|
+
end
|
|
19
|
+
defined[variable] = true
|
|
20
|
+
if valueType == "any" then
|
|
21
|
+
print(("variable `%s` implicitly has type `%s`"):format(variable, valueType, type(value)))
|
|
22
|
+
end
|
|
23
|
+
return true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
local fieldPairs<const> = {
|
|
27
|
+
{private, privates},
|
|
28
|
+
{getter, getProperties},
|
|
29
|
+
{setter, setProperties},
|
|
30
|
+
{accessor, nil}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
for _, pair in ipairs(fieldPairs) do
|
|
34
|
+
local source, target = pair[1], pair[2]
|
|
35
|
+
for variable, values in pairs(source) do
|
|
36
|
+
-- getPropertyValue
|
|
37
|
+
local value<const> = type(values) == "table" and values[1]
|
|
38
|
+
-- getPropertyType
|
|
39
|
+
local valueType<const> = type(values) == "table" and values[2] or "any"
|
|
40
|
+
local staticValue<const> = values and values[3] or false
|
|
41
|
+
if isVariableEligible(variable, valueType, value) then
|
|
42
|
+
-- fill table with keys and values
|
|
43
|
+
if target then
|
|
44
|
+
if staticValue then
|
|
45
|
+
target["static"][variable] = value
|
|
46
|
+
else
|
|
47
|
+
target["instance"][variable] = value
|
|
48
|
+
end
|
|
49
|
+
else
|
|
50
|
+
if staticValue then
|
|
51
|
+
getProperties["static"][variable] = value
|
|
52
|
+
setProperties["static"][variable] = value
|
|
53
|
+
else
|
|
54
|
+
getProperties["instance"][variable] = value
|
|
55
|
+
setProperties["instance"][variable] = value
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
return setmetatable({
|
|
63
|
+
new = function (self, ...)
|
|
64
|
+
local newInstanceArgs = {...}
|
|
65
|
+
print(self)
|
|
66
|
+
local constructor<const> = fields.constructor
|
|
67
|
+
constructor(self, nil, ...)
|
|
68
|
+
return setmetatable({}, {
|
|
69
|
+
__index = function (_, variableKey)
|
|
70
|
+
if getter["instance"][variableKey] then
|
|
71
|
+
return getProperties["instance"][variableKey]
|
|
72
|
+
elseif accessor["instance"][variableKey] then
|
|
73
|
+
return getProperties["instance"][variableKey]
|
|
74
|
+
end
|
|
75
|
+
end,
|
|
76
|
+
})
|
|
77
|
+
end
|
|
78
|
+
}, {
|
|
79
|
+
__index = function(_, variableKey)
|
|
80
|
+
assert(defined[variableKey], ("property `%s` not found"):format(variableKey))
|
|
81
|
+
-- isPropertyExist
|
|
82
|
+
if getter[variableKey] ~= nil then
|
|
83
|
+
if isStatic(getter, variableKey, "get") then
|
|
84
|
+
-- returnPropertyValue
|
|
85
|
+
return getProperties["static"][variableKey]
|
|
86
|
+
end
|
|
87
|
+
elseif accessor[variableKey] ~= nil then
|
|
88
|
+
if isStatic(accessor, variableKey, "accessor") then
|
|
89
|
+
return getProperties["static"][variableKey]
|
|
90
|
+
end
|
|
91
|
+
elseif private[variableKey] ~= nil then
|
|
92
|
+
print(("cannot read the private property `%s`"):format(variableKey))
|
|
93
|
+
elseif setter[variableKey] ~= nil then
|
|
94
|
+
print(("the setter only property `%s` can not be accessed"):format(variableKey))
|
|
95
|
+
else print(("something went wrong when trying to access `%s`"):format(variableKey)) end
|
|
96
|
+
end,
|
|
97
|
+
__newindex = function (_, variableKey, variableValue)
|
|
98
|
+
assert(defined[variableKey], ("property `%s` not found"):format(variableKey))
|
|
99
|
+
if setter[variableKey] ~= nil then
|
|
100
|
+
if not isStatic(setter, variableKey, "set") then
|
|
101
|
+
local valueType = setter[variableKey][2] or "any"
|
|
102
|
+
if type(variableValue) ~= valueType and valueType ~= "any" then
|
|
103
|
+
print(("cannot assign `%s` to `%s` on `%s`"):format(type(variableValue), valueType, variableKey))
|
|
104
|
+
return
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
getProperties["static"][variableKey] = variableValue
|
|
108
|
+
elseif accessor[variableKey] ~= nil then
|
|
109
|
+
if not isStatic(accessor, variableKey, "accessor") then
|
|
110
|
+
local valueType = accessor[variableKey][2] or "any"
|
|
111
|
+
if type(variableValue) ~= valueType and valueType ~= "any" then
|
|
112
|
+
print(("cannot assign `%s` to `%s` on `%s`"):format(type(variableValue), valueType, variableKey))
|
|
113
|
+
return
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
getProperties["static"][variableKey] = variableValue
|
|
117
|
+
elseif getter[variableKey] ~= nil then
|
|
118
|
+
print(("the getter only property `%s `can not be set"):format(variableKey))
|
|
119
|
+
else print(("something went wrong when trying to access `%s`"):format(variableKey)) end
|
|
120
|
+
end
|
|
121
|
+
})
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
myClass = class({
|
|
125
|
+
private = {
|
|
126
|
+
height = {197, "number"},
|
|
127
|
+
},
|
|
128
|
+
get = {
|
|
129
|
+
blood = {"O+", "any"},
|
|
130
|
+
},
|
|
131
|
+
set = {
|
|
132
|
+
date = {2005, "number"},
|
|
133
|
+
},
|
|
134
|
+
accessor = {
|
|
135
|
+
age = {20, "number"},
|
|
136
|
+
name = {"Lenix", "string"},
|
|
137
|
+
getBlood = {function(self) return self end, "function"}
|
|
138
|
+
},
|
|
139
|
+
constructor = function(self, super, name, age)
|
|
140
|
+
self.name = name
|
|
141
|
+
self.age = age
|
|
142
|
+
end
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
local Person = myClass:new("Dev", 21)
|
|
147
|
+
print(Person.name, Person.age)
|
|
148
|
+
-- Person.date = 2005
|
|
149
|
+
-- print(Person.date)
|
|
150
|
+
-- print(Person.age)
|
|
151
|
+
-- Person.age = 21
|
|
152
|
+
|
|
153
|
+
-- print(myClass.height)
|
|
154
|
+
-- print(myClass.blood)
|
|
155
|
+
-- myClass.date = 2026
|
|
156
|
+
-- print(myClass.age)
|
|
157
|
+
-- myClass.age = 21
|
|
158
|
+
-- print(myClass.age)
|
|
159
|
+
-- print(myClass.name)
|
|
160
|
+
-- myClass.name = "Dev"
|
|
161
|
+
-- print(myClass.name)
|
|
162
|
+
-- print(myClass.getBlood())
|
|
163
|
+
-- myClass.getBlood = function() return true end
|
|
164
|
+
-- print(myClass.getBlood())
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
__index = function(_, variableKey)
|
|
170
|
+
assert(defined[variableKey], ("property `%s` not found"):format(variableKey))
|
|
171
|
+
-- isPropertyExist
|
|
172
|
+
if getter[variableKey] ~= nil then
|
|
173
|
+
-- returnPropertyValue
|
|
174
|
+
return getProperties[variableKey]
|
|
175
|
+
elseif accessor[variableKey] ~= nil then
|
|
176
|
+
return getProperties[variableKey]
|
|
177
|
+
elseif private[variableKey] ~= nil then
|
|
178
|
+
print(("cannot read the private property `%s`"):format(variableKey))
|
|
179
|
+
elseif setter[variableKey] ~= nil then
|
|
180
|
+
print(("the setter only property `%s` are forbidden to be accessed"):format(variableKey))
|
|
181
|
+
else print(("something went wrong when trying to access `%s`"):format(variableKey)) end
|
|
182
|
+
end,
|
|
183
|
+
__newindex = function (_, variableKey, variableValue)
|
|
184
|
+
assert(defined[variableKey], ("property `%s` not found"):format(variableKey))
|
|
185
|
+
if setter[variableKey] ~= nil then
|
|
186
|
+
local valueType = setter[variableKey][2] or "any"
|
|
187
|
+
if type(variableValue) ~= valueType and valueType ~= "any" then
|
|
188
|
+
print(("cannot assign `%s` to `%s` on `%s`"):format(type(variableValue), valueType, variableKey))
|
|
189
|
+
return
|
|
190
|
+
end
|
|
191
|
+
getProperties[variableKey] = variableValue
|
|
192
|
+
elseif accessor[variableKey] ~= nil then
|
|
193
|
+
local valueType = accessor[variableKey][2] or "any"
|
|
194
|
+
if type(variableValue) ~= valueType and valueType ~= "any" then
|
|
195
|
+
print(("cannot assign `%s` to `%s` on `%s`"):format(type(variableValue), valueType, variableKey))
|
|
196
|
+
return
|
|
197
|
+
end
|
|
198
|
+
getProperties[variableKey] = variableValue
|
|
199
|
+
elseif getter[variableKey] ~= nil then
|
|
200
|
+
print(("the getter only property `%s `can not be set"):format(variableKey))
|
|
201
|
+
else print(("something went wrong when trying to access `%s`"):format(variableKey)) end
|
|
202
|
+
end
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
assert(_VERSION == "Lua 5.4", "THIS MODULE REQUIRES Lua 5.4")
|
|
2
|
+
|
|
3
|
+
local class<const> = function (fields)
|
|
4
|
+
local definedProperties<const> = {}
|
|
5
|
+
local promisedToBeConstructed<const> = {}
|
|
6
|
+
local private<const> = fields.private or {}
|
|
7
|
+
local getter<const> = fields.get or {}
|
|
8
|
+
local setter<const> = fields.set or {}
|
|
9
|
+
local accessor<const> = fields.accessor or {}
|
|
10
|
+
local privates<const> = {}
|
|
11
|
+
local setProperties<const> = {}
|
|
12
|
+
local getProperties<const> = {}
|
|
13
|
+
|
|
14
|
+
local isVariableEligible<const> = function (propertyKey, propertyType, propertyValue)
|
|
15
|
+
if definedProperties[propertyKey] then
|
|
16
|
+
print(("`%s` is already defined"):format(propertyKey))
|
|
17
|
+
return
|
|
18
|
+
elseif type(propertyValue) ~= propertyType and propertyType ~= "any" and propertyValue ~= nil then
|
|
19
|
+
error(("type mismatch for `%s`, defined `%s`, appointed `%s`"):format(propertyKey, propertyType, type(propertyValue)))
|
|
20
|
+
return
|
|
21
|
+
end
|
|
22
|
+
definedProperties[propertyKey] = true
|
|
23
|
+
if propertyType == "any" then
|
|
24
|
+
print(("variable `%s` implicitly has type `%s`"):format(propertyKey, propertyType, type(propertyValue)))
|
|
25
|
+
end
|
|
26
|
+
if propertyValue == nil and propertyType ~= "nil" then
|
|
27
|
+
promisedToBeConstructed[propertyKey] = true
|
|
28
|
+
end
|
|
29
|
+
return true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
local fieldPairs<const> = {
|
|
33
|
+
{private, privates},
|
|
34
|
+
{getter, getProperties},
|
|
35
|
+
{setter, setProperties},
|
|
36
|
+
{accessor, nil}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for _, pair in ipairs(fieldPairs) do
|
|
40
|
+
local field<const>, properties<const> = pair[1], pair[2]
|
|
41
|
+
for propertyKey, propertyValues in pairs(field) do
|
|
42
|
+
-- getPropertyValue
|
|
43
|
+
local propertyValue<const> = type(propertyValues) == "table" and propertyValues[1]
|
|
44
|
+
-- getPropertyType
|
|
45
|
+
assert(type(propertyValues) == 'table', ("syntax error at `%s`, expected `%s`, got `%s`"):format(propertyKey, "table", type(propertyValues)))
|
|
46
|
+
local propertyType<const> = propertyValues[2]
|
|
47
|
+
if isVariableEligible(propertyKey, propertyType, propertyValue) then
|
|
48
|
+
-- fill table with keys and values
|
|
49
|
+
if properties then
|
|
50
|
+
properties[propertyKey] = propertyValue
|
|
51
|
+
else
|
|
52
|
+
-- for the accessor, filling the get and set permission
|
|
53
|
+
getProperties[propertyKey], setProperties[propertyKey] = propertyValue, propertyValue
|
|
54
|
+
setter[propertyKey], getter[propertyKey] = accessor[propertyKey], accessor[propertyKey]
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
local get<const> = function (self, propertyKey)
|
|
61
|
+
if definedProperties[propertyKey] then
|
|
62
|
+
if getter[propertyKey] then
|
|
63
|
+
if type(self[propertyKey]) == 'function' then
|
|
64
|
+
return function(...) return self[propertyKey](self, ...) end
|
|
65
|
+
end
|
|
66
|
+
return self[propertyKey]
|
|
67
|
+
elseif private[propertyKey] then
|
|
68
|
+
print(("private property `%s` is not allowed to be accessed"):format(propertyKey))
|
|
69
|
+
else print(("tried to get the `%s` set-only property"):format(propertyKey)) end
|
|
70
|
+
else
|
|
71
|
+
print(("`%s` property does not exist"):format(propertyKey))
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
local set<const> = function (self, propertyKey, propertyValue)
|
|
75
|
+
if definedProperties[propertyKey] then
|
|
76
|
+
if setter[propertyKey] then
|
|
77
|
+
if type(propertyValue) == setter[propertyKey][2] or setter[propertyKey][2] == "any" then
|
|
78
|
+
self[propertyKey] = propertyValue
|
|
79
|
+
else print(("`%s` is not assignable to `%s`: on `%s`"):format(type(propertyValue), setter[propertyKey][2], propertyKey)) end
|
|
80
|
+
elseif private[propertyKey] then
|
|
81
|
+
print(("private property `%s` is not allowed to be assigned"):format(propertyKey))
|
|
82
|
+
else print(("tried to set the `%s` get-only property"):format(propertyKey)) end
|
|
83
|
+
else
|
|
84
|
+
print(("`%s` property does not exist"):format(propertyKey))
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
return setmetatable({
|
|
89
|
+
new = function(self, ...)
|
|
90
|
+
local instance<const> = {}
|
|
91
|
+
|
|
92
|
+
for _, pair in pairs(fieldPairs) do
|
|
93
|
+
for propertyKey, propertyValue in pairs(pair[2] or {}) do
|
|
94
|
+
instance[propertyKey] = propertyValue
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
setmetatable(instance, getmetatable(self))
|
|
99
|
+
|
|
100
|
+
if fields.constructor then
|
|
101
|
+
fields.constructor(instance, nil, ...)
|
|
102
|
+
else error('no constructor was provided') end
|
|
103
|
+
|
|
104
|
+
-- Constructor has finished, now validate
|
|
105
|
+
for propertyKey in pairs(promisedToBeConstructed) do
|
|
106
|
+
if instance[propertyKey] == nil then
|
|
107
|
+
error(('the `%s` was not instantiated in constructor as promised'):format(propertyKey))
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
return setmetatable({}, {
|
|
112
|
+
__index = function(_, propertyKey)
|
|
113
|
+
return get(instance, propertyKey)
|
|
114
|
+
end,
|
|
115
|
+
__newindex = function(_, propertyKey, varValue)
|
|
116
|
+
set(instance, propertyKey, varValue)
|
|
117
|
+
end
|
|
118
|
+
})
|
|
119
|
+
end
|
|
120
|
+
}, { })
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
local myClass<const> = class({
|
|
124
|
+
private = {
|
|
125
|
+
height = {nil, "number"},
|
|
126
|
+
},
|
|
127
|
+
get = {
|
|
128
|
+
blood = {nil, "string"},
|
|
129
|
+
getHeight = {function(self, new)
|
|
130
|
+
self.setHeight(self, new)
|
|
131
|
+
return self.height
|
|
132
|
+
end, "function"}
|
|
133
|
+
},
|
|
134
|
+
set = {
|
|
135
|
+
setHeight = {
|
|
136
|
+
function(new)
|
|
137
|
+
self.height = new
|
|
138
|
+
end, "function"
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
accessor = {
|
|
142
|
+
name = {nil, "string"},
|
|
143
|
+
age = {nil, "number"},
|
|
144
|
+
},
|
|
145
|
+
constructor = function(self, super, name, age, height, blood)
|
|
146
|
+
self.name = name
|
|
147
|
+
self.age = age
|
|
148
|
+
self.height = height
|
|
149
|
+
self.blood = blood
|
|
150
|
+
end
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
local Class<const> = myClass:new("Lenix", 20, 197, "O+")
|
|
155
|
+
Class.setHeight = function(self, new)
|
|
156
|
+
self.height = new
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
print(Class.getHeight(198))
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
--[[ These are the tests that we have tried to get working with Lua-OOP, if you have any suggestions or improvements, please let us know. ]]
|
|
2
|
+
|
|
3
|
+
local User = class({
|
|
4
|
+
name = {nil, false},
|
|
5
|
+
age = {nil, false},
|
|
6
|
+
constructor = function(self, super, name, age)
|
|
7
|
+
self.name = name
|
|
8
|
+
self.age = age
|
|
9
|
+
end
|
|
10
|
+
})
|
|
11
|
+
local u = User:new("Alice", 25)
|
|
12
|
+
assert(u.name == "Alice" and u.age == 25, "Test 1 failed")
|
|
13
|
+
local User = class({
|
|
14
|
+
password = {nil, true}, -- private
|
|
15
|
+
constructor = function(self, super, pwd)
|
|
16
|
+
self.password = pwd
|
|
17
|
+
end
|
|
18
|
+
})
|
|
19
|
+
local u = User:new("secret")
|
|
20
|
+
local ok = pcall(function() print(u.password) end)
|
|
21
|
+
assert(not ok, "Test 2 failed: private property accessible")
|
|
22
|
+
|
|
23
|
+
-- Test 3: Private property accessible internally
|
|
24
|
+
local User = class({
|
|
25
|
+
password = {nil, true},
|
|
26
|
+
getPassword = {function(self) return self.password end, false},
|
|
27
|
+
constructor = function(self, super, pwd)
|
|
28
|
+
self.password = pwd
|
|
29
|
+
end
|
|
30
|
+
})
|
|
31
|
+
local u = User:new("secret")
|
|
32
|
+
assert(u.getPassword() == "secret", "Test 3 failed")
|
|
33
|
+
local User = class({
|
|
34
|
+
count = {0, false, true}, -- static
|
|
35
|
+
name = {nil, false},
|
|
36
|
+
constructor = function(self, super, name)
|
|
37
|
+
self.name = name
|
|
38
|
+
end
|
|
39
|
+
})
|
|
40
|
+
User.count = 5
|
|
41
|
+
local u = User:new("Alice")
|
|
42
|
+
local ok = pcall(function() print(u.count) end)
|
|
43
|
+
assert(not ok, "Test 4 failed: static accessible on instance")
|
|
44
|
+
assert(User.count == 5, "Test 4 failed: static not on class")
|
|
45
|
+
|
|
46
|
+
-- Test 5: Instance properties on instance, not class
|
|
47
|
+
local ok2 = pcall(function() print(User.name) end)
|
|
48
|
+
assert(not ok2, "Test 5 failed: instance accessible on class")
|
|
49
|
+
local User = class({
|
|
50
|
+
id = {1, false, false, true}, -- immutable
|
|
51
|
+
constructor = function(self, super, id)
|
|
52
|
+
self.id = id
|
|
53
|
+
end
|
|
54
|
+
})
|
|
55
|
+
local u = User:new(100)
|
|
56
|
+
local ok = pcall(function() u.id = 999 end)
|
|
57
|
+
assert(not ok, "Test 6 failed: immutable modified")
|
|
58
|
+
assert(u.id == 100, "Test 6 failed: immutable changed")
|
|
59
|
+
|
|
60
|
+
-- Test 7: Mutable property can be changed
|
|
61
|
+
local User = class({
|
|
62
|
+
name = {nil, false, false, false}, -- mutable
|
|
63
|
+
constructor = function(self, super, name)
|
|
64
|
+
self.name = name
|
|
65
|
+
end
|
|
66
|
+
})
|
|
67
|
+
local u = User:new("Alice")
|
|
68
|
+
u.name = "Bob"
|
|
69
|
+
assert(u.name == "Bob", "Test 7 failed")
|
|
70
|
+
local User = class({
|
|
71
|
+
_value = {0, true},
|
|
72
|
+
get = {
|
|
73
|
+
value = function(self) return self._value * 2 end
|
|
74
|
+
},
|
|
75
|
+
constructor = function(self, super, val)
|
|
76
|
+
self._value = val
|
|
77
|
+
end
|
|
78
|
+
})
|
|
79
|
+
local u = User:new(5)
|
|
80
|
+
assert(u.value == 10, "Test 8 failed")
|
|
81
|
+
|
|
82
|
+
-- Test 9: Setter works
|
|
83
|
+
local User = class({
|
|
84
|
+
_value = {0, true},
|
|
85
|
+
getValue = {function(self) return self._value end, false}, -- Add getter
|
|
86
|
+
set = {
|
|
87
|
+
value = function(self, val) self._value = val * 2 end
|
|
88
|
+
},
|
|
89
|
+
constructor = function(self) self._value = 0 end
|
|
90
|
+
})
|
|
91
|
+
local u = User:new()
|
|
92
|
+
u.value = 5
|
|
93
|
+
assert(u.getValue() == 10, "Test 9 failed")
|
|
94
|
+
|
|
95
|
+
-- Test 10: Getter can't be modified (correct version)
|
|
96
|
+
local User = class({
|
|
97
|
+
_value = {0, true},
|
|
98
|
+
get = {
|
|
99
|
+
value = function(self) return self._value end -- Getter only, no setter
|
|
100
|
+
},
|
|
101
|
+
constructor = function(self) self._value = 10 end
|
|
102
|
+
})
|
|
103
|
+
local u = User:new()
|
|
104
|
+
local ok = pcall(function() u.value = 20 end) -- Try to set getter-only property
|
|
105
|
+
assert(not ok, "Test 10 failed: getter modified")
|
|
106
|
+
|
|
107
|
+
local Parent = class({
|
|
108
|
+
id = {1, false},
|
|
109
|
+
constructor = function(self, super, id)
|
|
110
|
+
self.id = id
|
|
111
|
+
end
|
|
112
|
+
})
|
|
113
|
+
local Child = class({
|
|
114
|
+
name = {nil, false},
|
|
115
|
+
constructor = function(self, super, name, id)
|
|
116
|
+
super(id)
|
|
117
|
+
self.name = name
|
|
118
|
+
end
|
|
119
|
+
}, Parent)
|
|
120
|
+
local c = Child:new("Alice", 100)
|
|
121
|
+
assert(c.id == 100 and c.name == "Alice", "Test 11 failed")
|
|
122
|
+
|
|
123
|
+
-- Test 12: Child inherits parent getters
|
|
124
|
+
local Parent = class({
|
|
125
|
+
value = {10, false},
|
|
126
|
+
get = {
|
|
127
|
+
getValue = function(self) return self.value end
|
|
128
|
+
},
|
|
129
|
+
constructor = function(self, super, val)
|
|
130
|
+
self.value = val
|
|
131
|
+
end
|
|
132
|
+
})
|
|
133
|
+
local Child = class({
|
|
134
|
+
name = {nil, false},
|
|
135
|
+
constructor = function(self, super, name, val)
|
|
136
|
+
super(val)
|
|
137
|
+
self.name = name
|
|
138
|
+
end
|
|
139
|
+
}, Parent)
|
|
140
|
+
local c = Child:new("Test", 42)
|
|
141
|
+
assert(c.getValue == 42, "Test 12 failed")
|
|
142
|
+
|
|
143
|
+
-- Test 13: Child inherits parent setters
|
|
144
|
+
local Parent = class({
|
|
145
|
+
_value = {0, true},
|
|
146
|
+
getValue = {function(self) return self._value end, false},
|
|
147
|
+
set = {
|
|
148
|
+
value = function(self, val) self._value = val * 2 end
|
|
149
|
+
},
|
|
150
|
+
constructor = function(self)
|
|
151
|
+
self._value = 0
|
|
152
|
+
end
|
|
153
|
+
})
|
|
154
|
+
local Child = class({
|
|
155
|
+
name = {nil, false},
|
|
156
|
+
constructor = function(self, super, name)
|
|
157
|
+
super()
|
|
158
|
+
self.name = name
|
|
159
|
+
end
|
|
160
|
+
}, Parent)
|
|
161
|
+
local c = Child:new("Test")
|
|
162
|
+
c.value = 5
|
|
163
|
+
assert(c.getValue() == 10, "Test 13 failed")
|
|
164
|
+
local Parent = class({
|
|
165
|
+
secret = {nil, true}, -- private
|
|
166
|
+
constructor = function(self, super, sec)
|
|
167
|
+
self.secret = sec
|
|
168
|
+
end
|
|
169
|
+
})
|
|
170
|
+
local Child = class({
|
|
171
|
+
name = {nil, false},
|
|
172
|
+
constructor = function(self, super, name, sec)
|
|
173
|
+
super(sec)
|
|
174
|
+
self.name = name
|
|
175
|
+
end
|
|
176
|
+
}, Parent)
|
|
177
|
+
local c = Child:new("Alice", "password")
|
|
178
|
+
local ok = pcall(function() print(c.secret) end)
|
|
179
|
+
assert(not ok, "Test 14 failed: parent private accessible")
|
|
180
|
+
|
|
181
|
+
-- Test 15: Parent immutable property blocked in child
|
|
182
|
+
local Parent = class({
|
|
183
|
+
id = {1, false, false, true}, -- immutable
|
|
184
|
+
constructor = function(self, super, id)
|
|
185
|
+
self.id = id
|
|
186
|
+
end
|
|
187
|
+
})
|
|
188
|
+
local Child = class({
|
|
189
|
+
constructor = function(self, super, id)
|
|
190
|
+
super(id)
|
|
191
|
+
end
|
|
192
|
+
}, Parent)
|
|
193
|
+
local c = Child:new(100)
|
|
194
|
+
local ok = pcall(function() c.id = 999 end)
|
|
195
|
+
assert(not ok, "Test 15 failed: parent immutable modified")
|
|
196
|
+
local Parent = class({
|
|
197
|
+
greet = {function(self) return "Hello from parent" end, false, false, false, true},
|
|
198
|
+
constructor = function(self) end
|
|
199
|
+
})
|
|
200
|
+
local Child = class({
|
|
201
|
+
greet = {function(self) return "Hello from child" end, false, false, true, false, true},
|
|
202
|
+
constructor = function(self, super) super() end
|
|
203
|
+
}, Parent)
|
|
204
|
+
local c = Child:new()
|
|
205
|
+
print(c.greet()) -- Should print "Hello from child", probably prints "Hello from parent"
|
|
206
|
+
local Grandparent = class({
|
|
207
|
+
id = {1, false},
|
|
208
|
+
constructor = function(self, super, id)
|
|
209
|
+
self.id = id
|
|
210
|
+
end
|
|
211
|
+
})
|
|
212
|
+
local Parent = class({
|
|
213
|
+
name = {nil, false},
|
|
214
|
+
constructor = function(self, super, name, id)
|
|
215
|
+
super(id)
|
|
216
|
+
self.name = name
|
|
217
|
+
end
|
|
218
|
+
}, Grandparent)
|
|
219
|
+
local Child = class({
|
|
220
|
+
age = {nil, false},
|
|
221
|
+
constructor = function(self, super, age, name, id)
|
|
222
|
+
super(name, id)
|
|
223
|
+
self.age = age
|
|
224
|
+
end
|
|
225
|
+
}, Parent)
|
|
226
|
+
local c = Child:new(20, "Alice", 100)
|
|
227
|
+
assert(c.id == 100 and c.name == "Alice" and c.age == 20, "Test 17 failed")
|
|
228
|
+
local Parent = class({
|
|
229
|
+
count = {0, false, true}, -- static
|
|
230
|
+
constructor = function(self) end
|
|
231
|
+
})
|
|
232
|
+
local Child = class({
|
|
233
|
+
constructor = function(self, super) super() end
|
|
234
|
+
}, Parent)
|
|
235
|
+
assert(Child.count == 0, "Test 18 failed")
|
|
236
|
+
-- This might fail - test it
|
|
237
|
+
|
|
238
|
+
local User = class({
|
|
239
|
+
name = {nil, false},
|
|
240
|
+
greet = {function(self) return "Hello " .. self.name end, false},
|
|
241
|
+
constructor = function(self, super, name)
|
|
242
|
+
self.name = name
|
|
243
|
+
end
|
|
244
|
+
})
|
|
245
|
+
local u = User:new("Alice")
|
|
246
|
+
assert(u.greet() == "Hello Alice", "Test 19 failed")
|
|
247
|
+
|
|
248
|
+
-- Test 20: Static methods work
|
|
249
|
+
local User = class({
|
|
250
|
+
create = {function(self, name) return "Created " .. name end, false, true}, -- 481
|
|
251
|
+
constructor = function(self) end
|
|
252
|
+
})
|
|
253
|
+
assert(User.create("Alice") == "Created Alice", "Test 20 failed")
|
|
254
|
+
local User = class({
|
|
255
|
+
name = {nil, false},
|
|
256
|
+
constructor = function(self, super, name)
|
|
257
|
+
self.name = name
|
|
258
|
+
end
|
|
259
|
+
})
|
|
260
|
+
local u1 = User:new("Alice")
|
|
261
|
+
local u2 = User:new("Bob")
|
|
262
|
+
u1.name = "Charlie"
|
|
263
|
+
assert(u1.name == "Charlie" and u2.name == "Bob", "Test 21 failed")
|
|
264
|
+
|
|
265
|
+
-- Test 22: Metatable protection
|
|
266
|
+
local User = class({
|
|
267
|
+
constructor = function(self) end
|
|
268
|
+
})
|
|
269
|
+
local u = User:new()
|
|
270
|
+
local mt = getmetatable(u)
|
|
271
|
+
assert(mt == "access denied", "Test 22 failed: metatable exposed")
|
|
272
|
+
|
|
273
|
+
-- Test 23: Constructor validation
|
|
274
|
+
local User = class({
|
|
275
|
+
name = {nil, false},
|
|
276
|
+
age = {nil, false},
|
|
277
|
+
constructor = function(self, super, name)
|
|
278
|
+
self.name = name
|
|
279
|
+
-- Forgot to set age
|
|
280
|
+
end
|
|
281
|
+
})
|
|
282
|
+
local ok = pcall(function() User:new("Alice") end)
|
|
283
|
+
assert(not ok, "Test 23 failed: validation missed unset property")
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
local Parent = class({
|
|
287
|
+
greet = {function(self) return "Hello from parent" end, false, false, false, true},
|
|
288
|
+
constructor = function(self) end
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
local Child = class({
|
|
292
|
+
greet = {function(self) return "Hello from child" end, false, false, false, false, true},
|
|
293
|
+
constructor = function(self, super) super() end
|
|
294
|
+
}, Parent)
|
|
295
|
+
|
|
296
|
+
local c = Child:new()
|
|
297
|
+
print(c.greet()) -- Should print "Hello from child"
|
|
298
|
+
|