Skip to content

Commit

Permalink
Merge pull request #3959 from bzierk/ch12-ch14
Browse files Browse the repository at this point in the history
Convert Chapters 12-14
  • Loading branch information
chriskrycho authored Jun 14, 2024
2 parents 047226f + c7462f3 commit 45c1a6d
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 155 deletions.
10 changes: 4 additions & 6 deletions src/ch12-01-accepting-command-line-arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,13 @@ the iterator produces.
The code in Listing 12-1 allows your `minigrep` program to read any command
line arguments passed to it and then collect the values into a vector.

<span class="filename">Filename: src/main.rs</span>
<Listing number="12-1" file-name="src/main.rs" caption="Collecting the command line arguments into a vector and printing them">

```rust
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-01/src/main.rs}}
```

<span class="caption">Listing 12-1: Collecting the command line arguments into
a vector and printing them</span>
</Listing>

First, we bring the `std::env` module into scope with a `use` statement so we
can use its `args` function. Notice that the `std::env::args` function is
Expand Down Expand Up @@ -101,14 +100,13 @@ arguments. Now we need to save the values of the two arguments in variables so
we can use the values throughout the rest of the program. We do that in Listing
12-2.

<span class="filename">Filename: src/main.rs</span>
<Listing number="12-2" file-name="src/main.rs" caption="Creating variables to hold the query argument and file path argument">

```rust,should_panic,noplayground
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-02/src/main.rs}}
```

<span class="caption">Listing 12-2: Creating variables to hold the query
argument and file path argument</span>
</Listing>

As we saw when we printed the vector, the program’s name takes up the first
value in the vector at `args[0]`, so we’re starting arguments at index `1`. The
Expand Down
10 changes: 4 additions & 6 deletions src/ch12-02-reading-a-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,24 @@ has an Emily Dickinson poem that will work well! Create a file called
*poem.txt* at the root level of your project, and enter the poem “I’m Nobody!
Who are you?”

<span class="filename">Filename: poem.txt</span>
<Listing number="12-3" file-name="poem.txt" caption="A poem by Emily Dickinson makes a good test case">

```text
{{#include ../listings/ch12-an-io-project/listing-12-03/poem.txt}}
```

<span class="caption">Listing 12-3: A poem by Emily Dickinson makes a good test
case</span>
</Listing>

With the text in place, edit *src/main.rs* and add code to read the file, as
shown in Listing 12-4.

<span class="filename">Filename: src/main.rs</span>
<Listing number="12-4" file-name="src/main.rs" caption="Reading the contents of the file specified by the second argument">

```rust,should_panic,noplayground
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-04/src/main.rs:here}}
```

<span class="caption">Listing 12-4: Reading the contents of the file specified
by the second argument</span>
</Listing>

First, we bring in a relevant part of the standard library with a `use`
statement: we need `std::fs` to handle files.
Expand Down
50 changes: 20 additions & 30 deletions src/ch12-03-improving-error-handling-and-modularity.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,13 @@ We’ll extract the functionality for parsing arguments into a function that
*src/lib.rs*. Listing 12-5 shows the new start of `main` that calls a new
function `parse_config`, which we’ll define in *src/main.rs* for the moment.

<span class="filename">Filename: src/main.rs</span>
<Listing number="12-5" file-name="src/main.rs" caption="Extracting a `parse_config` function from `main`">

```rust,ignore
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-05/src/main.rs:here}}
```

<span class="caption">Listing 12-5: Extracting a `parse_config` function from
`main`</span>
</Listing>

We’re still collecting the command line arguments into a vector, but instead of
assigning the argument value at index 1 to the variable `query` and the
Expand Down Expand Up @@ -112,14 +111,13 @@ other and what their purpose is.

Listing 12-6 shows the improvements to the `parse_config` function.

<span class="filename">Filename: src/main.rs</span>
<Listing number="12-6" file-name="src/main.rs" caption="Refactoring `parse_config` to return an instance of a `Config` struct">

```rust,should_panic,noplayground
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-06/src/main.rs:here}}
```

<span class="caption">Listing 12-6: Refactoring `parse_config` to return an
instance of a `Config` struct</span>
</Listing>

We’ve added a struct named `Config` defined to have fields named `query` and
`file_path`. The signature of `parse_config` now indicates that it returns a
Expand Down Expand Up @@ -179,14 +177,13 @@ changing `parse_config` into a `new` function associated with `Config`, we’ll
be able to create instances of `Config` by calling `Config::new`. Listing 12-7
shows the changes we need to make.

<span class="filename">Filename: src/main.rs</span>
<Listing number="12-7" file-name="src/main.rs" caption="Changing `parse_config` into `Config::new`">

```rust,should_panic,noplayground
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-07/src/main.rs:here}}
```

<span class="caption">Listing 12-7: Changing `parse_config` into
`Config::new`</span>
</Listing>

We’ve updated `main` where we were calling `parse_config` to instead call
`Config::new`. We’ve changed the name of `parse_config` to `new` and moved it
Expand Down Expand Up @@ -214,14 +211,13 @@ In Listing 12-8, we add a check in the `new` function that will verify that the
slice is long enough before accessing index 1 and 2. If the slice isn’t long
enough, the program panics and displays a better error message.

<span class="filename">Filename: src/main.rs</span>
<Listing number="12-8" file-name="src/main.rs" caption="Adding a check for the number of arguments">

```rust,ignore
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-08/src/main.rs:here}}
```

<span class="caption">Listing 12-8: Adding a check for the number of
arguments</span>
</Listing>

This code is similar to [the `Guess::new` function we wrote in Listing
9-13][ch9-custom-types]<!-- ignore -->, where we called `panic!` when the
Expand Down Expand Up @@ -265,14 +261,13 @@ function we’re now calling `Config::build` and the body of the function needed
to return a `Result`. Note that this won’t compile until we update `main` as
well, which we’ll do in the next listing.

<span class="filename">Filename: src/main.rs</span>
<Listing number="12-9" file-name="src/main.rs" caption="Returning a `Result` from `Config::build`">

```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-09/src/main.rs:here}}
```

<span class="caption">Listing 12-9: Returning a `Result` from
`Config::build`</span>
</Listing>

Our `build` function returns a `Result` with a `Config` instance in the success
case and a `&'static str` in the error case. Our error values will always be
Expand All @@ -299,14 +294,13 @@ tool with a nonzero error code away from `panic!` and instead implement it by
hand. A nonzero exit status is a convention to signal to the process that
called our program that the program exited with an error state.

<span class="filename">Filename: src/main.rs</span>
<Listing number="12-10" file-name="src/main.rs" caption="Exiting with an error code if building a `Config` fails">

```rust,ignore
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-10/src/main.rs:here}}
```

<span class="caption">Listing 12-10: Exiting with an error code if building a
`Config` fails</span>
</Listing>

In this listing, we’ve used a method we haven’t covered in detail yet:
`unwrap_or_else`, which is defined on `Result<T, E>` by the standard library.
Expand Down Expand Up @@ -350,14 +344,13 @@ Listing 12-11 shows the extracted `run` function. For now, we’re just making
the small, incremental improvement of extracting the function. We’re still
defining the function in *src/main.rs*.

<span class="filename">Filename: src/main.rs</span>
<Listing number="12-11" file-name="src/main.rs" caption="Extracting a `run` function containing the rest of the program logic">

```rust,ignore
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-11/src/main.rs:here}}
```

<span class="caption">Listing 12-11: Extracting a `run` function containing the
rest of the program logic</span>
</Listing>

The `run` function now contains all the remaining logic from `main`, starting
from reading the file. The `run` function takes the `Config` instance as an
Expand All @@ -373,14 +366,13 @@ us further consolidate the logic around handling errors into `main` in a
user-friendly way. Listing 12-12 shows the changes we need to make to the
signature and body of `run`.

<span class="filename">Filename: src/main.rs</span>
<Listing number="12-12" file-name="src/main.rs" caption="Changing the `run` function to return `Result`">

```rust,ignore
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-12/src/main.rs:here}}
```

<span class="caption">Listing 12-12: Changing the `run` function to return
`Result`</span>
</Listing>

We’ve made three significant changes here. First, we changed the return type of
the `run` function to `Result<(), Box<dyn Error>>`. This function previously
Expand Down Expand Up @@ -458,14 +450,13 @@ The contents of *src/lib.rs* should have the signatures shown in Listing 12-13
(we’ve omitted the bodies of the functions for brevity). Note that this won’t
compile until we modify *src/main.rs* in Listing 12-14.

<span class="filename">Filename: src/lib.rs</span>
<Listing number="12-13" file-name="src/lib.rs" caption="Moving `Config` and `run` into *src/lib.rs*">

```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-13/src/lib.rs:here}}
```

<span class="caption">Listing 12-13: Moving `Config` and `run` into
*src/lib.rs*</span>
</Listing>

We’ve made liberal use of the `pub` keyword: on `Config`, on its fields and its
`build` method, and on the `run` function. We now have a library crate that has
Expand All @@ -474,14 +465,13 @@ a public API we can test!
Now we need to bring the code we moved to *src/lib.rs* into the scope of the
binary crate in *src/main.rs*, as shown in Listing 12-14.

<span class="filename">Filename: src/main.rs</span>
<Listing number="12-14" file-name="src/main.rs" caption="Using the `minigrep` library crate in *src/main.rs*">

```rust,ignore
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-14/src/main.rs:here}}
```

<span class="caption">Listing 12-14: Using the `minigrep` library crate in
*src/main.rs*</span>
</Listing>

We add a `use minigrep::Config` line to bring the `Config` type from the
library crate into the binary crate’s scope, and we prefix the `run` function
Expand Down
25 changes: 10 additions & 15 deletions src/ch12-04-testing-the-librarys-functionality.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,13 @@ behavior we want the `search` function to have: it will take a query and the
text to search, and it will return only the lines from the text that contain
the query. Listing 12-15 shows this test, which won’t compile yet.

<span class="filename">Filename: src/lib.rs</span>
<Listing number="12-15" file-name="src/lib.rs" caption="Creating a failing test for the `search` function we wish we had">

```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-15/src/lib.rs:here}}
```

<span class="caption">Listing 12-15: Creating a failing test for the `search`
function we wish we had</span>
</Listing>

This test searches for the string `"duct"`. The text we’re searching is three
lines, only one of which contains `"duct"` (Note that the backslash after the
Expand All @@ -58,14 +57,13 @@ vector, as shown in Listing 12-16. Then the test should compile and fail
because an empty vector doesn’t match a vector containing the line `"safe,
fast, productive."`

<span class="filename">Filename: src/lib.rs</span>
<Listing number="12-16" file-name="src/lib.rs" caption="Defining just enough of the `search` function so our test will compile">

```rust,noplayground
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-16/src/lib.rs:here}}
```

<span class="caption">Listing 12-16: Defining just enough of the `search`
function so our test will compile</span>
</Listing>

Notice that we need to define an explicit lifetime `'a` in the signature of
`search` and use that lifetime with the `contents` argument and the return
Expand Down Expand Up @@ -128,14 +126,13 @@ Rust has a helpful method to handle line-by-line iteration of strings,
conveniently named `lines`, that works as shown in Listing 12-17. Note this
won’t compile yet.

<span class="filename">Filename: src/lib.rs</span>
<Listing number="12-17" file-name="src/lib.rs" caption="Iterating through each line in `contents`">

```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-17/src/lib.rs:here}}
```

<span class="caption">Listing 12-17: Iterating through each line in `contents`
</span>
</Listing>

The `lines` method returns an iterator. We’ll talk about iterators in depth in
[Chapter 13][ch13-iterators]<!-- ignore -->, but recall that you saw this way
Expand All @@ -149,14 +146,13 @@ Fortunately, strings have a helpful method named `contains` that does this for
us! Add a call to the `contains` method in the `search` function, as shown in
Listing 12-18. Note this still won’t compile yet.

<span class="filename">Filename: src/lib.rs</span>
<Listing number="12-18" file-name="src/lib.rs" caption="Adding functionality to see whether the line contains the string in `query`">

```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-18/src/lib.rs:here}}
```

<span class="caption">Listing 12-18: Adding functionality to see whether the
line contains the string in `query`</span>
</Listing>

At the moment, we’re building up functionality. To get it to compile, we need
to return a value from the body as we indicated we would in the function
Expand All @@ -169,14 +165,13 @@ to return. For that, we can make a mutable vector before the `for` loop and
call the `push` method to store a `line` in the vector. After the `for` loop,
we return the vector, as shown in Listing 12-19.

<span class="filename">Filename: src/lib.rs</span>
<Listing number="12-19" file-name="src/lib.rs" caption="Storing the lines that match so we can return them">

```rust,ignore
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-19/src/lib.rs:here}}
```

<span class="caption">Listing 12-19: Storing the lines that match so we can
return them</span>
</Listing>

Now the `search` function should return only the lines that contain `query`,
and our test should pass. Let’s run the test:
Expand Down
20 changes: 8 additions & 12 deletions src/ch12-05-working-with-environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,13 @@ the new `search_case_insensitive` function and rename our old test from
`one_result` to `case_sensitive` to clarify the differences between the two
tests, as shown in Listing 12-20.

<span class="filename">Filename: src/lib.rs</span>
<Listing number="12-20" file-name="src/lib.rs" caption="Adding a new failing test for the case-insensitive function we’re about to add">

```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-20/src/lib.rs:here}}
```

<span class="caption">Listing 12-20: Adding a new failing test for the
case-insensitive function we’re about to add</span>
</Listing>

Note that we’ve edited the old test’s `contents` too. We’ve added a new line
with the text `"Duct tape."` using a capital D that shouldn’t match the query
Expand All @@ -48,14 +47,13 @@ the same as the `search` function. The only difference is that we’ll lowercase
the `query` and each `line` so whatever the case of the input arguments,
they’ll be the same case when we check whether the line contains the query.

<span class="filename">Filename: src/lib.rs</span>
<Listing number="12-21" file-name="src/lib.rs" caption="Defining the `search_case_insensitive` function to lowercase the query and the line before comparing them">

```rust,noplayground
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-21/src/lib.rs:here}}
```

<span class="caption">Listing 12-21: Defining the `search_case_insensitive`
function to lowercase the query and the line before comparing them</span>
</Listing>

First, we lowercase the `query` string and store it in a shadowed variable with
the same name. Calling `to_lowercase` on the query is necessary so no
Expand Down Expand Up @@ -101,14 +99,13 @@ function to check the `ignore_case` field’s value and use that to decide
whether to call the `search` function or the `search_case_insensitive`
function, as shown in Listing 12-22. This still won’t compile yet.

<span class="filename">Filename: src/lib.rs</span>
<Listing number="12-22" file-name="src/lib.rs" caption="Calling either `search` or `search_case_insensitive` based on the value in `config.ignore_case`">

```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-22/src/lib.rs:there}}
```

<span class="caption">Listing 12-22: Calling either `search` or
`search_case_insensitive` based on the value in `config.ignore_case`</span>
</Listing>

Finally, we need to check for the environment variable. The functions for
working with environment variables are in the `env` module in the standard
Expand All @@ -117,14 +114,13 @@ we’ll use the `var` function from the `env` module to check if any value
has been set for an environment variable named `IGNORE_CASE`, as shown in
Listing 12-23.

<span class="filename">Filename: src/lib.rs</span>
<Listing number="12-23" file-name="src/lib.rs" caption="Checking for any value in an environment variable named `IGNORE_CASE`">

```rust,noplayground
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-23/src/lib.rs:here}}
```

<span class="caption">Listing 12-23: Checking for any value in an environment
variable named `IGNORE_CASE`</span>
</Listing>

Here, we create a new variable `ignore_case`. To set its value, we call the
`env::var` function and pass it the name of the `IGNORE_CASE` environment
Expand Down
Loading

0 comments on commit 45c1a6d

Please sign in to comment.