މޮޑިއުލް:Middleclass/doc: Difference between revisions

Content deleted Content added
No edit summary
m Bot: Replace deprecated <source> tag and "enclose" parameter; cosmetic changes
 
ފޮޅުވަތް 1:
<div dir=ltr>
Middleclass is an object-oriented library for Lua, written by Enrique García Cota (kikito) and [https://github.com/kikito/middleclass maintained at GitHub].
 
If you are familiar with Object Orientation in other languages (C++, Java, Ruby … ) then you will probably find this library very easy to use.
ފޮޅުވަތް 8:
== Quick Example ==
 
<sourcesyntaxhighlight lang="lua">
local class = require('Module:Middleclass').class
 
ފޮޅުވަތް 42:
mw.log(p1:speak())
mw.log(p2:speak())
</syntaxhighlight>
</source>
 
Output:
ފޮޅުވަތް 57:
You can compare classes and objects with the built-in methods <code>isInstanceOf</code>, <code>isSubclassOf</code>, and <code>includes</code>.
 
<sourcesyntaxhighlight lang="lua">
obj:isInstanceOf(MyClass)
aClass:isSubclassOf(Object)
aClass:includes(aMixin)
</syntaxhighlight>
</source>
 
Caution: this 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 whether obj and aClass are an object or a class, you can use the methods in Object. This is a special object that can be obtained from the class object.
ފޮޅުވަތް 67:
It is possible to get a special object ''Object'' from the class function.
 
<sourcesyntaxhighlight lang="lua">
local middleclass = require('Module:Middleclass')
local class = middleclass.class
ފޮޅުވަތް 73:
 
print(Object) -- prints 'class Object'
</syntaxhighlight>
</source>
 
The methods in Object are prepared to work with random types, not just classes and instances:
 
<sourcesyntaxhighlight lang="lua">
Object.isInstanceOf(obj, MyClass)
Object.isSubclassOf(aClass, Object)
Object.includes(aClass, aMixin)
</syntaxhighlight>
</source>
 
== Metamethods ==
ފޮޅުވަތް 89:
Let’s make an example with <code>__tostring</code>
 
<sourcesyntaxhighlight lang="lua">
Point = class('Point')
 
ފޮޅުވަތް 105:
mw.log(p1)
mw.log(p2)
</syntaxhighlight>
</source>
 
Output:
ފޮޅުވަތް 116:
The complete list of supported methods can be seen on middleclass’ source code:
 
<sourcesyntaxhighlight lang="lua">
'__add', '__call', '__concat', '__div', '__le', '__lt', '__mod', '__mul', '__pow', '__sub', '__tostring', '__unm'
</syntaxhighlight>
</source>
 
You may notice that <code>__index</code> is missing. That metamethod is reserved for the lib and can’t be used. On middleclass 1.x there was a way around this (via a mixin) but for now I don’t recommend using this metamethod with classes. You will probably be better off using a pure Lua table instead, if you need that.
ފޮޅުވަތް 128:
Mixins can be used for sharing methods between classes, without requiring them to inherit from the same father.
 
<sourcesyntaxhighlight lang="lua">
local class = require 'middleclass'
HasWings = { -- HasWings is a module, not a class. It can be "included" into classes
ފޮޅުވަތް 156:
mw.log(bee:fly())
mw.log(bat:fly())
</syntaxhighlight>
</source>
 
Output:
ފޮޅުވަތް 169:
Mixins can provide a special function called 'included'. This function will be invoked when the mixin is included on a class, allowing the programmer to do actions. The only two parameters are the mixin (normally implicit) and the class.
 
<sourcesyntaxhighlight lang="lua">
local class = require('Module:Middleclass').class
DrinksCoffee = {}
ފޮޅުވަތް 211:
mw.log(juan:drink(5))
mw.log(juan:drink(6))
</syntaxhighlight>
</source>
 
Output:
ފޮޅުވަތް 233:
* One exception to this rule is when classes are declared inside packages in that case, they can be declared as follows:
 
<sourcesyntaxhighlight lang="lua">
MyClass = class('package.MyClass')
</syntaxhighlight>
</source>
 
* Another exception is for internal classes (classed declared inside classes)
 
<sourcesyntaxhighlight lang="lua">
MyClass = class('package.MyClass')
MyClass.InternalClass = class('package.MyClass.InternalClass')
</syntaxhighlight>
</source>
 
=== Attributes, instances and constants ===
ފޮޅުވަތް 258:
* Instance methods should be declared using the colons, so they have an implicit ‘self’ parameter:
 
<sourcesyntaxhighlight lang="lua">
function MyClass:setX(x)
self.x = x
end
</syntaxhighlight>
</source>
 
* Class methods should use the special property ‘static’ for being defined:
 
<sourcesyntaxhighlight lang="lua">
function MyClass.static:classMethod()
return 'I am the ' .. self.name .. ' class. I am awesome'
end
</syntaxhighlight>
</source>
 
* Private methods should be preceded with an underscore: <code>_myPrivateMethod</code>
ފޮޅުވަތް 297:
The simplest one is just to precede your attributes with underscores. This is actually written on the Lua 5.1 reference, section 2.1, “Lexical conversions”, as a way to say “this is here, but please don’t use it”.
 
<sourcesyntaxhighlight lang="lua">
local class = require('middleclass')
MyClass = class('MyClass')
ފޮޅުވަތް 305:
self.publicStuff = 2
end
</syntaxhighlight>
</source>
 
However, this isn’t really making the properties “hidden”.
ފޮޅުވަތް 315:
Example:
 
<sourcesyntaxhighlight lang="lua">
-- File 'MyClass2.lua'
local class = require('middleclass')
ފޮޅުވަތް 331:
return(_internalClassCounter)
end
</syntaxhighlight>
</source>
 
The scope of local declarations on a lua file is the file itself. If you declare something “local” in one file it is not available on others, even if they “require” that file.
 
<sourcesyntaxhighlight lang="lua">
-- File 'main.lua'
 
ފޮޅުވަތް 344:
 
mw.log(MyClass2:getCount()) -- prints "0"
</syntaxhighlight>
</source>
 
Let me explain what happens here. The _internalClassCounter = 4 line is, in reality, creating a new global variable called internalClassCounter, and assigning it 4. The “really internal” one is “out of reach” on main.lua (unless someone does really tricky stuff with the environments). So getCount() works as expected.
ފޮޅުވަތް 352:
It is also possible to declare private methods. The trick here is not to “include” them on the class definition. On the following example, we will not declare it on <code>Class3:secretMethod</code>; instead we’ll create a local function. Since we’re not using the : operator any more, we have to make the “self” parameter explicit. Also, since we have to make it local, we have to deviate from the “usual” way of declaring Lua functions (the “usual” way of declaring functions makes them global):
 
<sourcesyntaxhighlight lang="lua">
-- File 'MyClass3.lua'
local class = require('middleclass')
ފޮޅުވަތް 369:
return _secretMethod(self) .. ' You will never know it!'
end
</syntaxhighlight>
</source>
 
 
<sourcesyntaxhighlight lang="lua">
-- File 'Main.lua'
require('MyClass3')
ފޮޅުވަތް 380:
 
mw.log(_secretMethod(peter)) -- throws an error - _secretMethod is nil here.
</syntaxhighlight>
</source>
 
This technique also allows the creation of private class methods. In MiddleClass, there’s really no difference between class methods and instance methods; the difference comes from what you pass to their ‘self’ parameter. So if you invoke _secretMethod like this: _secretMethod(MyClass3) it will be a class method.
ފޮޅުވަތް 386:
A slightly more efficient way of creating a class method would be getting rid of the ‘self’ parameter and use MyClass3 directly on the method’s body:
 
<sourcesyntaxhighlight lang="lua">
MyClass3 = class('MyClass3')
 
ފޮޅުވަތް 399:
return( 'Being a public class named ' .. theClass.name .. ' is not a bad thing.' )
end
</syntaxhighlight>
</source>
 
This gives a bit more of flexibility when overriding public class methods on subclasses.
ފޮޅުވަތް 405:
Finally, a subtle point regarding recursive private methods. If you need to create a private method that calls himself, you will need to declare the variable first, and then (on the next line) initialize it with the function value. Otherwise the variable will not be available when the function is created
 
<sourcesyntaxhighlight lang="lua">
MyClass3 = class('MyClass3')
 
ފޮޅުވަތް 424:
m = MyClass3:new()
m:recurseOver(5)
</syntaxhighlight>
</source>
 
Output:
ފޮޅުވަތް 453:
-By the way, the following example also shows how you can do “read-only-ish attributes”: you make them private, and make getters for them, but not setters.
 
<sourcesyntaxhighlight lang="lua">
-- File 'MyClass4.lua'
local class = require('middleclass')
ފޮޅުވަތް 480:
return _private[self].gender
end
</syntaxhighlight>
</source>
 
 
<sourcesyntaxhighlight lang="lua">
-- File 'main.lua'
 
ފޮޅުވަތް 507:
mw.log(stewie:getGender()) -- 'male'
mw.log(stewie.gender) -- 'female'
</syntaxhighlight>
</source>
 
=== Private members on the same file ===
ފޮޅުވަތް 515:
Just create an artificial scope with do … end, and declare private members as ‘local’ inside that block. Only the methods inside that block will have access to them:
 
<sourcesyntaxhighlight lang="lua">
-- File 'MyClass3.lua'
local class = require('middleclass')
ފޮޅުވަތް 536:
 
-- functions outside the do-end will not 'see' secretMethod, but they will see MyClass3.shout (because they see MyClass3)
</syntaxhighlight>
</source>
 
== MIT License ==