/zoeplat

To get this branch, use:
bzr branch http://9ix.org/bzr/zoeplat
1 by Josh C
zoetrope 1.3.1
1
-- Class: Class
2
-- This is a simple OOP single-inheritance implementation based
3
-- on the one suggested by <Programming in Lua at http://www.lua.org/pil/16.html>.
4
-- One big difference from what you may be expecting is that there are no
5
-- constructors per se; all subclasses share the same constructor method,
6
-- which takes a table of properties that are mixed into the instance.
7
-- e.g. Code like this:
8
--
9
-- (begin code)
10
-- MyClass = Class:extend{ color = 'red', name = 'robin' }
11
-- myObject = MyClass:new{ color = 'blue' }
12
-- (end code)
13
--
14
-- Would set myObject to have a color of 'blue' and a name of 'robin'. There is a
15
-- <onNew> event handler you can use to perform initialization based on these values.
16
--
17
-- Event: onNew
18
-- 		Called once, when a new object is created via <new()>.
19
20
Class = {
21
	-- Method: extend
22
	-- Creates a subclass of a class object, replacing any class properties
23
	-- with those in the object passed. It also sets the subclass's prototype
24
	-- property to this class. This alters the passed table in-place.
25
	--
26
	-- Arguments:
27
	-- 		obj - table of properties
28
	--
29
	-- Returns:
30
	-- 		subclassed table
31
32
	extend = function (self, obj)
33
		obj = obj or {}
34
		assert(type(obj) == 'table', 'must extend a table, received a ' .. type(obj))
35
	
36
		-- copy any table properties into the subclass, so that
37
		-- it does not accidentally overwrite them
38
				
39
		for key, value in pairs(self) do
40
			if key ~= '__index' and not obj[key] and type(value) == 'table' then
41
				obj[key] = copyTable(self[key])
42
			end
43
		end
44
		
45
		-- __index work to set up inheritance and getters/setters
46
47
		obj = obj or {}
48
		setmetatable(obj, self)
49
		self.__index = self
50
		obj.prototype = self
51
		return obj
52
	end,
53
54
	-- Method: new
55
	-- Extends an object and calls its onNew() handler if it is defined.
56
	-- This handler is meant for object-specific initialization,
57
	-- not class-wide work.
58
	--
59
	-- Arguments:
60
	--		obj - table of properties that the new object starts with,
61
	--			  overriding anything set in the class
62
	-- 
63
	-- Returns:
64
	-- 		new instance
65
	
66
	new = function (self, obj)
67
		obj = self:extend(obj)
68
		if obj.onNew then obj:onNew() end
69
		return obj
70
	end,
71
	
72
	-- Method: mixin
73
	-- Mixes all properties passed into the current object, overwriting any
74
	-- pre-existing values.
75
	--
76
	-- Arguments:
77
	--		obj - table of properties to mix into the object
78
	--
79
	-- Returns:
80
	--		current object
81
	
82
	mixin = function (self, obj)
83
		assert(type(obj) == 'table', 'must mix in a table, received a ' .. type(obj))
84
		for key, value in pairs(obj) do
85
			self[key] = obj[key]
86
		end
87
	end,
88
	
89
	-- Function: instanceOf
90
	-- Checks whether a certain object is anywhere in its inheritance chain.
91
	--
92
	-- Arguments:
93
	-- 		class - table to check against
94
	--
95
	-- Returns:
96
	-- 		boolean
97
98
	instanceOf = function (self, class)
99
		local proto = self.prototype
100
		
101
		while proto do
102
			if proto == class then
103
				return true
104
			end
105
			
106
			proto = proto.prototype
107
		end
108
		
109
		return false
110
	end
111
}