Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 84 additions & 10 deletions book/modules/creating_modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ In the [Basic Example](#basic-module-example) above, we had a module named `inc`
```nu
mv inc.nu increment.nu
use increment.nu *

# => Error: nu::parser::named_as_module
# => ...
# => help: Module increment can't export command named
Expand Down Expand Up @@ -120,10 +119,10 @@ Additionally, `main` has special behavior if used in a script file, regardless o

As mentioned briefly in the Overview above, modules can be created either as:

* `<module_name>.nu`: Useful for simple modules
* `<module_name>/mod.nu`: Useful for organizing larger module projects where submodules can easily map to subdirectories of the main module
1. `<module_name>.nu`: "File-form" - Useful for simple modules
2. `<module_name>/mod.nu`: "Directory-form" - 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:
The `increment.nu` example above is clearly an example of (1) the file-form. Let's try converting it to the directory-form:

```nu
mkdir increment
Expand Down Expand Up @@ -152,7 +151,7 @@ export def main []: int -> int {
}

export def "increment by" [amount: int]: int -> int {
$in + $amount
$in + $amount
}
```

Expand All @@ -166,7 +165,7 @@ export def main []: int -> int {
}

export def by [amount: int]: int -> int {
$in + $amount
$in + $amount
}
```

Expand All @@ -183,10 +182,7 @@ Submodules are modules that are exported from another module. There are two ways
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
To demonstrate the difference, let's create a new `my-utils` module, with our `increment` example as a submodule. Additionally, we'll create a new `range-into-list` command in its own submodule.

1. Create a directory for the new `my-utils` and move the `increment.nu` into it

Expand Down Expand Up @@ -277,6 +273,10 @@ ls / | sort-by modified | select ...$file_indices

Run `scope modules` again and notice that all of the commands from the submodules are re-exported into the `my-utils` module.

::: tip
While `export module` is the recommended and most common form, there is one module-design scenario in which `export use` is required -- `export use` can be used to _selectively export_ definitions from the submodule, something `export module` cannot do. See [Additional Examples - Selective Export](#selective-export-from-a-submodule) for an example.
:::

::: note
`module` without `export` defines only a local module; it does not export a submodule.
:::
Expand Down Expand Up @@ -471,3 +471,77 @@ use is-alphanumeric.nu *
# => Error:
# => help: `alpha-num-range` is neither a Nushell built-in or a known external command
```

### Selective Export from a Submodule

::: note
While the following is a rare use-case, this technique is used by the Standard Library to
make the `dirs` commands and its aliases available separately.
:::

As mentioned in the [Submodules](#submodules) section above, only `export use` can selectively export definitions from a submodule.

To demonstrate, let's add a modified form of the `go.nu` module example [above](#caveats) to `my-utils`:

```nu
# go.nu, in the my-utils directory
export def --env home [] {
cd ~
}

export def --env modules [] {
cd ($nu.default-config-dir | path join "scripts")
}

export alias h = home
export alias m = modules
```

This `go.nu` includes the following changes from the original:

- It doesn't rely on the `my-utils` mod since it will now be a submodule of `my-utils` instead
- It adds "shortcut" aliases:
`h`: Goes to the home directory (alias of `go home`)
`m`: Goes to the modules directory (alias of `go modules`)

A user could import _just_ the aliases with:

```nu
use my-utils/go.nu [h, m]
```

However, let's say we want to have `go.nu` be a submodule of `my-utils`. When a user imports `my-utils`, they should _only_ get the commands, but not the aliases. Edit `my-utils/mod.nu` and add:

```nu
export use ./go.nu [home, modules]
```

That _almost_ works -- It selectively exports `home` and `modules`, but not the aliases. However, it does so without the `go` prefix. For example:

```nu
use my-utils *
home
# => works
go home
# => Error: command not found
```

To export them as `go home` and `go modules`, make the following change to `my-utils/mod.nu`:

```nu
# Replace the existing `export use` with ...
export module go {
export use ./go.nu [home, modules]
}
```

This creates a new, exported submodule `go` in `my-utils` with the selectively (re)exported definitions for `go home` and `go modules`.

```nu
use my-utils *
# => As expected:
go home
# => works
home
# => Error: command not found
```
39 changes: 31 additions & 8 deletions book/modules/using_modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ The path to the module can be:
::: details Example

```nu
use ~/nushell/modules/nupm`
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.
Expand All @@ -69,7 +69,7 @@ The path to the module can be:
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`
::: important Important! Importing modules from `$env.NU_LIB_DIRS`
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.
Expand Down Expand Up @@ -104,7 +104,9 @@ The path to the module can be:

### 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.
The second argument to the `use` command is an optional list of the definitions to import. Again, the module documentation should provide recommendations. For example, the [Standard Library Chapter](../standard_library.md#importing-submodules) covers the recommended imports for each submodule.

Of course, 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**

Expand Down Expand Up @@ -135,9 +137,7 @@ The second argument to the `use` command is an optional list of the definitions

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**
- **Import one or more definitions from a module**

Nushell can also selectively import a subset of the definitions of a module. For example:

Expand All @@ -161,16 +161,39 @@ The second argument to the `use` command is an optional list of the definitions
use std/formats [ 'from ndjson' 'to ndjson' ]
```

::: note Importing submodules
While you can import a submodule by itself using `use <module> </submodule>` (e.g., `use std help`), the entire parent module and _all_ of its definitions (and thus submodules) will be _parsed_ when using this form. When possible, loading the submodule as a _module_ will result in faster code. For example:

```nu
# Faster
use std/help
```

:::

## 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:
As seen above with the `std/math` examples, some modules may export constant definitions. When importing the entire module, constants can be accessed through a record with the same name as the module:

```nu
# Importing entire module - Record access
use std/math
$math.PI
# or
# => 3.141592653589793

$math
# => ╭───────┬──────╮
# => │ GAMMA │ 0.58 │
# => │ E │ 2.72 │
# => │ PI │ 3.14 │
# => │ TAU │ 6.28 │
# => │ PHI │ 1.62 │
# => ╰───────┴──────╯

# Or importing all of the module's members
use std/math *
$PI
# => 3.141592653589793
```

## Hiding
Expand Down
2 changes: 1 addition & 1 deletion book/standard_library.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ use std formats *
```

::: 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.
As mentioned in [Using Modules](./modules/using_modules.md#module-definitions), this form (like `use std *`) 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
Expand Down