Merge pull request #106 from rustlings/new

rustlings v2
This commit is contained in:
komaeda 2019-01-23 22:04:01 +01:00 committed by GitHub
commit df3389cfb0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
75 changed files with 541 additions and 586 deletions

3
.gitignore vendored
View file

@ -1,2 +1,5 @@
*.swp
target/
**/*.rs.bk
Cargo.lock
.DS_Store

View file

@ -1,19 +0,0 @@
language: rust
branches:
only:
- master
cache:
cargo: true
script:
- cargo run --bin generate_readme
- git config user.name "Carol (Nichols || Goulding)"
- git config user.email "carol.nichols@gmail.com"
- git commit -am "Regenerate README" && git remote add upstream "https://$GH_TOKEN@github.com/carols10cents/rustlings.git" && git push -q upstream HEAD:master > /dev/null 2>&1 || true
notifications:
email:
on_success: never

View file

@ -1,9 +1,12 @@
[package]
name = "rustlings"
version = "0.1.0"
authors = ["Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
authors = ["olivia <819880950@qq.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com"]
edition = "2018"
[dependencies]
handlebars = "0.32.0"
serde_json = "1.0.10"
prlink = { git = "https://github.com/btbytes/prlink" }
clap = "2.32.0"
indicatif = "0.9.0"
console = "0.6.2"
syntect = "3.0.2"
notify = "4.0.0"

View file

@ -1,191 +0,0 @@
<!--
{{ autogenerated_notice }}
-->
# rustlings
Small exercises to get you used to reading and writing Rust code. Includes practice reading and
responding to compiler messages!
This repo is very much the smallest thing that could possibly work :)
## To do these exercises
Thanks to [btbytes'](https://twitter.com/btbytes) [prlinks](https://github.com/btbytes/prlink), you
can now click on the links below to load the exercises in the rust playground!
There are infinite correct answers-- the exercises are sometimes left very open-ended. Scroll down
in the playground to find comments that have hints.
If you need more help or would like to compare solutions, you can ask in [#rust-beginners on
irc.mozilla.org](https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-beginners ), the
[user forum](https://users.rust-lang.org/), or [the subreddit](https://reddit.com/r/rust). If an
exercise could be improved in any way, please [create an
issue](https://github.com/carols10cents/rustlings/issues/new) or submit a pull request!
### Variable bindings
[Relevant chapter in The Rust Programming
Language](https://doc.rust-lang.org/book/second-edition/ch03-01-variables-and-mutability.html)
{{ playground_link "variables/variables1.rs" }}
{{ playground_link "variables/variables2.rs" }}
{{ playground_link "variables/variables3.rs" }}
{{ playground_link "variables/variables4.rs" }}
### Functions
[Relevant chapter in The Rust Programming
Language](https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html)
{{ playground_link "functions/functions1.rs" }}
{{ playground_link "functions/functions2.rs" }}
{{ playground_link "functions/functions3.rs" }}
{{ playground_link "functions/functions4.rs" }}
{{ playground_link "functions/functions5.rs" }}
### Primitive types
[Relevant chapter in The Rust Programming
Language](https://doc.rust-lang.org/book/second-edition/ch03-02-data-types.html)
{{ playground_link "primitive_types/primitive_types1.rs" }}
{{ playground_link "primitive_types/primitive_types2.rs" }}
{{ playground_link "primitive_types/primitive_types3.rs" }}
{{ playground_link "primitive_types/primitive_types4.rs" }}
{{ playground_link "primitive_types/primitive_types5.rs" }}
{{ playground_link "primitive_types/primitive_types6.rs" }}
### Tests
Going out of order from the book to cover tests-- many of the following exercises will ask you to
make tests pass!
[Relevant chapter in The Rust Programming
Language](https://doc.rust-lang.org/book/second-edition/ch11-01-writing-tests.html)
{{ playground_link "tests/tests1.rs" }}
{{ playground_link "tests/tests2.rs" }}
{{ playground_link "tests/tests3.rs" }}
{{ playground_link "tests/tests4.rs" }}
### If
[Relevant chapter in The Rust Programming
Language](https://doc.rust-lang.org/book/second-edition/ch03-05-control-flow.html)
{{ playground_link "if/if1.rs" }}
### Strings
[Relevant chapter in The Rust Programming
Language](https://doc.rust-lang.org/book/second-edition/ch08-02-strings.html)
{{ playground_link "strings/strings1.rs" }}
{{ playground_link "strings/strings2.rs" }}
{{ playground_link "strings/strings3.rs" }}
### Move semantics
These exercises are adapted from [pnkfelix]()'s [Rust
Tutorial](https://pnkfelix.github.io/rust-examples-icfp2014/) -- thank you Felix!!!
Relevant chapters in the book:
- [Ownership](https://doc.rust-lang.org/book/second-edition/ch04-01-what-is-ownership.html)
- [References and borrowing](https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html)
Note that the exercises in this section may look similar to each other but they are subtly
different :)
{{ playground_link "move_semantics/move_semantics1.rs" }}
{{ playground_link "move_semantics/move_semantics2.rs" }}
{{ playground_link "move_semantics/move_semantics3.rs" }}
{{ playground_link "move_semantics/move_semantics4.rs" }}
### Modules
[Relevant chapter in The Rust Programming
Language](https://doc.rust-lang.org/book/second-edition/ch07-01-mod-and-the-filesystem.html)
{{ playground_link "modules/modules1.rs" }}
{{ playground_link "modules/modules2.rs" }}
### Macros
Check out:
- [The Macros section of the first edition of the book
book](https://doc.rust-lang.org/book/first-edition/macros.html)
- [The Macros appendix of the second edition of the
book](https://doc.rust-lang.org/book/second-edition/appendix-04-macros.html)
- [The Little Book of Rust Macros](https://danielkeep.github.io/tlborm/book/index.html)
{{ playground_link "macros/macros1.rs" }}
{{ playground_link "macros/macros2.rs" }}
{{ playground_link "macros/macros3.rs" }}
{{ playground_link "macros/macros4.rs" }}
### Error Handling
The [Error
Handling](https://doc.rust-lang.org/book/second-edition/ch09-02-recoverable-errors-with-result.html)
and [Generics](https://doc.rust-lang.org/book/second-edition/ch10-01-syntax.html) sections are
relevant.
{{ playground_link "error_handling/option1.rs" }}
{{ playground_link "error_handling/result1.rs" }}
{{ playground_link "error_handling/errors1.rs" }}
{{ playground_link "error_handling/errors2.rs" }}
{{ playground_link "error_handling/errors3.rs" }}
{{ playground_link "error_handling/errorsn.rs" }}
### Standard library types
#### `Arc`
The [Concurrency](https://doc.rust-lang.org/book/second-edition/ch16-03-shared-state.html) section
is relevant.
{{ playground_link "standard_library_types/arc1.rs" }}
#### Iterators
Do not adjust your monitors-- iterators 1 and 2 are indeed missing. Iterator 3 is a bit challenging
so we're leaving space for some exercises to lead up to it!
Check out the [Iterators chapter of the
book](https://doc.rust-lang.org/book/second-edition/ch13-02-iterators.html) and the [Iterator
docs](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html).
{{ playground_link "standard_library_types/iterator3.rs" }}
{{ playground_link "standard_library_types/iterators4.rs" }}
### Threads
See [the Dining Philosophers
example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) and the
[Concurrency Chapter](https://doc.rust-lang.org/book/second-edition/ch16-01-threads.html) from the
book.
{{ playground_link "threads/threads1.rs" }}
### Uncategorized
A few exercises based on things I've encountered or had trouble with getting used to.
{{ playground_link "ex1.rs" }}
{{ playground_link "ex2.rs" }}
{{ playground_link "ex3.rs" }}
{{ playground_link "ex4.rs" }}
{{ playground_link "ex5.rs" }}
{{ playground_link "ex6.rs" }}
## To help with this repo/TODO list
* File issues for problems or suggestions!
* Contribute more exercises! Anything that took you time to get used to, or that you had trouble
with, or that deserves practice would be a good exercise!
* How could the process of doing these exercises work better? This is an open-ended question :) Are
the playground links good enough? Are there ways that we could make going to the next exercise
easier without forking the playground??

235
README.md

File diff suppressed because one or more lines are too long

20
default_out.md Normal file
View file

@ -0,0 +1,20 @@
Thanks for installing `rustlings`!
## Is this your first time?
Let's make sure you're up to speed:
- You have Rust installed, preferably via `rustup`
- You have `~/.cargo/bin` added to your PATH variable
- You have cloned this repository (https://github.com/rustlings/rustlings)
- You have installed Rust language support for your editor
- You have locally installed the `rustlings` command by running:
```sh
cargo install --path .
```
If you've done all of this (or even most of it), congrats! You're ready
to start working with Rust.
To get started, run `rustlings verify` in order to get the first exercise.
Make sure to have your editor open!

6
ex1.rs
View file

@ -1,6 +0,0 @@
// ex1.rs
// Make me compile! :)
fn main() {
println();
}

10
ex2.rs
View file

@ -1,10 +0,0 @@
// ex2.rs
// Make me compile!
fn something() -> String {
"hi!"
}
fn main() {
println!("{}", something());
}

10
ex3.rs
View file

@ -1,10 +0,0 @@
// ex3.rs
// Make me compile!
struct Foo {
capacity: i32,
}
fn main() {
println!("{:?}", Foo { capacity: 3 });
}

14
ex4.rs
View file

@ -1,14 +0,0 @@
// ex4.rs
// Make me compile!
fn something() -> Result<i32, std::num::ParseIntError> {
let x:i32 = "3".parse();
Ok(x * 4)
}
fn main() {
match something() {
Ok(..) => println!("You win!"),
Err(e) => println!("Oh no something went wrong: {}", e),
}
}

22
ex5.rs
View file

@ -1,22 +0,0 @@
// ex5.rs
// Make me compile!
enum Reaction<'a> {
Sad(&'a str),
Happy(&'a str),
}
fn express(sentiment: Reaction) {
match sentiment {
Reaction::Sad(s) => println!(":( {}", s),
Reaction::Happy(s) => println!(":) {}", s),
}
}
fn main () {
let x = Reaction::Happy("It's a great day for Rust!");
express(x);
express(x);
let y = Reaction::Sad("This code doesn't compile yet.");
express(y);
}

47
ex6.rs
View file

@ -1,47 +0,0 @@
// ex6.rs
// Make me compile! Scroll down for hints :)
fn main() {
let robot_name = Some(String::from("Bors"));
match robot_name {
Some(name) => println!("Found a name: {}", name),
None => (),
}
println!("robot_name is: {:?}", robot_name);
}
// Hint: The following two statements are equivalent:
// let x = &y;
// let ref x = y;

View file

@ -0,0 +1,5 @@
For this exercise check out the sections:
- [Error Handling](https://doc.rust-lang.org/book/2018-edition/ch09-02-recoverable-errors-with-result.html)
- [Generics](https://doc.rust-lang.org/book/2018-edition/ch10-01-syntax.html)
of the Rust Book.

View file

View file

View file

View file

View file

View file

View file

@ -0,0 +1,7 @@
### Functions
Here, you'll learn how to write functions and how Rust's compiler can trace things way back.
#### Book Sections
- [How Functions Work](https://doc.rust-lang.org/stable/book/ch03-03-how-functions-work.html)

View file

View file

View file

View file

View file

7
exercises/if/README.md Normal file
View file

@ -0,0 +1,7 @@
### If
`if`, the most basic type of control flow, is what you'll learn here.
#### Book Sections
- [Control Flow - if expressions](https://doc.rust-lang.org/stable/book/ch03-05-control-flow.html#if-expressions)

1
if/if1.rs → exercises/if/if1.rs Normal file → Executable file
View file

@ -9,6 +9,7 @@ pub fn bigger(a: i32, b:i32) -> i32 {
// Scroll down for hints.
}
// Don't mind this for now :)
#[cfg(test)]
mod tests {
use super::*;

View file

@ -0,0 +1,10 @@
### Macros
Rust's macro system is very powerful, but also kind of difficult to wrap your
head around. We're not going to teach you how to write your own fully-featured
modules, instead we'll show you how to use and create them.
#### Book Sections
- [Macros](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)
- [The Little Book of Rust Macros](https://danielkeep.github.io/tlborm/book/index.html)

0
macros/macros1.rs → exercises/macros/macros1.rs Normal file → Executable file
View file

0
macros/macros2.rs → exercises/macros/macros2.rs Normal file → Executable file
View file

0
macros/macros3.rs → exercises/macros/macros3.rs Normal file → Executable file
View file

0
macros/macros4.rs → exercises/macros/macros4.rs Normal file → Executable file
View file

View file

@ -0,0 +1,7 @@
### Modules
In this section we'll give you an introduction to Rust's module system.
#### Book Sections
- [The Module System](https://doc.rust-lang.org/stable/book/ch07-02-modules-and-use-to-control-scope-and-privacy.html)

0
modules/modules1.rs → exercises/modules/modules1.rs Normal file → Executable file
View file

45
exercises/modules/modules2.rs Executable file
View file

@ -0,0 +1,45 @@
// modules2.rs
// Make me compile! Scroll down for hints :)
mod delicious_snacks {
use self::fruits::PEAR as fruit;
use self::veggies::CUCUMBER as veggie;
mod fruits {
pub const PEAR: &'static str = "Pear";
pub const APPLE: &'static str = "Apple";
}
mod veggies {
pub const CUCUMBER: &'static str = "Cucumber";
pub const CARROT: &'static str = "Carrot";
}
}
fn main() {
println!("favorite snacks: {} and {}",
delicious_snacks::fruit,
delicious_snacks::veggie);
}
// The delicious_snacks module is trying to present an external
// interface (the `fruit` and `veggie` constants) that is different than
// its internal structure (the `fruits` and `veggies` modules and
// associated constants). It's almost there except for one keyword missing for
// each constant.

View file

@ -0,0 +1,10 @@
### Move Semantics
These exercises are adapted from [pnkfelix](https://github.com/pnkfelix)'s [Rust Tutorial](https://pnkfelix.github.io/rust-examples-icfp2014/) -- Thank you Felix!!!
#### Book Sections
For this section, the book links are especially important.
- [Ownership](https://doc.rust-lang.org/stable/book/ch04-01-what-is-ownership.html)
- [Reference and borrowing](https://doc.rust-lang.org/stable/book/ch04-02-references-and-borrowing.html)

View file

@ -0,0 +1,8 @@
### Primitive Types
Rust has a couple of basic types that are directly implemented into the
compiler. In this section, we'll go through the most important ones.
#### Book Sections
- [Data Types](https://doc.rust-lang.org/stable/book/ch03-02-data-types.html)

View file

@ -39,11 +39,11 @@ fn main() {
// Take a look at the Understanding Ownership -> Slices -> Other Slices section of the book:
// https://doc.rust-lang.org/stable/book/second-edition/ch04-03-slices.html#other-slices
// https://doc.rust-lang.org/book/ch04-03-slices.html
// and use the starting and ending indices of the items in the Array
// that you want to end up in the slice.
// If you're curious why the right hand of the `==` comparison does not
// have an ampersand for a reference since the left hand side is a
// reference, take a look at the Deref coercions section of the book:
// https://doc.rust-lang.org/stable/book/second-edition/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods
// https://doc.rust-lang.org/book/ch15-02-deref.html

View file

@ -39,7 +39,7 @@ fn main() {
// Take a look at the Data Types -> The Tuple Type section of the book:
// https://doc.rust-lang.org/stable/book/second-edition/ch03-02-data-types.html#the-tuple-type
// https://doc.rust-lang.org/stable/book/ch03-02-data-types.html#the-tuple-type
// Particularly the part about destructuring (second to last example in the section).
// You'll need to make a pattern to bind `name` and `age` to the appropriate parts
// of the tuple. You can do it!!

View file

@ -41,5 +41,5 @@ fn main() {
// While you could use a destructuring `let` for the tuple here, try
// indexing into it instead, as explained in the last example of the
// Data Types -> The Tuple Type section of the book:
// https://doc.rust-lang.org/stable/book/second-edition/ch03-02-data-types.html#the-tuple-type
// https://doc.rust-lang.org/stable/book/ch03-02-data-types.html#the-tuple-type
// Now you have another tool in your toolbox!

View file

@ -0,0 +1,5 @@
For the Arc exercise check out the chapter [Shared-State Concurrency](https://doc.rust-lang.org/book/2018-edition/ch16-03-shared-state.html) of the Rust Book.
For the Iterator exercise check out the chapters [Iterator](https://doc.rust-lang.org/book/2018-edition/ch13-02-iterators.html) of the Rust Book and the [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.htmlj).
Do not adjust your monitors-- iterators 1 and 2 are indeed missing. Iterator 3 is a bit challenging so we're leaving space for some exercises to lead up to it!

View file

@ -0,0 +1,9 @@
### Strings
Rust has two string types, a string slice (`&str`) and an owned string (`String`).
We're not going to dictate when you should use which one, but we'll show you how
to identify and create them, as well as use them.
#### Book Sections
- [Strings](https://doc.rust-lang.org/stable/book/ch08-02-strings.html)

0
strings/strings1.rs → exercises/strings/strings1.rs Normal file → Executable file
View file

0
strings/strings2.rs → exercises/strings/strings2.rs Normal file → Executable file
View file

20
exercises/test1.rs Normal file
View file

@ -0,0 +1,20 @@
// test1.rs
// This is a test for the following sections:
// - Variables
// - Functions
// Mary is buying apples. One apple usually costs 2 dollars, but if you buy
// more than 40 at once, each apple only costs 1! Write a function that calculates
// the price of an order of apples given the order amount.
fn main() {
let price1 = calculateprice(55);
let price2 = calculateprice(40);
// Don't modify this!
if price1 == 55 && price2 == 80 {
println!("Good job!");
} else {
panic!("Uh oh! Wrong price!");
}
}

5
tests/tests4.rs → exercises/test2.rs Normal file → Executable file
View file

@ -1,4 +1,7 @@
// tests4.rs
// test2.rs
// This is a test for the following sections:
// - Tests
// This test isn't testing our function -- make it do that in such a way that
// the test passes. Then write a second test that tests that we get the result
// we expect to get when we call `times_two` with a negative number.

3
strings/strings3.rs → exercises/test3.rs Normal file → Executable file
View file

@ -1,4 +1,7 @@
// strings3.rs
// This is a test for the following sections:
// - Strings
// Ok, here are a bunch of values-- some are `Strings`, some are `&strs`. Your
// task is to call one of these two functions on each value depending on what
// you think each value is. That is, add either `string_slice` or `string`

12
exercises/test4.rs Normal file
View file

@ -0,0 +1,12 @@
// test4.rs
// This test covers the sections:
// - Modules
// - Macros
// Write a macro that passes the test! No hints this time, you can do it!
fn main() {
if my_macro!("world!") != "Hello world!" {
panic!("Oh no! Wrong output!");
}
}

View file

@ -0,0 +1,7 @@
### Tests
Going out of order from the book to cover tests -- many of the following exercises will ask you to make tests pass!
#### Book Sections
- [Writing Tests](https://doc.rust-lang.org/stable/book/ch11-01-writing-tests.html)

2
tests/tests1.rs → exercises/tests/tests1.rs Normal file → Executable file
View file

@ -1,7 +1,7 @@
// tests1.rs
// Tests are important to ensure that your code does what you think it should do.
// Tests can be run on this file with the following command:
// rustc --test tests1.rs
// rustlings run --test exercises/tests/tests1.rs
// This test has a problem with it -- make the test compile! Make the test
// pass! Make the test fail! Scroll down for hints :)

0
tests/tests2.rs → exercises/tests/tests2.rs Normal file → Executable file
View file

4
tests/tests3.rs → exercises/tests/tests3.rs Normal file → Executable file
View file

@ -1,6 +1,6 @@
// tests3.rs
// This test isn't testing our function -- make it do that in such a way that
// the test passes. Then write a second test that tests that we get the result
// the test passes. Then write a second test that tests whether we get the result
// we expect to get when we call `is_even(5)`. Scroll down for hints!
pub fn is_even(num: i32) -> bool {
@ -13,7 +13,7 @@ mod tests {
#[test]
fn is_true_when_even() {
assert!(false);
assert!();
}
}

View file

@ -0,0 +1 @@
For this exercise check out the [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) and the chapter [Concurrency](https://doc.rust-lang.org/book/2018-edition/ch16-01-threads.html) of the Rust Book.

0
threads/threads1.rs → exercises/threads/threads1.rs Normal file → Executable file
View file

View file

@ -0,0 +1,7 @@
### Variables
Here you'll learn about simple variables.
#### Book Sections
- [Variables and Mutability](https://doc.rust-lang.org/stable/book/ch03-01-variables-and-mutability.html)

View file

View file

View file

View file

View file

@ -1,45 +0,0 @@
// modules2.rs
// Make me compile! Scroll down for hints :)
mod us_presidential_frontrunners {
use self::democrats::HILLARY_CLINTON as democrat;
use self::republicans::DONALD_TRUMP as republican;
mod democrats {
pub const HILLARY_CLINTON: &'static str = "Hillary Clinton";
pub const BERNIE_SANDERS: &'static str = "Bernie Sanders";
}
mod republicans {
pub const DONALD_TRUMP: &'static str = "Donald Trump";
pub const JEB_BUSH: &'static str = "Jeb Bush";
}
}
fn main() {
println!("candidates: {} and {}",
us_presidential_frontrunners::democrat,
us_presidential_frontrunners::republican);
}
// The us_presidential_frontrunners module is trying to present an external
// interface (the `democrat` and `republican` constants) that is different than
// its internal structure (the `democrats` and `republicans` modules and
// associated constants). It's almost there except for one keyword missing for
// each constant.

View file

@ -1,49 +0,0 @@
// This script reads README-template.md and generates the playground links
// from the Rust source files in the various directories.
// To add a new exercise, add it to the appropriate place in README-template.md
// and then make sure to recompile this script (because the template gets
// included at compile time and then run it to generate a new version of
// README.md.
extern crate handlebars;
extern crate prlink;
#[macro_use]
extern crate serde_json;
use handlebars::{Handlebars, Helper, RenderContext, RenderError};
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;
fn main() {
let mut template_file = File::open("README-template.hbs").unwrap();
let mut template = String::new();
template_file.read_to_string(&mut template).unwrap();
let autogenerated_notice = "This file was autogenerated by the script in src/bin/generate_readme.rs.
Please edit either the script or the template in README-template.md in
order to make changes here rather than committing the changes directly.";
let mut generated_readme = File::create("README.md").unwrap();
let mut hbs = Handlebars::new();
hbs.register_helper("playground_link", Box::new(playground_link_helper));
write!(
generated_readme,
"{}",
hbs.render_template(
&template,
&json!({ "autogenerated_notice": autogenerated_notice }),
).unwrap()
).unwrap();
}
fn playground_link_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
let filename = PathBuf::from(h.param(0).unwrap().value().as_str().unwrap());
let link = prlink::linkify_file(&filename);
rc.writer.write(link.into_bytes().as_ref())?;
Ok(())
}

96
src/main.rs Normal file
View file

@ -0,0 +1,96 @@
use crate::run::run;
use crate::verify::verify;
use clap::{crate_version, App, Arg, SubCommand};
use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::io::BufRead;
use std::sync::mpsc::channel;
use std::time::Duration;
use syntect::easy::HighlightFile;
use syntect::highlighting::{Style, ThemeSet};
use syntect::parsing::SyntaxSet;
use syntect::util::as_24_bit_terminal_escaped;
mod run;
mod util;
mod verify;
fn main() {
let matches = App::new("rustlings")
.version(crate_version!())
.author("Olivia Hugger, Carol Nichols")
.about("Rustlings is a collection of small exercises to get you used to writing and reading Rust code")
.subcommand(SubCommand::with_name("verify").alias("v").about("Verifies all exercises according to the recommended order"))
.subcommand(SubCommand::with_name("watch").alias("w").about("Reruns `verify` when files were edited"))
.subcommand(
SubCommand::with_name("run")
.alias("r")
.about("Runs/Tests a single exercise")
.arg(Arg::with_name("file").required(true).index(1))
.arg(Arg::with_name("test").short("t").long("test").help("Run the file as a test")),
)
.get_matches();
let ss = SyntaxSet::load_defaults_newlines();
let ts = ThemeSet::load_defaults();
if None == matches.subcommand_name() {
println!("");
println!(r#" welcome to... "#);
println!(r#" _ _ _ "#);
println!(r#" _ __ _ _ ___| |_| (_)_ __ __ _ ___ "#);
println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
println!(r#" | | | |_| \__ \ |_| | | | | | (_| \__ \ "#);
println!(r#" |_| \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
println!(r#" |___/ "#);
println!("");
}
if let Some(matches) = matches.subcommand_matches("run") {
run(matches.clone());
}
if let Some(_) = matches.subcommand_matches("verify") {
match verify() {
Ok(_) => {}
Err(_) => std::process::exit(1),
}
}
if let Some(_) = matches.subcommand_matches("watch") {
watch().unwrap();
}
if let None = matches.subcommand_name() {
let mut highlighter =
HighlightFile::new("default_out.md", &ss, &ts.themes["base16-eighties.dark"]).unwrap();
for maybe_line in highlighter.reader.lines() {
let line = maybe_line.unwrap();
let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
}
}
println!("\x1b[0m");
}
fn watch() -> notify::Result<()> {
let (tx, rx) = channel();
let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
watcher.watch("./exercises", RecursiveMode::Recursive)?;
let _ignored = verify();
loop {
match rx.recv() {
Ok(event) => match event {
DebouncedEvent::Chmod(_) | DebouncedEvent::Write(_) => {
let _ignored = verify();
}
_ => {}
},
Err(e) => println!("watch error: {:?}", e),
}
}
}

55
src/run.rs Normal file
View file

@ -0,0 +1,55 @@
use crate::util::clean;
use crate::verify::test;
use console::{style, Emoji};
use indicatif::ProgressBar;
use std::process::Command;
pub fn run(matches: clap::ArgMatches) {
if let Some(filename) = matches.value_of("file") {
if matches.is_present("test") {
match test(filename) {
Ok(_) => (),
Err(_) => (),
}
std::process::exit(0);
}
let bar = ProgressBar::new_spinner();
bar.set_message(format!("Compiling {}...", filename).as_str());
bar.enable_steady_tick(100);
let compilecmd = Command::new("rustc")
.args(&[filename, "-o", "temp"])
.output()
.expect("fail");
bar.set_message(format!("Running {}...", filename).as_str());
if compilecmd.status.success() {
let runcmd = Command::new("./temp").output().expect("fail");
bar.finish_and_clear();
if runcmd.status.success() {
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
let formatstr = format!("{} Successfully ran {}", Emoji("", ""), filename);
println!("{}", style(formatstr).green());
clean();
} else {
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
println!("{}", String::from_utf8_lossy(&runcmd.stderr));
let formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), filename);
println!("{}", style(formatstr).red());
clean();
}
} else {
bar.finish_and_clear();
let formatstr = format!(
"{} Compilation of {} failed! Compiler error message:\n",
Emoji("⚠️ ", "!"),
filename
);
println!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
clean();
}
} else {
panic!("Please supply a filename!");
}
}

5
src/util.rs Normal file
View file

@ -0,0 +1,5 @@
use std::fs::remove_file;
pub fn clean() {
let _ignored = remove_file("temp");
}

106
src/verify.rs Normal file
View file

@ -0,0 +1,106 @@
use crate::util::clean;
use console::{style, Emoji};
use indicatif::ProgressBar;
use std::process::Command;
pub fn verify() -> Result<(), ()> {
compile_only("exercises/variables/variables1.rs")?;
compile_only("exercises/variables/variables2.rs")?;
compile_only("exercises/variables/variables3.rs")?;
compile_only("exercises/variables/variables4.rs")?;
test("exercises/if/if1.rs")?;
compile_only("exercises/functions/functions1.rs")?;
compile_only("exercises/functions/functions2.rs")?;
compile_only("exercises/functions/functions3.rs")?;
compile_only("exercises/functions/functions4.rs")?;
compile_only("exercises/functions/functions5.rs")?;
compile_only("exercises/test1.rs")?;
compile_only("exercises/primitive_types/primitive_types1.rs")?;
compile_only("exercises/primitive_types/primitive_types2.rs")?;
compile_only("exercises/primitive_types/primitive_types3.rs")?;
compile_only("exercises/primitive_types/primitive_types4.rs")?;
compile_only("exercises/primitive_types/primitive_types5.rs")?;
compile_only("exercises/primitive_types/primitive_types6.rs")?;
test("exercises/tests/tests1.rs")?;
test("exercises/tests/tests2.rs")?;
test("exercises/tests/tests3.rs")?;
test("exercises/test2.rs")?;
compile_only("exercises/strings/strings1.rs")?;
compile_only("exercises/strings/strings2.rs")?;
compile_only("exercises/test3.rs")?;
compile_only("exercises/modules/modules1.rs")?;
compile_only("exercises/modules/modules2.rs")?;
compile_only("exercises/macros/macros1.rs")?;
compile_only("exercises/macros/macros2.rs")?;
compile_only("exercises/macros/macros3.rs")?;
compile_only("exercises/macros/macros4.rs")?;
compile_only("exercises/test4.rs")?;
compile_only("exercises/move_semantics/move_semantics1.rs")?;
compile_only("exercises/move_semantics/move_semantics2.rs")?;
compile_only("exercises/move_semantics/move_semantics3.rs")?;
compile_only("exercises/move_semantics/move_semantics4.rs")?;
test("exercises/error_handling/errors1.rs")?;
test("exercises/error_handling/errors2.rs")?;
test("exercises/error_handling/errors3.rs")?;
test("exercises/error_handling/errorsn.rs")?;
compile_only("exercises/error_handling/option1.rs")?;
test("exercises/error_handling/result1.rs")?;
Ok(())
}
fn compile_only(filename: &str) -> Result<(), ()> {
let bar = ProgressBar::new_spinner();
bar.set_message(format!("Compiling {}...", filename).as_str());
bar.enable_steady_tick(100);
let compilecmd = Command::new("rustc")
.args(&[filename, "-o", "temp", "--color", "always"])
.output()
.expect("fail");
bar.finish_and_clear();
if compilecmd.status.success() {
let formatstr = format!(
"{} Successfully compiled {}!",
Emoji("", ""),
filename
);
println!("{}", style(formatstr).green());
clean();
Ok(())
} else {
let formatstr = format!(
"{} Compilation of {} failed! Compiler error message:\n",
Emoji("⚠️ ", "!"),
filename
);
println!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
clean();
Err(())
}
}
pub fn test(filename: &str) -> Result<(), ()> {
let bar = ProgressBar::new_spinner();
bar.set_message(format!("Testing {}...", filename).as_str());
bar.enable_steady_tick(100);
let testcmd = Command::new("rustc")
.args(&["--test", filename, "-o", "temp"])
.output()
.expect("fail");
bar.finish_and_clear();
if testcmd.status.success() {
let formatstr = format!("{} Successfully tested {}!", Emoji("", ""), filename);
println!("{}", style(formatstr).green());
clean();
Ok(())
} else {
let formatstr = format!(
"{} Testing of {} failed! Please try again.",
Emoji("⚠️ ", "!"),
filename
);
println!("{}", style(formatstr).red());
clean();
Err(())
}
}