mirror of
https://github.com/kikito/middleclass.git
synced 2024-11-08 09:34:22 +00:00
Merge branch '3.0'
This commit is contained in:
commit
0a6eb856e6
@ -7,6 +7,6 @@ env:
|
||||
install:
|
||||
- sudo apt-get install luajit
|
||||
- sudo apt-get install luarocks
|
||||
- sudo luarocks install telescope
|
||||
- sudo luarocks install busted
|
||||
|
||||
script: "tsc -f spec/*"
|
||||
script: "busted"
|
||||
|
23
CHANGELOG.md
Normal file
23
CHANGELOG.md
Normal file
@ -0,0 +1,23 @@
|
||||
middleclass changelog
|
||||
====================
|
||||
|
||||
Version 3.0
|
||||
|
||||
* Anything that behaves reasonably like a class can be a class (no internal list of classes)
|
||||
* The `class` global function is now just the return value of `require
|
||||
'middleclass'`. It is a callable table, but works exactly as before.
|
||||
* The global variable `Object` becomes `class.Object`
|
||||
* The global function `instanceOf` becomes `class.Object.isInstanceOf`. Parameter order is reversed.
|
||||
* The global function `subclassOf` becomes `class.Object.static.isSubclassOf`. Parameter order is reversed.
|
||||
* The global function `implements` becomes `class.Object.static.implements`. Parameter order is reversed.
|
||||
* Specs have been translated from telescope to busted
|
||||
|
||||
|
||||
Version 2.0
|
||||
|
||||
* Static methods are now separated from instance methods
|
||||
* class.superclass has now become class.super
|
||||
* It's now possible to do class.subclasses
|
||||
* middleclass is now a single file; init.lua has dissapeared
|
||||
* license is changed from BSD to MIT. License included in source FTW
|
||||
|
97
README.md
Normal file
97
README.md
Normal file
@ -0,0 +1,97 @@
|
||||
middleclass
|
||||
===========
|
||||
|
||||
[![Build Status](https://travis-ci.org/kikito/middleclass.png?branch=master)](https://travis-ci.org/kikito/middleclass)
|
||||
|
||||
A simple OOP library for Lua. It has inheritance, metamethods (operators), class variables and weak mixin support.
|
||||
|
||||
h1. Quick Look
|
||||
|
||||
local class = require 'middleclass'
|
||||
|
||||
local Fruit = class('Fruit') -- 'Fruit' is the class' name
|
||||
|
||||
function Fruit:initialize(sweetness)
|
||||
self.sweetness = sweetness
|
||||
end
|
||||
|
||||
Fruit.static.sweetness_threshold = 5 -- class variable (also admits methods)
|
||||
|
||||
function Fruit:isSweet()
|
||||
return self.sweetness > Fruit.sweetness_threshold
|
||||
end
|
||||
|
||||
local Lemon = class('Lemon', Fruit) -- subclassing
|
||||
|
||||
function Lemon:initialize()
|
||||
Fruit.initialize(self, 1) -- invoking the superclass' initializer
|
||||
end
|
||||
|
||||
local lemon = Lemon:new()
|
||||
|
||||
print(lemon:isSweet()) -- false
|
||||
|
||||
h1. Documentation
|
||||
|
||||
See the "github wiki page":https://github.com/kikito/middleclass/wiki for examples & documentation.
|
||||
|
||||
h1. Installation
|
||||
|
||||
Just copy the middleclass.lua file wherever you want it (for example on a lib/ folder). Then write this in any Lua file where you want to use it:
|
||||
|
||||
local class = require 'middleclass'
|
||||
|
||||
h1. Specs
|
||||
|
||||
This project uses [busted](http://olivinelabs.com/busted/) for its specs. If you want to run the specs, you will have to install it first. Then just execute the following:
|
||||
|
||||
cd /folder/where/the/spec/folder/is
|
||||
busted
|
||||
|
||||
h1. Performance tests
|
||||
|
||||
Middleclass also comes with a small performance test suite. Just run the following command:
|
||||
|
||||
lua performance/run.lua
|
||||
|
||||
h1. Updating from 2.0
|
||||
|
||||
Middleclass used to expose several global variables on the main scope. It does not do that any more.
|
||||
|
||||
`class` is now returned by `require 'middleclass'`, and it is not set globally. So you can do this:
|
||||
|
||||
local class = require 'middleclass'
|
||||
local MyClass = class('MyClass') -- works as before
|
||||
|
||||
`Object` is not a global variable any more. But you can get it from `class.Object`
|
||||
|
||||
local class = require 'middleclass'
|
||||
local Object = class.Object
|
||||
|
||||
print(Object) -- prints 'class Object'
|
||||
|
||||
The public functions `instanceOf`, `subclassOf` and `includes` have been replaced by `Object.isInstanceOf`, `Object.static.isSubclassOf` and `Object.static.includes`.
|
||||
|
||||
Before:
|
||||
|
||||
instanceOf(MyClass, obj)
|
||||
subclassOf(Object, aClass)
|
||||
includes(aMixin, aClass)
|
||||
|
||||
After:
|
||||
|
||||
obj:isInstanceOf(MyClass)
|
||||
aClass:isSubclassOf(Object)
|
||||
aClass:includes(aMixin)
|
||||
|
||||
The previous code will throw an error if `obj` is not an object, or if `aClass` is not a class (since they will not implement `isInstanceOf`, `isSubclassOf` or `includes`).
|
||||
If you are unsure of wether `obj` and `aClass` are an object or a class, you can use the methods in `Object`. They are prepared to work with random types, not just classes and instances:
|
||||
|
||||
Object.isInstanceOf(obj, MyClass)
|
||||
Object.isSubclassOf(aClass, Object)
|
||||
Object.includes(aClass, aMixin)
|
||||
|
||||
Notice that the parameter order is not the same now as it was in 2.x. Also note the change in naming: `isInstanceOf` instead of `istanceOf`, and `isSubclassOf` instead of `subclassOf`.
|
||||
|
||||
|
||||
|
@ -1,75 +0,0 @@
|
||||
h1. MiddleClass
|
||||
|
||||
!https://travis-ci.org/kikito/middleclass.png?branch=master!:https://travis-ci.org/kikito/middleclass
|
||||
|
||||
Lua OOP classes usually end being:
|
||||
|
||||
* multi-file libraries, too difficult to understand
|
||||
* very small libraries, not very powerful
|
||||
|
||||
Middleclass attemps to be a mid-sized library (~140 lines of code, on a single file), with clean, easy to understand code, and yet powerful enough to be used in most cases.
|
||||
|
||||
h1. Documentation
|
||||
|
||||
See the "github wiki page":https://github.com/kikito/middleclass/wiki for examples & documentation.
|
||||
|
||||
h1. Features
|
||||
|
||||
* ~140 lines of code
|
||||
* top-level Object class
|
||||
* all methods are virtual
|
||||
* instance.class returns the instance's class
|
||||
* @Class.name@ returns the class name (a string)
|
||||
* @Class.super@ returns its super class
|
||||
* Class methods can be defined with Class.static.methodname
|
||||
* Subclassing:
|
||||
** @class(name)@ creates a subclass of @Object@
|
||||
** @class(name, Superclass)@ creates a subclass of the class @SuperClass@
|
||||
** @SuperClass:subclass(name)@ also creates a subclass of the class @SuperClass@
|
||||
* Instantiation:
|
||||
** Classes can define an @initialize@ method for initializing new instances. They can accept an arbitrary number of params.
|
||||
** Instances are created by doing @Class:new(params)@ or also @Class(params)@
|
||||
** SuperClass' methods can be used by using this syntax: @SuperClass.initialize(self, params)@.
|
||||
* support for Lua metamethods: just define a method called @__tostring@, @__add@, etc. and your instances will be able to use it.
|
||||
* Mixins:
|
||||
** A very simple mechanism for sharing functionality among a group of classes that are otherwise non-related.
|
||||
** Mixins are just simple lua tables with functions inside them.
|
||||
** @Class:include(mixin)@ will copy the function definitions of @mixin@ to @class@
|
||||
** If @mixin@ contains a function, called @included@, that function will be invoked right after the functions have been copied. It allows for modifying the class more profoundly.
|
||||
* The function @instanceOf(class, instance)@ returns @true@ if @instance@ is an instance of the class @Class@
|
||||
* The function @subclassOf(Superclass, Class)@ returns @true@ if @Class@ is a subclass of @SuperClass@
|
||||
* The function @includes(mixin, Class)@ returns @true@ if @Class@ (or one of its superclasses) includes @mixin@.
|
||||
|
||||
Features left out:
|
||||
|
||||
* metaclasses
|
||||
* classes are not Objects (instances are)
|
||||
* simulating a 'super' keyword (for performance concerns)
|
||||
|
||||
h1. Installation
|
||||
|
||||
Just copy the middleclass.lua file wherever you want it (for example on a lib/ folder). Then write this in any Lua file where you want to use it:
|
||||
|
||||
<pre>require 'middleclass'</pre>
|
||||
|
||||
The @package.path@ variable must be configured so that the folder in which middleclass.lua is copied is available, of course.
|
||||
|
||||
Please make sure that you read the license, too (for your convenience it's now included at the beginning of the middleclass.lua file).
|
||||
|
||||
h1. Specs
|
||||
|
||||
This project uses "telescope":https://github.com/norman/telescope for its specs. If you want to run the specs, you will have to install telescope first. Then just execute the following from the root inspect folder:
|
||||
|
||||
<pre>
|
||||
tsc -f spec/*
|
||||
</pre>
|
||||
|
||||
h1. Performance tests
|
||||
|
||||
Middleclass also comes with a small performance test suite. Just run the following command:
|
||||
|
||||
<pre>
|
||||
lua performance/run.lua
|
||||
</pre>
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
Version 2.0
|
||||
|
||||
* Static methods are now separated from instance methods
|
||||
* class.superclass has now become class.super
|
||||
* It's now possible to do class.subclasses
|
||||
* middleclass is now a single file; init.lua has dissapeared
|
||||
* license is changed from BSD to MIT. License included in source FTW
|
||||
|
104
middleclass.lua
104
middleclass.lua
@ -27,71 +27,71 @@ local middleclass = {
|
||||
]]
|
||||
}
|
||||
|
||||
local function _setClassDictionariesMetatables(klass)
|
||||
local dict = klass.__instanceDict
|
||||
local function _setClassDictionariesMetatables(aClass)
|
||||
local dict = aClass.__instanceDict
|
||||
dict.__index = dict
|
||||
|
||||
local super = klass.super
|
||||
local super = aClass.super
|
||||
if super then
|
||||
local superStatic = super.static
|
||||
setmetatable(dict, super.__instanceDict)
|
||||
setmetatable(klass.static, { __index = function(_,k) return dict[k] or superStatic[k] end })
|
||||
setmetatable(aClass.static, { __index = function(_,k) return dict[k] or superStatic[k] end })
|
||||
else
|
||||
setmetatable(klass.static, { __index = function(_,k) return dict[k] end })
|
||||
setmetatable(aClass.static, { __index = function(_,k) return dict[k] end })
|
||||
end
|
||||
end
|
||||
|
||||
local function _setClassMetatable(klass)
|
||||
setmetatable(klass, {
|
||||
__tostring = function() return "class " .. klass.name end,
|
||||
__index = klass.static,
|
||||
__newindex = klass.__instanceDict,
|
||||
local function _setClassMetatable(aClass)
|
||||
setmetatable(aClass, {
|
||||
__tostring = function() return "class " .. aClass.name end,
|
||||
__index = aClass.static,
|
||||
__newindex = aClass.__instanceDict,
|
||||
__call = function(self, ...) return self:new(...) end
|
||||
})
|
||||
end
|
||||
|
||||
local function _createClass(name, super)
|
||||
local klass = { name = name, super = super, static = {}, __mixins = {}, __instanceDict={} }
|
||||
klass.subclasses = setmetatable({}, {__mode = "k"})
|
||||
local aClass = { name = name, super = super, static = {}, __mixins = {}, __instanceDict={} }
|
||||
aClass.subclasses = setmetatable({}, {__mode = "k"})
|
||||
|
||||
_setClassDictionariesMetatables(klass)
|
||||
_setClassMetatable(klass)
|
||||
_setClassDictionariesMetatables(aClass)
|
||||
_setClassMetatable(aClass)
|
||||
|
||||
return klass
|
||||
return aClass
|
||||
end
|
||||
|
||||
local function _createLookupMetamethod(klass, name)
|
||||
local function _createLookupMetamethod(aClass, name)
|
||||
return function(...)
|
||||
local method = klass.super[name]
|
||||
assert( type(method)=='function', tostring(klass) .. " doesn't implement metamethod '" .. name .. "'" )
|
||||
local method = aClass.super[name]
|
||||
assert( type(method)=='function', tostring(aClass) .. " doesn't implement metamethod '" .. name .. "'" )
|
||||
return method(...)
|
||||
end
|
||||
end
|
||||
|
||||
local function _setClassMetamethods(klass)
|
||||
for _,m in ipairs(klass.__metamethods) do
|
||||
klass[m]= _createLookupMetamethod(klass, m)
|
||||
local function _setClassMetamethods(aClass)
|
||||
for _,m in ipairs(aClass.__metamethods) do
|
||||
aClass[m]= _createLookupMetamethod(aClass, m)
|
||||
end
|
||||
end
|
||||
|
||||
local function _setDefaultInitializeMethod(klass, super)
|
||||
klass.initialize = function(instance, ...)
|
||||
local function _setDefaultInitializeMethod(aClass, super)
|
||||
aClass.initialize = function(instance, ...)
|
||||
return super.initialize(instance, ...)
|
||||
end
|
||||
end
|
||||
|
||||
local function _includeMixin(klass, mixin)
|
||||
local function _includeMixin(aClass, mixin)
|
||||
assert(type(mixin)=='table', "mixin must be a table")
|
||||
for name,method in pairs(mixin) do
|
||||
if name ~= "included" and name ~= "static" then klass[name] = method end
|
||||
if name ~= "included" and name ~= "static" then aClass[name] = method end
|
||||
end
|
||||
if mixin.static then
|
||||
for name,method in pairs(mixin.static) do
|
||||
klass.static[name] = method
|
||||
aClass.static[name] = method
|
||||
end
|
||||
end
|
||||
if type(mixin.included)=="function" then mixin:included(klass) end
|
||||
klass.__mixins[mixin] = true
|
||||
if type(mixin.included)=="function" then mixin:included(aClass) end
|
||||
aClass.__mixins[mixin] = true
|
||||
end
|
||||
|
||||
local Object = _createClass("Object", nil)
|
||||
@ -100,7 +100,7 @@ Object.static.__metamethods = { '__add', '__call', '__concat', '__div', '__le',
|
||||
'__mod', '__mul', '__pow', '__sub', '__tostring', '__unm' }
|
||||
|
||||
function Object.static:allocate()
|
||||
assert(self, "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
|
||||
assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
|
||||
return setmetatable({ class = self }, self.__instanceDict)
|
||||
end
|
||||
|
||||
@ -111,7 +111,7 @@ function Object.static:new(...)
|
||||
end
|
||||
|
||||
function Object.static:subclass(name)
|
||||
assert(self, "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
|
||||
assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
|
||||
assert(type(name) == "string", "You must provide a name(string) for your class")
|
||||
|
||||
local subclass = _createClass(name, self)
|
||||
@ -125,32 +125,48 @@ end
|
||||
|
||||
function Object.static:subclassed(other) end
|
||||
|
||||
function Object.static:isSubclassOf(other)
|
||||
return type(other) == 'table' and
|
||||
type(self) == 'table' and
|
||||
type(self.super) == 'table' and
|
||||
( self.super == other or
|
||||
type(self.super.isSubclassOf) == 'function' and
|
||||
self.super:isSubclassOf(other)
|
||||
)
|
||||
end
|
||||
|
||||
function Object.static:include( ... )
|
||||
assert(self, "Make sure you that you are using 'Class:include' instead of 'Class.include'")
|
||||
assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'")
|
||||
for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end
|
||||
return self
|
||||
end
|
||||
|
||||
function Object.static:includes(mixin)
|
||||
return type(mixin) == 'table' and
|
||||
type(self) == 'table' and
|
||||
type(self.__mixins) == 'table' and
|
||||
( self.__mixins[mixin] or
|
||||
type(self.super) == 'table' and
|
||||
type(self.super.includes) == 'function' and
|
||||
self.super:includes(mixin)
|
||||
)
|
||||
end
|
||||
|
||||
function Object:initialize() end
|
||||
|
||||
function Object:__tostring() return "instance of " .. tostring(self.class) end
|
||||
|
||||
function instanceOf(aClass, obj)
|
||||
if type(aClass) ~= 'table' or type(obj) ~= 'table' or not obj.class then return false end
|
||||
if obj.class == aClass then return true end
|
||||
return subclassOf(aClass, obj.class)
|
||||
function Object:isInstanceOf(aClass)
|
||||
return type(self) == 'table' and
|
||||
type(self.class) == 'table' and
|
||||
type(aClass) == 'table' and
|
||||
( aClass == self.class or
|
||||
type(aClass.isSubclassOf) == 'function' and
|
||||
self.class:isSubclassOf(aClass)
|
||||
)
|
||||
end
|
||||
|
||||
function subclassOf(other, aClass)
|
||||
if type(other) ~= 'table' or type(aClass) ~= 'table' or not aClass.super then return false end
|
||||
return aClass.super == other or subclassOf(other, aClass.super)
|
||||
end
|
||||
|
||||
function includes(mixin, aClass)
|
||||
if type(mixin) ~= 'table' or type(aClass) ~= 'table' or not aClass.__mixins then return false end
|
||||
if aClass.__mixins[mixin] then return true end
|
||||
return includes(mixin, aClass.super)
|
||||
end
|
||||
|
||||
function middleclass.class(name, super, ...)
|
||||
super = super or Object
|
||||
|
@ -1,4 +1,4 @@
|
||||
require 'middleclass'
|
||||
local class = require 'middleclass'
|
||||
|
||||
time = require 'performance/time'
|
||||
|
||||
|
@ -1,89 +1,89 @@
|
||||
local class = require 'middleclass'
|
||||
local Object = class.Object
|
||||
|
||||
context('Object', function()
|
||||
describe('Object', function()
|
||||
|
||||
|
||||
context('name', function()
|
||||
test('is correctly set', function()
|
||||
assert_equal(Object.name, 'Object')
|
||||
describe('name', function()
|
||||
it('is correctly set', function()
|
||||
assert.equal(Object.name, 'Object')
|
||||
end)
|
||||
end)
|
||||
|
||||
context('tostring', function()
|
||||
test('returns "class Object"', function()
|
||||
assert_equal(tostring(Object), 'class Object')
|
||||
describe('tostring', function()
|
||||
it('returns "class Object"', function()
|
||||
assert.equal(tostring(Object), 'class Object')
|
||||
end)
|
||||
end)
|
||||
|
||||
context('()', function()
|
||||
test('returns an object, like Object:new()', function()
|
||||
describe('()', function()
|
||||
it('returns an object, like Object:new()', function()
|
||||
local obj = Object()
|
||||
assert_true(instanceOf(Object, obj))
|
||||
assert.is_true(obj:isInstanceOf(Object))
|
||||
end)
|
||||
end)
|
||||
|
||||
context('subclass', function()
|
||||
describe('subclass', function()
|
||||
|
||||
test('throws an error when used without the :', function()
|
||||
assert_error(function() Object.subclass() end)
|
||||
it('throws an error when used without the :', function()
|
||||
assert.error(function() Object.subclass() end)
|
||||
end)
|
||||
|
||||
test('throws an error when no name is given', function()
|
||||
assert_error( function() Object:subclass() end)
|
||||
it('throws an error when no name is given', function()
|
||||
assert.error( function() Object:subclass() end)
|
||||
end)
|
||||
|
||||
context('when given a class name', function()
|
||||
describe('when given a class name', function()
|
||||
|
||||
local SubClass
|
||||
|
||||
before(function()
|
||||
before_each(function()
|
||||
SubClass = Object:subclass('SubClass')
|
||||
end)
|
||||
|
||||
test('it returns a class with the correct name', function()
|
||||
assert_equal(SubClass.name, 'SubClass')
|
||||
it('it returns a class with the correct name', function()
|
||||
assert.equal(SubClass.name, 'SubClass')
|
||||
end)
|
||||
|
||||
test('it returns a class with the correct superclass', function()
|
||||
assert_equal(SubClass.super, Object)
|
||||
it('it returns a class with the correct superclass', function()
|
||||
assert.equal(SubClass.super, Object)
|
||||
end)
|
||||
|
||||
test('it includes the subclass in the list of subclasses', function()
|
||||
assert_true(Object.subclasses[SubClass])
|
||||
it('it includes the subclass in the list of subclasses', function()
|
||||
assert.is_true(Object.subclasses[SubClass])
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
context('instance creation', function()
|
||||
describe('instance creation', function()
|
||||
|
||||
local SubClass
|
||||
|
||||
before(function()
|
||||
before_each(function()
|
||||
SubClass = class('SubClass')
|
||||
function SubClass:initialize() self.mark=true end
|
||||
end)
|
||||
|
||||
context('allocate', function()
|
||||
describe('allocate', function()
|
||||
|
||||
test('allocates instances properly', function()
|
||||
it('allocates instances properly', function()
|
||||
local instance = SubClass:allocate()
|
||||
assert_equal(instance.class, SubClass)
|
||||
assert_equal(tostring(instance), "instance of " .. tostring(SubClass))
|
||||
assert.equal(instance.class, SubClass)
|
||||
assert.equal(tostring(instance), "instance of " .. tostring(SubClass))
|
||||
end)
|
||||
|
||||
test('throws an error when used without the :', function()
|
||||
assert_error(Object.allocate)
|
||||
it('throws an error when used without the :', function()
|
||||
assert.error(Object.allocate)
|
||||
end)
|
||||
|
||||
test('does not call the initializer', function()
|
||||
it('does not call the initializer', function()
|
||||
local allocated = SubClass:allocate()
|
||||
assert_nil(allocated.mark)
|
||||
assert.is_nil(allocated.mark)
|
||||
end)
|
||||
|
||||
test('can be overriden', function()
|
||||
it('can be overriden', function()
|
||||
|
||||
local previousAllocate = SubClass.static.allocate
|
||||
|
||||
@ -94,26 +94,244 @@ context('Object', function()
|
||||
end
|
||||
|
||||
local allocated = SubClass:allocate()
|
||||
assert_true(allocated.mark)
|
||||
assert.is_true(allocated.mark)
|
||||
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
context('new', function()
|
||||
describe('new', function()
|
||||
|
||||
test('initializes instances properly', function()
|
||||
it('initializes instances properly', function()
|
||||
local instance = SubClass:new()
|
||||
assert_equal(instance.class, SubClass)
|
||||
assert.equal(instance.class, SubClass)
|
||||
end)
|
||||
|
||||
test('throws an error when used without the :', function()
|
||||
assert_error(SubClass.new)
|
||||
it('throws an error when used without the :', function()
|
||||
assert.error(SubClass.new)
|
||||
end)
|
||||
|
||||
test('calls the initializer', function()
|
||||
it('calls the initializer', function()
|
||||
local initialized = SubClass:new()
|
||||
assert_true(initialized.mark)
|
||||
assert.is_true(initialized.mark)
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
describe('isInstanceOf', function()
|
||||
|
||||
describe('nils, integers, strings, tables, and functions', function()
|
||||
local o = Object:new()
|
||||
local primitives = {nil, 1, 'hello', {}, function() end}
|
||||
|
||||
for _,primitive in pairs(primitives) do
|
||||
local theType = type(primitive)
|
||||
describe('A ' .. theType, function()
|
||||
|
||||
local f1 = function() return Object.isInstanceOf(primitive, Object) end
|
||||
local f2 = function() return Object.isInstanceOf(primitive, o) end
|
||||
local f3 = function() return Object.isInstanceOf(primitive, primitive) end
|
||||
|
||||
describe('does not throw errors', function()
|
||||
it('instanceOf(Object, '.. theType ..')', function()
|
||||
assert.not_error(f1)
|
||||
end)
|
||||
it('instanceOf(' .. theType .. ', Object:new())', function()
|
||||
assert.not_error(f2)
|
||||
end)
|
||||
it('instanceOf(' .. theType .. ',' .. theType ..')', function()
|
||||
assert.not_error(f3)
|
||||
end)
|
||||
end)
|
||||
|
||||
it('makes instanceOf return false', function()
|
||||
assert.is_false(f1())
|
||||
assert.is_false(f2())
|
||||
assert.is_false(f3())
|
||||
end)
|
||||
|
||||
end)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
describe('An instance', function()
|
||||
local Class1 = class('Class1')
|
||||
local Class2 = class('Class2', Class1)
|
||||
local Class3 = class('Class3', Class2)
|
||||
local UnrelatedClass = class('Unrelated')
|
||||
|
||||
local o1, o2, o3 = Class1:new(), Class2:new(), Class3:new()
|
||||
|
||||
it('isInstanceOf(Object)', function()
|
||||
assert.is_true(o1:isInstanceOf(Object))
|
||||
assert.is_true(o2:isInstanceOf(Object))
|
||||
assert.is_true(o3:isInstanceOf(Object))
|
||||
end)
|
||||
|
||||
it('isInstanceOf its class', function()
|
||||
assert.is_true(o1:isInstanceOf(Class1))
|
||||
assert.is_true(o2:isInstanceOf(Class2))
|
||||
assert.is_true(o3:isInstanceOf(Class3))
|
||||
end)
|
||||
|
||||
it('is instanceOf its class\' superclasses', function()
|
||||
assert.is_true(o2:isInstanceOf(Class1))
|
||||
assert.is_true(o3:isInstanceOf(Class1))
|
||||
assert.is_true(o3:isInstanceOf(Class2))
|
||||
end)
|
||||
|
||||
it('is not instanceOf its class\' subclasses', function()
|
||||
assert.is_false(o1:isInstanceOf(Class2))
|
||||
assert.is_false(o1:isInstanceOf(Class3))
|
||||
assert.is_false(o2:isInstanceOf(Class3))
|
||||
end)
|
||||
|
||||
it('is not instanceOf an unrelated class', function()
|
||||
assert.is_false(o1:isInstanceOf(UnrelatedClass))
|
||||
assert.is_false(o2:isInstanceOf(UnrelatedClass))
|
||||
assert.is_false(o3:isInstanceOf(UnrelatedClass))
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
describe('isSubclassOf', function()
|
||||
|
||||
describe('nils, integers, etc', function()
|
||||
local primitives = {nil, 1, 'hello', {}, function() end}
|
||||
|
||||
for _,primitive in pairs(primitives) do
|
||||
local theType = type(primitive)
|
||||
describe('A ' .. theType, function()
|
||||
|
||||
local f1 = function() return Object.isSubclassOf(Object, primitive) end
|
||||
local f2 = function() return Object.isSubclassOf(primitive, o) end
|
||||
local f3 = function() return Object.isSubclassOf(primitive, primitive) end
|
||||
|
||||
describe('does not throw errors', function()
|
||||
it('isSubclassOf(Object, '.. theType ..')', function()
|
||||
assert.not_error(f1)
|
||||
end)
|
||||
it('isSubclassOf(' .. theType .. ', Object:new())', function()
|
||||
assert.not_error(f2)
|
||||
end)
|
||||
it('isSubclassOf(' .. theType .. ',' .. theType ..')', function()
|
||||
assert.not_error(f3)
|
||||
end)
|
||||
end)
|
||||
|
||||
it('makes isSubclassOf return false', function()
|
||||
assert.is_false(f1())
|
||||
assert.is_false(f2())
|
||||
assert.is_false(f3())
|
||||
end)
|
||||
|
||||
end)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
describe('Any class (except Object)', function()
|
||||
local Class1 = class('Class1')
|
||||
local Class2 = class('Class2', Class1)
|
||||
local Class3 = class('Class3', Class2)
|
||||
local UnrelatedClass = class('Unrelated')
|
||||
|
||||
it('isSubclassOf(Object)', function()
|
||||
assert.is_true(Class1:isSubclassOf(Object))
|
||||
assert.is_true(Class2:isSubclassOf(Object))
|
||||
assert.is_true(Class3:isSubclassOf(Object))
|
||||
end)
|
||||
|
||||
it('is subclassOf its direct superclass', function()
|
||||
assert.is_true(Class2:isSubclassOf(Class1))
|
||||
assert.is_true(Class3:isSubclassOf(Class2))
|
||||
end)
|
||||
|
||||
it('is subclassOf its ancestors', function()
|
||||
assert.is_true(Class3:isSubclassOf(Class1))
|
||||
end)
|
||||
|
||||
it('is a subclassOf its class\' subclasses', function()
|
||||
assert.is_true(Class2:isSubclassOf(Class1))
|
||||
assert.is_true(Class3:isSubclassOf(Class1))
|
||||
assert.is_true(Class3:isSubclassOf(Class2))
|
||||
end)
|
||||
|
||||
it('is not a subclassOf an unrelated class', function()
|
||||
assert.is_false(Class1:isSubclassOf(UnrelatedClass))
|
||||
assert.is_false(Class2:isSubclassOf(UnrelatedClass))
|
||||
assert.is_false(Class3:isSubclassOf(UnrelatedClass))
|
||||
end)
|
||||
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('includes', function()
|
||||
|
||||
describe('nils, numbers, etc', function()
|
||||
local o = Object:new()
|
||||
local primitives = {nil, 1, 'hello', {}, function() end}
|
||||
|
||||
for _,primitive in pairs(primitives) do
|
||||
local theType = type(primitive)
|
||||
describe('A ' .. theType, function()
|
||||
|
||||
local f1 = function() return Object.includes(Object, primitive) end
|
||||
local f2 = function() return Object.includes(primitive, o) end
|
||||
local f3 = function() return Object.includes(primitive, primitive) end
|
||||
|
||||
|
||||
describe('don\'t throw errors', function()
|
||||
it('includes(Object, '.. theType ..')', function()
|
||||
assert.not_error(f1)
|
||||
end)
|
||||
it('includes(' .. theType .. ', Object:new())', function()
|
||||
assert.not_error(f2)
|
||||
end)
|
||||
it('includes(' .. theType .. ',' .. theType ..')', function()
|
||||
assert.not_error(f3)
|
||||
end)
|
||||
end)
|
||||
|
||||
it('make includes return false', function()
|
||||
assert.is_false(f1())
|
||||
assert.is_false(f2())
|
||||
assert.is_false(f3())
|
||||
end)
|
||||
|
||||
end)
|
||||
end -- for
|
||||
|
||||
end)
|
||||
|
||||
describe('A class', function()
|
||||
|
||||
local Class1 = class('Class1')
|
||||
local Class2 = class('Class2', Class1)
|
||||
local Class3 = class('Class3', Class2)
|
||||
local UnrelatedClass = class('Unrelated')
|
||||
|
||||
local hasFoo = { foo=function() return 'foo' end }
|
||||
Class1:include(hasFoo)
|
||||
|
||||
it('returns true if it includes a mixin', function()
|
||||
assert.is_true(Class1:includes(hasFoo))
|
||||
end)
|
||||
|
||||
it('returns true if its superclass includes a mixin', function()
|
||||
assert.is_true(Class2:includes(hasFoo))
|
||||
assert.is_true(Class3:includes(hasFoo))
|
||||
end)
|
||||
|
||||
it('returns false otherwise', function()
|
||||
assert.is_false(UnrelatedClass:includes(hasFoo))
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
end)
|
||||
@ -121,6 +339,4 @@ context('Object', function()
|
||||
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
|
||||
|
@ -1,28 +1,28 @@
|
||||
local class = require 'middleclass'
|
||||
local Object = class.Object
|
||||
|
||||
context('class()', function()
|
||||
describe('class()', function()
|
||||
|
||||
context('when given no params', function()
|
||||
test('it throws an error', function()
|
||||
assert_error(class)
|
||||
describe('when given no params', function()
|
||||
it('it throws an error', function()
|
||||
assert.error(class)
|
||||
end)
|
||||
end)
|
||||
|
||||
context('when given a name', function()
|
||||
test('the resulting class has the correct name and Object as its superclass', function()
|
||||
describe('when given a name', function()
|
||||
it('the resulting class has the correct name and Object as its superclass', function()
|
||||
local TheClass = class('TheClass')
|
||||
assert_equal(TheClass.name, 'TheClass')
|
||||
assert_equal(TheClass.super, Object)
|
||||
assert.equal(TheClass.name, 'TheClass')
|
||||
assert.equal(TheClass.super, Object)
|
||||
end)
|
||||
end)
|
||||
|
||||
context('when given a name and a superclass', function()
|
||||
test('the resulting class has the correct name and superclass', function()
|
||||
describe('when given a name and a superclass', function()
|
||||
it('the resulting class has the correct name and superclass', function()
|
||||
local TheSuperClass = class('TheSuperClass')
|
||||
local TheSubClass = class('TheSubClass', TheSuperClass)
|
||||
assert_equal(TheSubClass.name, 'TheSubClass')
|
||||
assert_equal(TheSubClass.super, TheSuperClass)
|
||||
assert.equal(TheSubClass.name, 'TheSubClass')
|
||||
assert.equal(TheSubClass.super, TheSuperClass)
|
||||
end)
|
||||
end)
|
||||
|
||||
|
@ -1,76 +1,76 @@
|
||||
local class = require 'middleclass'
|
||||
|
||||
context('A Class', function()
|
||||
describe('A Class', function()
|
||||
|
||||
context('Default stuff', function()
|
||||
describe('Default stuff', function()
|
||||
|
||||
local AClass
|
||||
|
||||
before(function()
|
||||
before_each(function()
|
||||
AClass = class('AClass')
|
||||
end)
|
||||
|
||||
context('name', function()
|
||||
test('is correctly set', function()
|
||||
assert_equal(AClass.name, 'AClass')
|
||||
describe('name', function()
|
||||
it('is correctly set', function()
|
||||
assert.equal(AClass.name, 'AClass')
|
||||
end)
|
||||
end)
|
||||
|
||||
context('tostring', function()
|
||||
test('returns "class *name*"', function()
|
||||
assert_equal(tostring(AClass), 'class AClass')
|
||||
describe('tostring', function()
|
||||
it('returns "class *name*"', function()
|
||||
assert.equal(tostring(AClass), 'class AClass')
|
||||
end)
|
||||
end)
|
||||
|
||||
context('()', function()
|
||||
test('returns an object, like Class:new()', function()
|
||||
describe('()', function()
|
||||
it('returns an object, like Class:new()', function()
|
||||
local obj = AClass()
|
||||
assert_equal(obj.class, AClass)
|
||||
assert.equal(obj.class, AClass)
|
||||
end)
|
||||
end)
|
||||
|
||||
context('include', function()
|
||||
test('throws an error when used without the :', function()
|
||||
assert_error(function() AClass.include() end)
|
||||
describe('include', function()
|
||||
it('throws an error when used without the :', function()
|
||||
assert.error(function() AClass.include() end)
|
||||
end)
|
||||
test('throws an error when passed a non-table:', function()
|
||||
assert_error(function() AClass:include(1) end)
|
||||
it('throws an error when passed a non-table:', function()
|
||||
assert.error(function() AClass:include(1) end)
|
||||
end)
|
||||
end)
|
||||
|
||||
context('subclass', function()
|
||||
describe('subclass', function()
|
||||
|
||||
test('throws an error when used without the :', function()
|
||||
assert_error(function() AClass.subclass() end)
|
||||
it('throws an error when used without the :', function()
|
||||
assert.error(function() AClass.subclass() end)
|
||||
end)
|
||||
|
||||
test('throws an error when no name is given', function()
|
||||
assert_error( function() AClass:subclass() end)
|
||||
it('throws an error when no name is given', function()
|
||||
assert.error( function() AClass:subclass() end)
|
||||
end)
|
||||
|
||||
context('when given a subclass name', function()
|
||||
describe('when given a subclass name', function()
|
||||
|
||||
local SubClass
|
||||
|
||||
before(function()
|
||||
before_each(function()
|
||||
function AClass.static:subclassed(other) self.static.child = other end
|
||||
SubClass = AClass:subclass('SubClass')
|
||||
end)
|
||||
|
||||
test('it returns a class with the correct name', function()
|
||||
assert_equal(SubClass.name, 'SubClass')
|
||||
it('it returns a class with the correct name', function()
|
||||
assert.equal(SubClass.name, 'SubClass')
|
||||
end)
|
||||
|
||||
test('it returns a class with the correct superclass', function()
|
||||
assert_equal(SubClass.super, AClass)
|
||||
it('it returns a class with the correct superclass', function()
|
||||
assert.equal(SubClass.super, AClass)
|
||||
end)
|
||||
|
||||
test('it invokes the subclassed hook method', function()
|
||||
assert_equal(SubClass, AClass.child)
|
||||
it('it invokes the subclassed hook method', function()
|
||||
assert.equal(SubClass, AClass.child)
|
||||
end)
|
||||
|
||||
test('it includes the subclass in the list of subclasses', function()
|
||||
assert_true(AClass.subclasses[SubClass])
|
||||
it('it includes the subclass in the list of subclasses', function()
|
||||
assert.is_true(AClass.subclasses[SubClass])
|
||||
end)
|
||||
|
||||
end)
|
||||
@ -81,56 +81,56 @@ context('A Class', function()
|
||||
|
||||
|
||||
|
||||
context('attributes', function()
|
||||
describe('attributes', function()
|
||||
|
||||
local A, B
|
||||
|
||||
before(function()
|
||||
before_each(function()
|
||||
A = class('A')
|
||||
A.static.foo = 'foo'
|
||||
|
||||
B = class('B', A)
|
||||
end)
|
||||
|
||||
test('are available after being initialized', function()
|
||||
assert_equal(A.foo, 'foo')
|
||||
it('are available after being initialized', function()
|
||||
assert.equal(A.foo, 'foo')
|
||||
end)
|
||||
|
||||
test('are available for subclasses', function()
|
||||
assert_equal(B.foo, 'foo')
|
||||
it('are available for subclasses', function()
|
||||
assert.equal(B.foo, 'foo')
|
||||
end)
|
||||
|
||||
test('are overridable by subclasses, without affecting the superclasses', function()
|
||||
it('are overridable by subclasses, without affecting the superclasses', function()
|
||||
B.static.foo = 'chunky bacon'
|
||||
assert_equal(B.foo, 'chunky bacon')
|
||||
assert_equal(A.foo, 'foo')
|
||||
assert.equal(B.foo, 'chunky bacon')
|
||||
assert.equal(A.foo, 'foo')
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
context('methods', function()
|
||||
describe('methods', function()
|
||||
|
||||
local A, B
|
||||
|
||||
before(function()
|
||||
before_each(function()
|
||||
A = class('A')
|
||||
function A.static:foo() return 'foo' end
|
||||
|
||||
B = class('B', A)
|
||||
end)
|
||||
|
||||
test('are available after being initialized', function()
|
||||
assert_equal(A:foo(), 'foo')
|
||||
it('are available after being initialized', function()
|
||||
assert.equal(A:foo(), 'foo')
|
||||
end)
|
||||
|
||||
test('are available for subclasses', function()
|
||||
assert_equal(B:foo(), 'foo')
|
||||
it('are available for subclasses', function()
|
||||
assert.equal(B:foo(), 'foo')
|
||||
end)
|
||||
|
||||
test('are overridable by subclasses, without affecting the superclasses', function()
|
||||
it('are overridable by subclasses, without affecting the superclasses', function()
|
||||
function B.static:foo() return 'chunky bacon' end
|
||||
assert_equal(B:foo(), 'chunky bacon')
|
||||
assert_equal(A:foo(), 'foo')
|
||||
assert.equal(B:foo(), 'chunky bacon')
|
||||
assert.equal(A:foo(), 'foo')
|
||||
end)
|
||||
|
||||
end)
|
||||
|
@ -1,67 +0,0 @@
|
||||
local class = require 'middleclass'
|
||||
local Object = class.Object
|
||||
|
||||
context('includes', function()
|
||||
|
||||
context('nils, numbers, etc', function()
|
||||
local o = Object:new()
|
||||
local primitives = {nil, 1, 'hello', {}, function() end}
|
||||
|
||||
for _,primitive in pairs(primitives) do
|
||||
local theType = type(primitive)
|
||||
context('A ' .. theType, function()
|
||||
|
||||
local f1 = function() return includes(Object, primitive) end
|
||||
local f2 = function() return includes(primitive, o) end
|
||||
local f3 = function() return includes(primitive, primitive) end
|
||||
|
||||
context('don\'t throw errors', function()
|
||||
test('includes(Object, '.. theType ..')', function()
|
||||
assert_not_error(f1)
|
||||
end)
|
||||
test('includes(' .. theType .. ', Object:new())', function()
|
||||
assert_not_error(f2)
|
||||
end)
|
||||
test('includes(' .. theType .. ',' .. theType ..')', function()
|
||||
assert_not_error(f3)
|
||||
end)
|
||||
end)
|
||||
|
||||
test('make includes return false', function()
|
||||
assert_false(f1())
|
||||
assert_false(f2())
|
||||
assert_false(f3())
|
||||
end)
|
||||
|
||||
end)
|
||||
end -- for
|
||||
|
||||
end)
|
||||
|
||||
context('A class', function()
|
||||
|
||||
local Class1 = class('Class1')
|
||||
local Class2 = class('Class2', Class1)
|
||||
local Class3 = class('Class3', Class2)
|
||||
local UnrelatedClass = class('Unrelated')
|
||||
|
||||
local hasFoo = { foo=function() return 'foo' end }
|
||||
Class1:include(hasFoo)
|
||||
|
||||
test('returns true if it includes a mixin', function()
|
||||
assert_true(includes(hasFoo, Class1))
|
||||
end)
|
||||
|
||||
test('returns true if its superclass includes a mixin', function()
|
||||
assert_true(includes(hasFoo, Class2))
|
||||
assert_true(includes(hasFoo, Class3))
|
||||
end)
|
||||
|
||||
test('returns false otherwise', function()
|
||||
assert_false(includes(hasFoo, UnrelatedClass))
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
end)
|
||||
|
@ -1,81 +0,0 @@
|
||||
local class = require 'middleclass'
|
||||
local Object = class.Object
|
||||
|
||||
context('instanceOf', function()
|
||||
|
||||
context('nils, integers, strings, tables, and functions', function()
|
||||
local o = Object:new()
|
||||
local primitives = {nil, 1, 'hello', {}, function() end}
|
||||
|
||||
for _,primitive in pairs(primitives) do
|
||||
local theType = type(primitive)
|
||||
context('A ' .. theType, function()
|
||||
|
||||
local f1 = function() return instanceOf(Object, primitive) end
|
||||
local f2 = function() return instanceOf(primitive, o) end
|
||||
local f3 = function() return instanceOf(primitive, primitive) end
|
||||
|
||||
context('does not throw errors', function()
|
||||
test('instanceOf(Object, '.. theType ..')', function()
|
||||
assert_not_error(f1)
|
||||
end)
|
||||
test('instanceOf(' .. theType .. ', Object:new())', function()
|
||||
assert_not_error(f2)
|
||||
end)
|
||||
test('instanceOf(' .. theType .. ',' .. theType ..')', function()
|
||||
assert_not_error(f3)
|
||||
end)
|
||||
end)
|
||||
|
||||
test('makes instanceOf return false', function()
|
||||
assert_false(f1())
|
||||
assert_false(f2())
|
||||
assert_false(f3())
|
||||
end)
|
||||
|
||||
end)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
context('An instance', function()
|
||||
local Class1 = class('Class1')
|
||||
local Class2 = class('Class2', Class1)
|
||||
local Class3 = class('Class3', Class2)
|
||||
local UnrelatedClass = class('Unrelated')
|
||||
|
||||
local o1, o2, o3 = Class1:new(), Class2:new(), Class3:new()
|
||||
|
||||
test('is instanceOf(Object)', function()
|
||||
assert_true(instanceOf(Object, o1))
|
||||
assert_true(instanceOf(Object, o2))
|
||||
assert_true(instanceOf(Object, o3))
|
||||
end)
|
||||
|
||||
test('is instanceOf its class', function()
|
||||
assert_true(instanceOf(Class1, o1))
|
||||
assert_true(instanceOf(Class2, o2))
|
||||
assert_true(instanceOf(Class3, o3))
|
||||
end)
|
||||
|
||||
test('is instanceOf its class\' superclasses', function()
|
||||
assert_true(instanceOf(Class1, o2))
|
||||
assert_true(instanceOf(Class1, o3))
|
||||
assert_true(instanceOf(Class2, o3))
|
||||
end)
|
||||
|
||||
test('is not instanceOf its class\' subclasses', function()
|
||||
assert_false(instanceOf(Class2, o1))
|
||||
assert_false(instanceOf(Class3, o1))
|
||||
assert_false(instanceOf(Class3, o2))
|
||||
end)
|
||||
|
||||
test('is not instanceOf an unrelated class', function()
|
||||
assert_false(instanceOf(UnrelatedClass, o1))
|
||||
assert_false(instanceOf(UnrelatedClass, o2))
|
||||
assert_false(instanceOf(UnrelatedClass, o3))
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
end)
|
@ -1,24 +1,24 @@
|
||||
local class = require 'middleclass'
|
||||
|
||||
context('An instance', function()
|
||||
describe('An instance', function()
|
||||
|
||||
context('attributes', function()
|
||||
describe('attributes', function()
|
||||
|
||||
local Person
|
||||
|
||||
before(function()
|
||||
before_each(function()
|
||||
Person = class('Person')
|
||||
function Person:initialize(name)
|
||||
self.name = name
|
||||
end
|
||||
end)
|
||||
|
||||
test('are available in the instance after being initialized', function()
|
||||
it('are available in the instance after being initialized', function()
|
||||
local bob = Person:new('bob')
|
||||
assert_equal(bob.name, 'bob')
|
||||
assert.equal(bob.name, 'bob')
|
||||
end)
|
||||
|
||||
test('are available in the instance after being initialized by a superclass', function()
|
||||
it('are available in the instance after being initialized by a superclass', function()
|
||||
local AgedPerson = class('AgedPerson', Person)
|
||||
function AgedPerson:initialize(name, age)
|
||||
Person.initialize(self, name)
|
||||
@ -26,17 +26,17 @@ context('An instance', function()
|
||||
end
|
||||
|
||||
local pete = AgedPerson:new('pete', 31)
|
||||
assert_equal(pete.name, 'pete')
|
||||
assert_equal(pete.age, 31)
|
||||
assert.equal(pete.name, 'pete')
|
||||
assert.equal(pete.age, 31)
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
context('methods', function()
|
||||
describe('methods', function()
|
||||
|
||||
local A, B, a, b
|
||||
|
||||
before(function()
|
||||
before_each(function()
|
||||
A = class('A')
|
||||
function A:overridden() return 'foo' end
|
||||
function A:regular() return 'regular' end
|
||||
@ -48,16 +48,16 @@ context('An instance', function()
|
||||
b = B:new()
|
||||
end)
|
||||
|
||||
test('are available for any instance', function()
|
||||
assert_equal(a:overridden(), 'foo')
|
||||
it('are available for any instance', function()
|
||||
assert.equal(a:overridden(), 'foo')
|
||||
end)
|
||||
|
||||
test('are inheritable', function()
|
||||
assert_equal(b:regular(), 'regular')
|
||||
it('are inheritable', function()
|
||||
assert.equal(b:regular(), 'regular')
|
||||
end)
|
||||
|
||||
test('are overridable', function()
|
||||
assert_equal(b:overridden(), 'bar')
|
||||
it('are overridable', function()
|
||||
assert.equal(b:overridden(), 'bar')
|
||||
end)
|
||||
|
||||
end)
|
||||
|
@ -1,9 +1,9 @@
|
||||
local class = require 'middleclass'
|
||||
local Object = class.Object
|
||||
|
||||
context('Metamethods', function()
|
||||
describe('Metamethods', function()
|
||||
|
||||
context('Custom Metamethods', function()
|
||||
describe('Custom Metamethods', function()
|
||||
-- Tests all metamethods. Note that __len is missing (lua makes table length unoverridable)
|
||||
-- I'll use a() to note the length of vector "a" (I would have preferred to use #a, but it's not possible)
|
||||
-- I'll be using 'a' instead of 'self' on this example since it is shorter
|
||||
@ -45,12 +45,12 @@ context('Metamethods', function()
|
||||
__mul = { 4*a, Vector(4,8,12) }--,
|
||||
--__index = { b[1], 3 }
|
||||
}) do
|
||||
test(metamethod .. ' works as expected', function()
|
||||
assert_equal(values[1], values[2])
|
||||
it(metamethod .. ' works as expected', function()
|
||||
assert.equal(values[1], values[2])
|
||||
end)
|
||||
end
|
||||
|
||||
context('Inherited Metamethods', function()
|
||||
describe('Inherited Metamethods', function()
|
||||
local Vector2= class('Vector2', Vector)
|
||||
function Vector2:initialize(x,y,z) Vector.initialize(self,x,y,z) end
|
||||
|
||||
@ -70,36 +70,36 @@ context('Metamethods', function()
|
||||
__pow = { c^d, Vector(0,0,0) },
|
||||
__mul = { 4*c, Vector(4,8,12) }
|
||||
}) do
|
||||
test(metamethod .. ' works as expected', function()
|
||||
assert_equal(values[1], values[2])
|
||||
it(metamethod .. ' works as expected', function()
|
||||
assert.equal(values[1], values[2])
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
context('Default Metamethods', function()
|
||||
describe('Default Metamethods', function()
|
||||
|
||||
local Peter, peter
|
||||
|
||||
before(function()
|
||||
before_each(function()
|
||||
Peter = class('Peter')
|
||||
peter = Peter()
|
||||
end)
|
||||
|
||||
context('A Class', function()
|
||||
test('has a call metamethod properly set', function()
|
||||
assert_true(instanceOf(Peter, peter))
|
||||
describe('A Class', function()
|
||||
it('has a call metamethod properly set', function()
|
||||
assert.is_true(peter:isInstanceOf(Peter))
|
||||
end)
|
||||
test('has a tostring metamethod properly set', function()
|
||||
assert_equal(tostring(Peter), 'class Peter')
|
||||
it('has a tostring metamethod properly set', function()
|
||||
assert.equal(tostring(Peter), 'class Peter')
|
||||
end)
|
||||
end)
|
||||
|
||||
context('An instance', function()
|
||||
test('has a tostring metamethod, returning a different result from Object.__tostring', function()
|
||||
assert_not_equal(Peter.__tostring, Object.__tostring)
|
||||
assert_equal(tostring(peter), 'instance of class Peter')
|
||||
describe('An instance', function()
|
||||
it('has a tostring metamethod, returning a different result from Object.__tostring', function()
|
||||
assert.not_equal(Peter.__tostring, Object.__tostring)
|
||||
assert.equal(tostring(peter), 'instance of class Peter')
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
@ -1,10 +1,10 @@
|
||||
local class = require 'middleclass'
|
||||
|
||||
context('A Mixin', function()
|
||||
describe('A Mixin', function()
|
||||
|
||||
local Mixin1, Mixin2, Class1, Class2
|
||||
|
||||
before(function()
|
||||
before_each(function()
|
||||
Mixin1, Mixin2 = {},{}
|
||||
|
||||
function Mixin1:included(theClass) theClass.includesMixin1 = true end
|
||||
@ -23,30 +23,30 @@ context('A Mixin', function()
|
||||
function Class2:bar2() return 'bar2' end
|
||||
end)
|
||||
|
||||
test('invokes the "included" method when included', function()
|
||||
assert_true(Class1.includesMixin1)
|
||||
it('invokes the "included" method when included', function()
|
||||
assert.is_true(Class1.includesMixin1)
|
||||
end)
|
||||
|
||||
test('has all its functions (except "included") copied to its target class', function()
|
||||
assert_equal(Class1:bar(), 'bar')
|
||||
assert_nil(Class1.included)
|
||||
it('has all its functions (except "included") copied to its target class', function()
|
||||
assert.equal(Class1:bar(), 'bar')
|
||||
assert.is_nil(Class1.included)
|
||||
end)
|
||||
|
||||
test('makes its functions available to subclasses', function()
|
||||
assert_equal(Class2:baz(), 'baz')
|
||||
it('makes its functions available to subclasses', function()
|
||||
assert.equal(Class2:baz(), 'baz')
|
||||
end)
|
||||
|
||||
test('allows overriding of methods in the same class', function()
|
||||
assert_equal(Class2:foo(), 'foo1')
|
||||
it('allows overriding of methods in the same class', function()
|
||||
assert.equal(Class2:foo(), 'foo1')
|
||||
end)
|
||||
|
||||
test('allows overriding of methods on subclasses', function()
|
||||
assert_equal(Class2:bar2(), 'bar2')
|
||||
it('allows overriding of methods on subclasses', function()
|
||||
assert.equal(Class2:bar2(), 'bar2')
|
||||
end)
|
||||
|
||||
test('makes new static methods available in classes', function()
|
||||
assert_equal(Class1:bazzz(), 'bazzz')
|
||||
assert_equal(Class2:bazzz(), 'bazzz')
|
||||
it('makes new static methods available in classes', function()
|
||||
assert.equal(Class1:bazzz(), 'bazzz')
|
||||
assert.equal(Class2:bazzz(), 'bazzz')
|
||||
end)
|
||||
|
||||
end)
|
||||
|
@ -1,75 +0,0 @@
|
||||
local class = require 'middleclass'
|
||||
local Object = class.Object
|
||||
|
||||
context('subclassOf', function()
|
||||
|
||||
context('nils, integers, etc', function()
|
||||
local primitives = {nil, 1, 'hello', {}, function() end}
|
||||
|
||||
for _,primitive in pairs(primitives) do
|
||||
local theType = type(primitive)
|
||||
context('A ' .. theType, function()
|
||||
|
||||
local f1 = function() return subclassOf(Object, primitive) end
|
||||
local f2 = function() return subclassOf(primitive, o) end
|
||||
local f3 = function() return subclassOf(primitive, primitive) end
|
||||
|
||||
context('does not throw errors', function()
|
||||
test('subclassOf(Object, '.. theType ..')', function()
|
||||
assert_not_error(f1)
|
||||
end)
|
||||
test('subclassOf(' .. theType .. ', Object:new())', function()
|
||||
assert_not_error(f2)
|
||||
end)
|
||||
test('subclassOf(' .. theType .. ',' .. theType ..')', function()
|
||||
assert_not_error(f3)
|
||||
end)
|
||||
end)
|
||||
|
||||
test('makes subclassOf return false', function()
|
||||
assert_false(f1())
|
||||
assert_false(f2())
|
||||
assert_false(f3())
|
||||
end)
|
||||
|
||||
end)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
context('Any class (except Object)', function()
|
||||
local Class1 = class('Class1')
|
||||
local Class2 = class('Class2', Class1)
|
||||
local Class3 = class('Class3', Class2)
|
||||
local UnrelatedClass = class('Unrelated')
|
||||
|
||||
test('is subclassOf(Object)', function()
|
||||
assert_true(subclassOf(Object, Class1))
|
||||
assert_true(subclassOf(Object, Class2))
|
||||
assert_true(subclassOf(Object, Class3))
|
||||
end)
|
||||
|
||||
test('is subclassOf its direct superclass', function()
|
||||
assert_true(subclassOf(Class1, Class2))
|
||||
assert_true(subclassOf(Class2, Class3))
|
||||
end)
|
||||
|
||||
test('is subclassOf its ancestors', function()
|
||||
assert_true(subclassOf(Class1, Class3))
|
||||
end)
|
||||
|
||||
test('is a subclassOf its class\' subclasses', function()
|
||||
assert_false(subclassOf(Class2, Class1))
|
||||
assert_false(subclassOf(Class3, Class1))
|
||||
assert_false(subclassOf(Class3, Class2))
|
||||
end)
|
||||
|
||||
test('is not a subclassOf an unrelated class', function()
|
||||
assert_false(subclassOf(UnrelatedClass, Class1))
|
||||
assert_false(subclassOf(UnrelatedClass, Class2))
|
||||
assert_false(subclassOf(UnrelatedClass, Class3))
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
end)
|
Loading…
Reference in New Issue
Block a user