1
0
mirror of https://github.com/rust-lang/rustlings.git synced 2025-12-26 00:11:49 +02:00

Compare commits

...

24 Commits
5.1.1 ... 5.2.0

Author SHA1 Message Date
mokou
3309a01b5e chore: release 5.2.0 2022-08-27 19:48:15 +01:00
liv
5a03e46d69 Merge pull request #1166 from rust-lang/all-contributors/add-Kodylow
docs: add Kodylow as a contributor for content
2022-08-25 12:12:23 +02:00
allcontributors[bot]
bf95a34553 docs: update .all-contributorsrc [skip ci] 2022-08-25 10:12:15 +00:00
allcontributors[bot]
33e501981a docs: update AUTHORS.md [skip ci] 2022-08-25 10:12:14 +00:00
liv
4ee9a0f6b9 Merge pull request #1164 from Kodylow/quiz1-typo-fix
Fix Quiz 1 >= Typo
2022-08-25 12:11:49 +02:00
Kody Low
d6e26bb350 2nd assert is for greater than or equal to, not "more than" like it says in the instructions 2022-08-24 08:33:17 -07:00
liv
f6a37e28ba Merge pull request #1163 from rust-lang/all-contributors/add-GabrielBianconi
docs: add GabrielBianconi as a contributor for content
2022-08-24 11:16:05 +02:00
liv
a2f66e6a67 Merge pull request #1161 from GabrielBianconi/patch-1
Fix typo in `threads3` hint
2022-08-24 11:15:52 +02:00
allcontributors[bot]
b92e7b968f docs: update .all-contributorsrc [skip ci] 2022-08-24 09:15:52 +00:00
allcontributors[bot]
6c2630afcf docs: update AUTHORS.md [skip ci] 2022-08-24 09:15:51 +00:00
Gabriel Bianconi
86506fa5fd Fix typo in threads3 hint 2022-08-22 23:47:23 -04:00
liv
96098d228a Merge pull request #1151 from magnusrodseth/1031-reset-exercise
Add reset command for a given filename
2022-08-18 14:07:15 +02:00
magnusrodseth
d59dde320b chore: Add suggested changes 2022-08-18 12:47:26 +02:00
liv
fb7d3bf35d Merge pull request #1155 from rust-lang/all-contributors/add-rubiesonthesky
docs: add rubiesonthesky as a contributor for content
2022-08-18 11:54:39 +02:00
allcontributors[bot]
50272a58e2 docs: update .all-contributorsrc [skip ci] 2022-08-18 09:54:30 +00:00
allcontributors[bot]
93f60d3f8d docs: update AUTHORS.md [skip ci] 2022-08-18 09:54:29 +00:00
liv
97bf2469b6 Merge pull request #1154 from rust-lang/all-contributors/add-magnusrodseth
docs: add magnusrodseth as a contributor for content
2022-08-18 11:54:06 +02:00
allcontributors[bot]
2088dfbaf6 docs: update .all-contributorsrc [skip ci] 2022-08-18 09:53:55 +00:00
allcontributors[bot]
e889c5bb60 docs: update AUTHORS.md [skip ci] 2022-08-18 09:53:54 +00:00
liv
44d609816b Merge pull request #1150 from magnusrodseth/1109-options2-test
`options2`: Convert the main function into tests
2022-08-18 11:53:16 +02:00
magnusrodseth
99ea2cbba7 chore: make options2 not compile deliberately 2022-08-17 16:53:41 +02:00
magnusrodseth
0aff5340b5 test: Add integration tests 2022-08-17 16:43:48 +02:00
magnusrodseth
6f44cb1dd2 feat: Add reset command, given a filename 2022-08-17 16:31:53 +02:00
magnusrodseth
52a29aa84b test: Convert main function to working tests 2022-08-17 12:50:34 +02:00
10 changed files with 181 additions and 40 deletions

View File

@@ -1506,6 +1506,42 @@
"contributions": [
"content"
]
},
{
"login": "magnusrodseth",
"name": "Magnus Rødseth",
"avatar_url": "https://avatars.githubusercontent.com/u/59113973?v=4",
"profile": "http://magnusrodseth.vercel.app",
"contributions": [
"content"
]
},
{
"login": "rubiesonthesky",
"name": "rubiesonthesky",
"avatar_url": "https://avatars.githubusercontent.com/u/2591240?v=4",
"profile": "https://github.com/rubiesonthesky",
"contributions": [
"content"
]
},
{
"login": "GabrielBianconi",
"name": "Gabriel Bianconi",
"avatar_url": "https://avatars.githubusercontent.com/u/1275491?v=4",
"profile": "http://www.gabrielbianconi.com/",
"contributions": [
"content"
]
},
{
"login": "Kodylow",
"name": "Kody Low",
"avatar_url": "https://avatars.githubusercontent.com/u/74332828?v=4",
"profile": "https://github.com/Kodylow",
"contributions": [
"content"
]
}
],
"contributorsPerLine": 8,

View File

@@ -214,6 +214,10 @@ authors.
<td align="center"><a href="https://github.com/markusboehme"><img src="https://avatars.githubusercontent.com/u/5074759?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Markus Boehme</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=markusboehme" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/nico-vromans"><img src="https://avatars.githubusercontent.com/u/48183857?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nico Vromans</b></sub></a><br /><a href="#content-nico-vromans" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/vostok92"><img src="https://avatars.githubusercontent.com/u/540339?v=4?s=100" width="100px;" alt=""/><br /><sub><b>vostok92</b></sub></a><br /><a href="#content-vostok92" title="Content">🖋</a></td>
<td align="center"><a href="http://magnusrodseth.vercel.app"><img src="https://avatars.githubusercontent.com/u/59113973?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Magnus Rødseth</b></sub></a><br /><a href="#content-magnusrodseth" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/rubiesonthesky"><img src="https://avatars.githubusercontent.com/u/2591240?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rubiesonthesky</b></sub></a><br /><a href="#content-rubiesonthesky" title="Content">🖋</a></td>
<td align="center"><a href="http://www.gabrielbianconi.com/"><img src="https://avatars.githubusercontent.com/u/1275491?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gabriel Bianconi</b></sub></a><br /><a href="#content-GabrielBianconi" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/Kodylow"><img src="https://avatars.githubusercontent.com/u/74332828?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kody Low</b></sub></a><br /><a href="#content-Kodylow" title="Content">🖋</a></td>
</tr>
</table>

View File

@@ -1,3 +1,20 @@
<a name="5.2.0"></a>
## 5.2.0 (2022-08-27)
#### Added
- Added a `reset` command
#### Changed
- **options2**: Convert the exercise to use tests
#### Fixed
- **threads3**: Fixed a typo
- **quiz1**: Adjusted the explanations to be consistent with
the tests
<a name="5.1.1"></a>
## 5.1.1 (2022-08-17)

View File

@@ -1,6 +1,6 @@
[package]
name = "rustlings"
version = "5.1.1"
version = "5.2.0"
authors = ["Liv <mokou@fastmail.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
edition = "2021"

View File

@@ -3,23 +3,34 @@
// I AM NOT DONE
fn main() {
let optional_word = Some(String::from("rustlings"));
// TODO: Make this an if let statement whose value is "Some" type
word = optional_word {
println!("The word is: {}", word);
} else {
println!("The optional word doesn't contain anything");
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple_option() {
let target = "rustlings";
let optional_target = Some(target);
// TODO: Make this an if let statement whose value is "Some" type
word = optional_target {
assert_eq!(word, target);
}
}
let mut optional_integers_vec: Vec<Option<i8>> = Vec::new();
for x in 1..10 {
optional_integers_vec.push(Some(x));
}
#[test]
fn layered_option() {
let mut range = 10;
let mut optional_integers: Vec<Option<i8>> = Vec::new();
for i in 0..(range + 1) {
optional_integers.push(Some(i));
}
// TODO: make this a while let statement - remember that vector.pop also adds another layer of Option<T>
// You can stack `Option<T>`'s into while let and if let
integer = optional_integers_vec.pop() {
println!("current value: {}", integer);
// TODO: make this a while let statement - remember that vector.pop also adds another layer of Option<T>
// You can stack `Option<T>`'s into while let and if let
integer = optional_integers.pop() {
assert_eq!(integer, range);
range -= 1;
}
}
}

View File

@@ -5,7 +5,7 @@
// - If
// Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy
// more than 40 at once, each apple only costs 1! Write a function that calculates
// 40 or more at once, each apple only costs 1! Write a function that calculates
// the price of an order of apples given the quantity bought. No hints this time!
// I AM NOT DONE

View File

@@ -545,7 +545,7 @@ is the easiest, but how do you do it safely so that it doesn't panic in your fac
[[exercises]]
name = "options2"
path = "exercises/options/options2.rs"
mode = "compile"
mode = "test"
hint = """
check out:
https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html
@@ -1012,7 +1012,7 @@ hint = """
An alternate way to handle concurrency between threads is to use
a mpsc (multiple producer, single consumer) channel to communicate.
With both a sending end and a receiving end, it's possible to
send values in one thread and receieve them in another.
send values in one thread and receive them in another.
Multiple producers are possible by using clone() to create a duplicate
of the original sending end.
See https://doc.rust-lang.org/book/ch16-02-message-passing.html for more info.

View File

@@ -1,6 +1,6 @@
use crate::exercise::{Exercise, ExerciseList};
use crate::project::RustAnalyzerProject;
use crate::run::run;
use crate::run::{reset, run};
use crate::verify::verify;
use argh::FromArgs;
use console::Emoji;
@@ -26,7 +26,7 @@ mod run;
mod verify;
// In sync with crate version
const VERSION: &str = "5.1.1";
const VERSION: &str = "5.2.0";
#[derive(FromArgs, PartialEq, Debug)]
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
@@ -47,6 +47,7 @@ enum Subcommands {
Verify(VerifyArgs),
Watch(WatchArgs),
Run(RunArgs),
Reset(ResetArgs),
Hint(HintArgs),
List(ListArgs),
Lsp(LspArgs),
@@ -71,6 +72,15 @@ struct RunArgs {
name: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "reset")]
/// Resets a single exercise using "git stash -- <filename>"
struct ResetArgs {
#[argh(positional)]
/// the name of the exercise
name: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "hint")]
/// Returns a hint for the given exercise
@@ -85,7 +95,6 @@ struct HintArgs {
/// Enable rust-analyzer for exercises
struct LspArgs {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "list")]
/// Lists the exercises available in Rustlings
@@ -164,7 +173,9 @@ fn main() {
"Pending"
};
let solve_cond = {
(e.looks_done() && subargs.solved) || (!e.looks_done() && subargs.unsolved) || (!subargs.solved && !subargs.unsolved)
(e.looks_done() && subargs.solved)
|| (!e.looks_done() && subargs.unsolved)
|| (!subargs.solved && !subargs.unsolved)
};
if solve_cond && (filter_cond || subargs.filter.is_none()) {
let line = if subargs.paths {
@@ -205,6 +216,12 @@ fn main() {
run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1));
}
Subcommands::Reset(subargs) => {
let exercise = find_exercise(&subargs.name, &exercises);
reset(exercise).unwrap_or_else(|_| std::process::exit(1));
}
Subcommands::Hint(subargs) => {
let exercise = find_exercise(&subargs.name, &exercises);
@@ -212,7 +229,8 @@ fn main() {
}
Subcommands::Verify(_subargs) => {
verify(&exercises, (0, exercises.len()), verbose).unwrap_or_else(|_| std::process::exit(1));
verify(&exercises, (0, exercises.len()), verbose)
.unwrap_or_else(|_| std::process::exit(1));
}
Subcommands::Lsp(_subargs) => {
@@ -236,12 +254,18 @@ fn main() {
Subcommands::Watch(_subargs) => match watch(&exercises, verbose) {
Err(e) => {
println!("Error: Could not watch your progress. Error message was {:?}.", e);
println!(
"Error: Could not watch your progress. Error message was {:?}.",
e
);
println!("Most likely you've run out of disk space or your 'inotify limit' has been reached.");
std::process::exit(1);
}
Ok(WatchStatus::Finished) => {
println!("{emoji} All exercises completed! {emoji}", emoji = Emoji("🎉", ""));
println!(
"{emoji} All exercises completed! {emoji}",
emoji = Emoji("🎉", "")
);
println!("\n{}\n", FENISH_LINE);
}
Ok(WatchStatus::Unfinished) => {
@@ -252,8 +276,10 @@ fn main() {
}
}
fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>, should_quit: Arc<AtomicBool>) {
fn spawn_watch_shell(
failed_exercise_hint: &Arc<Mutex<Option<String>>>,
should_quit: Arc<AtomicBool>,
) {
let failed_exercise_hint = Arc::clone(failed_exercise_hint);
println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.");
thread::spawn(move || loop {
@@ -290,16 +316,22 @@ fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>, should_q
fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
if name.eq("next") {
exercises.iter().find(|e| !e.looks_done()).unwrap_or_else(|| {
println!("🎉 Congratulations! You have done all the exercises!");
println!("🔚 There are no more exercises to do next!");
std::process::exit(1)
})
exercises
.iter()
.find(|e| !e.looks_done())
.unwrap_or_else(|| {
println!("🎉 Congratulations! You have done all the exercises!");
println!("🔚 There are no more exercises to do next!");
std::process::exit(1)
})
} else {
exercises.iter().find(|e| e.name == name).unwrap_or_else(|| {
println!("No exercise found for '{}'!", name);
std::process::exit(1)
})
exercises
.iter()
.find(|e| e.name == name)
.unwrap_or_else(|| {
println!("No exercise found for '{}'!", name);
std::process::exit(1)
})
}
}
@@ -337,8 +369,13 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<WatchStatus> {
let filepath = b.as_path().canonicalize().unwrap();
let pending_exercises = exercises
.iter()
.find(|e| filepath.ends_with(&e.path)).into_iter()
.chain(exercises.iter().filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)));
.find(|e| filepath.ends_with(&e.path))
.into_iter()
.chain(
exercises
.iter()
.filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)),
);
let num_done = exercises.iter().filter(|e| e.looks_done()).count();
clear_screen();
match verify(pending_exercises, (num_done, exercises.len()), verbose) {

View File

@@ -1,3 +1,5 @@
use std::process::Command;
use crate::exercise::{Exercise, Mode};
use crate::verify::test;
use indicatif::ProgressBar;
@@ -15,6 +17,19 @@ pub fn run(exercise: &Exercise, verbose: bool) -> Result<(), ()> {
Ok(())
}
// Resets the exercise by stashing the changes.
pub fn reset(exercise: &Exercise) -> Result<(), ()> {
let command = Command::new("git")
.args(["stash", "--"])
.arg(&exercise.path)
.spawn();
match command {
Ok(_) => Ok(()),
Err(_) => Err(()),
}
}
// Invoke the rust compiler on the path of the given exercise
// and run the ensuing binary.
// This is strictly for non-test binaries, so output is displayed

View File

@@ -110,6 +110,27 @@ fn run_single_test_no_exercise() {
.code(1);
}
#[test]
fn reset_single_exercise() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["reset", "intro1"])
.assert()
.code(0);
}
#[test]
fn reset_no_exercise() {
Command::cargo_bin("rustlings")
.unwrap()
.arg("reset")
.assert()
.code(1)
.stderr(predicates::str::contains(
"positional arguments not provided",
));
}
#[test]
fn get_hint_for_single_test() {
Command::cargo_bin("rustlings")
@@ -126,7 +147,7 @@ fn all_exercises_require_confirmation() {
for exercise in glob("exercises/**/*.rs").unwrap() {
let path = exercise.unwrap();
if path.file_name().unwrap() == "mod.rs" {
continue
continue;
}
let source = {
let mut file = File::open(&path).unwrap();