|
| 1 | +## How to write your cog |
| 2 | + |
| 3 | +`;;` draws its main features from modules, named "cogs". |
| 4 | +Writing one is rather straightforward, but a couple rules have to be respected. |
| 5 | + |
| 6 | +### Match `[a-z][a-z_0-9]*\.py` |
| 7 | + |
| 8 | +Don't run away ~~yet~~! This simply means that the name of your file must be **full lowercase** and it has to start by a letter (any file starting with `_` or a digit will be ignored). Once you have that file, just drop it in the `cogs` folder and that's all. |
| 9 | + |
| 10 | +### Don't forget your tools |
| 11 | + |
| 12 | +Every cog must contain a `cog` variable, which has to be an instance of `gearbox.Cog`. Here's what a standard cog header looks like: |
| 13 | +```python |
| 14 | +import gearbox |
| 15 | +cog = gearbox.Cog() |
| 16 | +``` |
| 17 | +> By default, your cog's name will be the file name, minus the `.py` part. |
| 18 | +To change this, simply pass a new name as an argument to `gearbox.Cog()`. |
| 19 | + |
| 20 | +### Creating a command |
| 21 | + |
| 22 | +#### The basics |
| 23 | + |
| 24 | +If you're familiar with `discord.py`, then you probably know about `async`, `await` and all that stuff. If not, don't worry! You don't need that to write stuff. |
| 25 | + |
| 26 | +Every command must be "decorated" by placing `@cog.command` before its definition. After that step, it'll be recognized by `;;` as a command - as long as it has a valid name (see above). Here's a really simple command: |
| 27 | + |
| 28 | +```python |
| 29 | +@cog.command |
| 30 | +def hello(): |
| 31 | + return 'Hello, world!' |
| 32 | +``` |
| 33 | + |
| 34 | +Straightforward, right? Your command just have to return something, and `;;` will send it in the good channel. If you return nothing... Well, nothing happens. |
| 35 | +But what if you want it to greet someone specifically? |
| 36 | + |
| 37 | +#### Special arguments |
| 38 | + |
| 39 | +Greeting a user can be done very simply: |
| 40 | + |
| 41 | +```python |
| 42 | +@cog.command |
| 43 | +def hello(author): |
| 44 | + return 'Hello, %s!' % author.name |
| 45 | +``` |
| 46 | + |
| 47 | +> If you really aren't familiar with `discord.py`, have a look at [their documentation](http://discordpy.readthedocs.io/en/latest/). For very simple usage, you can get a user/channel/server name with `.name`. |
| 48 | +
|
| 49 | +> Wondering what this `%` thing does? Basically, it's the same as `'Hello, ' + author.name + '!'` but shorter and fancier. |
| 50 | +[Learn more here](https://docs.python.org/3.5/library/stdtypes.html#printf-style-string-formatting) |
| 51 | + |
| 52 | +As you can see, simply putting `author` in the function definition will give you the corresponding object. Why? Because `;;` is made in such a way that it'll look at what you want, and attempt to provide it to you so you don't need to write extra pieces of code. Here's a list of those "special" arguments: *(as of v0.1.0)* |
| 53 | + |
| 54 | +|Argument | Description |
| 55 | +|- |
| 56 | +|`client` | The application's `discord.Client()` |
| 57 | +|`message` | The Message object which was sent - don't use like a string! |
| 58 | +|`author` | Shortcut for `message.author` |
| 59 | +|`channel` | Shortcut for `message.channel` |
| 60 | +|`server` | Shortcut for `message.server` |
| 61 | + |
| 62 | +*Remember that using those will give you special values, which might not correspond to your expectations.* |
| 63 | + |
| 64 | +#### Normal arguments |
| 65 | + |
| 66 | +Now maybe you simply want to write a `repeat` command, but you don't know how to get the text? Just ask for it! |
| 67 | + |
| 68 | +```python |
| 69 | +@cog.command |
| 70 | +def repeat(what_they_said): |
| 71 | + return what_they_said |
| 72 | +``` |
| 73 | + |
| 74 | +When sending arguments to commands, `;;` will take care of special arguments, then send the rest of the message to the other arguments. If you need multiple arguments, just define them! |
| 75 | + |
| 76 | +```python |
| 77 | +@cog.command |
| 78 | +def add(number_a, number_b): |
| 79 | + return str(int(number_a) + int(number_b)) |
| 80 | +``` |
| 81 | + |
| 82 | +> *May change in future versions* |
| 83 | +If the user doesn't provide the arguments you need, for example if they type `add 4`, `;;` will send an empty string (`''`) for each missing arguments. |
| 84 | + |
| 85 | +> If the user sends too many arguments, for example by typing `add 1 2 3`, then your last argument will receive the extra information. Here, `number_a` would contain `'1'` but `number_b` would contain `'2 3'`. You can discard unwanted information by adding a third argument which will take it: |
| 86 | +```python |
| 87 | +def add(number_a, number_b, trash): |
| 88 | +``` |
| 89 | + |
| 90 | +#### More arguments! |
| 91 | + |
| 92 | +Let's say you want to have a command that takes a string, then a series of strings, and inserts that first string between all the others, i.e. `, 1 2 3` would give `1,2,3` - wow, that's just like `str.join()`! |
| 93 | +You'll want to have the first argument, then "all the rest". Of course, you could get away with using `def join(my_string, all_the_rest):` and then use `.split()`, but ;; can do that for you! Simply add `*` before your last argument, and it'll receive a nice little list of whatever was sent: |
| 94 | + |
| 95 | +```python |
| 96 | +@cog.command |
| 97 | +def join(my_string, *all_the_rest): |
| 98 | + return my_string.join(all_the_rest) |
| 99 | +``` |
| 100 | + |
| 101 | +#### About `async` and `await` |
| 102 | + |
| 103 | +What if you're an advanced user and you know all that async stuff already and just want to add your tasks to the event loop while awaiting coroutines? |
| 104 | + |
| 105 | +```python |
| 106 | +async def command(client): |
| 107 | +``` |
| 108 | + |
| 109 | +It's that simple. If your command is a coroutine, then `;;` will simply `await` it (if you want to send a message, do it yourself!); and the `client` argument will give you access to the main client. Hint, the loop is at `client.loop` |
| 110 | + |
| 111 | +### Decorating your command |
| 112 | + |
| 113 | +No, this isn't about adding a cute little ribbon onto it. *(as of v0.1.0)* |
| 114 | + |
| 115 | +You've already used the decorator `@cog.command` to indicate that your function was a `;;` command and not a random function. |
| 116 | +You can do a bit more, here, have a list: |
| 117 | + |
| 118 | +##### `@cog.rename(name)` |
| 119 | +This will change the name of your command. It's useful, for example, if you want your command to be called `str` but you can't because of Python's `str()` function. Just call your function `asdf` and put `@cog.rename('str')` before it. |
| 120 | + |
| 121 | +##### `@cog.alias(alias, ...)` |
| 122 | +This creates aliases for your command. Let's say you find `encrypt` is a quite long name, just add `@cog.alias('en')` and you'll be able to call your command with `encrypt` *and* `en`. |
| 123 | + |
| 124 | +##### `@cog.init` |
| 125 | +This doesn't apply to a command, but to a regular function - it marks it, so it will be called when the cog is loaded. You can only have one init function. |
| 126 | +> *Not yet implemented as of v0.1.0* |
| 127 | +
|
| 128 | +##### `@cog.exit` |
| 129 | +This doesn't apply to a command, but to a regular function - it marks it, so it will be called when the cog is unloaded. You can only have one exit function. |
| 130 | +> *Not yet implemented as of v0.1.0* |
| 131 | +
|
| 132 | +### Using your cog |
| 133 | + |
| 134 | +As written above, you just need to drop it in the `cogs` folder! |
| 135 | +If `;;` is running, it'll automatically load it within a couple of seconds, and reload it when you edit it. Don't worry, if you break stuff, it'll keep running the old code until the new one is working. |
| 136 | +If you have name conflicts with another module, call your commands with `cog_name.command_name` to avoid collisions. |
0 commit comments