• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lunarmodules / Penlight / 7742759193

01 Feb 2024 02:24PM UTC coverage: 88.938% (-0.7%) from 89.675%
7742759193

push

github

web-flow
docs: Fix typos (#462)

7 of 7 new or added lines in 2 files covered. (100.0%)

120 existing lines in 14 files now uncovered.

5443 of 6120 relevant lines covered (88.94%)

256.25 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.35
/lua/pl/class.lua
1
--- Provides a reusable and convenient framework for creating classes in Lua.
2
-- Two possible notations:
3
--
4
--    B = class(A)
5
--    class.B(A)
6
--
7
-- The latter form creates a named class within the current environment. Note
8
-- that this implicitly brings in `pl.utils` as a dependency.
9
--
10
-- See the Guide for further @{01-introduction.md.Simplifying_Object_Oriented_Programming_in_Lua|discussion}
11
-- @module pl.class
12

13
local error, getmetatable, io, pairs, rawget, rawset, setmetatable, tostring, type =
14
    _G.error, _G.getmetatable, _G.io, _G.pairs, _G.rawget, _G.rawset, _G.setmetatable, _G.tostring, _G.type
138✔
15
local compat
16

17
-- this trickery is necessary to prevent the inheritance of 'super' and
18
-- the resulting recursive call problems.
19
local function call_ctor (c,obj,...)
20
    local init = rawget(c,'_init')
1,554✔
21
    local parent_with_init = rawget(c,'_parent_with_init')
1,554✔
22

23
    if parent_with_init then
1,554✔
24
        if not init then -- inheriting an init
402✔
25
            init = rawget(parent_with_init, '_init')
84✔
26
            parent_with_init = rawget(parent_with_init, '_parent_with_init')
84✔
27
        end
28
        if parent_with_init then -- super() points to one above wherever _init came from
402✔
29
            rawset(obj,'super',function(obj,...)
636✔
30
                call_ctor(parent_with_init,obj,...)
132✔
31
            end)
32
        end
33
    else
34
        -- Without this, calling super() where none exists will sometimes loop and stack overflow
35
        rawset(obj,'super',nil)
1,152✔
36
    end
37

38
    local res = init(obj,...)
1,554✔
39
    if parent_with_init then -- If this execution of call_ctor set a super, unset it
1,524✔
40
        rawset(obj,'super',nil)
306✔
41
    end
42

43
    return res
1,524✔
44
end
45

46
--- initializes an __instance__ upon creation.
47
-- @function class:_init
48
-- @param ... parameters passed to the constructor
49
-- @usage local Cat = class()
50
-- function Cat:_init(name)
51
--   --self:super(name)   -- call the ancestor initializer if needed
52
--   self.name = name
53
-- end
54
--
55
-- local pussycat = Cat("pussycat")
56
-- print(pussycat.name)  --> pussycat
57

58
--- checks whether an __instance__ is derived from some class.
59
-- Works the other way around as `class_of`. It has two ways of using;
60
-- 1) call with a class to check against, 2) call without params.
61
-- @function instance:is_a
62
-- @param some_class class to check against, or `nil` to return the class
63
-- @return `true` if `instance` is derived from `some_class`, or if `some_class == nil` then
64
-- it returns the class table of the instance
65
-- @usage local pussycat = Lion()  -- assuming Lion derives from Cat
66
-- if pussycat:is_a(Cat) then
67
--   -- it's true, it is a Lion, but also a Cat
68
-- end
69
--
70
-- if pussycat:is_a() == Lion then
71
--   -- It's true
72
-- end
73
local function is_a(self,klass)
74
    if klass == nil then
246✔
75
        -- no class provided, so return the class this instance is derived from
76
        return getmetatable(self)
6✔
77
    end
78
    local m = getmetatable(self)
240✔
79
    if not m then return false end --*can't be an object!
240✔
80
    while m do
282✔
81
        if m == klass then return true end
264✔
82
        m = rawget(m,'_base')
108✔
83
    end
84
    return false
18✔
85
end
86

87
--- checks whether an __instance__ is derived from some class.
88
-- Works the other way around as `is_a`.
89
-- @function some_class:class_of
90
-- @param some_instance instance to check against
91
-- @return `true` if `some_instance` is derived from `some_class`
92
-- @usage local pussycat = Lion()  -- assuming Lion derives from Cat
93
-- if Cat:class_of(pussycat) then
94
--   -- it's true
95
-- end
96
local function class_of(klass,obj)
97
    if type(klass) ~= 'table' or not rawget(klass,'is_a') then return false end
186✔
98
    return klass.is_a(obj,klass)
186✔
99
end
100

101
--- cast an object to another class.
102
-- It is not clever (or safe!) so use carefully.
103
-- @param some_instance the object to be changed
104
-- @function some_class:cast
105
local function cast (klass, obj)
106
    return setmetatable(obj,klass)
6✔
107
end
108

109

110
local function _class_tostring (obj)
UNCOV
111
    local mt = obj._class
×
112
    local name = rawget(mt,'_name')
×
113
    setmetatable(obj,nil)
×
114
    local str = tostring(obj)
×
115
    setmetatable(obj,mt)
×
116
    if name then str = name ..str:gsub('table','') end
×
117
    return str
×
118
end
119

120
local function tupdate(td,ts,dont_override)
121
    for k,v in pairs(ts) do
3,570✔
122
        if not dont_override or td[k] == nil then
3,372✔
123
            td[k] = v
3,354✔
124
        end
125
    end
126
end
127

128
local function _class(base,c_arg,c)
129
    -- the class `c` will be the metatable for all its objects,
130
    -- and they will look up their methods in it.
131
    local mt = {}   -- a metatable for the class to support __call and _handler
558✔
132
    -- can define class by passing it a plain table of methods
133
    local plain = type(base) == 'table' and not getmetatable(base)
558✔
134
    if plain then
558✔
135
        c = base
18✔
136
        base = c._base
18✔
137
    else
138
        c = c or {}
540✔
139
    end
140

141
    if type(base) == 'table' then
558✔
142
        -- our new class is a shallow copy of the base class!
143
        -- but be careful not to wipe out any methods we have been given at this point!
144
        tupdate(c,base,plain)
198✔
145
        c._base = base
198✔
146
        -- inherit the 'not found' handler, if present
147
        if rawget(c,'_handler') then mt.__index = c._handler end
198✔
148
    elseif base ~= nil then
360✔
UNCOV
149
        error("must derive from a table type",3)
×
150
    end
151

152
    c.__index = c
558✔
153
    setmetatable(c,mt)
558✔
154
    if not plain then
558✔
155
        if base and rawget(base,'_init') then c._parent_with_init = base end -- For super and inherited init
540✔
156
        c._init = nil
540✔
157
    end
158

159
    if base and rawget(base,'_class_init') then
558✔
160
        base._class_init(c,c_arg)
12✔
161
    end
162

163
    -- expose a ctor which can be called by <classname>(<args>)
164
    mt.__call = function(class_tbl,...)
165
        local obj
166
        if rawget(c,'_create') then obj = c._create(...) end
1,620✔
167
        if not obj then obj = {} end
1,428✔
168
        setmetatable(obj,c)
1,428✔
169

170
        if rawget(c,'_init') or rawget(c,'_parent_with_init') then -- constructor exists
1,428✔
171
            local res = call_ctor(c,obj,...)
1,422✔
172
            if res then -- _if_ a ctor returns a value, it becomes the object...
1,398✔
173
                obj = res
66✔
174
                setmetatable(obj,c)
66✔
175
            end
176
        end
177

178
        if base and rawget(base,'_post_init') then
1,404✔
UNCOV
179
            base._post_init(obj)
×
180
        end
181

182
        return obj
1,404✔
183
    end
184
    -- Call Class.catch to set a handler for methods/properties not found in the class!
185
    c.catch = function(self, handler)
186
        if type(self) == "function" then
18✔
187
            -- called using . instead of :
UNCOV
188
            handler = self
×
189
        end
190
        c._handler = handler
18✔
191
        mt.__index = handler
18✔
192
    end
193
    c.is_a = is_a
558✔
194
    c.class_of = class_of
558✔
195
    c.cast = cast
558✔
196
    c._class = c
558✔
197

198
    if not rawget(c,'__tostring') then
558✔
199
        c.__tostring = _class_tostring
354✔
200
    end
201

202
    return c
558✔
203
end
204

205
--- create a new class, derived from a given base class.
206
-- Supporting two class creation syntaxes:
207
-- either `Name = class(base)` or `class.Name(base)`.
208
-- The first form returns the class directly and does not set its `_name`.
209
-- The second form creates a variable `Name` in the current environment set
210
-- to the class, and also sets `_name`.
211
-- @function class
212
-- @param base optional base class
213
-- @param c_arg optional parameter to class constructor
214
-- @param c optional table to be used as class
215
local class
216
class = setmetatable({},{
276✔
217
    __call = function(fun,...)
218
        return _class(...)
516✔
219
    end,
220
    __index = function(tbl,key)
221
        if key == 'class' then
42✔
UNCOV
222
            io.stderr:write('require("pl.class").class is deprecated. Use require("pl.class")\n')
×
223
            return class
×
224
        end
225
        compat = compat or require 'pl.compat'
42✔
226
        local env = compat.getfenv(2)
42✔
227
        return function(...)
228
            local c = _class(...)
42✔
229
            c._name = key
42✔
230
            rawset(env,key,c)
42✔
231
            return c
42✔
232
        end
233
    end
234
})
138✔
235

236
class.properties = class()
184✔
237

238
function class.properties._class_init(klass)
276✔
239
    klass.__index = function(t,key)
240
        -- normal class lookup!
241
        local v = klass[key]
36✔
242
        if v then return v end
36✔
243
        -- is it a getter?
244
        v = rawget(klass,'get_'..key)
30✔
245
        if v then
30✔
246
            return v(t)
12✔
247
        end
248
        -- is it a field?
249
        return rawget(t,'_'..key)
18✔
250
    end
251
    klass.__newindex = function (t,key,value)
252
        -- if there's a setter, use that, otherwise directly set table
253
        local p = 'set_'..key
42✔
254
        local setter = klass[p]
42✔
255
        if setter then
42✔
256
            setter(t,value)
16✔
257
        else
258
            rawset(t,key,value)
30✔
259
        end
260
    end
261
end
262

263

264
return class
138✔
265

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc