From 8acf85ae8ce6adf007ec3d4f27aa20d3ff432b8d Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Fri, 6 Jan 2023 17:55:54 +0100 Subject: [PATCH 01/13] rewritten exercise --- assignments/rustlatin.adoc | 146 ++++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 57 deletions(-) diff --git a/assignments/rustlatin.adoc b/assignments/rustlatin.adoc index 301aa91a..e04c1245 100644 --- a/assignments/rustlatin.adoc +++ b/assignments/rustlatin.adoc @@ -1,116 +1,148 @@ = Exercise: rustlatin :source-language: rust -In this exercise we will implement a Rust-y, simpler variant of https://en.wikipedia.org/wiki/Pig_Latin[Pig Latin] +In this exercise we will implement a Rust-y, simpler variant of https://en.wikipedia.org/wiki/Pig_Latin[Pig Latin]: Depending on if a word starts with a vowel or not, either a suffix or a prefix is added to the word -You will learn: +== Learning Goals -* How to create a Rust library -* How to deal with `Strings` and splitting -* How to deal with `char` of a `String` -* An early taste of Iterators -* How to define Globals -* Arrays vs Vectors -* See Rust compiler's type inference in action -* Most common way to do string concatenation +You will learn how to: -== Specification +* create a Rust library +* split a `&str` at specified `char` +* get single `char` out of a `&str` +* iterate over a `&str` +* define Globals +* compare a value to the content of an array +* use the Rust compiler's type inference to your advantage +* to concatenate `&str` +* return the content of a `Vec` as `String`. + + +== Prerequisists + +Todo! + +== Tasks For this exercise we define * the Vowels of English alphabet -> `['a', 'e', 'i', 'o', 'u']` * a sentence is a collection of ASCII characters with words that are separated by a white space -For any given sentence, you have to modify each word of the sentence using the following logic: +Implement a function that splits a sentence into its words, and adds a suffix or prefix to them according to the following rules: * If the word begins with a vowel -> add prefix “sr” to the word * If the word does not begin with a vowel -> add suffix “rs” to the word -== Tasks +The function returns a `String` containing the modified words. + +In order to learn as much as possible we recommend following the step-by-step solution. + +== Step-by-step-Solution +=== Getting started + +Find the exercise skeletton. -=== Step 1 +The folder contains each step as it's own numbered lib.rs file. Each file contains starter code and a test that needs to pass in order for the step to be considered complete. -Create a new `lib` and name it `rustlatin`. +==== Rust Analyzer +A part of this exercise is seeing type inference in action and to use it to help to determine the type the funktion is going to return. To make sure the file can be indexed by Rust Analyzer, rename the file you're currently working on "lib.rs". Name it back to it's numbered version when you are finished. + + + + + +=== Step 1: Splitting a sentence and pushing its words into a vector. + +Iterate over the sentence to split it into words. Use the white space as separator. Push each word into the vector `collection_of_words`. Add the correct return type to the function signature. +Run the test to see if it passes. .Click to see the solution [%collapsible] ==== -[source,bash] +[source,rust] ---- -cargo new --lib rustlatin +fn rustlatin(sentence: &str) -> Vec<&str> { + let mut collection_of_words = Vec::new(); + + for word in sentence.split(' ') { + collection_of_words.push(word); + }; + + collection_of_words +} ---- ==== -=== Step 2 +=== Step 2 Concatenating String types. -Create a global variable in the file that defines the Vowels as specified above +After iterating over the sentence to split it into words, add the suffix `"rs"` to each word before pushing it to the vector. To concatenate two `&str` the first needs to be turned into the owned type with `to_owned`. Then `String` and `&str` can be added using `+`. Add the correct return type to the function signature. +Run the test to see if it passes. .Click to see the solution [%collapsible] ==== [source,rust] ---- -const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; +fn rustlatin(sentence: &str) -> Vec { + let mut collection_of_words = Vec::new(); + + for word in sentence.split(' ') { + collection_of_mod_words.push(word.to_owned() + "rs") + + }; + collection_of_words +} ---- ==== -=== Step 3 +=== Step 3: Iterating over a word to return the first character. +After iterating over the sentence to split it into words, add the first character of each word to the vector. -Copy paste this skeleton of the function +(Here is the info missing how people are going to learn about chars(), and how it returns an iterator and not the character, either cheat sheet, documentation or we explain it here) -[source,rust] ----- -fn rustlatin(sentence: String) -> String { - unimplemented!() -} ----- +Add the correct return type to the function signature. +Run the test to see if it passes. .Click to see the sample solution [%collapsible] ==== [source,rust] ---- -fn rustlatin(sentence: &str) -> String { - let mut new_words = Vec::new(); +fn rustlatin(sentence: &str) -> Vec { + let mut collection_of_chars = Vec::new(); + for word in sentence.split(' ') { - let first_char_of_word = word.chars().next().unwrap(); - if VOWELS.contains(&first_char_of_word) { - new_words.push("sr".to_string() + word); - } else { - new_words.push(word.to_string() + "rs"); - } - } - - new_words.join(" ") + let first_char = word.chars().next().unwrap(); + collection_of_chars.push(first_char); + }; + collection_of_chars } ---- ==== -=== Step 4 +=== Step 4: Putting everything together: Comparing values and returning the content of the vector as `String`. -Add tests +Check if the first character of each word is a vowel. Add the prefix or suffix according to the rules above. Return the content of the vector as `String`. +Run the tests to see if they pass. .Click to see the hints/solutions for tests [%collapsible] ==== [source,rust] ---- -#[test] -fn correct_translation() { - // Why can we compare `&str` and `String` here? - // https://doc.rust-lang.org/stable/std/string/struct.String.html#impl-PartialEq%3C%26%27a%20str%3E - assert_eq!( - "rustrs helpsrs yours sravoid sra lotrs srof srirritating bugsrs", - rustlatin("rust helps you avoid a lot of irritating bugs") - ) -} - -#[test] -fn incorrect() { - assert_ne!( - "this shouldrs not workrs", - rustlatin("this should not work") - ) +fn rustlatin(sentence: &str) -> String { + let mut collection_of_words = Vec::new(); + + for word in sentence.split(' ') { + let first_char = word.chars().next().unwrap(); + if VOWELS.contains(&first_char) { + collection_of_words.push("sr".to_string() + word); + } else { + collection_of_words.push(word.to_string() + "rs"); + } + }; + collection_of_words.join(" ") } ---- ==== From 19aec535ad2f5a41b6bf11025c047bc7570ddd80 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Fri, 13 Jan 2023 11:35:37 +0100 Subject: [PATCH 02/13] changed step 4 --- assignments/rustlatin.adoc | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/assignments/rustlatin.adoc b/assignments/rustlatin.adoc index e04c1245..414ae6b2 100644 --- a/assignments/rustlatin.adoc +++ b/assignments/rustlatin.adoc @@ -123,7 +123,11 @@ fn rustlatin(sentence: &str) -> Vec { === Step 4: Putting everything together: Comparing values and returning the content of the vector as `String`. -Check if the first character of each word is a vowel. Add the prefix or suffix according to the rules above. Return the content of the vector as `String`. +Add another function that checks if the first character of each word is a vowel. It adds the prefix or suffix according to the rules above. + +Call the function in each iteration. + +In `fn rustlatin` return the content of the vector as `String`. Run the tests to see if they pass. .Click to see the hints/solutions for tests @@ -131,18 +135,11 @@ Run the tests to see if they pass. ==== [source,rust] ---- -fn rustlatin(sentence: &str) -> String { - let mut collection_of_words = Vec::new(); - - for word in sentence.split(' ') { - let first_char = word.chars().next().unwrap(); - if VOWELS.contains(&first_char) { - collection_of_words.push("sr".to_string() + word); - } else { - collection_of_words.push(word.to_string() + "rs"); - } - }; - collection_of_words.join(" ") +// how to check if first character is a vowel, and modify the word! +if VOWELS.contains(&first_char) { + collection_of_words.push("sr".to_string() + word); +} else { + collection_of_words.push(word.to_string() + "rs"); } ---- ==== From d4e67f2ff57f46fd8ea80ae4c68fd8ad4a6df5b4 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Fri, 20 Jan 2023 17:51:37 +0100 Subject: [PATCH 03/13] add rustlatin templates and solutions --- assignments/_templates/rustlatin/Cargo.lock | 7 +++ assignments/_templates/rustlatin/Cargo.toml | 8 +++ assignments/_templates/rustlatin/src/lib_1.rs | 27 ++++++++++ assignments/_templates/rustlatin/src/lib_2.rs | 19 +++++++ assignments/_templates/rustlatin/src/lib_3.rs | 20 ++++++++ assignments/_templates/rustlatin/src/lib_4.rs | 45 +++++++++++++++++ assignments/solutions/rustlatin/Cargo.lock | 7 +++ assignments/solutions/rustlatin/Cargo.toml | 8 +++ assignments/solutions/rustlatin/src/lib_1.rs | 18 +++++++ assignments/solutions/rustlatin/src/lib_2.rs | 20 ++++++++ assignments/solutions/rustlatin/src/lib_3.rs | 20 ++++++++ assignments/solutions/rustlatin/src/lib_4.rs | 49 +++++++++++++++++++ 12 files changed, 248 insertions(+) create mode 100644 assignments/_templates/rustlatin/Cargo.lock create mode 100644 assignments/_templates/rustlatin/Cargo.toml create mode 100644 assignments/_templates/rustlatin/src/lib_1.rs create mode 100644 assignments/_templates/rustlatin/src/lib_2.rs create mode 100644 assignments/_templates/rustlatin/src/lib_3.rs create mode 100644 assignments/_templates/rustlatin/src/lib_4.rs create mode 100644 assignments/solutions/rustlatin/Cargo.lock create mode 100644 assignments/solutions/rustlatin/Cargo.toml create mode 100644 assignments/solutions/rustlatin/src/lib_1.rs create mode 100644 assignments/solutions/rustlatin/src/lib_2.rs create mode 100644 assignments/solutions/rustlatin/src/lib_3.rs create mode 100644 assignments/solutions/rustlatin/src/lib_4.rs diff --git a/assignments/_templates/rustlatin/Cargo.lock b/assignments/_templates/rustlatin/Cargo.lock new file mode 100644 index 00000000..51efe7e8 --- /dev/null +++ b/assignments/_templates/rustlatin/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rustlatin" +version = "0.1.0" diff --git a/assignments/_templates/rustlatin/Cargo.toml b/assignments/_templates/rustlatin/Cargo.toml new file mode 100644 index 00000000..e593ca8b --- /dev/null +++ b/assignments/_templates/rustlatin/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rustlatin" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/assignments/_templates/rustlatin/src/lib_1.rs b/assignments/_templates/rustlatin/src/lib_1.rs new file mode 100644 index 00000000..b0dc50bc --- /dev/null +++ b/assignments/_templates/rustlatin/src/lib_1.rs @@ -0,0 +1,27 @@ +const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; +// ^^^^^^^^^ The vowls are contained in an array, because the length never changes. +// It's a global const because it will not be modified in any way and only +// serves as a reference. + +fn rustlatin(sentence: &str) -> Vec { + // ^^^^^^^ The correct return type needs to be added by you, + // depending on what the vector's exact type is. + + let mut collection_of_words = Vec::new(); + // ^^^^^^^^^^^^ When you first open this file RA is not able to infer + // the type of this vector. Once you do the implementation, + // the type should appear here automatically. + + // Your implementation goes here: + + + collection_of_words +} + + +#[test] +fn correct_splitting(){ + assert_eq!(vec!["This", "sentence", "needs", "to", "be", "split"], rustlatin("This sentence needs to be split")) + +} + diff --git a/assignments/_templates/rustlatin/src/lib_2.rs b/assignments/_templates/rustlatin/src/lib_2.rs new file mode 100644 index 00000000..0b8a321e --- /dev/null +++ b/assignments/_templates/rustlatin/src/lib_2.rs @@ -0,0 +1,19 @@ +const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; + +fn rustlatin(sentence: &str) -> Vec { + // ^^^^^^^ The correct return type needs to be added by you, + // depending on what the vector's exact type is. + let mut collection_of_words = Vec::new(); + + for word in sentence.split(' ') { + // Your implementation goes here: + + }; + collection_of_words +} + +#[test] +fn concatenated(){ + assert_eq!( vec!["dors", "yours", "likers", "rustrs"], rustlatin("do you like rust")) +} + diff --git a/assignments/_templates/rustlatin/src/lib_3.rs b/assignments/_templates/rustlatin/src/lib_3.rs new file mode 100644 index 00000000..699898c3 --- /dev/null +++ b/assignments/_templates/rustlatin/src/lib_3.rs @@ -0,0 +1,20 @@ +const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; + +fn rustlatin(sentence: &str) -> Vec { + // ^^^^^^^ The correct return type needs to be added by you, + // depending on what the vector's exact type is. + let mut collection_of_chars = Vec::new(); + + for word in sentence.split(' ') { + // Your implementation goes here: + + }; + collection_of_chars +} + + +#[test] +fn return_the_char(){ + assert_eq!(vec!['n', 't', 'd', 'b', 'i', 'a', 'r', 'v'], rustlatin("note the difference between iterator and return values")) +} + diff --git a/assignments/_templates/rustlatin/src/lib_4.rs b/assignments/_templates/rustlatin/src/lib_4.rs new file mode 100644 index 00000000..12631105 --- /dev/null +++ b/assignments/_templates/rustlatin/src/lib_4.rs @@ -0,0 +1,45 @@ + +const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; + +fn rustlatin(sentence: &str) -> String { + + let mut collection_of_words = Vec::new(); + + for word in sentence.split(' ') { + let first_char = word.chars().next().unwrap(); + // Your implementation goes here + }; + // return the content of collection_of_words as String +} + +// fn latinize() goes here + + + + +#[test] +fn test_latinizer() { + assert_eq!(latinize("rust"), "rustrs"); + assert_eq!(latinize("helps"), "helpsrs"); + assert_eq!(latinize("you"), "yours"); + assert_eq!(latinize("avoid"), "sravoid"); + +} + +#[test] +fn correct_translation() { + // Why can we compare `&str` and `String` here? + // https://doc.rust-lang.org/stable/std/string/struct.String.html#impl-PartialEq%3C%26%27a%20str%3E + assert_eq!( + "rustrs helpsrs yours sravoid sra lotrs srof srirritating bugsrs", + rustlatin("rust helps you avoid a lot of irritating bugs") + ) +} + +#[test] +fn incorrect() { + assert_ne!( + "this shouldrs not workrs", + rustlatin("this should not work") + ) +} diff --git a/assignments/solutions/rustlatin/Cargo.lock b/assignments/solutions/rustlatin/Cargo.lock new file mode 100644 index 00000000..51efe7e8 --- /dev/null +++ b/assignments/solutions/rustlatin/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rustlatin" +version = "0.1.0" diff --git a/assignments/solutions/rustlatin/Cargo.toml b/assignments/solutions/rustlatin/Cargo.toml new file mode 100644 index 00000000..e593ca8b --- /dev/null +++ b/assignments/solutions/rustlatin/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rustlatin" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/assignments/solutions/rustlatin/src/lib_1.rs b/assignments/solutions/rustlatin/src/lib_1.rs new file mode 100644 index 00000000..0a3b36c5 --- /dev/null +++ b/assignments/solutions/rustlatin/src/lib_1.rs @@ -0,0 +1,18 @@ +const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; + +fn rustlatin(sentence: &str) -> Vec<&str> { + let mut collection_of_words = Vec::new(); + + for word in sentence.split(' ') { + collection_of_words.push(word); + }; + + collection_of_words +} + + +#[test] +fn correct_splitting(){ + assert_eq!(vec!["This", "sentence", "needs", "to", "be", "split"], rustlatin("This sentence needs to be split")) + +} diff --git a/assignments/solutions/rustlatin/src/lib_2.rs b/assignments/solutions/rustlatin/src/lib_2.rs new file mode 100644 index 00000000..0bb0bf55 --- /dev/null +++ b/assignments/solutions/rustlatin/src/lib_2.rs @@ -0,0 +1,20 @@ +use std::str::Chars; + +const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; + +fn rustlatin(sentence: &str) -> Vec { + let mut collection_of_words = Vec::new(); + + for word in sentence.split(' ') { + collection_of_words.push(word.to_owned() + "rs") + + }; + collection_of_words +} + + +#[test] +fn concatenated(){ + assert_eq!( vec!["dors", "yours", "likers", "rustrs"], rustlatin("do you like rust")) +} + diff --git a/assignments/solutions/rustlatin/src/lib_3.rs b/assignments/solutions/rustlatin/src/lib_3.rs new file mode 100644 index 00000000..8550f49e --- /dev/null +++ b/assignments/solutions/rustlatin/src/lib_3.rs @@ -0,0 +1,20 @@ +use std::str::Chars; + +const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; + +fn rustlatin(sentence: &str) -> Vec { + let mut words = Vec::new(); + + for word in sentence.split(' ') { + let first_char = word.chars().next().unwrap(); + words.push(first_char); + }; + words + +} + +#[test] +fn return_the_char(){ + assert_eq!(vec!['n', 't', 'd', 'b', 'i', 'a', 'r', 'v'], rustlatin("note the difference between iterator and return values")) +} + diff --git a/assignments/solutions/rustlatin/src/lib_4.rs b/assignments/solutions/rustlatin/src/lib_4.rs new file mode 100644 index 00000000..cd1b5ed4 --- /dev/null +++ b/assignments/solutions/rustlatin/src/lib_4.rs @@ -0,0 +1,49 @@ +const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; + +fn rustlatin(sentence: &str) -> String { + let mut words = Vec::new(); + + for word in sentence.split(' ') { + words.push(latinize(word)); + + }; + words.join(" ") +} + +fn latinize(word: &str) -> String { + let first_char_of_word = word.chars().next().unwrap(); + if VOWELS.contains(&first_char_of_word) { + "sr".to_string() + word + } else { + word.to_string() + "rs" + } +} + +#[test] +fn test_latinizer() { + assert_eq!(latinize("rust"), "rustrs"); + assert_eq!(latinize("helps"), "helpsrs"); + assert_eq!(latinize("you"), "yours"); + assert_eq!(latinize("avoid"), "sravoid"); + +} + + + +#[test] +fn correct_translation() { + // Why can we compare `&str` and `String` here? + // https://doc.rust-lang.org/stable/std/string/struct.String.html#impl-PartialEq%3C%26%27a%20str%3E + assert_eq!( + "rustrs helpsrs yours sravoid sra lotrs srof srirritating bugsrs", + rustlatin("rust helps you avoid a lot of irritating bugs") + ) +} + +#[test] +fn incorrect() { + assert_ne!( + "this shouldrs not workrs", + rustlatin("this should not work") + ) +} From d1ba7b1ae869ee0ab0452d400756e1134b3184d2 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Fri, 20 Jan 2023 17:53:13 +0100 Subject: [PATCH 04/13] add skeleton location and prerequisits --- assignments/rustlatin.adoc | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/assignments/rustlatin.adoc b/assignments/rustlatin.adoc index 414ae6b2..1331aa2b 100644 --- a/assignments/rustlatin.adoc +++ b/assignments/rustlatin.adoc @@ -20,7 +20,15 @@ You will learn how to: == Prerequisists -Todo! +You must be able to +* define variables as mutable +* use for loop +* use an if/else construction +* read Rust documentation +* define a function with signature and return type +* define arrays and vectors +* distinguish between `String` and `&str` + == Tasks @@ -41,12 +49,14 @@ In order to learn as much as possible we recommend following the step-by-step so == Step-by-step-Solution === Getting started -Find the exercise skeletton. +Find the exercise skeletton in trainingmaterial/assignments/_templates/rustlatin -The folder contains each step as it's own numbered lib.rs file. Each file contains starter code and a test that needs to pass in order for the step to be considered complete. +The folder contains each step as it's own numbered `lib.rs` file. Each file contains starter code and a test that needs to pass in order for the step to be considered complete. ==== Rust Analyzer -A part of this exercise is seeing type inference in action and to use it to help to determine the type the funktion is going to return. To make sure the file can be indexed by Rust Analyzer, rename the file you're currently working on "lib.rs". Name it back to it's numbered version when you are finished. +A part of this exercise is seeing type inference in action and to use it to help to determine the type the funktion is going to return. To make sure the file can be indexed by Rust Analyzer, make sure +* that the `rustlatin` folder is your rootfolder in VSCoderename +* rename the file you're currently working on to `lib.rs`. Name it back to it's numbered version when you are finished. @@ -123,7 +133,7 @@ fn rustlatin(sentence: &str) -> Vec { === Step 4: Putting everything together: Comparing values and returning the content of the vector as `String`. -Add another function that checks if the first character of each word is a vowel. It adds the prefix or suffix according to the rules above. +Add another function that checks if the first character of each word is a vowel. It adds the prefix or suffix to the word according to the rules above. Call the function in each iteration. @@ -135,11 +145,14 @@ Run the tests to see if they pass. ==== [source,rust] ---- -// how to check if first character is a vowel, and modify the word! -if VOWELS.contains(&first_char) { - collection_of_words.push("sr".to_string() + word); -} else { - collection_of_words.push(word.to_string() + "rs"); + +fn latinize(word: &str) -> String { + let first_char_of_word = word.chars().next().unwrap(); + if VOWELS.contains(&first_char_of_word) { + "sr".to_string() + word + } else { + word.to_string() + "rs" + } } ---- ==== From e867845db8d8e1bec5417163f0fad71c3a871324 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Fri, 20 Jan 2023 18:44:02 +0100 Subject: [PATCH 05/13] add documentation links --- assignments/rustlatin.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignments/rustlatin.adoc b/assignments/rustlatin.adoc index 1331aa2b..c1888a73 100644 --- a/assignments/rustlatin.adoc +++ b/assignments/rustlatin.adoc @@ -64,7 +64,7 @@ A part of this exercise is seeing type inference in action and to use it to help === Step 1: Splitting a sentence and pushing its words into a vector. -Iterate over the sentence to split it into words. Use the white space as separator. Push each word into the vector `collection_of_words`. Add the correct return type to the function signature. +Iterate over the sentence to split it into words. Use the white space as separator. https://doc.rust-lang.org/std/vec/struct.Vec.html#method.push[Push] each word into the vector `collection_of_words`. Add the correct return type to the function signature. Run the test to see if it passes. .Click to see the solution From 1cc2253d83f738d5604a2b66347db094676c0401 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Mon, 23 Jan 2023 14:54:13 +0100 Subject: [PATCH 06/13] corrections and tasks added --- assignments/_templates/rustlatin/src/lib_1.rs | 5 ++++- assignments/_templates/rustlatin/src/lib_2.rs | 4 +++- assignments/_templates/rustlatin/src/lib_3.rs | 4 +++- assignments/_templates/rustlatin/src/lib_4.rs | 5 +++-- assignments/solutions/rustlatin/src/lib_3.rs | 4 ++-- assignments/solutions/rustlatin/src/lib_4.rs | 6 +++--- 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/assignments/_templates/rustlatin/src/lib_1.rs b/assignments/_templates/rustlatin/src/lib_1.rs index b0dc50bc..9a843c92 100644 --- a/assignments/_templates/rustlatin/src/lib_1.rs +++ b/assignments/_templates/rustlatin/src/lib_1.rs @@ -3,7 +3,7 @@ const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; // It's a global const because it will not be modified in any way and only // serves as a reference. -fn rustlatin(sentence: &str) -> Vec { +fn rustlatin(sentence: &str) -> Vec<_> { // ^^^^^^^ The correct return type needs to be added by you, // depending on what the vector's exact type is. @@ -13,6 +13,9 @@ fn rustlatin(sentence: &str) -> Vec { // the type should appear here automatically. // Your implementation goes here: + // Iterate over the sentence to split it into words. + // Push the words into the vector. + // Correct the return type of the vector collection_of_words diff --git a/assignments/_templates/rustlatin/src/lib_2.rs b/assignments/_templates/rustlatin/src/lib_2.rs index 0b8a321e..439eb852 100644 --- a/assignments/_templates/rustlatin/src/lib_2.rs +++ b/assignments/_templates/rustlatin/src/lib_2.rs @@ -1,12 +1,14 @@ const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; -fn rustlatin(sentence: &str) -> Vec { +fn rustlatin(sentence: &str) -> Vec<_> { // ^^^^^^^ The correct return type needs to be added by you, // depending on what the vector's exact type is. let mut collection_of_words = Vec::new(); for word in sentence.split(' ') { // Your implementation goes here: + // Add the suffix "rs" to each word before pushing it to the vector + // Correct the return type of the function. }; collection_of_words diff --git a/assignments/_templates/rustlatin/src/lib_3.rs b/assignments/_templates/rustlatin/src/lib_3.rs index 699898c3..ae0cce57 100644 --- a/assignments/_templates/rustlatin/src/lib_3.rs +++ b/assignments/_templates/rustlatin/src/lib_3.rs @@ -1,12 +1,14 @@ const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; -fn rustlatin(sentence: &str) -> Vec { +fn rustlatin(sentence: &str) -> Vec<_> { // ^^^^^^^ The correct return type needs to be added by you, // depending on what the vector's exact type is. let mut collection_of_chars = Vec::new(); for word in sentence.split(' ') { // Your implementation goes here: + // Add the first char of each word to the vector. + // Correct the return type of the vector. }; collection_of_chars diff --git a/assignments/_templates/rustlatin/src/lib_4.rs b/assignments/_templates/rustlatin/src/lib_4.rs index 12631105..14ab29fd 100644 --- a/assignments/_templates/rustlatin/src/lib_4.rs +++ b/assignments/_templates/rustlatin/src/lib_4.rs @@ -8,12 +8,13 @@ fn rustlatin(sentence: &str) -> String { for word in sentence.split(' ') { let first_char = word.chars().next().unwrap(); // Your implementation goes here + // pushes the latinized words into the vector }; - // return the content of collection_of_words as String + collection_of_words.join(" ") } // fn latinize() goes here - +// adds prefix "sr" and suffix "rs" according to the rules diff --git a/assignments/solutions/rustlatin/src/lib_3.rs b/assignments/solutions/rustlatin/src/lib_3.rs index 8550f49e..852e89b2 100644 --- a/assignments/solutions/rustlatin/src/lib_3.rs +++ b/assignments/solutions/rustlatin/src/lib_3.rs @@ -3,11 +3,11 @@ use std::str::Chars; const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; fn rustlatin(sentence: &str) -> Vec { - let mut words = Vec::new(); + let mut collection_of_words = Vec::new(); for word in sentence.split(' ') { let first_char = word.chars().next().unwrap(); - words.push(first_char); + collection_of_words.push(first_char); }; words diff --git a/assignments/solutions/rustlatin/src/lib_4.rs b/assignments/solutions/rustlatin/src/lib_4.rs index cd1b5ed4..77c10ff8 100644 --- a/assignments/solutions/rustlatin/src/lib_4.rs +++ b/assignments/solutions/rustlatin/src/lib_4.rs @@ -1,13 +1,13 @@ const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u']; fn rustlatin(sentence: &str) -> String { - let mut words = Vec::new(); + let mut collection_of_words = Vec::new(); for word in sentence.split(' ') { - words.push(latinize(word)); + collection_of_words.push(latinize(word)); }; - words.join(" ") + collection_of_words.join(" ") } fn latinize(word: &str) -> String { From 7dbd574e3fe2b7a558a3716762b5eaf80565566a Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Mon, 23 Jan 2023 14:54:42 +0100 Subject: [PATCH 07/13] formatting and explanations added --- assignments/rustlatin.adoc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/assignments/rustlatin.adoc b/assignments/rustlatin.adoc index c1888a73..aa7c9ce8 100644 --- a/assignments/rustlatin.adoc +++ b/assignments/rustlatin.adoc @@ -17,7 +17,6 @@ You will learn how to: * to concatenate `&str` * return the content of a `Vec` as `String`. - == Prerequisists You must be able to @@ -46,25 +45,26 @@ The function returns a `String` containing the modified words. In order to learn as much as possible we recommend following the step-by-step solution. -== Step-by-step-Solution + === Getting started Find the exercise skeletton in trainingmaterial/assignments/_templates/rustlatin The folder contains each step as it's own numbered `lib.rs` file. Each file contains starter code and a test that needs to pass in order for the step to be considered complete. -==== Rust Analyzer +=== Rust Analyzer A part of this exercise is seeing type inference in action and to use it to help to determine the type the funktion is going to return. To make sure the file can be indexed by Rust Analyzer, make sure * that the `rustlatin` folder is your rootfolder in VSCoderename * rename the file you're currently working on to `lib.rs`. Name it back to it's numbered version when you are finished. - - +== Step-by-step-Solution === Step 1: Splitting a sentence and pushing its words into a vector. -Iterate over the sentence to split it into words. Use the white space as separator. https://doc.rust-lang.org/std/vec/struct.Vec.html#method.push[Push] each word into the vector `collection_of_words`. Add the correct return type to the function signature. +Iterate over the sentence to split it into words. Use the white space as separator. This can be done with the https://doc.rust-lang.org/std/primitive.str.html#method.split[`.split()`] method, where the separator character `' '` goes into the paranthesis. This method returns an iterator over substrings of the string slice. In Rust, iterators are lazy, that means just calling `.split()` on a `&str` doesn't do anything by itself. It needs to be in combination with something that advances the iteration, such as a `for` loop, or a manual advancement such as the `.next()` method. These will yield the actual object you want to use. + + https://doc.rust-lang.org/std/vec/struct.Vec.html#method.push[Push] each word into the vector `collection_of_words`. Add the correct return type to the function signature. Run the test to see if it passes. .Click to see the solution @@ -86,7 +86,7 @@ fn rustlatin(sentence: &str) -> Vec<&str> { === Step 2 Concatenating String types. -After iterating over the sentence to split it into words, add the suffix `"rs"` to each word before pushing it to the vector. To concatenate two `&str` the first needs to be turned into the owned type with `to_owned`. Then `String` and `&str` can be added using `+`. Add the correct return type to the function signature. +After iterating over the sentence to split it into words, add the suffix `"rs"` to each word before pushing it to the vector. To concatenate two `&str` the first needs to be turned into the owned type with `.to_owned()`. Then `String` and `&str` can be added using `+`. Add the correct return type to the function signature. Run the test to see if it passes. .Click to see the solution @@ -109,7 +109,9 @@ fn rustlatin(sentence: &str) -> Vec { === Step 3: Iterating over a word to return the first character. After iterating over the sentence to split it into words, add the first character of each word to the vector. -(Here is the info missing how people are going to learn about chars(), and how it returns an iterator and not the character, either cheat sheet, documentation or we explain it here) +Check the Rust documentation on the https://doc.rust-lang.org/std/primitive.str.html#[primitive str Type] for a method that returns an iterator over the `chars` of a `&str`. The `char` type is a unicode scalar value that represents a single character. + +Since iterators don't do anything by themselves, it needs to be advanced first, with the `.next()` method. This method returns an `Option(Self::Item)`, where `Self::Item` is the `char` in this case. You don't need to handle it with pattern matching in this case, a simple `unwrap()` will do, as a `None` is not expected to happen. Add the correct return type to the function signature. Run the test to see if it passes. From 9da9dd7cf8f9e455f994e2cdf483ffe1e6bc0f75 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Mon, 30 Jan 2023 15:23:07 +0100 Subject: [PATCH 08/13] add contains() explanation --- assignments/rustlatin.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignments/rustlatin.adoc b/assignments/rustlatin.adoc index aa7c9ce8..5e2fd6e4 100644 --- a/assignments/rustlatin.adoc +++ b/assignments/rustlatin.adoc @@ -135,7 +135,7 @@ fn rustlatin(sentence: &str) -> Vec { === Step 4: Putting everything together: Comparing values and returning the content of the vector as `String`. -Add another function that checks if the first character of each word is a vowel. It adds the prefix or suffix to the word according to the rules above. +Add another function that checks if the first character of each word is a vowel. https://doc.rust-lang.org/std/primitive.slice.html#method.contains[contains()] is the method to help you with this. It adds the prefix or suffix to the word according to the rules above. Call the function in each iteration. From 09878d90fb55dac3e462fe6cc5453c29ebe75012 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 24 Jan 2023 09:42:28 +0100 Subject: [PATCH 09/13] move away from the deprecated actions/setup-ruby --- .github/workflows/pages.yaml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pages.yaml b/.github/workflows/pages.yaml index 781d7011..52a98b66 100644 --- a/.github/workflows/pages.yaml +++ b/.github/workflows/pages.yaml @@ -10,24 +10,21 @@ jobs: uses: actions/checkout@v1 - name: Set up Ruby 2.6 - uses: actions/setup-ruby@v1 + uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 + bundler-cache: true - name: Set up Node 16 uses: actions/setup-node@v3 with: node-version: 16 - - name: Install Dependencies - run: | - npm ci - gem install bundler - bundle install --jobs 4 --retry 3 + - name: Install Node dependencies + run: npm ci - name: Build - run: | - PATH="$(pwd)/node_modules/.bin:$PATH" ./rake + run: PATH="$(pwd)/node_modules/.bin:$PATH" ./rake - name: Deploy uses: ferrous-systems/shared-github-actions/github-pages@main From 9e345f4f29cd1c9914b5ee70effa04154d962fd7 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 24 Jan 2023 09:43:18 +0100 Subject: [PATCH 10/13] update action versions --- .github/workflows/pages.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pages.yaml b/.github/workflows/pages.yaml index 52a98b66..fefa941d 100644 --- a/.github/workflows/pages.yaml +++ b/.github/workflows/pages.yaml @@ -7,7 +7,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v1 + uses: actions/checkout@v3 - name: Set up Ruby 2.6 uses: ruby/setup-ruby@v1 From 54c95c34bd4c564782860bec49d49a2515127040 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 24 Jan 2023 09:45:32 +0100 Subject: [PATCH 11/13] better scope on clause --- .github/workflows/pages.yaml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pages.yaml b/.github/workflows/pages.yaml index fefa941d..dce488be 100644 --- a/.github/workflows/pages.yaml +++ b/.github/workflows/pages.yaml @@ -1,5 +1,14 @@ -name: pages -on: [push, pull_request] +--- + +name: GitHub Pages +on: + # The website will be deployed when any of these branches is pushed to: + push: + branches: + - main + - training_material_wip + # Perform builds without uploads for pull requests: + pull_request: jobs: pages: From df58be60da7cdbf30824d59e75135318a5b52863 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 24 Jan 2023 09:50:59 +0100 Subject: [PATCH 12/13] build both branches at the same time --- .github/workflows/pages.yaml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pages.yaml b/.github/workflows/pages.yaml index dce488be..c57405af 100644 --- a/.github/workflows/pages.yaml +++ b/.github/workflows/pages.yaml @@ -11,12 +11,21 @@ on: pull_request: jobs: - pages: + build: + name: Build runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + branch: + - main + - training_material_wip steps: - name: Checkout repository uses: actions/checkout@v3 + with: + ref: "${{ matrix.branch }}" - name: Set up Ruby 2.6 uses: ruby/setup-ruby@v1 @@ -35,9 +44,9 @@ jobs: - name: Build run: PATH="$(pwd)/node_modules/.bin:$PATH" ./rake - - name: Deploy - uses: ferrous-systems/shared-github-actions/github-pages@main + - name: Upload content + uses: actions/upload-artifact@v3 with: + name: "content-${{ matrix.branch }}" path: target/ - token: ${{ secrets.GITHUB_TOKEN }} - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + retention-days: 1 From b31c75546d216f5d210419f1e1b2d6d5d9faf10e Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 24 Jan 2023 10:06:38 +0100 Subject: [PATCH 13/13] add deployment job --- .github/workflows/pages.yaml | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/.github/workflows/pages.yaml b/.github/workflows/pages.yaml index c57405af..4fc6ceee 100644 --- a/.github/workflows/pages.yaml +++ b/.github/workflows/pages.yaml @@ -50,3 +50,40 @@ jobs: name: "content-${{ matrix.branch }}" path: target/ retention-days: 1 + + publish: + name: Publish + runs-on: ubuntu-latest + + needs: [build] + if: github.event_name == 'push' + + permissions: + pages: write + id-token: write + + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + steps: + - name: Download contents for the main branch + uses: actions/download-artifact@v3 + with: + name: content-main + path: target/ + + - name: Download contents for the training_material_wip branch + uses: actions/download-artifact@v3 + with: + name: content-training_material_wip + path: target/next/ + + - name: Upload GitHub Pages content + uses: actions/upload-pages-artifact@v1 + with: + path: target/ + + - name: Deploy to GitHub Pages + uses: actions/deploy-pages@v1 + id: deployment