From ac759fbd6bbb510fa50ed149b37665a314c440fc Mon Sep 17 00:00:00 2001 From: NotTheDr01ds <32344964+NotTheDr01ds@users.noreply.github.com> Date: Sun, 27 Oct 2024 16:03:31 -0400 Subject: [PATCH 1/3] Module chapter rewrite --- .vuepress/configs/sidebar/en.ts | 11 +- book/modules.md | 538 +------------------------------ book/modules/creating_modules.md | 473 +++++++++++++++++++++++++++ book/modules/using_modules.md | 234 ++++++++++++++ book/standard_library.md | 84 +---- cookbook/modules.md | 71 ++++ 6 files changed, 814 insertions(+), 597 deletions(-) create mode 100644 book/modules/creating_modules.md create mode 100644 book/modules/using_modules.md create mode 100644 cookbook/modules.md diff --git a/.vuepress/configs/sidebar/en.ts b/.vuepress/configs/sidebar/en.ts index 1b0b6a9ea14..b4bcf5f2fec 100644 --- a/.vuepress/configs/sidebar/en.ts +++ b/.vuepress/configs/sidebar/en.ts @@ -51,7 +51,15 @@ export const sidebarEn: SidebarConfig = { '/book/variables.md', '/book/control_flow.md', '/book/scripts.md', - '/book/modules.md', + { + text: 'Modules', + link: '/book/modules.md', + collapsible: false, + children: [ + '/book/modules/using_modules.md', + '/book/modules/creating_modules.md', + ], + }, '/book/overlays.md', '/book/testing.md', '/book/style_guide.md', @@ -145,6 +153,7 @@ export const sidebarEn: SidebarConfig = { '/cookbook/foreign_shell_scripts', '/cookbook/pattern_matching', '/cookbook/external_completers', + '/cookbook/modules', '/cookbook/files', '/cookbook/git', '/cookbook/parsing_git_log', diff --git a/book/modules.md b/book/modules.md index 3c28ea29e5b..8a7692a79ab 100644 --- a/book/modules.md +++ b/book/modules.md @@ -1,534 +1,14 @@ # Modules -Similar to many other programming languages, Nushell also has modules to organize your code. Each module is a "bag" containing a bunch of definitions (typically commands) that you can export (take out of the bag) and use in your current scope. Since Nushell is also a shell, modules allow you to modify environment variables when importing them. +Like many programming languages, Nushell supports writing and using _modules_ as a way to organize code more efficiently. Modules can be thought of a "containers" that hold various definitions, including: -## Quick Overview +- Additional custom commands +- Aliases +- Constants +- Environment variables +- And even other modules (a.k.a., submodules) -There are three ways to define a module in Nushell: +Many users will start off using modules written by others, then progress to writing their own. This chapter covers those two topics: -1. "inline" - - `module spam { ... }` -2. from a file - - using a .nu file as a module -3. from a directory - - directory must contain a `mod.nu` file - -In Nushell, creating a module and importing definitions from a module are two different actions. The former is done using the `module` keyword. The latter using the `use` keyword. You can think of `module` as "wrapping definitions into a bag" and `use` as "opening a bag and taking definitions from it". In most cases, calling `use` will create the module implicitly, so you typically don't need to use `module` that much. - -You can define the following things inside a module: - -- Commands\* (`def`) -- Aliases (`alias`) -- Known externals\* (`extern`) -- Submodules (`module`) -- Imported symbols from other modules (`use`) -- Environment setup (`export-env`) - -Only definitions marked with `export` are possible to access from outside the module ("take out of the bag"). Definitions not marked with `export` are allowed but are visible only inside the module (you could call them private). (_`export-env` is special and does not require `export`._) - -_\*These definitions can also be named `main` (see below)._ - -## "Inline" Modules - -The simplest (and probably least useful) way to define a module is an "inline" module can be defined like this: - -```nu -module greetings { - export def hello [name: string] { - $"hello ($name)!" - } - - export def hi [where: string] { - $"hi ($where)!" - } -} - -use greetings hello - -hello "world" -``` - -_You can paste the code into a file and run it with `nu`, or type into the REPL._ - -First, we create a module (put `hello` and `hi` commands into a "bag" called `greetings`), then we import the `hello` command from the module (find a "bag" called `greetings` and take `hello` command from it) with `use`. - -## Modules from Files - -A .nu file can be a module. Just take the contents of the module block from the example above and save it to a file `greetings.nu`. The module name is automatically inferred as the stem of the file ("greetings"). - -```nu -# greetings.nu - -export def hello [name: string] { - $"hello ($name)!" -} - -export def hi [where: string] { - $"hi ($where)!" -} -``` - -then - -```nu -> use greetings.nu hello - -> hello -``` - -The result should be similar as in the previous section. - -::: tip Note -Note that the `use greetings.nu hello` call here first implicitly creates the `greetings` module, -then takes `hello` from it. You could also write it as `module greetings.nu`, `use greetings hello`. -Using `module` can be useful if you're not interested in any definitions from the module but want to, -e.g., re-export the module (`export module greetings.nu`). -::: - -## Modules from Directories - -Finally, a directory can be imported as a module. The only condition is that it needs to contain a `mod.nu` file (even empty, which is not particularly useful, however). The `mod.nu` file defines the root module. Any submodules (`export module`) or re-exports (`export use`) must be declared inside the `mod.nu` file. We could write our `greetings` module like this: - -_In the following examples, `/` is used at the end to denote that we're importing a directory but it is not required._ - -```nu -# greetings/mod.nu - -export def hello [name: string] { - $"hello ($name)!" -} - -export def hi [where: string] { - $"hi ($where)!" -} -``` - -then - -```nu -> use greetings/ hello - -> hello -``` - -The name of the module follows the same rule as module created from a file: Stem of the directory name, i.e., the directory name, is used as the module name. Again, you could do this as a two-step action using `module` and `use` separately, as explained in the previous section. - -::: tip Note -You can define `main` command inside `mod.nu` to create a command named after the module directory. -::: - -## Import Pattern - -Anything after the [`use`](/commands/docs/use.md) keyword forms an **import pattern** which controls how the definitions are imported. -The import pattern has the following structure `use head members...` where `head` defines the module (name of an existing module, file, or directory). The members are optional and specify what exactly should be imported from the module. - -Using our `greetings` example: - -```nu -use greetings -``` - -imports all symbols prefixed with the `greetings` namespace (can call `greetings hello` and `greetings hi`). - -```nu -use greetings hello -``` - -will import the `hello` command directly without any prefix. - -```nu -use greetings [hello, hi] -``` - -imports multiple definitions<> directly without any prefix. - -```nu -use greetings * -``` - -will import all names directly without any prefix. - -## `main` - -Exporting a command called `main` from a module defines a command named as the module. Let's extend our `greetings` example: - -```nu -# greetings.nu - -export def hello [name: string] { - $"hello ($name)!" -} - -export def hi [where: string] { - $"hi ($where)!" -} - -export def main [] { - "greetings and salutations!" -} -``` - -then - -```nu -> use greetings.nu - -> greetings -greetings and salutations! - -> greetings hello world -hello world! -``` - -The `main` is exported only when - -- no import pattern members are used (`use greetings.nu`) -- glob member is used (`use greetings.nu *`) - -Importing definitions selectively (`use greetings.nu hello` or `use greetings.nu [hello hi]`) does not define the `greetings` command from `main`. You can, however, selectively import `main` using `use greetings main` (or `[main]`) which defines _only_ the `greetings` command without pulling in `hello` or `hi`. - -Additionally, `main` has special behavior if used in a script file, regardless of whether it is exported or not. See the [section on scripts](scripts.html#parameterizing-scripts) for more details. - -Apart from commands (`def`, `def --env`), known externals (`extern`) can also be named `main`. - -## Submodules and Subcommands - -Submodules are modules inside modules. They are automatically created when you call `use` on a directory: Any .nu files inside the directory are implicitly added as submodules of the main module. There are two more ways to add a submodule to a module: - -1. Using `export module` -2. Using `export use` - -The difference is that `export module some-module` _only_ adds the module as a submodule, while `export use some-module` _also_ re-exports the submodule's definitions. Since definitions of submodules are available when importing from a module, `export use some-module` is typically redundant, unless you want to re-export its definitions without the namespace prefix. - -::: tip Note -`module` without `export` defines only a local module, it does not export a submodule. -::: - -Let's illustrate this with an example. Assume three files: - -```nu -# greetings.nu - -export def hello [name: string] { - $"hello ($name)!" -} - -export def hi [where: string] { - $"hi ($where)!" -} - -export def main [] { - "greetings and salutations!" -} -``` - -```nu -# animals.nu - -export def dog [] { - "haf" -} - -export def cat [] { - "meow" -} -``` - -```nu -# voice.nu - -export use greetings.nu * - -export module animals.nu - -``` - -Then: - -```nu -> use voice.nu - -> voice animals dog -haf - -> voice animals cat -meow - -> voice hello world -hello world - -> voice hi there -hi there! - -> voice greetings -greetings and salutations! - -``` - -As you can see, defining the submodule structure also shapes the command line API. In Nushell, namespaces directly folds into subcommands. This is true for all definitions: aliases, commands, known externals, modules. - -## Environment Variables - -Modules can define an environment using [`export-env`](/commands/docs/export-env.md): - -```nu -# greetings.nu - -export-env { - $env.MYNAME = "Arthur, King of the Britons" -} - -export def hello [] { - $"hello ($env.MYNAME)" -} -``` - -When [`use`](/commands/docs/use.md) is evaluated, it will run the code inside the [`export-env`](/commands/docs/export-env.md) block and merge its environment into the current scope: - -```nu -> use greetings.nu - -> $env.MYNAME -Arthur, King of the Britons - -> greetings hello -hello Arthur, King of the Britons! -``` - -::: tip -The module implementation can use its own scoped environment variables without them bleeding into users scope. For example: - -```nu -# greetings-local.nu - -export def hello [] { - $env.MYNAMELOCAL = "Arthur, King of the Britons" - $"hello ($env.MYNAMELOCAL)" -} -``` - -```nu -> use greetings-local.nu - -> $env.MYNAMELOCAL -Error: nu::shell::column_not_found -[…] - -> greetings-local hello -hello Arthur, King of the Britons! -``` - -::: - -## Caveats - -Like any programming language, Nushell is also a product of a tradeoff and there are limitations to our module system. - -### `export-env` runs only when the `use` call is _evaluated_ - -If you also want to keep your variables in separate modules and export their environment, you could try to [`export use`](/commands/docs/export_use.md) it: - -```nu -# purpose.nu -export-env { - $env.MYPURPOSE = "to build an empire." -} - -export def greeting_purpose [] { - $"Hello ($env.MYNAME). My purpose is ($env.MYPURPOSE)" -} -``` - -and then use it - -```nu -> use purpose.nu - -> purpose greeting_purpose -``` - -However, this won't work, because the code inside the module is not _evaluated_, only _parsed_ (only the `export-env` block is evaluated when you call `use purpose.nu`). To export the environment of `greetings.nu`, you need to add it to the `export-env` module: - -```nu -# purpose.nu -export-env { - use greetings.nu - $env.MYPURPOSE = "to build an empire." -} - -export def greeting_purpose [] { - $"Hello ($env.MYNAME). My purpose is ($env.MYPURPOSE)" -} -``` - -then - -```nu -> use purpose.nu - -> purpose greeting_purpose -Hello Arthur, King of the Britons. My purpose is to build an empire. -``` - -Calling `use purpose.nu` ran the `export-env` block inside `purpose.nu` which in turn ran `use greetings.nu` which in turn ran the `export-env` block inside `greetings.nu`, preserving the environment changes. - -### Module file / command cannot be named after parent module - -- Module directory cannot contain .nu file named after the directory (`spam/spam.nu`) - - Consider a `spam` directory containing both `spam.nu` and `mod.nu`, calling `use spam *` would create an ambiguous situation where the `spam` module would be defined twice. -- Module cannot contain file named after the module - - Same case as above: Module `spam` containing both `main` and `spam` commands would create an ambiguous situation when exported as `use spam *`. - -## Examples - -This section describes some useful patterns using modules. - -### Local Definitions - -Anything defined in a module without the [`export`](/commands/docs/export.md) keyword will work only in the module's scope. - -```nu -# greetings.nu - -use tools/utils.nu generate-prefix # visible only locally (we assume the file exists) - -export def hello [name: string] { - greetings-helper "hello" "world" -} - -export def hi [where: string] { - greetings-helper "hi" "there" -} - -def greetings-helper [greeting: string, subject: string] { - $"(generate-prefix)($greeting) ($subject)!" -} -``` - -then - -```nu -> use greetings.nu * - - -> hello "world" -hello world! - -> hi "there" -hi there! - -> greetings-helper "foo" "bar" # fails because 'greetings-helper' is not exported - -> generate-prefix # fails because the command is imported only locally inside the module -``` - -### Dumping Files into Directory - -A common pattern in traditional shells is dumping and auto-sourcing files from a directory (for example, loading custom completions). In Nushell, doing this directly is currently not possible, but directory modules can still be used. - -Here we'll create a simple completion module with a submodule dedicated to some Git completions: - -1. Create the completion directory - - `mkdir ($nu.default-config-dir | path join completions)` - -2. Create an empty `mod.nu` for it - - `touch ($nu.default-config-dir | path join completions mod.nu)` - -3. Put the following snippet in `git.nu` under the `completions` directory - - ```nu - export extern main [ - --version(-v) - -C: string - # ... etc. - ] - - export extern add [ - --verbose(-v) - --dry-run(-n) - # ... etc. - ] - - export extern checkout [ - branch: string@complete-git-branch - ] - - def complete-git-branch [] { - # ... code to list git branches - } - ``` - -4. Add `export module git.nu` to `mod.nu` -5. Add the parent of the `completions` directory to your NU_LIB_DIRS inside `env.nu` - - ```nu - $env.NU_LIB_DIRS = [ - ... - $nu.default-config-dir - ] - ``` - -6. Import the completions to Nushell in your `config.nu`: - - `use completions *` - -Now you've set up a directory where you can put your completion files, and you should have some Git completions the next time you start Nushell. - -::: tip Note -This will use the file name (in our example `git` from `git.nu`) as the module name. This means some completions might not work if the definition has the base command in its name. -For example, if you defined our known externals in our `git.nu` as `export extern 'git push' []`, etc. and followed the rest of the steps, you would get subcommands like `git git push`, etc. -You would need to call `use completions git *` to get the desired subcommands. For this reason, using `main` as outlined in the step above is the preferred way to define subcommands. -::: - -### Setting environment + aliases (conda style) - -`def --env` commands, `export-env` block and aliases can be used to dynamically manipulate "virtual environments" (a concept well known from Python). - -We use it in our [official virtualenv integration](https://github.com/pypa/virtualenv/blob/main/src/virtualenv/activation/nushell/activate.nu). Another example is our [unofficial Conda module](https://github.com/nushell/nu_scripts/blob/main/modules/virtual_environments/conda.nu). - -::: warning -Work in progress -::: - -## Hiding - -Any custom command or alias, imported from a module or not, can be "hidden", restoring the previous definition. -We do this with the [`hide`](/commands/docs/hide.md) command: - -```nu -> def foo [] { "foo" } - -> foo -foo - -> hide foo - -> foo # error! command not found! -``` - -The [`hide`](/commands/docs/hide.md) command also accepts import patterns, just like [`use`](/commands/docs/use.md). -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 the module's exports, without the prefix - -:::tip Note -`hide` is not a supported keyword at the root of a module (unlike `def` etc.) -::: +- [Using Modules](./modules/using_modules.md) +- [Creating Modules](./modules/creating_modules.md) diff --git a/book/modules/creating_modules.md b/book/modules/creating_modules.md new file mode 100644 index 00000000000..08fae101438 --- /dev/null +++ b/book/modules/creating_modules.md @@ -0,0 +1,473 @@ +# Creating Modules + +[[toc]] + +::: important +When working through the examples below, it is recommended that you start a new shell before importing an updated version of each module or command. This will help reduce any confusion caused by definitions from previous imports. +::: + +## Overview + +Modules (and Submodules, to be covered below) are created in one of two ways: + +- Most commonly, by creating a file with a series of `export` statements of definitions to be exported from the module. +- For submodules inside a module, using the `module` command + +::: tip +While it's possible to use the `module` command to create a module directly at the commandline, it's far more useful and common to store the module definitions in a file for reusability. +::: + +The module file can be either: + +- A file named `mod.nu`, in which case its _directory_ becomes the module name +- Any other `.nu` file, in which case the filename becomes the module name + +### Simple Module Example + +Create a file named `inc.nu` with the following: + +```nu +export def increment []: int -> int { + $in + 1 +} +``` + +This is a module! We can now import it and use the `increment` command: + +```nu +use inc.nu * +5 | increment +# => 6 +``` + +Of course, you can easily distribute this file so that others can make use of the module as well. + +## Exports + +We covered the types of definitions that are available in modules briefly in [Using Modules](./using_modules.md) from the end-user's perspective. Module authors, on the other hand, need to know _how_ to create the export definitions for: + +- Commands ([`export def`](/commands/docs/export_def.md)) +- Aliases ([`export alias`](/commands/docs/export_alias.md)) +- Constants ([`export const`](/commands/docs/export_const.md)) +- Known externals ([`export extern`](/commands/docs/export_extern.md)) +- Submodules ([`export module`](/commands/docs/export_module.md)) +- Imported symbols from other modules ([`export use`](/commands/docs/export_use.md)) +- Environment setup ([`export-env`](/commands/docs/export-env.md)) + +::: tip +Only definitions marked with `export` (or `export-env` for environment variables) are accessible when the module is imported. Definitions not marked with `export` are only visible from inside the module. In some languages, these would be called "private" definitions. An example can be found below in [Additional Examples](#local-definitions). +::: + +### `main` Exports + +::: important +An export cannot have the same name as that of the module itself. +::: + +In the [Basic Example](#basic-module-example) above, we had a module named `inc` with a command named `increment`. However, if you try to renamed that file to `increment.nu`, it will fail to import. + +```nu +mv inc.nu increment.nu +use increment.nu * + +# => Error: nu::parser::named_as_module +# => ... +# => help: Module increment can't export command named +# => the same as the module. Either change the module +# => name, or export `main` command. +``` + +As helpfully mentioned in the error message, you can simply rename the export `main`, in which case it will take on the name of the module when imported. Edit the `increment.nu` file: + +```nu +export def main []: int -> int { + $in + 1 +} +``` + +Then: + +```nu +use ./increment.nu +2024 | inc +# => 2025 +``` + +::: note +`main` can be used for both `export def` and `export extern` definitions. +::: + +::: tip +`main` definitions are imported in the following cases: + +- The entire module is imported with `use ` or `use ` +- The `*` glob is used to import all of the modules definitions (e.g., `use *`, etc.) +- The `main` definition is explicitly imported with `use main`, `use [main]`, etc.) + +Conversely, the following forms do _not_ import the `main` definition: + +````nu +use +# or +use [ ] +::: + +::: note +Additionally, `main` has special behavior if used in a script file, regardless of whether it is exported or not. See the [Scripts](scripts.html#parameterizing-scripts) chapter for more details. +::: + +## Module Files + +As mentioned briefly in the Overview above, modules can be created either as: + +* `.nu`: Useful for simple modules +* `/mod.nu`: Useful for organizing larger module projects where submodules can easily map to subdirectories of the main module + +The `increment.nu` example above is clearly an example of the former. Let's convert it to the directory form: + +```nu +mkdir increment +mv increment.nu increment/mod.nu + +use increment * +41 | increment +# => 42 +```` + +Notice that the behavior of the module once imported is identical regardless of whether the file-form or directory-form is used; only its path changes. + +::: note +Technically, you can import this either using the directory form above or explicitly with `use increment/mod.nu *`, but the directory shorthand is preferred when using a `mod.nu`. +::: + +## Subcommands + +As covered in [Custom Commands](../custom_commands.md), subcommands allow us to group commands logically. Using modules, this can be done in one of two ways: + +1. As with any custom command, the command can be defined as `" "`, using a space inside quotes. Let's add an `increment by` subcommand to the `increment` module we defined above: + +```nu +export def main []: int -> int { + $in + 1 +} + +export def "increment by" [amount: int]: int -> int { + $in + $amount +} +``` + +It can then be imported with `use increment *` to load both the `increment` command and `increment by` subcommand. + +2. Alternatively, we can define the subcommand simply using the name `by`, since importing the entire `increment` module will result in the same commands: + +```nu +export def main []: int -> int { + $in + 1 +} + +export def by [amount: int]: int -> int { + $in + $amount +} +``` + +This module is imported using `use increment` (without the glob `*`) and results in the same `increment` command and `increment by` subcommand. + +::: note +We'll continue to use this version for further examples below, so notice that the import pattern has changed to `use increment` (rather than `use increment *`) below. +::: + +## Submodules + +Submodules are modules that are exported from another module. There are two ways to add a submodule to a module: + +1. With `export module`: Exports (a) the submodule and (b) its definitions as members of the submodule +2. With `export use`: Exports (a) the submodule and (b) its definitions as members of the parent module + +To demonstrate the difference, let's add to our `increment` example by: + +- Adding a new `range-into-list` module and command +- Creating a new parent module `my-utils` with `increment` and `range-into-list` as its submodules + +1. Create a directory for the new `my-utils` and move the `increment.nu` into it + + ```nu + mkdir my-utils + # Adjust the following as needed + mv increment/mod.nu my-utils/increment.nu + rm increment + cd my-utils + ``` + +2. In the `my-utils` directory, create a `range-into-list.nu` file with the following: + + ```nu + export def main []: range -> list { + # It looks odd, yes, but the following is just + # a simple way to convert ranges to lists + each {||} + } + ``` + +3. Test it: + + ```nu + use range-into-list.nu + 1..5 | range-into-list | describe + # => list (stream) + ``` + +4. We should now have a `my-utils` directory with the: + + - `increment.nu` module + - `range-into-list.nu` module + +The following examples show how to create a module with submodules. + +### Example: Submodule with `export module` + +The most common form for a submodule definition is with `export module`. + +1. Create a new module named `my-utils`. Since we're in the `my-utils` directory, we will create a `mod.nu` to define it. This version of `my-utils/mod.nu` will contain: + + ```nu + export module ./increment.nu + export module ./range-into-list.nu + ``` + +2. We now have a module `my-init` with the two submodules. Try it out: + + ```nu + # Go to the parent directory of my-utils + cd .. + use my-utils * + 5 | increment by 4 + # => 9 + + let file_indices = 0..2..<10 | range-into-list + ls | select ...$file_indices + # => Returns the 1st, 3rd, 5th, 7th, and 9th file in the directory + ``` + +Before proceeding to the next section, run `scope modules` and look for the `my-utils` module. Notice that it has no commands of its own; just the two submodules. + +### Example: Submodule with `export use` + +Alternatively, we can (re)export the _definitions_ from other modules. This is slightly different from the first form, in that the commands (and other definitions, if they were present) from `increment` and `range-into-list` become _members_ of the `my-utils` module itself. We'll be able to see the difference in the output of the `scope modules` command. + +Let's change `my-utils/mod.nu` to: + +```nu +export use ./increment.nu +export use ./range-into-list.nu +``` + +Try it out using the same commands as above: + +```nu +# Go to the parent directory of my-utils +cd .. +use my-utils * +5 | increment by 4 +# => 9 + +let file_indices = 0..2..<10 | range-into-list +ls / | sort-by modified | select ...$file_indices +# => Returns the 1st, 3rd, 5th, 7th, and 9th file in the directory, oldest-to-newest +``` + +Run `scope modules` again and notice that all of the commands from the submodules are re-exported into the `my-utils` module. + +::: note +`module` without `export` defines only a local module; it does not export a submodule. +::: + +## Documenting Modules + +As with [custom commands](../custom_commands.md#documenting-your-command), modules can include documentation that can be viewed with `help `. The documentation is simply a series of commented lines at the beginning of the module file. Let's document the `my-utils` module: + +```nu +# A collection of helpful utility functions + +export use ./increment.nu +export use ./range-into-list.nu +``` + +Now examine the help: + +```nu +use my-utils * +help my-utils + +# => A collection of helpful utility functions +``` + +Also notice that, because the commands from `increment` and `range-into-list` are re-exported with `export use ...`, those commands show up in the help for the main module as well. + +## Environment Variables + +Modules can define an environment using [`export-env`](/commands/docs/export-env.md). Let's extend our `my-utils` module with an environment variable export for a common directory where we'll place our modules in the future. This directory is (by default) in the `$env.NU_LIB_DIRS` search path discussed in [Using Modules - Module Path](./using_modules.md#module-path). + +```nu +# A collection of helpful utility functions + +export use ./increment.nu +export use ./range-into-list.nu + +export-env { + $env.NU_MODULES_DIR = ($nu.default-config-dir | path join "scripts") +} +``` + +When this module is imported with `use`, the code inside the [`export-env`](/commands/docs/export-env.md) block is run and the its environment merged into the current scope: + +```nu +use my-utils +$env.NU_MODULES_DIR +# => Returns the directory name +cd $env.NU_MODULES_DIR +``` + +::: tip +As with any command defined without `--env`, commands and other definitions in the module use their own scope for environment. This allows changes to be made internal to the module without them bleeding into the user's scope. Add the following to the bottom of `my-utils/mod.nu`: + +```nu +export def examine-module [] { + # Changes the PWD environment variable + cd $env.CURRENT_FILE + ls +} +``` + +Running this command changes the directory _locally_ in the module, but the changes are not propogated to the parent scope. + +::: + +## Caveats + +### `export-env` runs only when the `use` call is _evaluated_ + +Attempting to import a module's environment within another environment may not work as expected. Let's create a new module `go.nu` that creates "shortcuts" to common directories. One of these will be the `$env.NU_MODULES_DIR` defined above in `my-utils`. + +We might try: + +```nu +# go.nu, in the parent directory of my-utils +use my-utils + +export def --env home [] { + cd ~ +} + +export def --env modules [] { + cd $env.NU_MODULES_DIR +} +``` + +And then import it: + +```nu +use go.nu +go home +# => Works +go modules +# => Error: $env.NU_MODULES_DIR is not found +``` + +This doesn't work because `my-utils` isn't _evaluated_ in this case; it is only _parsed_ when the `go.nu` module is imported. While this brings all of the other exports into scope, it doese not _run_ the `export-env` block. + +::: important +As mentioned at the start of this chapter, trying this while `my-utils` (and its `$env.NU_MODULES_DIR`) is still in scope from a previous import will _not_ fail as expected. Test in a new shell session to see the "normal" failure. +::: + +To bring `my-utils` exported environment into scope for the `go.nu` module, there are two options: + +1. Import the module in each command where it is needed + + By placing `use my-utils` in the `go home` command itself, its `export-env` will be _evaludated_ when the command is. For example: + + ```nu + # go.nu + export def --env home [] { + cd ~ + } + + export def --env modules [] { + use my-utils + cd $env.NU_MODULES_DIR + } + ``` + +2. Import the `my-utils` environment inside an `export-env` block in the `go.nu` module + + ```nu + use my-utils + export-env { + use my-utils [] + } + + export def --env home [] { + cd ~ + } + + export def --env modules [] { + cd $env.NU_MODULES_DIR + } + ``` + + In the example above, `go.nu` imports `my-utils` twice: + + 1. The first `use my-utils` imports the module and its definitions (except for the environment) into the module scope. + 2. The second `use my-utils []` imports nothing _but_ the environment into `go.nu`'s exported environment block. Because the `export-env` of `go.nu` is executed when the module is first imported, the `use my-utils []` is also evaluated. + +Note that the first method keeps `my-utils` environment inside the `go.nu` module's scope. The second, on the other hand, re-exports `my-utils` environment into the user scope. + +### Module files and commands cannot be named after parent module + +A `.nu` file cannot have the same name as its module directory (e.g., `spam/spam.nu`) as this would create an ambiguous sitation with the name being defined twice. This is similar to the situation described above where a command cannot have the same name as its parent. + +## Windows Path Syntax + +::: important +Nushell on Windows supports both forward-slashes and back-slashes as the path separator. However, to ensure that they work on all platforms, using only the forward-slash `/` in your modules is highly recommended. +::: + +## Additional Examples + +### Local Definitions + +As mentioned above, definitions in a module without the [`export`](/commands/docs/export.md) keyword are only accessible in the module's scope. + +To demonstrate, create a new module `is-alphanumeric.nu`. Inside this module, we'll create a `str is-alphanumeric` command. If any of the characters in the string are not alpha-numeric, it returns `false`: + +```nu +# is-alphanumeric.nu +def alpha-num-range [] { + [ + ...(seq char 'a' 'z') + ...(seq char 'A' 'Z') + ...(seq 0 9 | each { into string }) + ] +} + +export def "str is-alphanumeric" []: string -> bool { + if ($in == '') { + false + } else { + let chars = (split chars) + $chars | all {|char| $char in (alpha-num-range)} + } +} +``` + +Notice that we have two definitions in this module -- `alpha-num-range` and `str is-alphanumeric`, but only the second is exported. + +```nu +use is-alphanumeric.nu * +'Word' | str is-alphanumeric +# => true +'Some punctutation?!' | str is-alphanumeric +# => false +'a' in (alpha-num-range) +# => Error: +# => help: `alpha-num-range` is neither a Nushell built-in or a known external command +``` diff --git a/book/modules/using_modules.md b/book/modules/using_modules.md new file mode 100644 index 00000000000..63b218ae570 --- /dev/null +++ b/book/modules/using_modules.md @@ -0,0 +1,234 @@ +# Using Modules + +[[toc]] + +## Overview + +End-users can add new functionality to Nushell by using ("importing") modules written by others. Modules can include: + +- Commands +- Aliases +- Constants +- Externs +- Other modules (as submodules) +- Environment variables + +To import a module and its definitions, we call the [`use`](/commands/docs/use.md) command: + +```nu +use +``` + +For example: + +```nu +use std/log +log info "Hello, Modules" +``` + +::: tip +The example above uses the [Standard Library](../standard_library.md), a collection of modules built-in to Nushell. Because it is readily available to all Nushell users, we'll also use it for several of the examples below. +::: + +## Installing Modules + +Installing a module is simply a matter of placing its files in a directory. This might be done via `git clone` (or other version control system), a package manager such as `nupm`, or manually. The module's documentation should provide recommendations. + +## Importing Modules + +Anything after the [`use`](/commands/docs/use.md) keyword forms an **import pattern** which controls how the definitions are imported. + +Notice above that `use` has two arguments: + +- A path to the module +- (Optional) The definitions to import + +The module's documentation will usually tell you the recommended way to import it. However, it can still be useful to understand the options available: + +### Module Path + +The path to the module can be: + +- An absolute or relative path to a directory containing a `mod.nu` file: + + ::: details Example + + ```nu + use ~/nushell/modules/nupm` + ``` + + Note that the module name (its directory) can end in a `/` (or `\` on Windows), but as with most commands that take a paths (e.g., `cd`), this is completely optional. + + ::: + +- A relative path to a directory containing a `mod.nu` file: + + ::: details Example + + ```nu + # cd then use the mod.nu in the relative nupm directory + cd ~/nushell/modules + use nupm + # or + use nupm/ + ``` + + Note that the module name (its directory) can end in a `/` (or `\` on Windows), but as with most commands that take a paths (e.g., `cd`), this is completely optional. + ::: + + ::: important Important! Importing modules from `$env.NU_LIB_PATH` + When importing a module via a relative path, Nushell first searches from the current directory. If a matching module is not found at that location, Nushell then searches each directory in the `$env.NU_LIB_DIRS` list. + + This allows you to install modules to a location that is easily accessible via a relative path regardless of the current directory. + ::: + +- An absolute or relative path to a Nushell module file. As above, Nushell will search the `$env.NU_LIB_DIRS` for a matching relative path. + + ::: details Example + + ```nu + use ~/nushell/modules/std-rfc/bulk-rename.nu + # Or + cd ~/nushell/modules + use std-rfc/bulk-rename.nu + ``` + + ::: + +- A virtual directory: + + ::: details Example + The standard library modules mentioned above are stored in a virtual filesystem with a `std` directory. Consider this an alternate form of the "absolute path" examples above. + + ```nu + use std/assert + assert equal 'string1' "string1" + ``` + + ::: + +- Less commonly, the name of a module already created with the [`module`](/commands/docs/module.md) command. While it is possible to use this command to create a module at the commandline, this isn't common or useful. Instead, this form is primarily used by module authors to define a submodule. See [Creating Modules - Submodules](./creating_modules.md#submodules). + +### Module Definitions + +The second argument to the `use` command is an optional list of the definitions to import. Again, the module documentation should provide recommendations, but you always have the option to choose a form that works best for your use-case. + +- **Import an entire module/submodule as a command with subcommands** + + In an earlier example above, we imported the `std/log` module without specifying the definitions: + + ```nu + use std/log + log info "Hello, std/log Module" + ``` + + Notice that this imports the `log` submodule with all of its _subcommands_ (e.g., `log info`, `log error`, etc.) into the current scope. + + Compare the above to the next version, where the command becomes `std log info`: + + ```nu + use std + std log info "Hello, std Module" + ``` + +- **Import all of the definitions from a module** + + Alternatively, you can import the definitions themselves into the current scope. For example: + + ```nu + use std/formats * + ls | to jsonl + ``` + + Notice how the `to jsonl` command is placed directly in the current scope, rather than being a subcommand of `formats`. + + The [Standard Library Chapter](../standard_library.md) covers the recommended imports for each submodule. + +- **Import one or more commands from a module** + + Nushell can also selectively import a subset of the definitions of a module. For example: + + ```nu + use std/math PI + let circle = 2 * $PI * $radius + ``` + + Keep in mind that the definitions can be: + + - Commands + - Aliases + - Constants + - Externs + - Other modules (as submodules) + - Environment variables (always imported) + + Less commonly, a list of imports can also be used: + + ```nu + use std/formats [ 'from ndjson' 'to ndjson' ] + ``` + +## Importing Constants + +As seen above with the `std/math` examples, some modules may export constant definitions. The syntax for accessing a constant varies slightly depending on how it was imported. For example: + +```nu +use std/math +$math.PI +# or +use std/math * +$PI +``` + +## Hiding + +Any custom command or alias, imported from a module or not, can be "hidden", restoring the previous definition. +We do this with the [`hide`](/commands/docs/hide.md) command. + +The `hide` command also accepts import patterns, just like [`use`](/commands/docs/use.md). The import pattern is interpreted slightly differently, though. It can be one of the following: + +- If the name is a custom command, it hides it directly. Otherwise ... +- If the name is a module name, hides all of its exports prefixed with the module name + +For example, using `std/assert`: + +```nu +use std/assert +assert equal 1 2 +# => Assertion failed +assert true +# => Assertion passes + +hide assert +assert equal 1 1 +# => Error: +# => help: A command with that name exists in module `assert`. Try importing it with `use` + +assert true +# => Error: +# => help: A command with that name exists in module `assert`. Try importing it with `use` + +``` + +Just as you can `use` a subset of the module's definitions, you can also `hide` them selectively as well: + +```nu +use std/assert +hide assert main +assert equal 1 1 +# => assertion passes + +assert true +# => Error: +# => help: A command with that name exists in module `assert`. Try importing it with `use` +``` + +::: tip +`main` is covered in more detail in [Creating Modules](./creating_modules.md#main-exports), but for end-users, `main` simply means "the command named the same as the module." In this case the `assert` module exports a `main` command that "masquerades" as the `assert` command. Hiding `main` has the effect of hiding the `assert` command, but not its subcommands. +::: + +## See Also + +- To make a module always be available without having to `use` it in each Nushell session, simply add its import (`use`) to your startup configuration. See the [Configuration](../configuration.md) Chapter to learn how. + +- Modules can also be used as part of an [Overlay](../overlays.md). diff --git a/book/standard_library.md b/book/standard_library.md index eb0d99ee2e7..4eb51b0634c 100644 --- a/book/standard_library.md +++ b/book/standard_library.md @@ -34,6 +34,8 @@ The `use std` command above loads the entire standard library so that you can se ## Importing the Standard Library +The Standard Library modules and submodules are imported with the [`use`](/commands/docs/use.md) command, just as any other module. See [Using Modules](./modules/using_modules.md) for more information. + While working at the commandline, it can be convenient to load the entire standard library using: ```nu @@ -50,83 +52,49 @@ See the [notes below](#optimal-startup) on how to ensure that your configuration Each submodule of the standard library can be loaded separately. Again, _for best performance, load only the submodule(s) that you need in your code._ -There are several forms that can be used: - -#### 1. Import the submodule - -Examples: - -```nu -use std/iter -[2 5 "4" 7] | iter filter-map {|it| $it ** 2} - -use std/help -help ls -help commands -``` - -This form requires that you prefix the command using the submodule name. This can be useful in two scenarios. +See [Importing Modules](./modules/using_modules.md#importing-modules) for general information on using modules. The recommended import for each of the Standard Library submodules is listed below: -1. In the `use std/iter` example, it's important to prefix the commands with the `iter` namespace. If, on the other hand, you were to `use std/iter *`, you would shadow the built-in `find` command with the `iter` module's `find` command. +#### 1. Submodules with ` ` form -2. In the `use std/help` example, `help` is both the submodule name and the name of the main command it exports. Using `use std/help` allows you to access: - - ```nu - help - help aliases - help modules - help commands - help operators - help externs - ``` - - In this case, the `std/help` commands are meant to shadow (replace) the built-in versions. - -Submodules that are normally imported with `use std/`: +These submodules are normally imported with `use std/` (without a glob/`*`): - `use std/assert`: `assert` and its subcommands - `use std/bench`: The benchmarking command `bench` - `use std/dirs`: The directory stack command `dirs` and its subcommands - `use std/input`: The `input display` command - `use std/help`: An alternative version of the `help` command and its subcommands which supports completion and other features -- `use std/iters`: Additional `iters`-prefixed iteration commands. Note: See-also alternative option #3 below. +- `use std/iters`: Additional `iters`-prefixed iteration commands. - `use std/log`: The `log ` such as `log warning ` -- `use std/math`: Mathematical constants such as `$math.E`. These can also be imported without a prefix using Form #2 below. +- `use std/math`: Mathematical constants such as `$math.E`. These can also be imported as definitions as in Form #2 below. -#### 2. Import the _contents_ of the module directly +#### 2. Import the _definitions_ (contents) of the module directly -For certain submodules, you will want the commands from a submodule to be available in the current scope, so that you _can_ simply access the command by name. For instance: +Some submodules are easier to use when their definitions (commands, aliases, contants, etc.) are loaded into the current scope. For instance: ```nu use std/formats * ls | to jsonl ``` -Submodules that are normally imported with `use std/ *`: +Submodules that are normally imported with `use std/ *` (**with** a glob/`*`): - `use std/dt *`: Additional commands for working with `date` values - `use std/formats *`: Additional `to` and `from` format conversions - `use std/math *`: The math constants without a prefix, such as `$E`. Note that the prefixed form #1 above is likely more understandable when reading and maintaining code. - `use std/xml *`: Additional commands for working with XML data -#### 3. Importing specific subcommands +#### 3. `use std ` -As with most modules, you can choose to import only a subset of the commands. For instance, the following would import the `zip-with` command without requiring that it be called with`iter zip-with`. - -```nu -use std/iter [ zip-with ] -``` - -#### 4. `use std ` - -While it is _possible_ to import Standard Library submodules using a space-separated form: +It is _possible_ to import Standard Library submodules using a space-separated form: ```nu use std log use std formats * ``` -However, similar to `use std *`, this form first loads the _entire_ Standard Library into scope and _then_ imports the submodules. In contrast, using the slash-separated version _only_ imports the submodule and will be much faster as a result. +::: important +However, similar to `use std *`, this form first loads the _entire_ Standard Library into scope and _then_ imports the submodules. In contrast, the slash-separated versions in #1 and #2 above _only_ import the submodule and will be much faster as a result. +::: ## The Standard Library Candidate Module @@ -160,7 +128,7 @@ Of course, if a candidate command in `std-rfc` no longer works or has too many i ## Disabling the Standard Library -To disable the standard library, you can start using: +To disable the standard library, you can start Nushell using: ```nu nu --no-std-lib @@ -192,28 +160,10 @@ view files } ``` -Edit those files to use the recommended syntax below. -::: +Edit those files to use the recommended syntax in the [Importing Submodules](#importing-submodules) section above. ::: note If a Nushell library (e.g., from [the `nu_scripts` repository](https://github.com/nushell/nu_scripts)), example, or doc is using this syntax, please report it via an issue or PR. These will be updated over time after Nushell 0.99.0 is released. If a third-party module is using this syntax, please report it to the author/maintainers to update. ::: - -## Viewing Standard Library Source - -::: tip Did You Know? -Because the standard library is simply composed of [custom commands](./custom_commands.html) in [modules](./modules.html) and [submodules](./modules.html#submodules-and-subcommands), you can see the source for each command with the [`view source`](/commands/docs/view_source.md) command. For example, to view the source for the `ellie` command (with syntax highlighting): - -```nu -use std/util * -view source ellie | nu-highlight -::: - -## Windows Path Syntax - -::: important -Nushell on Windows supports both forward-slashes and back-slashes as the path separator. However, to ensure cross-platform support for scripts and modules using `std`, using only the forward-slash `/` when importing Standard Library submodules is highly recommended. -::: -``` diff --git a/cookbook/modules.md b/cookbook/modules.md new file mode 100644 index 00000000000..f35d13af5e1 --- /dev/null +++ b/cookbook/modules.md @@ -0,0 +1,71 @@ +# Module Scenarios + +### Dumping Files into Directory + +A common pattern in traditional shells is dumping and auto-sourcing files from a directory (for example, loading custom completions). In Nushell, doing this directly is currently not possible, but directory modules can still be used. + +Here we'll create a simple completion module with a submodule dedicated to some Git completions: + +1. Create the completion directory + + `mkdir ($nu.default-config-dir | path join completions)` + +2. Create an empty `mod.nu` for it + + `touch ($nu.default-config-dir | path join completions mod.nu)` + +3. Put the following snippet in `git.nu` under the `completions` directory + + ```nu + export extern main [ + --version(-v) + -C: string + # ... etc. + ] + + export extern add [ + --verbose(-v) + --dry-run(-n) + # ... etc. + ] + + export extern checkout [ + branch: string@complete-git-branch + ] + + def complete-git-branch [] { + # ... code to list git branches + } + ``` + +4. Add `export module git.nu` to `mod.nu` +5. Add the parent of the `completions` directory to your NU_LIB_DIRS inside `env.nu` + + ```nu + $env.NU_LIB_DIRS = [ + ... + $nu.default-config-dir + ] + ``` + +6. Import the completions to Nushell in your `config.nu`: + + `use completions *` + +Now you've set up a directory where you can put your completion files, and you should have some Git completions the next time you start Nushell. + +::: tip Note +This will use the file name (in our example `git` from `git.nu`) as the module name. This means some completions might not work if the definition has the base command in its name. +For example, if you defined our known externals in our `git.nu` as `export extern 'git push' []`, etc. and followed the rest of the steps, you would get subcommands like `git git push`, etc. +You would need to call `use completions git *` to get the desired subcommands. For this reason, using `main` as outlined in the step above is the preferred way to define subcommands. +::: + +### Setting environment + aliases (conda style) + +`def --env` commands, `export-env` block and aliases can be used to dynamically manipulate "virtual environments" (a concept well known from Python). + +We use it in our [official virtualenv integration](https://github.com/pypa/virtualenv/blob/main/src/virtualenv/activation/nushell/activate.nu). Another example is our [unofficial Conda module](https://github.com/nushell/nu_scripts/blob/main/modules/virtual_environments/conda.nu). + +::: warning +Work in progress +::: From 4f6d1f49fe49c4e0840584532e02fc4e3631cf7c Mon Sep 17 00:00:00 2001 From: NotTheDr01ds <32344964+NotTheDr01ds@users.noreply.github.com> Date: Sun, 27 Oct 2024 16:42:22 -0400 Subject: [PATCH 2/3] Small tweaks while writing PR notes --- book/modules.md | 1 + book/modules/creating_modules.md | 10 +++++----- book/modules/using_modules.md | 9 +-------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/book/modules.md b/book/modules.md index 8a7692a79ab..2ea13ab3157 100644 --- a/book/modules.md +++ b/book/modules.md @@ -5,6 +5,7 @@ Like many programming languages, Nushell supports writing and using _modules_ as - Additional custom commands - Aliases - Constants +- Externs - Environment variables - And even other modules (a.k.a., submodules) diff --git a/book/modules/creating_modules.md b/book/modules/creating_modules.md index 08fae101438..c10720e7006 100644 --- a/book/modules/creating_modules.md +++ b/book/modules/creating_modules.md @@ -40,11 +40,11 @@ use inc.nu * # => 6 ``` -Of course, you can easily distribute this file so that others can make use of the module as well. +Of course, you can easily distribute a file like this so that others can make use of the module as well. ## Exports -We covered the types of definitions that are available in modules briefly in [Using Modules](./using_modules.md) from the end-user's perspective. Module authors, on the other hand, need to know _how_ to create the export definitions for: +We covered the types of definitions that are available in modules briefly in the main Modules Overview above. While this might be enough explanation for an end-user, module authors will need to know _how_ to create the export definitions for: - Commands ([`export def`](/commands/docs/export_def.md)) - Aliases ([`export alias`](/commands/docs/export_alias.md)) @@ -55,7 +55,7 @@ We covered the types of definitions that are available in modules briefly in [Us - Environment setup ([`export-env`](/commands/docs/export-env.md)) ::: tip -Only definitions marked with `export` (or `export-env` for environment variables) are accessible when the module is imported. Definitions not marked with `export` are only visible from inside the module. In some languages, these would be called "private" definitions. An example can be found below in [Additional Examples](#local-definitions). +Only definitions marked with `export` (or `export-env` for environment variables) are accessible when the module is imported. Definitions not marked with `export` are only visible from inside the module. In some languages, these would be called "private" or "local" definitions. An example can be found below in [Additional Examples](#local-definitions). ::: ### `main` Exports @@ -64,7 +64,7 @@ Only definitions marked with `export` (or `export-env` for environment variables An export cannot have the same name as that of the module itself. ::: -In the [Basic Example](#basic-module-example) above, we had a module named `inc` with a command named `increment`. However, if you try to renamed that file to `increment.nu`, it will fail to import. +In the [Basic Example](#basic-module-example) above, we had a module named `inc` with a command named `increment`. However, if we rename that file to `increment.nu`, it will fail to import. ```nu mv inc.nu increment.nu @@ -85,7 +85,7 @@ export def main []: int -> int { } ``` -Then: +Now it works as expected: ```nu use ./increment.nu diff --git a/book/modules/using_modules.md b/book/modules/using_modules.md index 63b218ae570..06c9c1ec547 100644 --- a/book/modules/using_modules.md +++ b/book/modules/using_modules.md @@ -4,14 +4,7 @@ ## Overview -End-users can add new functionality to Nushell by using ("importing") modules written by others. Modules can include: - -- Commands -- Aliases -- Constants -- Externs -- Other modules (as submodules) -- Environment variables +End-users can add new functionality to Nushell by using ("importing") modules written by others. To import a module and its definitions, we call the [`use`](/commands/docs/use.md) command: From 0a7db6f9a554ac21ebc4d098b7765fdd790e94ed Mon Sep 17 00:00:00 2001 From: NotTheDr01ds <32344964+NotTheDr01ds@users.noreply.github.com> Date: Sun, 27 Oct 2024 16:48:27 -0400 Subject: [PATCH 3/3] Fix typos --- book/modules/creating_modules.md | 6 +++--- book/standard_library.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/book/modules/creating_modules.md b/book/modules/creating_modules.md index c10720e7006..01077da6907 100644 --- a/book/modules/creating_modules.md +++ b/book/modules/creating_modules.md @@ -338,7 +338,7 @@ export def examine-module [] { } ``` -Running this command changes the directory _locally_ in the module, but the changes are not propogated to the parent scope. +Running this command changes the directory _locally_ in the module, but the changes are not propagated to the parent scope. ::: @@ -373,7 +373,7 @@ go modules # => Error: $env.NU_MODULES_DIR is not found ``` -This doesn't work because `my-utils` isn't _evaluated_ in this case; it is only _parsed_ when the `go.nu` module is imported. While this brings all of the other exports into scope, it doese not _run_ the `export-env` block. +This doesn't work because `my-utils` isn't _evaluated_ in this case; it is only _parsed_ when the `go.nu` module is imported. While this brings all of the other exports into scope, it does not _run_ the `export-env` block. ::: important As mentioned at the start of this chapter, trying this while `my-utils` (and its `$env.NU_MODULES_DIR`) is still in scope from a previous import will _not_ fail as expected. Test in a new shell session to see the "normal" failure. @@ -423,7 +423,7 @@ Note that the first method keeps `my-utils` environment inside the `go.nu` modul ### Module files and commands cannot be named after parent module -A `.nu` file cannot have the same name as its module directory (e.g., `spam/spam.nu`) as this would create an ambiguous sitation with the name being defined twice. This is similar to the situation described above where a command cannot have the same name as its parent. +A `.nu` file cannot have the same name as its module directory (e.g., `spam/spam.nu`) as this would create an ambiguous condition with the name being defined twice. This is similar to the situation described above where a command cannot have the same name as its parent. ## Windows Path Syntax diff --git a/book/standard_library.md b/book/standard_library.md index 4eb51b0634c..e36d8a5cccb 100644 --- a/book/standard_library.md +++ b/book/standard_library.md @@ -69,7 +69,7 @@ These submodules are normally imported with `use std/` (without a glo #### 2. Import the _definitions_ (contents) of the module directly -Some submodules are easier to use when their definitions (commands, aliases, contants, etc.) are loaded into the current scope. For instance: +Some submodules are easier to use when their definitions (commands, aliases, constants, etc.) are loaded into the current scope. For instance: ```nu use std/formats *