mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-12-26 00:11:49 +02:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
999601d828 | ||
|
|
10d4d61d19 | ||
|
|
70e59cca3c | ||
|
|
7d6e2812fb | ||
|
|
05e8f02d0a | ||
|
|
9a14d72f08 | ||
|
|
04d0f78a2c |
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustlings"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
authors = ["Lynn <819880950@qq.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com"]
|
||||
edition = "2018"
|
||||
|
||||
@@ -10,3 +10,4 @@ indicatif = "0.9.0"
|
||||
console = "0.6.2"
|
||||
syntect = "3.0.2"
|
||||
notify = "4.0.0"
|
||||
toml = "0.4.10"
|
||||
|
||||
49
README.md
49
README.md
@@ -13,27 +13,36 @@ Alternatively, for a first-time Rust learner, there's several other resources:
|
||||
|
||||
## Getting Started
|
||||
|
||||
To use `rustlings` you need to have [Rust](https://www.rust-lang.org/) installed on your computer. To install Rust, go to [rustup.rs](https://rustup.rs/).
|
||||
|
||||
Once Rust is installed, clone the `rustlings` repository and enter the resulting directory:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/rust-lang/rustlings.git
|
||||
cd rustlings
|
||||
```
|
||||
|
||||
_Note: If you're on MacOS, make sure you've installed Xcode and its developer tools by typing `xcode-select --install`._
|
||||
|
||||
_Note: If you have Xcode 10+ installed, you also need to install the package file found at `/Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg`._
|
||||
|
||||
Once in the directory you can install `rustlings` on your machine and run the introduction:
|
||||
You will need to have Rust installed. You can get it by visiting https://rustup.rs. This'll also install Cargo, Rust's package/project manager.
|
||||
|
||||
## MacOS/Linux
|
||||
|
||||
Just run:
|
||||
|
||||
```bash
|
||||
cargo install --path .
|
||||
rustlings
|
||||
curl -L https://git.io/rustlings | bash
|
||||
# Or if you want it to be installed to a different path:
|
||||
curl -L https://git.io/rustlings | bash -s mypath/
|
||||
```
|
||||
|
||||
If you choose to not install the `rustlings` command, just replace `rustlings` with `cargo run` in the rest of this text.
|
||||
This will install Rustlings and give you access to the `rustlings` command. Run it to get started!
|
||||
|
||||
## Windows/Manually
|
||||
|
||||
Basically: Clone the repository, checkout to the latest tag, run `cargo install`.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/rust-lang/rustlings
|
||||
cd rustlings
|
||||
git checkout tags/1.0.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
|
||||
cargo install --force --path .
|
||||
```
|
||||
|
||||
Same as above, run `rustlings` to get started.
|
||||
|
||||
## Doing exercises
|
||||
|
||||
@@ -96,18 +105,20 @@ If you are interested in improving or adding new ones, please feel free to contr
|
||||
First step is to add the exercise! Call it `exercises/yourTopic/yourTopicN.rs`, make sure to
|
||||
put in some helpful links, and link to sections of the book in `exercises/yourTopic/README.md`.
|
||||
|
||||
Then, you'll want to make sure it gets verified when you run `rustlings verify`. Open `src/verify.rs` and
|
||||
put your exercise somewhere in there:
|
||||
Next you want to make sure it runs when using `rustlings`. All exercises are stored in `info.toml`, under the `exercises` array. They're ordered by the order they're ran when using `rustlings verify`.
|
||||
|
||||
You want to make sure where in the file you add your exercise. If you're not sure, add it at the bottom and ask in your pull request. To add an exercise, edit the file like this:
|
||||
```diff
|
||||
...
|
||||
compile_only("exercises/functions5.rs")?;
|
||||
+ compile_only("exercises/yourTopic/yourTopicN.rs")?;
|
||||
compile_only("exercises/test1.rs")?;
|
||||
+ [[exercises]]
|
||||
+ path = "exercises/yourTopic/yourTopicN.rs"
|
||||
+ mode = "compile"
|
||||
...
|
||||
```
|
||||
|
||||
That's all!
|
||||
The `mode` attribute decides whether Rustlings will only compile your exercise, or compile and test it. If you have tests to verify in your exercise, choose `test`, otherwise `compile`.
|
||||
|
||||
That's all! Feel free to put up a pull request.
|
||||
|
||||
### Working on the source code
|
||||
|
||||
|
||||
199
info.toml
Normal file
199
info.toml
Normal file
@@ -0,0 +1,199 @@
|
||||
# VARIABLES
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/variables/variables1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/variables/variables2.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/variables/variables3.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/variables/variables4.rs"
|
||||
mode = "compile"
|
||||
|
||||
# IF
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/if/if1.rs"
|
||||
mode = "test"
|
||||
|
||||
# FUNCTIONS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/functions/functions1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/functions/functions2.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/functions/functions3.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/functions/functions4.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/functions/functions5.rs"
|
||||
mode = "compile"
|
||||
|
||||
# TEST 1
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/test1.rs"
|
||||
mode = "test"
|
||||
|
||||
# PRIMITIVE TYPES
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/primitive_types/primitive_types1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/primitive_types/primitive_types2.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/primitive_types/primitive_types3.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/primitive_types/primitive_types4.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/primitive_types/primitive_types5.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/primitive_types/primitive_types6.rs"
|
||||
mode = "compile"
|
||||
|
||||
# TESTS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/tests/tests1.rs"
|
||||
mode = "test"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/tests/tests2.rs"
|
||||
mode = "test"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/tests/tests3.rs"
|
||||
mode = "test"
|
||||
|
||||
# TEST 2
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/test2.rs"
|
||||
mode = "test"
|
||||
|
||||
# STRINGS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/strings/strings1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/strings/strings2.rs"
|
||||
mode = "compile"
|
||||
|
||||
# TEST 3
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/test3.rs"
|
||||
mode = "compile"
|
||||
|
||||
# MODULES
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/modules/modules1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/modules/modules2.rs"
|
||||
mode = "compile"
|
||||
|
||||
# MACROS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/macros/macros1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/macros/macros2.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/macros/macros3.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/macros/macros4.rs"
|
||||
mode = "compile"
|
||||
|
||||
# TEST 4
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/test4.rs"
|
||||
mode = "compile"
|
||||
|
||||
# MOVE SEMANTICS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/move_semantics/move_semantics1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/move_semantics/move_semantics2.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/move_semantics/move_semantics3.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/move_semantics/move_semantics4.rs"
|
||||
mode = "compile"
|
||||
|
||||
# ERROR HANDLING
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/error_handling/errors1.rs"
|
||||
mode = "test"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/error_handling/errors2.rs"
|
||||
mode = "test"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/error_handling/errors3.rs"
|
||||
mode = "test"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/error_handling/errorsn.rs"
|
||||
mode = "test"
|
||||
|
||||
# OPTIONS / RESULTS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/error_handling/option1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/error_handling/result1.rs"
|
||||
mode = "test"
|
||||
|
||||
# THREADS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/threads/threads1.rs"
|
||||
mode = "compile"
|
||||
51
install.sh
Executable file
51
install.sh
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "Let's get you set up with Rustlings!"
|
||||
|
||||
echo "Checking requirements..."
|
||||
if [ -x "$(git)" ]
|
||||
then
|
||||
echo "WARNING: Git does not seem to be installed."
|
||||
echo "Please download Git using your package manager or over https://git-scm.com/!"
|
||||
exit 1
|
||||
else
|
||||
echo "SUCCESS: Git is installed"
|
||||
fi
|
||||
|
||||
if [ -x "$(rustc)" ]
|
||||
then
|
||||
echo "WARNING: Rust does not seem to be installed."
|
||||
echo "Please download Rust using https://rustup.rs!"
|
||||
exit 1
|
||||
else
|
||||
echo "SUCCESS: Rust is installed"
|
||||
fi
|
||||
|
||||
if [ -x "$(cargo)" ]
|
||||
then
|
||||
echo "WARNING: Cargo does not seem to be installed."
|
||||
echo "Please download Rust and Cargo using https://rustup.rs!"
|
||||
exit 1
|
||||
else
|
||||
echo "SUCCESS: Cargo is installed"
|
||||
fi
|
||||
|
||||
Path=${1:-rustlings/}
|
||||
echo "Cloning Rustlings at $Path..."
|
||||
git clone -q https://github.com/rust-lang/rustlings $Path
|
||||
|
||||
Version=$(curl -s https://api.github.com/repos/rust-lang/rustlings/releases/latest | python -c "import json,sys;obj=json.load(sys.stdin);print(obj['tag_name']);")
|
||||
echo "Checking out version $Version..."
|
||||
cd $Path
|
||||
git checkout -q tags/$Version
|
||||
|
||||
echo "Installing the 'rustlings' executable..."
|
||||
cargo install --force --path .
|
||||
|
||||
if [ -x "$(rustlings)" ]
|
||||
then
|
||||
echo "WARNING: Please check that you have '~/.cargo/bin' in your PATH environment variable!"
|
||||
fi
|
||||
|
||||
echo "All done! Run 'rustlings' to get started."
|
||||
|
||||
@@ -3,6 +3,7 @@ use crate::verify::verify;
|
||||
use clap::{crate_version, App, Arg, SubCommand};
|
||||
use notify::DebouncedEvent;
|
||||
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
|
||||
use std::ffi::OsStr;
|
||||
use std::io::BufRead;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::time::Duration;
|
||||
@@ -47,7 +48,7 @@ fn main() {
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("run") {
|
||||
run(matches.clone());
|
||||
run(matches.clone()).unwrap();
|
||||
}
|
||||
|
||||
if let Some(_) = matches.subcommand_matches("verify") {
|
||||
@@ -85,8 +86,10 @@ fn watch() -> notify::Result<()> {
|
||||
loop {
|
||||
match rx.recv() {
|
||||
Ok(event) => match event {
|
||||
DebouncedEvent::Chmod(_) | DebouncedEvent::Write(_) => {
|
||||
let _ignored = verify();
|
||||
DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
|
||||
if b.extension() == Some(OsStr::new("rs")) {
|
||||
let _ignored = verify();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
|
||||
99
src/run.rs
99
src/run.rs
@@ -2,54 +2,71 @@ use crate::util::clean;
|
||||
use crate::verify::test;
|
||||
use console::{style, Emoji};
|
||||
use indicatif::ProgressBar;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
use toml::Value;
|
||||
|
||||
pub fn run(matches: clap::ArgMatches) {
|
||||
pub fn run(matches: clap::ArgMatches) -> Result<(), ()> {
|
||||
if let Some(filename) = matches.value_of("file") {
|
||||
if matches.is_present("test") {
|
||||
match test(filename) {
|
||||
Ok(_) => (),
|
||||
Err(_) => (),
|
||||
}
|
||||
std::process::exit(0);
|
||||
let toml: Value = fs::read_to_string("info.toml").unwrap().parse().unwrap();
|
||||
let tomlvec: &Vec<Value> = toml.get("exercises").unwrap().as_array().unwrap();
|
||||
let mut exercises = tomlvec.clone();
|
||||
exercises.retain(|i| i.get("path").unwrap().as_str().unwrap() == filename);
|
||||
if exercises.is_empty() {
|
||||
println!("No exercise found for your filename!");
|
||||
std::process::exit(1);
|
||||
}
|
||||
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.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();
|
||||
let exercise: &Value = &exercises[0];
|
||||
match exercise.get("mode").unwrap().as_str().unwrap() {
|
||||
"test" => test(exercise.get("path").unwrap().as_str().unwrap())?,
|
||||
"compile" => compile_and_run(exercise.get("path").unwrap().as_str().unwrap())?,
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
panic!("Please supply a filename!");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_and_run(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.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();
|
||||
Ok(())
|
||||
} 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();
|
||||
Err(())
|
||||
}
|
||||
} 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();
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +1,20 @@
|
||||
use crate::util::clean;
|
||||
use console::{style, Emoji};
|
||||
use indicatif::ProgressBar;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
use toml::Value;
|
||||
|
||||
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")?;
|
||||
test("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")?;
|
||||
compile_only("exercises/threads/threads1.rs")?;
|
||||
let toml: Value = fs::read_to_string("info.toml").unwrap().parse().unwrap();
|
||||
let tomlvec: &Vec<Value> = toml.get("exercises").unwrap().as_array().unwrap();
|
||||
for i in tomlvec {
|
||||
match i.get("mode").unwrap().as_str().unwrap() {
|
||||
"test" => test(i.get("path").unwrap().as_str().unwrap())?,
|
||||
"compile" => compile_only(i.get("path").unwrap().as_str().unwrap())?,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user