dbks logo

deathbykeystroke

The Life of Raku Module Authoring

// date: 2021-12-22
// filed: rakudo, programming
// perma

Hello, world! This article is a lot about fez and how you can get started writing your first module and making it available to other users. Presuming you have rakudo and zef installed, install fez!

$ zef install fez
===> Searching for: fez
===> Updating fez mirror: https://360.zef.pm/
===> Updated fez mirror: https://360.zef.pm/
===> Testing: fez:ver<32>:auth<zef:tony-o>:api<0>
[fez]   Fez - Raku / Perl6 package utility
[fez]   USAGE
[fez]     fez command [args]
[fez]   COMMANDS
[fez]     register              registers you up for a new account
[fez]     login                 logs you in and saves your key info
[fez]     upload                creates a distribution tarball and uploads
[fez]     meta                  update your public meta info (website, email, name)
[fez]     reset-password        initiates a password reset using the email
[fez]                           that you registered with
[fez]     list                  lists the dists for the currently logged in user
[fez]     remove                removes a dist from the ecosystem (requires fully
[fez]                           qualified dist name, copy from `list` if in doubt)
[fez]     org                   org actions, use `fez org help` for more info
[fez]   ENV OPTIONS
[fez]     FEZ_CONFIG            if you need to modify your config, set this env var
[fez]   CONFIGURATION (using: /home/tonyo/.fez-config.json)
[fez]     Copy this to a cool location and write your own requestors/bundlers or
[fez]     ignore it and use the default curl/wget/git tools for great success.
===> Testing [OK] for fez:ver<32>:auth<zef:tony-o>:api<0>
===> Installing: fez:ver<32>:auth<zef:tony-o>:api<0>

1 bin/ script [fez] installed to:
/home/tonyo/.local/share/perl6/site/bin

Make sure that the last line is in your $PATH so the next set of commands all run smoothly. Now we can start writing the actual module, let's write ROT13 since it's a fairly easy problem to solve and this article really is less about module content than how to get working with fez.

Writing the Module

Our module directory structure:

.
├── lib
│   └── ROT13.rakumod
├── t
│   ├── 00-use.rakutest
│   └── 01-tests.rakutest
└── META6.json

lib is the main content of your module, it's where all of your module's utilities, helpers, and organization happens. Each file corresponds to one or more modules or classes, more on in the META6.json paragraph below.

META6.json is how zef knows what the module is, it's how fez knows what it's uploading, and it's how rakudo knows how to load what and from where. Let's take a look at the structure of META6.json:

t contains all of your module's tests. If you have "author only" tests then you'd also have a directory xt and that directory works roughly the same. For your users' sanity WRITE TESTS!

{
  "name": "ROT13",
  "auth": "zef:tony-o",
  "version": "0.0.1",
  "api": 0,

  "provides": {
    "ROT13": "lib/ROT13.rakumod"
  },

  "depends":       [],
  "build-depends": [],
  "test-depends":  [],

  "tags":        [ "ROT13", "crypto" ],
  "description": "ROT13 everything!"
}

A quick discussion about dists. A dist is the fully qualified name of your module and it contains the name, auth, and version. It's how zef can differentiate your ROT13 module from mine. It works in conjunction with use, such as use ROT13:auth<zef:tony-o>, and in zef: zef install ROT13:auth<tony-o>:ver<0.0.1>. The dist string is always qualified with both the :auth and the :ver internally to raku and the ecosystem, but the end user isn't required to type the fully qualified dist if they're less picky about what version/author of the module they'd like. In use statements you can combine auth and ver to get the author or version you're expecting or you can omit one or both.

It's better practice to fully qualify your use statements; as more modules hit the ecosystem with the same name, this practice will help keep your modules running smoothly.

Let's whip up a quick ROT13 module, in lib/ROT13.rakumod dump the following

unit module ROT13;

sub rot13(Str() $_) is export { .trans('a..zA..Z'=>'n..za..mN..ZA..Z') }

Great, you can test it now (from the root of your module directory) with raku -I. -e 'use ROT13; say rot13("hello, WoRlD!");. You should get output of uryyb, JbEyQ!.

Now fill in your test files and run the tests with zef test .

Publishing Your Module

Register

If you're not registered with fez, now's the time!

$ fez register
>>= Email: omitted@somewhere.com
>>= Username: tony-o
>>= Password:
>>= Registration successful, requesting auth key
>>= Username: tony-o
>>= Password:
>>= Login successful, you can now upload dists

Check Yourself

$ fez checkbuild
>>= Inspecting ./META6.json
>>= meta<provides> looks OK
>>= meta<resources> looks OK
>>= ROT13:ver<0.0.1>:auth<zef:tony-o> looks OK

Oh snap, we're lookin' good!

Publish

$ fez upload
>>= Hey! You did it! Your dist will be indexed shortly.

Only thing to note here is that if there's a problem indexing your module then you'll receive an email with the gripe.

Further Reading

You can read more about fez here:

Perhaps you'd prefer listening:

That's it! If there's other things you'd like to know about fez, zef, or ecosystems then send tony-o some chat in IRC or an email!