1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
Tutorial: Adding verbs to objects online:
----------------------------------------
Perlmoo can be programmed online, by adding new verbs to objects.
The basics:
----------
Suppose we have a ball object, and we want to make it be able to bounce.
This is a two-step process - first we add the verb to the object, then we
add the actual code to the moo to make the bounce happen.
Adding the verb to the object is just a matter of using the "teach" command:
teach ball to bounce this none none
(See 'help teach' in the moo for the full syntax to this command.)
"teach ball to bounce this none none" means that for the bounce verb to take
effect, the user must enter the following command:
"bounce ball"
Now to tell the moo what to do if the ball is bounced:
verbcode ball bounce "return 'It bounces!'"
(See 'help verbcode' in the moo for the full syntax to this command.)
Now when someone types "bounce ball", they get back "It bounces!". How'd
that work? Well, verbcode is a command that adds code into the moo to be run
when a verb is called. The code, "return 'It bounces!'", is run inside a
subroutine. Anything returned from the subroutine is displayed to the user.
More complex code:
-----------------
Let's get a little bit more complicated, and make the name of the ball be
output when it bounces:
verbcode ball bounce "$this=shift; return 'The '.$this->name.' bounces!'"
Remember, this code is running inside a subroutine. The subroutine is passed
at least 2 parameters - the first is the object that the subroutine is a
verb of. (The second is a VerbCall, which lets you see what parameters the
user entered.) So, when we do:
$this=shift;
$this is now set to be the ball object. And so $this->name will call the name
method of the ball, and return the ball's name.
Let's try one more thing - it'd be nice if when the ball bounced, everyone
else in the same room as it saw it bounce. I've written this as a multi-line
construct so you can follow it easily, but you'll have to flatten the code
ont into 1 single line to enter it into the moo:
verbcode ball bounce "
$this=shift;
$verbcall=shift;
$room=$verbcall->caller->location;
if ($room) {
$room->announce($verbcall->caller,
$verbcall->caller->name.
' bounces the '.$this->name.'.')
};
return 'The '.$this->name.' bounces!'
"
Notice that I'veused the verbcall object here to find out the name of who
bounced the ball (the caller), and where the caller is located.
See the contrib directory for more complex examples of objects.
Inheritance:
-----------
Every object in the moo has a parent, and will by default inherit all verbs
from the parent. That includes verbs that are coded online. For example:
create ball named egg
bounce egg
The egg inherited the ball's bounce verb. Of course, eggs are different than
balls - they don't bounce very well. So we could override the egg's bounce
verb to make it do something different:
verbcode egg bounce "$this=shift; return 'The '.$this->name.' cracks.'"
Now when we bounce the egg, we see it crack. But suppose we want to see it
bounce first - we can pull in the code from our parent object using the
super() method, as follows:
verbcode egg bounce "
$this=shift;
$verbcode=shift;
return $this->super($verbcode), 'The '.$this->name.' cracks.'
"
Now when the egg is bounced, the ball's bounce code is run first, and
returns "The egg bounces!". To that is added "The egg cracks.".
Moo infrastructure:
------------------
Here are a few things you should know about the moo infrastructure (very
sketchy right now):
* Every object in the moo is also a perl object.
* Every verb in the moo corresponds to a method in an object named verb_<name>.
* Any method of an object whose name ends in _safe, is a special "in-db"
method, that is actually contained in the moo database, and can be modified
online.
* There is a special object called a VerbCall that contains a parsed
command line. These get passed into verb methods to tell the methods what
to do. A verbcall basically contains the text the user entered in, parsed
some, so we can easily find the direct object, indirect object, etc.
* Another special object is a Verb. Each object in the moo may contain
several Verbs. A Verb is like a subroutine definition - it lets the moo
match lines of text entered by users to verb methods in objects.
* Finally, we have the Error object. Any function in the entire moo can
legally return an erro object, so be sure to test for them with
Error::iserror($ret). Error objects are basically how you raise an exception
to say something's not right. (Ie, return Error->new("whoops!"))
* Any property of an object that ends in _msg is intended to be a message
parsed by Text::subst.
* The file basedb.pl is to set up properties for base objects in the moo
core (as well as add verbs, help texts, etc). If you edit it, you may
need to change the moo db version number (in Db.pm), and run
perlmoo-dbconvert to get the changes into db.pl.
* Never use SUPER in perlmoo. This is because SUPER doesn't seem to work
when called from inside a safe. That's probably because of namespace
problems. There are currently 2 solutions:
1. For dealing with code that runs outside of a safe, ie, the core perlmoo
code, the crummy workaround I've came up with is to explicitly call your
parent package's method, ie, 'Container::location($this)'. Note though that
this means that if your parent package doesn't implement the method, but
_it's_ parent does, then, instead of the grandparren't method being called,
your parent actually inherits AUTOLOAD, which is called instead. So to work
around this, I have to add stub functions here and there. It's a mess.
2. For code that runs inside a safe, I actually have a much cleaner
solution. Just use $thing->super(@params) to call the overridden method.
Programming outside the moo:
---------------------------
I'm always greatful to those who send me patches and new code for the moo.
See the TODO and WISHLIST for ideas of stuff to work on.
|