/ld26

To get this branch, use:
bzr branch http://9ix.org/bzr/ld26
1 by Josh C
zoetrope 1.4
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
{
22
	-- Method: extend
23
	-- Creates a subclass of a class object, replacing any class properties
24
	-- with those in the object passed. It also sets the subclass's prototype
25
	-- property to this class. This alters the passed table in-place.
26
	--
27
	-- Arguments:
28
	-- 		obj - table of properties
29
	--
30
	-- Returns:
31
	-- 		subclassed table
32
33
	extend = function (self, obj)
34
		obj = obj or {}
35
		assert(type(obj) == 'table', 'must extend a table, received a ' .. type(obj))
36
	
37
		-- copy any table properties into the subclass, so that
38
		-- it does not accidentally overwrite them
39
				
40
		for key, value in pairs(self) do
41
			if key ~= '__index' and not obj[key] and type(value) == 'table' then
42
				obj[key] = copyTable(self[key])
43
			end
44
		end
45
		
46
		-- __index work to set up inheritance and getters/setters
47
48
		obj = obj or {}
49
		setmetatable(obj, self)
50
		self.__index = self
51
		obj.prototype = self
52
		return obj
53
	end,
54
55
	-- Method: new
56
	-- Extends an object and calls its onNew() handler if it is defined.
57
	-- This handler is meant for object-specific initialization,
58
	-- not class-wide work.
59
	--
60
	-- Arguments:
61
	--		obj - table of properties that the new object starts with,
62
	--			  overriding anything set in the class
63
	-- 
64
	-- Returns:
65
	-- 		new instance
66
	
67
	new = function (self, obj)
68
		obj = self:extend(obj)
69
		if obj.onNew then obj:onNew() end
70
		return obj
71
	end,
72
	
73
	-- Method: mixin
74
	-- Mixes all properties passed into the current object, overwriting any
75
	-- pre-existing values.
76
	--
77
	-- Arguments:
78
	--		obj - table of properties to mix into the object
79
	--
80
	-- Returns:
81
	--		current object
82
	
83
	mixin = function (self, obj)
84
		assert(type(obj) == 'table', 'must mix in a table, received a ' .. type(obj))
85
		for key, value in pairs(obj) do
86
			self[key] = obj[key]
87
		end
88
	end,
89
	
90
	-- Function: instanceOf
91
	-- Checks whether a certain object is anywhere in its inheritance chain.
92
	--
93
	-- Arguments:
94
	-- 		class - table to check against
95
	--
96
	-- Returns:
97
	-- 		boolean
98
99
	instanceOf = function (self, class)
100
		local proto = self.prototype
101
		
102
		while proto do
103
			if proto == class then
104
				return true
105
			end
106
			
107
			proto = proto.prototype
108
		end
109
		
110
		return false
111
	end
112
}