Creating and using modules§
A module is usually a source file or set of source files that expose Raku constructs [1] .
Modules are typically packages (classes, roles, grammars), subroutines, and sometimes variables. In Raku module can also refer to a type of package declared with the module
keyword (see Module Packages and the examples below) but here we mostly mean "module" as a set of source files in a namespace.
Looking for and installing modules.§
zef
is the application used for installing modules in Raku. Modules are listed in the Raku ecosystem and can be searched there or from the command line using zef search
:
zef search WWW
will return a list of modules that includes WWW in their name, for instance. Then,
zef install WWW
will install the module with that particular name, if it is not already installed [2] .
Basic structure§
Module distributions (in the set of related source files sense) in Raku have the same structure as any distribution in the Perl family of languages: there is a main project directory containing a README
and a LICENSE
file, a lib
directory for the source files, which may be individually referred to as modules and/or may themselves define modules with the module
keyword [3]
, a t
directory for tests, and possibly a bin
directory for executable programs and scripts.
See filename extensions for current and historic extensions for various file types.
Loading and basic importing§
Loading a module makes the packages in the same namespace declared within available in the file scope of the loader. Importing from a module makes the symbols exported available in the lexical scope of the importing statement.
need
§
need
loads a compunit
at compile time.
need MyModule;
Any packages in the namespace defined within will also be available.
# MyModule.rakumodunit ;
MyModule::Class
will be defined when MyModule
is loaded, and you can use it directly employing its fully qualified name (FQN). Classes and other types defined that way are not automatically exported; you will need to explicitly export it if you want to use it by its short name:
# MyModule.rakumodunit ;is export
And then
use MyModule;my = Class.new();say .raku;
use
§
use
loads and then imports from a compunit at compile time. It will look for files that end in .rakumod
. See here for where the runtime will look for modules.
use MyModule;
This is equivalent to:
need MyModule;import MyModule;
See also selective importing to restrict what you import.
require
§
require
loads a compunit and imports definite symbols at runtime.
say "loading MyModule";require MyModule;
The compunit name can be in a runtime variable if you put it inside an indirect lookup.
my = 'MyModule';require ::();
The symbols provided by the loaded module will not be imported into the current scope. You may use dynamic lookup or dynamic subsets to use them by providing the fully qualified name of a symbol, for instance:
require ::("Test");my = ::("Test::EXPORT::DEFAULT::&ok");mmk('oi‽'); # OUTPUT: «ok 1 - »
The FQN of ok
is Test::EXPORT::DEFAULT::&ok
. We are aliasing it to mmk
so that we can use that symbol provided by Test
in the current scope.
To import symbols you must define them at compile time. NOTE: require
is lexically scoped:
sub do-somethingsay ::('MyModule'); # This will NOT contain the MyModule symboldo-something();# &something will not be defined here
If MyModule
doesn't export &something
then require
will fail.
A require
with compile-time symbol will install a placeholder package
that will be updated to the loaded module, class, or package. Note that the placeholder will be kept, even if require failed to load the module. This means that checking if a module loaded like this is wrong:
# *** WRONG: ***try require Foo;if ::('Foo') ~~ Failure# *** WRONG: ***
As the compile-time installed package causes ::('Foo')
to never be a Failure
. The correct way is:
# Use return value to test whether loading succeeded:(try require Foo) === Nil and say "Failed to load Foo!";# Or use a runtime symbol lookup with require, to avoid compile-time# package installation:try require ::('Foo');if ::('Foo') ~~ Failure
In the current (6.d) version of the language, require
d symbols are no longer transitively exposed, which means that you need to import symbols from the module they were originally declared, not from the module where they have been imported.
Lexical module loading§
Raku takes great care to avoid global state, i.e. whatever you do in your module, it should not affect other code. For instance, that's why subroutine definitions are lexically (my
) scoped by default. If you want others to see them, you need to explicitly make them our
scoped or export them.
Classes are exported by default on the assumption that loading a module will not be of much use when you cannot access the classes it contains. Loaded classes are thus registered only in the scope which loaded them in the first place [4]
. This means that we will have to use
a class in every scope in which we actually employ it.
use Foo; # Foo has "use Bar" somewhere.use Bar;my = Foo.new;my = Bar.new;
Exporting and selective importing§
is export§
Packages, subroutines, variables, constants, and enums are exported by marking them with the is export trait (also note the tags available for indicating authors and versions).
unit :ver<1.0.3>:auth<John Hancock (jhancock@example.com)>;our is export = 3;sub foo is export ;constant FOO is export = "foobar";is export <one two three>;# for multi methods, if you declare a proto you# only need to mark the proto with is exportproto quux(Str , |) is export ;multi quux(Str ) ;multi quux(Str , ) ;# for multi methods, you only need to mark one with is export# but the code is most consistent if all are markedmulti quux(Str ) is export ;multi quux(Str , ) is export ;# Packages like classes can be exported toois export ;# If a subpackage is in the namespace of the current package# it doesn't need to be explicitly exported;
As with all traits, if applied to a routine, is export
should appear after any argument list.
sub foo(Str ) is export
You can pass named parameters to is export
to group symbols for exporting so that the importer can pick and choose. There are three predefined tags: ALL
, DEFAULT
and MANDATORY
.
# lib/MyModule.rakumodunit ;sub bag is export# objects with tag ':MANDATORY' are always exportedsub pants is export(:MANDATORY)sub sunglasses is export(:day)sub torch is export(:night)sub underpants is export(:ALL)
# main.rakuuse lib 'lib';use MyModule; # bag, pantsuse MyModule :DEFAULT; # the sameuse MyModule :day; # pants, sunglassesuse MyModule :night; # pants, torchuse MyModule :ALL; # bag, pants, sunglasses, torch, underpants
Note: there currently is no way for the user to import a single object if the module author hasn't made provision for that, and it is not an easy task at the moment (see RT #127305). One way the author can provide such access is to give each export
trait its own unique tag. (And the tag can be the object name!). Then the user can either (1) import all objects:
use Foo :ALL;
or (2) import one or more objects selectively:
use Foo :bar, :s5;
Notes:
1. The :MANDATORY
tag on an exported sub ensures it will be exported no matter whether the using program adds any tag or not.
2. All exported subs without an explicit tag are implicitly :DEFAULT
.
3. The space after the module name and before the tag is mandatory.
4. Multiple import tags may be used (separated by commas). For example:
# main.rakuuse lib 'lib';use MyModule :day, :night; # pants, sunglasses, torch
5. Multiple tags may be used in the export
trait, but they must all be separated by either commas, or whitespace, but not both.
sub foo() is export(:foo :s2 :net)sub bar() is export(:bar, :s3, :some)
UNIT::EXPORT::*§
Beneath the surface, is export
is adding the symbols to a UNIT
scoped package in the EXPORT
namespace. For example, is export(:FOO)
will add the target to the UNIT::EXPORT::FOO
package. This is what Raku is really using to decide what to import.
unit ;sub foo is exportsub bar is export(:other)
Is the same as:
unit ;mymy
For most purposes, is export
is sufficient but the EXPORT
packages are useful when you want to produce the exported symbols dynamically. For example:
# lib/MyModule.rakumodunit ;my
# main.rakuuse MyModule;say sqrt-of-four; # OUTPUT: «2»say log-of-zero; # OUTPUT: «-Inf»
EXPORT§
You can export arbitrary symbols with an EXPORT
sub. EXPORT
must return a Map
, where the keys are the symbol names and the values are the desired values. The names should include the sigil (if any) for the associated type.
# lib/MyModule.rakumodsub EXPORT
Which is going to be used from this main file:
# main.rakuuse lib 'lib';use MyModule;say ; # OUTPUT: «one»say ; # OUTPUT: «(one two three)»say ; # OUTPUT: «{one => two, three => four}»doit(); # OUTPUT: «Greetings from exported sub»say ShortName.new; # OUTPUT: «MyModule::Class.new»
Please note that EXPORT
can't be declared inside a package because it is part of the compunit rather than the package.
Whereas UNIT::EXPORT
packages deal with the named parameters passed to use
, the EXPORT
sub handles positional parameters. If you pass positional parameters to use
, they will be passed to EXPORT
. If a positional is passed, the module no longer exports default symbols. You may still import them explicitly by passing :DEFAULT
to use
along with your positional parameters.
# lib/MyModulesub EXPORT(?)sub always is export(:MANDATORY)#import with :ALL or :DEFAULT to getsub shy is export
Used from this main program
# main.rakuuse lib 'lib';use MyModule 'foo';say foo.new(); # OUTPUT: «MyModule::Class.new»always(); # OK - is importedshy(); # FAIL - «shy used at line 8. Did you mean 'say'?»
You can combine EXPORT
with type captures for interesting effect. This example creates a ?
postfix which will only work on Cool
s; please note that, by using $_
as an argument, we don't need to use a variable in the routine body and use just .so
, acting by default on the topic variable.
# lib/MakeQuestionable.rakumodsub EXPORT(::Questionable)
Which is used from here:
use lib 'lib';use MakeQuestionable Cool;say ( 0?, 1?, ?, %( a => "b" )? ).join(' '); # OUTPUT: «False True False True»
Introspection§
To list exported symbols of a module first query the export tags supported by the module.
use URI::Escape;say URI::Escape::EXPORT::.keys;# OUTPUT: «(DEFAULT ALL)»
Then use the tag you like and pick the symbol by its name.
say URI::Escape::EXPORT::DEFAULT::.keys;# OUTPUT: «(&uri-escape &uri-unescape &uri_escape &uri_unescape)»my = URI::Escape::EXPORT::DEFAULT::<&uri_escape>;
Be careful not to put sub EXPORT
after unit
declarator. If you do so, it'll become just a sub inside your package, rather than the special export sub:
unit ;sub EXPORT # WRONG!!! Sub is scoped wrong
As explained in its definition, sub EXPORT
is part of the compunit, not the package. So this would be the right way to do it:
sub EXPORT # RIGHT!!! Sub is outside the moduleunit ;
Finding installed modules§
It is up to the module installer to know where compunit
expects modules to be placed. There will be a location provided by the distribution and in the current home directory. In any case, letting the module installer deal with your modules is a safe bet.
cd your-module-dir
zef --force install .
A user may have a collection of modules not found in the normal ecosystem, maintained by a module or package manager, but needed regularly. Instead of using the use lib
pragma one can use the RAKULIB
environment variable to point to module locations. For example:
export RAKULIB=/path/to/my-modules,/path/to/more/modules
Note that the comma (',') is used as the directory separator.
The directories in the RAKULIB
path will be searched for modules when Raku need
s, use
s or require
s them. Directories that start with a dot are ignored and symlinks are followed.
To avoid performance penalties at module load time, you may need to ensure that directories added to this path are not too large; see here for more information.
Testing modules and a distribution§
It is important in this section to repeat the note at the beginning of this document, namely that there is a difference between a Raku distribution
, which approximates a module in other languages, and a Raku module declaration. The reason for this is that a single file may contain a number of class
, module
, role
etc declarations, or these declarations may be spread between different files. In addition, when a distribution
is published (see Distributing modules) it may be necessary to provide access to other resources, such as callable utilities.
Raku also allows for a single distribution to provide multiple compunit
s that can be use
d (or require
d etc). The information about a distribution is contained in the META6.json
file in the distribution's root directory. See below for more about META6.json
. Each entity that the distribution allows to be use
d (or require
d etc), also called a compunit
, is placed in the provides
section of the META6.json
(as specified below).
It should also be noted that when writing the depends
section of the META6.json
file, it is the name of the distribution that is listed, not the name of the compunit
that is desired. Although, for very many entities, the name of the distribution and the name of the compunit are the same. Another global effect of the depends
list in a distribution made available to the Ecosystem, is that package managers, e.g. zef
, can look for compunit
names in all distributions available.
Given this arrangement, the rakudo compiler, or a package manager such as zef, can obtain all the information needed about each compunit
from a META6.json
file in a directory.
This also means that a testing program such as Perl's prove
or the Raku equivalent prove6 can be run in the root directory of the distribution as, e.g.,
prove -e 'raku -I.'
or
prove6 -I.
In both cases, the testing program looks for a directory t/
and runs the test programs there (see Testing).
The parameter -I., rather than -Ilib, in the examples above is significant because then the compiler will inspect the META6.json
file in the root directory of the distribution.
If you are just beginning to develop a module (or series of modules), and you have not decided what to call or where to place the code (perhaps splitting it into several *.rakumod
files), but assuming all the module files are under the lib/
directory, then it is possible to use
prove6 -Ilib
This is deceptive. A distribution may pass all the tests based on local files, and it may pass release steps, but the distribution (and the modules/classes/roles it contains) may not be automatically installed. To give a common example, but not the only way this problem can manifest itself, if the distribution is listed in the depends
section of another distribution, and a user is trying to install the other distribution using zef
(or a package manager using the same testing regime), perhaps using a CLI command zef install --deps-only .
, then zef
arranges for the tests of the dependent modules based on -I. and not -Ilib
. This will lead to rakudo errors complaining about the absence of named compunits unless the META6.json file is correct.
The most basic test that should be run for each compunit
that is defined for the distribution is
use-ok 'MyModule';
assuming inside META6.json
there is a line such as
provides: { "MyModule": "lib/MyModule.rakumod" },
It is also highly recommended to use the Test::META
meta-ok
test, which verifies the validity of the META6.json
file. If you wish to add a distribution (module) to the Ecosystem
, then this test will be applied to the distribution.
Since meta-ok
only needs to be tested by the developer/maintainer of a module, it can be within a set of extended tests in another directory, e.g. /xt
. This is because prove6
, for example, only runs the tests in t/
by default. Then to run the extended tests:
prove6 -I. xt/
Indeed it is becoming common practice by Raku community developers to place the extensive testing of a distribution in xt/
and to put minimal sanity tests in t/
. Extensive testing is essential for development and quality control, but it can slow down the installation of popular distributions.
An alternative to placing the meta-ok
test in an extended test directory, but to ensure that it is only run when a developer or maintainer wants to, is to make the test dependent on an environment variable, e.g., in t/99-author-test.rakutest
there is the following code
use Test;plan 1;if ?<AUTHOR_TESTING>else
Then when testing the module by the developer, use
AUTHOR_TESTING=1 prove6 -I.
Distributing modules§
If you've written a Raku module and would like to share it with the community, we'd be delighted to have it listed in the Raku modules directory. :)
Currently, there are three ways to distribute a module. No matter which method you choose, your module will be indexed on the raku.land and raku.land websites. The three module distribution networks, or ecosystems, are:
zef ecosystem using the
fez
module uploader utility. Use of thefez
command is the newest and perhaps easiest way to distribute your module and is growing in popularity.CPAN This is the same ecosystem Perl is using. Modules are uploaded as .zip or .tar.gz files on PAUSE.
p6c Up until recently the only ecosystem. It is based on Github repositories which are directly accessed. It has only limited capability for versioning.
The process of sharing your module consists of two steps, preparing the module and uploading the module to one of the ecosystems mentioned above. More details on the two steps are below.
Preparing the module§
For a module to work in any of the ecosystems, it needs to follow a certain structure. Here is how to do that:
Using a dist manager§
fez
Run the commands:
fez init MyNew::Module # Will create the following: # MyNew--Module/ # ├── lib # │ └── MyNew # │ └── Module.rakumod # ├── META6.json # └── t # └── 00-use.rakutest
If you need to add new modules, classes, resources, build-depends, or depends you may use the following (respectively, these resources will automatically be added to META6.json):
fez module My::New::Module fez module --class My::New::Module fez resource xyz fez depends --build Build::Dependency fez depends Runtime::Dependency
Manually§
Create a project directory named after your module. For example, if your module is
Vortex::TotalPerspective
, then create a project directory namedVortex-TotalPerspective
.Make your project directory look like this:
Vortex-TotalPerspective/ ├── lib │ └── Vortex │ └── TotalPerspective.rakumod ├── LICENSE ├── META6.json ├── README.md └── bin │ └── vortex └── t └── basic.rakutest
If your project contains other modules that help the main module do its job, they should go in your lib directory like so:
lib └── Vortex ├── TotalPerspective.rakumod └── TotalPerspective ├── FairyCake.rakumod └── Gargravarr.rakumod
If you have any additional files (such as templates or a dynamic library) that you wish to have installed so you can access them at runtime, they should be placed in a
resources
subdirectory of your project, e.g.:resources └── templates └── default-template.mustache
The file must then be referenced in
META6.json
(see below for more onMETA6.json
) so that the distribution path can be provided to the program.{ "name" : "Vortex::TotalPerspective", "provides" : { "Vortex::TotalPerspective" : "lib/Vortex/TotalPerspective.rakumod" }, "resources": [ "templates/default-template.mustache"] }
The additional file can then be accessed inside module code. Note the example here is returning a
Distribution::Resource
object. It should not be considered as a path to an object in the filesystem.my = <templates/default-template.mustache>.slurp;Programs and scripts that you need in the
$PATH
for execution need to be included in thebin
directory; these will be copied to whatever directory your installed Rakudo distribution has allotted for executables; typically this will be/path/to/installation/share/perl6/site/bin/
, a folder that should be available in$PATH
. Note: the perl6 path component predates the language name change.The
README.md
file is a markdown-formatted text file, which will later be automatically rendered as HTML by GitHub/GitLab for modules kept in those ecosystems or by raku.land website for modules kept on CPAN.Regarding the
LICENSE
file, if you have no other preference, you might just use the same one that Rakudo Raku uses. Just copy/paste the raw form of its license into your ownLICENSE
file.The license field in META6.json should be one of the standardized names listed here: https://spdx.org/licenses/. In the case of the Artistic 2.0 license, which is what many of our ecosystem modules use, its identifier is
Artistic-2.0
. Having standardized identifiers make it easy for humans and computers alike to know which license was actually used by looking at the metadata!If you can't find your license on
spdx.org
or you use your own license, you should put the license's name in the license field. For more details see https://design.raku.org/S22.html#license.If you don't yet have any tests, you can leave out the
t
directory andbasic.rakutest
file for now. For more information on how to write tests (for now), you might have a look at how other modules useTest
.To document your modules, use Raku Pod markup inside them. Module documentation is most appreciated and will be especially important once the Raku module directory (or some other site) begins rendering Pod docs as HTML for easy browsing. If you have extra docs (in addition to the Pod docs in your module(s)), create a
doc
directory for them. Follow the same folder structure as thelib
directory like so:doc └── Vortex └── TotalPerspective.rakudoc
If your module requires extra processing during installation to fully integrate with and use non-Raku operating system resources, you may need to add a
Build.rakumod
file (a "build hook") to the top-level directory. It will be used by thezef
installer as the first step in the installation process. See the README forzef
for a brief example. Also see various usage scenarios in existing ecosystem modules such aszef
itself.Make your
META6.json
file look something like this:{ "raku" : "6.c", "name" : "Vortex::TotalPerspective", "api" : "1", "auth" : "github:SomeAuthor", "version" : "0.0.1", "description" : "Wonderful simulation to get some perspective.", "authors" : [ "ÿÿ<var>ÿÿYour Nameÿÿ</var>ÿÿ" ], "license" : "Artistic-2.0", "provides" : { "Vortex::TotalPerspective" : "lib/Vortex/TotalPerspective.rakumod" }, "depends" : [ ], "build-depends" : [ ], "test-depends" : [ ], "resources" : [ ], "tags": [ "Vortex", "Total", "Perspective" ], "source-url" : "git://github.com/ÿÿ<var>ÿÿyouÿÿ</var>ÿÿ/Vortex-TotalPerspective.git" }
The attributes in this file are analyzed by the
META6
class. They are divided into optional, mandatory and customary. Mandatory are the ones you need to insert into your file, and customary are those used by the current Raku ecosystem and possibly displayed on the module page if it's published, but you have no obligation to use it.For choosing a version numbering scheme, try and use "major.minor.patch" (see the spec on versioning for further details). This will go into the
version
key ofMETA6.json
. This field is optional, but used by installation to match against installed version, if one exists. Thedescription
field is also mandatory, and includes a short description of the module.The
name
key is compulsory, andzef
will fail if you do not include it. Even if you have created a META6.json file just to express the dependencies for a series of scripts, this section must be included.Optionally, you can set an
api
field. Incrementing this indicates that the interface provided by your module is not backwards compatible with a previous version. You can use it if you want to adhere to Semantic Versioning. A best practice is to simply keep theapi
field to the same value as your major version number. A dependency can then depend on your module by including an:api
part, which will ensure backwards incompatible releases will not be pulled in.The
auth
section identifies the author in GitHub or other repository hosting site, such as Bitbucket or GitLab. This field is customary, since it's used to identify the author in the ecosystem, and opens the possibility of having modules with the same name and different authors.The
authors
section includes a list of all the module authors. In the case there is only one author, a single element list must be supplied. This field is optional.In the
provides
section, include all the namespaces provided by your distribution and that you wish to be installed; only module files that are explicitly included here will be installed and available withuse
orrequire
in other programs. This field is mandatory.Set
raku
version to the minimum Raku version your module works with. This field is mandatory. Use6.c
if your module is valid for Christmas release and newer ones, use6.d
if it requires, at least the Diwali version.The
resources
section is optional, but if present, should contain a list of the files in yourresources
directory that you wish to be installed. These will be installed with hashed names alongside your library files. Note: Accessing these files via%?RESOURCES
is not getting their installed locations or anIO
class: You are accessing aDistribution::Resource
. object indexed on the name provided.The
tags
section is also optional. It is used to describe the module in the Raku ecosystem.The
depends
,build-depends
, andtest-depends
sections include different modules that are used in those phases of the of installation. All are optional, but if present must contain the required modules for those phases. These dependencies might optionally useVersion
specification strings;zef
will check for the presence and versions of these modules and install or upgrade them if needed.//... "depends": [ "URI", "File::Temp", "JSON::Fast", "Pod::To::BigPage:ver<0.5.0+>", "Pod::To::HTML:ver<0.6.1+>", "OO::Monitors", "File::Find", "Test::META" ], //...
Additionally,
depends
can be either an array as above or a hash that uses two keys,runtime
andbuild
, whose function should be self-descriptive, and which are used, for instance, inInline::Python
://... "depends" : { "build": { "requires": [ "Distribution::Builder::MakeFromJSON", { "from" : "bin", "name" : { "by-distro.name" : { "macosx" : "python2.7-config", "debian" : "python2.7-config", "" : "python2-config" } } } ] }, "runtime": { "requires": [ "python2.7:from<native>" ] } }, // ...
In general, the array form will be more than enough for most cases.
Finally,
source-url
indicates the URL of the repository where the module is developed; this is one of the customary modules if you are going to publish it in the module ecosystem. The current module ecosystem will link this URL from the project description. [6]The
Test::META
module can help you check the correctness of the META6.json file; this module will check for all the mandatory fields and that the type used for all of them is correct.There are more fields described in the
META
design documents, but not all of these are implemented by existing package managers. Hence you should stick to the fields described in the above example block to ensure compatibility with existing package managers such aszef
. You can also check Moritz Lenz's repository of all modules for examples, but bear in mind that some of them might use fields, such assource-type
above, which are currently ignored.If you want to test your module you can use the following command to install the module directly from the module folder you just created.
zef install ./your-module-folder
Note that doing so precompiles and installs your module. If you make changes to the source, you'll need to re-install the module. (See
use lib
pragma,-I
command line switch, orRAKULIB
environment variable, to include a path to your module source while developing it, so you don't have to install it at all).
Upload your module to CPAN§
A prerequisite for using CPAN is a PAUSE user account. If you don't have an account already, you can create one here The process takes about 5 minutes and some e-mail back and forth.
Create a package of your module:
cd your-module-folder tar czf Vortex-TotalPerspective-0.0.1.tar.gz \ --transform s/^\./Vortex-TotalPerspective-0.0.1/ --exclude-vcs\ --exclude=.[^/]*
If you use git you can also use the following command to create a package directly for a given commit.
git archive --prefix=Vortex-TotalPerspective-0.0.1/ \ -o ../Vortex-TotalPerspective-0.0.1.tar.gz HEAD
Go to PAUSE, log in and navigate to
Upload a file to CPAN
.Make sure you select
Perl6
as the Target Directory. For your first upload, you have to enter the stringPerl6
in the text field. On subsequent uploads, you can select thePerl6
directory from the selection box right below the input field.Select your file and click Upload! If everything was fine with your dist, you should see your module tar file in your
Perl6
directory along with both aMETA
and aREADME
file named after your module filename.Make sure you have a META6.json file in your dist and that the dist version you're uploading is higher than the currently uploaded version. Those are the most common upload errors.
Upload your module to zef ecosystem§
If you want to use the zef ecosystem then you need to register your username using fez.
Install fez if you haven't done so already
zef install fez
Register your user with zef's ecosystem
fez register
>>= Email: your@email.com
>>= Username: username
>>= Password:
>>= registration successful, requesting auth key
>>= login successful, you can now upload dists
Now you can upload your module!
Before doing the following, ensure your META6.json
file's auth
matches zef:<username>
and then:
fez upload
>>= Vortex::TotalPerspective:ver<0.1.2>:auth<zef:username> looks OK
>>= Hey! You did it! Your dist will be indexed shortly
Versioning and fez§
To prevent changes to a versioned distribution (remember a distribution may contain more than one module), only one upload of a distribution per version is permitted. If a developer makes changes to code in a repository, the changes will not be reflected in the
fez
system. So changes to code must be accompanied by a bump in the version number and the new version uploaded tofez
.
Upload your module to p6c§
The Raku community is migrating to the fez ecosystem (see above). For developers who have modules on the p6c ecosystem and migrated them to fez, please remove them from the p6c ecosystem. If you do not have the commit bit, open a pull request or ping someone on IRC (#raku at libera.chat) to get help.
If you want to use the p6c ecosystem you need to use git for your module's version control. The instructions herein assume that you have a GitHub account so that your module can be shared from its GitHub repository, however another provider such as GitLab should work as long as it works in a similar way.
Put your project under git version control if you haven't done so already.
Once you're happy with your project, create a repository for it on GitHub. See GitHub's help docs if necessary. Your GitHub repository should be named the same as your project directory. Immediately after creating the GitHub repo, GitHub shows you how to configure your local repository to know about your GitHub repository.
Push your project to GitHub.
Consider setting up automated testing. One option is to use the github workflows functionality, and an example can be found for the Mi6-Helper App.
Create a PR (Pull Request) on ecosystem adding your module to META.list, or ping someone on IRC (#raku at libera.chat) to get help having it added.
After the pull request has been accepted, wait for an hour. If your module doesn't show up on https://raku.land/, please view the log file to see if it identifies an error with your module or
meta
file.
That's it! Thanks for contributing to the Raku community!
If you'd like to try out installing your module, use the zef module installer tool which is included with Rakudo Star Raku:
zef install Vortex::TotalPerspective
This will download your module to its own working directory (~/.zef
), build it there, and install the module into your local Raku installation directory.
To use Vortex::TotalPerspective
from your scripts, just write use Vortex::TotalPerspective
, and your Raku implementation will know where to look for the module file(s).
Modules and tools related to module authoring§
You can find a list of modules and tools that aim to improve the experience of writing/test modules at Modules Extra
Contact information§
To discuss module development in general, or if your module would fill a need in the ecosystem, naming, etc., you can use the #raku on irc.libera.chat IRC channel.
A repository to discuss tooling issues is available at https://github.com/Raku/toolchain-bikeshed.