Compare commits

...

11 commits

Author SHA1 Message Date
Kim Hokyeong e8ec2fddf9
Merge 275071b740 into d07de879a7 2024-12-11 08:29:23 +09:00
manmen-mi 275071b740 cargo fmt --all --check 2024-12-08 12:05:21 +09:00
manmen-mi e5f0a8f997 holy clippy 2024-12-08 11:50:49 +09:00
manmen-mi 027cbdb629 format / reduce diff 2024-12-08 11:46:56 +09:00
manmen-mi 6760560920 hold replacer in app_state insted of main / watcher 2024-12-08 11:44:13 +09:00
manmen-mi 5cd711e909 trim_end_with_slash 2024-12-08 11:19:51 +09:00
manmen-mi 1ffe7fc837 fix 2024-12-08 11:16:02 +09:00
Kim Hokyeong 509d240d2b
add unit test 2024-12-08 02:12:43 +00:00
manmen-mi 2c09341074 to contain String 2024-12-07 22:01:18 +09:00
manmen-mi 96816a7b78 try subcommand 2024-12-07 21:40:18 +09:00
manmen-mi d49f192835 add arg 2024-12-07 21:40:03 +09:00
3 changed files with 83 additions and 1 deletions

View file

@ -21,6 +21,7 @@ use crate::{
exercise::{Exercise, RunnableExercise}, exercise::{Exercise, RunnableExercise},
info_file::ExerciseInfo, info_file::ExerciseInfo,
term::{self, CheckProgressVisualizer}, term::{self, CheckProgressVisualizer},
url_replacer::UrlReplacer,
}; };
const STATE_FILE_NAME: &str = ".rustlings-state.txt"; const STATE_FILE_NAME: &str = ".rustlings-state.txt";
@ -68,6 +69,7 @@ impl AppState {
pub fn new( pub fn new(
exercise_infos: Vec<ExerciseInfo>, exercise_infos: Vec<ExerciseInfo>,
final_message: String, final_message: String,
base_url: Option<String>,
) -> Result<(Self, StateFileStatus)> { ) -> Result<(Self, StateFileStatus)> {
let cmd_runner = CmdRunner::build()?; let cmd_runner = CmdRunner::build()?;
let mut state_file = OpenOptions::new() let mut state_file = OpenOptions::new()
@ -80,6 +82,9 @@ impl AppState {
format!("Failed to open or create the state file {STATE_FILE_NAME}") format!("Failed to open or create the state file {STATE_FILE_NAME}")
})?; })?;
// replacer for rustbook url
let url_replacer = base_url.as_ref().map(|url| UrlReplacer::new(url));
let dir_canonical_path = term::canonicalize("exercises"); let dir_canonical_path = term::canonicalize("exercises");
let mut exercises = exercise_infos let mut exercises = exercise_infos
.into_iter() .into_iter()
@ -90,7 +95,11 @@ impl AppState {
let path = exercise_info.path().leak(); let path = exercise_info.path().leak();
let name = exercise_info.name.leak(); let name = exercise_info.name.leak();
let dir = exercise_info.dir.map(|dir| &*dir.leak()); let dir = exercise_info.dir.map(|dir| &*dir.leak());
let hint = exercise_info.hint.leak().trim_ascii(); let mut hint = exercise_info.hint.leak().trim_ascii();
if let Some(replacer) = &url_replacer {
hint = replacer.replace(hint).leak();
}
let canonical_path = dir_canonical_path.as_deref().map(|dir_canonical_path| { let canonical_path = dir_canonical_path.as_deref().map(|dir_canonical_path| {
let mut canonical_path; let mut canonical_path;

View file

@ -21,6 +21,7 @@ mod init;
mod list; mod list;
mod run; mod run;
mod term; mod term;
mod url_replacer;
mod watch; mod watch;
const CURRENT_FORMAT_VERSION: u8 = 1; const CURRENT_FORMAT_VERSION: u8 = 1;
@ -35,6 +36,10 @@ struct Args {
/// Only use this if Rustlings fails to detect exercise file changes. /// Only use this if Rustlings fails to detect exercise file changes.
#[arg(long)] #[arg(long)]
manual_run: bool, manual_run: bool,
/// Change rustbook url to passed one.
#[arg(long)]
base_url: Option<String>,
} }
#[derive(Subcommand)] #[derive(Subcommand)]
@ -94,6 +99,7 @@ fn main() -> Result<ExitCode> {
let (mut app_state, state_file_status) = AppState::new( let (mut app_state, state_file_status) = AppState::new(
info_file.exercises, info_file.exercises,
info_file.final_message.unwrap_or_default(), info_file.final_message.unwrap_or_default(),
args.base_url,
)?; )?;
// Show the welcome message if the state file doesn't exist yet. // Show the welcome message if the state file doesn't exist yet.

67
src/url_replacer.rs Normal file
View file

@ -0,0 +1,67 @@
pub struct UrlReplacer {
base_url: String,
}
const EN_BASE_URL: &str = "https://doc.rust-lang.org/book";
impl UrlReplacer {
/// this fn will trim url end with '/'
pub fn new(base_url: &str) -> Self {
let url = if base_url.ends_with('/') {
base_url.trim_end_matches('/').to_owned()
} else {
base_url.to_owned()
};
Self { base_url: url }
}
/// replace rustbook url
pub fn replace(&self, hint: &str) -> String {
hint.replace(EN_BASE_URL, &self.base_url)
}
}
#[cfg(test)]
mod test {
use super::*;
const TEST_DOMAIN: &str = "https://doc.rust-kr.org";
#[test]
fn non_rustbook_url() {
let replacer = UrlReplacer::new(&String::from(TEST_DOMAIN));
let hint = "\
hints (...) lines (...)
link: https://example.com/ch03-02-data-types.html";
assert_eq!(hint, replacer.replace(hint));
}
#[test]
fn replace_rustbook_url() {
let replacer = UrlReplacer::new(&String::from(TEST_DOMAIN));
let hint = "\
hints (...) lines (...)
link: https://doc.rust-lang.org/book/ch03-02-data-types.html";
assert_eq!(
"\
hints (...) lines (...)
link: https://doc.rust-kr.org/ch03-02-data-types.html",
replacer.replace(hint)
);
}
#[test]
fn trim_end_with_slash() {
let mut domain = String::from(TEST_DOMAIN);
domain.push('/');
let replacer = UrlReplacer::new(&domain);
assert_eq!(TEST_DOMAIN, replacer.base_url);
}
}