In our subcommand match we'll add a new function called
write
to handle our Write
subcommand. We'll pass it
the argument title and we'll "import" it from a library
called digital_garden
.
use digital_garden::write;
fn main() -> Result<()> {
color_eyre::install()?;
let opt = Opt::from_args();
dbg!(&opt);
match opt.cmd {
Command::Write { title } => write(title),
}
}
To create this library, add a new section in Cargo.toml
.
We can give our library a name and set which file to treat
as the entrypoint. src/lib.rs
is the default file for
a library crate, but we can also be explicit about what we
want to happen.
[lib]
name = "digital_garden"
path = "src/lib.rs"
This leaves us with two crates, a binary crate, of which we can have any amount, and a library crate, of which we can only have 0 or 1.
We'll create the src/lib.rs
file with the following
contents.
mod write;
pub use write::write;
Rust's module system is explicit, so when we write
mod write
, we are saying that the library digital_garden
has a module write
, such that the path to the module is
digital_garden::write
.
In our case digital_garden::write
corresponds to a file
at src/write.rs
.
Secondly, the pub use write::write
says that we have a
function called write
in the module called write
and
that the function will be exposed from lib publicly, so
people who have the digital_garden
library installed
will be able to use the write function as
digital_garden::write
.
In JavaScript the closest analogue is exporting a function from another file that exports it.
export { write } from './write.js';
By using use, we're shortening the public path to the write
function. A private module "write" with a function "write"
also exists at digital_garden::write::write
. If you try
to use this path, Rust will tell you there is a private
module there.
Finally, in src/write.rs
, we can write a public function
that matches the return type of our main function, since
we're using it as the return value from our match function.
We'll accept an Option<String>
as an argument as well,
since that's what we expect from the cli arguments.
use color_eyre::Result;
pub fn write(_title: Option<String>) -> Result<()> {
todo!()
}
The purpose of creating this module path is because we know that we're going to set up more modules for each subcommand in the future, and we can control both the placement of our code on disk, as well as the path users will interact with to use our module.