Modules
Note! The current implementation of modules is quite bare-bones and will be expanded in the future. For example, it is not yet possible to import a module from within a module.
A simple module can be defined like this:
or in a file named the same as the the module you want to create:
export def hello [name: string] {
$"hello ($name)!"
}
export def hi [where: string] {
$"hi ($where)!"
}
We defined hello
and hi
custom commands inside a greetings
module.
The export
keyword makes it possible to later import the commands from the module.
Similar to def, it is also possible to mark with the export
keyword (you can learn more about def-env in the chapter).
Using modules
By itself, the module does not do anything. To use what the module exports, we need to it.
> use greetings
> greetings hello "world"
hello world!
> greetings hi "there"
hi there!
The hello
and hi
commands are now available with the greetings
prefix.
In general, anything after the use keyword forms an import pattern which controls how the symbols are imported. The import pattern can be one of the following:
use greetings
Imports all symbols with the module name as a prefix (we saw this in the previous example).
The hello
symbol will be imported directly without any prefix.
use greetings [ hello, hi ]
Imports multiple symbols directly without any prefix
use greetings *
You can also use the module name and the *
glob to import all names directly without any prefix
Module Files
Nushell lets you implicitly treat a source file as a module. Let’s start by saving the body of the module definition into a file:
# greetings.nu
export def hello [name: string] {
$"hello ($name)!"
}
export def hi [where: string] {
$"hi ($where)!"
}
Now, you can call use directly on the file:
Nushell automatically infers the module’s name from the stem of the file (“greetings” without the “.nu” extension). You can use any import patterns as described above with the file name instead of the module name.
Any custom commands defined in a module without the export
keyword will work only in the module’s scope:
# greetings.nu
export def hello [name: string] {
}
export def hi [where: string] {
greetings-helper "hi" "there"
}
def greetings-helper [greeting: string, subject: string] {
$"($greeting) ($subject)!"
}
Then, in Nushell we import all definitions from the “greetings.nu”:
> use greetings.nu *
> hello "world"
hello world!
> hi "there"
hi there!
> greetings-helper "foo" "bar" # fails because 'greetings-helper' is not exported
Environment Variables
So far we used modules just to import custom commands. It is possible to export environment variables the same way. The syntax is slightly different than what you might be used to from commands like let-env or :
# greetings.nu
export env MYNAME { "Arthur, King of the Britons" }
export def hello [name: string] {
$"hello ($name)"
}
You can notice we do not assign the value to MYNAME
directly. Instead, we give it a block of code ({ ...}
) that gets evaluated every time we call use. We can demonstrate this property, for example, with the command:
> module roll { export env ROLL { random dice | into string } }
> use roll ROLL
> $env.ROLL
4
> $env.ROLL
4
> use roll ROLL
> $env.ROLL
6
6
As mentioned above, you can export definitions and environment variables from modules. This lets you more easily group related definitions together and export the ones you want to make public.
You can also export aliases and externs, giving you a way to only use these features when you need. Exporting externs also gives you the ability to hide custom completion commands in a module, so they don’t have to be part of the global namespace.
Here’s the full list of ways you can export:
export def
- export a custom commandexport def-env
- export a custom environment commandexport env
- export an environment variableexport alias
- export an aliasexport extern
- export a known external definition
Hiding
Any custom command, alias or environment variable, imported from a module or not, can be “hidden”, restoring the previous definition. (Note, it is not yet possible to export aliases from modules but they can still be hidden.) We do this with the command:
> def foo [] { "foo" }
> foo
foo
> hide foo
> foo # error! command not found!
The hide command also accepts import patterns, just like . The import pattern is interpreted slightly differently, though. It can be one of the following:
hide foo
or hide greetings
- If the name is a custom command or an environment variable, hides it directly. Otherwise:
- If the name is a module name, hides all of its exports prefixed with the module name
hide greetings hello
- Hides only the prefixed command / environment variable
hide greetings [hello, hi]
- Hides only the prefixed commands / environment variables
hide greetings *
- Hides all of the module’s exports, without the prefix
Let’s show these with examples. We saw direct hiding of a custom command already. Let’s try environment variables:
> let-env FOO = "FOO"
> $env.FOO
FOO
> hide FOO
> $env.FOO # error! environment variable not found!
And finally, when the name is the module name (assuming the previous greetings
module):
> use greetings.nu
> $env."greetings MYNAME"
Arthur, King of the Britons
> greetings hello "world"
hello world!
> hide greetings
> $env."greetings MYNAME" # error! environment variable not found!
> greetings hello "world" # error! command not found!