diff --git a/book/modules/creating_modules.md b/book/modules/creating_modules.md index 3475223f6a5..760ebf23b1c 100644 --- a/book/modules/creating_modules.md +++ b/book/modules/creating_modules.md @@ -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 @@ -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: -* `.nu`: Useful for simple modules -* `/mod.nu`: Useful for organizing larger module projects where submodules can easily map to subdirectories of the main module +1. `.nu`: "File-form" - Useful for simple modules +2. `/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 @@ -152,7 +151,7 @@ export def main []: int -> int { } export def "increment by" [amount: int]: int -> int { - $in + $amount + $in + $amount } ``` @@ -166,7 +165,7 @@ export def main []: int -> int { } export def by [amount: int]: int -> int { - $in + $amount + $in + $amount } ``` @@ -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 @@ -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. ::: @@ -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 +``` diff --git a/book/modules/using_modules.md b/book/modules/using_modules.md index 06c9c1ec547..9b4a3853e28 100644 --- a/book/modules/using_modules.md +++ b/book/modules/using_modules.md @@ -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. @@ -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. @@ -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** @@ -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: @@ -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 ` (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 diff --git a/book/standard_library.md b/book/standard_library.md index e36d8a5cccb..7ea765448f3 100644 --- a/book/standard_library.md +++ b/book/standard_library.md @@ -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