├── .devcontainer └── devcontainer.json ├── .gitignore ├── LICENSE ├── README.md ├── assets └── banner.svg ├── examples └── cli-utils │ ├── .gitignore │ ├── Cargo.toml │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── src │ ├── colors.rs │ ├── config.rs │ └── lib.rs │ └── tests │ ├── test_colors.rs │ └── test_simple.rs └── lab.md /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/rust 3 | { 4 | "name": "Rust", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/rust:0-1-bullseye", 7 | "customizations": { 8 | "vscode": { 9 | "extensions": [ 10 | "GitHub.copilot", 11 | "rust-lang.rust-analyzer", 12 | "vadimcn.vscode-lldb" 13 | ] 14 | } 15 | } 16 | 17 | // Use 'mounts' to make the cargo cache persistent in a Docker Volume. 18 | // "mounts": [ 19 | // { 20 | // "source": "devcontainer-cargo-cache-${devcontainerId}", 21 | // "target": "/usr/local/cargo", 22 | // "type": "volume" 23 | // } 24 | // ] 25 | 26 | // Features to add to the dev container. More info: https://containers.dev/features. 27 | // "features": {}, 28 | 29 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 30 | // "forwardPorts": [], 31 | 32 | // Use 'postCreateCommand' to run commands after the container is created. 33 | // "postCreateCommand": "rustc --version", 34 | 35 | // Configure tool-specific properties. 36 | // "customizations": {}, 37 | 38 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 39 | // "remoteUser": "root" 40 | } 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | **/target 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Alfredo Deza 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [![Coursera Course](./assets/banner.svg)](https://insight.paiml.com/58m "Coursera Specialization") 2 | 3 | This repository is part of the Rust Fundamentals Coursera course and Systems Engineering specialization by Duke University 4 | 5 | # Applied Rust 6 | 7 | _Rust Bootcamp week 4: Applying Rust to build a library_ 8 | 9 | This week, you will learn how to build a Rust library with Cargo and apply debugging, testing, and documentation patterns that are applicable in a professional setting. You'll use new Cargo commands to work with the library and you'll get an idea on how to work with Rust libraries in other projects. Finally, you'll work closely with public and private code and adding tests to it. The tests will help you verify your work and increase confidence for a solid release. 10 | 11 | This is the last wee of the Rust Bootcamp. There are 4 weeks in total: 12 | 13 | - [week 1](https://github.com/alfredodeza/rust-setup) 14 | - [week 2](https://github.com/alfredodeza/rust-fundamentals) 15 | - [week 3](https://github.com/alfredodeza/rust-structs-types-enums/) 16 | - [week 4](https://github.com/alfredodeza/applied-rust) 👈 You are here! 17 | 18 | 💡 Are you just looking for a 👉 [Rust template](https://github.com/alfredodeza/rust-template) to get started easily with a project? The [template](https://github.com/alfredodeza/rust-template) has everything you need! 19 | 20 | [![DS500](https://ds500.paiml.com/assets/social/g6u1k.png)](https://ds500.paiml.com/learn/course/g6u1k/ "Rust Fundamentals Course") 21 | 22 | 23 | ## Contents 24 | This week uses an example use-case to create a Rust library from scratch. Instead of separate projects as examples, it uses one single example that you can use as a reference. All the code is in the [./examples](./examples) directory. Make sure you have Rust installed and you are using [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-0000-alfredodeza). 25 | 26 | This repository is *Codespaces ready*, and it is set as a template repository. You can create a new repository from this template and start working on your own with Codespaces. This means that Rust, Copilot, and all the extensions are already installed and configured for you. 27 | 28 | ### Lesson 1: Building a real-world library 29 | - [Adding code to lib.rs](https://github.com/alfredodeza/applied-rust/blob/main/examples/cli-utils/src/lib.rs#L24) 30 | - [Documenting your code](https://github.com/alfredodeza/applied-rust/blob/main/examples/cli-utils/src/lib.rs#L1-L23) 31 | - [Using a Makefile](./examples/cli-utils/Makefile) 32 | 33 | ### Lesson 2: 34 | - [Using Cargo for dependencies](./examples/cli-utils/Cargo.toml) 35 | - [Extending with modules](./examples/cli-utils/src/config.rs) 36 | - [Defining Public and Private modules](https://github.com/alfredodeza/applied-rust/blob/main/examples/cli-utils/src/lib.rs#L13-L14) 37 | - [Public and Private fields](https://github.com/alfredodeza/applied-rust/blob/main/examples/cli-utils/src/config.rs#L15-L36) 38 | 39 | ### Lesson 3: Testing Rust Code 40 | - [Organizing test files](./examples/cli-utils/tests) 41 | - [Understanding testing private code](https://github.com/alfredodeza/applied-rust/blob/main/examples/cli-utils/src/lib.rs#L38-L61) 42 | - [Writing your first test](./examples/cli-utils/tests/test_simple.rs) 43 | - [Other assert macros](https://github.com/alfredodeza/applied-rust/blob/main/examples/cli-utils/src/lib.rs#L49) 44 | 45 | ### Lesson 4: Practice lab 46 | Use the included [practice lab](./lab.md) to apply the content you've learned in this week. Follow the steps to create your own repository and apply the requirements to complete the lab so that you end up creating a library in Rust. 47 | 48 | ## Resources 49 | 50 | **Coursera Courses** 51 | 52 | - [MLOps Machine Learning Operations Specialization](https://www.coursera.org/specializations/mlops-machine-learning-duke) 53 | - [Linux and Bash for Data Engineering](https://www.coursera.org/learn/linux-and-bash-for-data-engineering-duke) 54 | - [Open Source Platforms for MLOps](https://www.coursera.org/learn/open-source-platforms-duke) 55 | - [Python Essentials for MLOps](https://www.coursera.org/learn/python-essentials-mlops-duke) 56 | - [Web Applications and Command-Line tools for Data Engineering](https://www.coursera.org/learn/web-app-command-line-tools-for-data-engineering-duke) 57 | - [Python and Pandas for Data Engineering](https://www.coursera.org/learn/python-and-pandas-for-data-engineering-duke) 58 | - [Scripting with Python and SQL for Data Engineering](https://www.coursera.org/learn/scripting-with-python-sql-for-data-engineering-duke) 59 | 60 | **Readings** 61 | - [Rust Book](https://doc.rust-lang.org/book/) 62 | - [First steps with Rust Learning Path](https://learn.microsoft.com/training/paths/rust-first-steps/?WT.mc_id=academic-0000-alfredodeza) 63 | 64 | **Other courses** 65 | - [DevOps command-line tools in Python and Rust](https://learning.oreilly.com/videos/devops-command-line-tools/28037639VIDEOPAIML/) 66 | 67 | -------------------------------------------------------------------------------- /assets/banner.svg: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | Duke University 11 | 12 | 13 | 14 | 15 | Rust Programming specialization 16 | 17 | 18 | 19 | coursera 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/cli-utils/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /examples/cli-utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cli-utils" 3 | version = "0.1.1" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /examples/cli-utils/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Alfredo Deza 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/cli-utils/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /bin/bash 2 | .PHONY: help 3 | 4 | help: 5 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' 6 | 7 | clean: ## Clean the project using cargo 8 | cargo clean 9 | 10 | build: ## Build the project using cargo 11 | cargo build 12 | 13 | lint: ## Lint the project using cargo 14 | @rustup component add clippy 2> /dev/null 15 | cargo clippy 16 | 17 | fmt: ## Format the project using cargo 18 | @rustup component add rustfmt 2> /dev/null 19 | cargo fmt 20 | 21 | bump: ## Bump the version number 22 | @echo "Current version is $(shell cargo pkgid | cut -d# -f2)" 23 | @read -p "Enter new version number: " version; \ 24 | updated_version=$$(cargo pkgid | cut -d# -f2 | sed -E "s/([0-9]+\.[0-9]+\.[0-9]+)$$/$$version/"); \ 25 | sed -i -E "s/^version = .*/version = \"$$updated_version\"/" Cargo.toml 26 | @echo "New version is $(shell cargo pkgid | cut -d# -f2)"% -------------------------------------------------------------------------------- /examples/cli-utils/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/cli-utils/src/colors.rs: -------------------------------------------------------------------------------- 1 | //! Colorized output utilities for the terminal using ANSI escape codes. 2 | //! # Examples: 3 | //! ``` 4 | //! use cli_utils::colors::*; 5 | //! println!("{}{}{}", red("Red"), green("Green"), blue("Blue")); 6 | //! ``` 7 | 8 | /// Returns a string with the ANSI escape code for red. 9 | /// # Examples: 10 | /// ``` 11 | /// use cli_utils::colors::*; 12 | /// println!("{}", red("Red")); 13 | /// ``` 14 | pub fn red(s: &str) -> String { 15 | format!("\x1b[31m{}\x1b[0m", s) 16 | } 17 | 18 | pub fn green(s: &str) -> String { 19 | format!("\x1b[32m{}\x1b[0m", s) 20 | } 21 | 22 | pub fn blue(s: &str) -> String { 23 | format!("\x1b[34m{}\x1b[0m", s) 24 | } 25 | 26 | pub fn bold(s: &str) -> String { 27 | format!("\x1b[1m{}\x1b[0m", s) 28 | } 29 | 30 | pub fn reset(s: &str) -> String { 31 | format!("\x1b[0m{}\x1b[0m", s) 32 | } 33 | 34 | pub enum Color{ 35 | Red, 36 | Green, 37 | Blue, 38 | Bold, 39 | } 40 | 41 | pub struct ColorString { 42 | pub color: Color, 43 | pub string: String, 44 | pub colorized: String 45 | } 46 | 47 | impl ColorString { 48 | // create a method that will use the string and color fields to create a colorized string and assign it to the colorized field 49 | pub fn paint(&mut self) { 50 | match self.color { 51 | Color::Red => self.colorized = red(&self.string), 52 | Color::Green => self.colorized = green(&self.string), 53 | Color::Blue => self.colorized = blue(&self.string), 54 | Color::Bold => self.colorized = bold(&self.string), 55 | }; 56 | } 57 | 58 | pub fn reset(&mut self) { 59 | self.colorized = reset(&self.string); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /examples/cli-utils/src/config.rs: -------------------------------------------------------------------------------- 1 | //! This module contains the configuration options for the application. 2 | //! # Examples: 3 | //! ``` 4 | //! use cli_utils::config::Logging; 5 | //! let config = Logging::new(); 6 | //! ``` 7 | //! 8 | pub enum LogLevel { 9 | Debug, 10 | Info, 11 | Warn, 12 | Error, 13 | } 14 | 15 | pub enum LogOutput { 16 | Stdout, 17 | Stderr, 18 | File(String), 19 | } 20 | 21 | /// This struct contains configuration options for the application. 22 | /// # Examples: 23 | /// ``` 24 | /// use cli_utils::config::Logging; 25 | /// let config = Logging::new(); 26 | /// ``` 27 | /// 28 | /// Creating a new instance of the Logging struct: 29 | /// ``` 30 | /// use cli_utils::config::{Logging, LogLevel, LogOutput}; 31 | /// let config = Logging{ enabled: true, level: LogLevel::Info, destination: LogOutput::Stdout }; 32 | /// ``` 33 | pub struct Logging { 34 | pub enabled: bool, 35 | pub level: LogLevel, 36 | pub destination: LogOutput, 37 | } 38 | 39 | impl Logging { 40 | pub fn new() -> Self { 41 | Self { 42 | enabled: false, 43 | level: LogLevel::Info, 44 | destination: LogOutput::Stdout, 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /examples/cli-utils/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This is a library that provides utilities for command-line tools. 2 | //! So far it only provides a function to read a line from stdin. 3 | //! # Examples: 4 | //! ``` 5 | //! use cli_utils::read_stdin; 6 | //! let input = read_stdin(); 7 | //! ``` 8 | //! # Panics: 9 | //! The `read_stdin` function will panic if it fails to read a line with a message "Failed to read input line". 10 | 11 | use std::io::{BufRead, BufReader}; 12 | 13 | pub mod config; 14 | pub mod colors; 15 | 16 | 17 | /// This function reads a line from stdin and returns it as a String. 18 | /// It will panic if it fails to read a line with a message "Failed to read input line". 19 | /// # Examples: 20 | /// ``` 21 | /// use cli_utils::read_stdin; 22 | /// let input = read_stdin(); 23 | /// ``` 24 | pub fn read_stdin() -> String { 25 | let stdin = std::io::stdin(); 26 | let mut reader = BufReader::new(stdin.lock()); 27 | _read_stdin(&mut reader) 28 | } 29 | 30 | fn _read_stdin(reader: &mut R) -> String { 31 | let mut line = String::new(); 32 | reader 33 | .read_line(&mut line) 34 | .expect("Failed to read input line"); 35 | line.trim().to_string() 36 | } 37 | 38 | #[cfg(test)] 39 | mod tests { 40 | use super::_read_stdin; 41 | use std::io::Cursor; 42 | 43 | #[test] 44 | fn test_read_input() { 45 | let input = "Hello, world!\n"; 46 | let expected_output = "Hello, world!"; 47 | let mut reader = Cursor::new(input); 48 | let output = _read_stdin(&mut reader); 49 | assert_eq!(output, expected_output); 50 | } 51 | 52 | #[test] 53 | fn test_read_input_empty() { 54 | let input = ""; 55 | let expected_output = ""; 56 | let mut reader = Cursor::new(input); 57 | let output = _read_stdin(&mut reader); 58 | assert_eq!(output, expected_output); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /examples/cli-utils/tests/test_colors.rs: -------------------------------------------------------------------------------- 1 | use cli_utils::colors::{ColorString, Color}; 2 | 3 | #[test] 4 | fn test_red_coloring() { 5 | let mut color_string = ColorString { 6 | color: Color::Red, 7 | string: "Red".to_string(), 8 | colorized: "".to_string(), 9 | }; 10 | color_string.paint(); 11 | assert_eq!(color_string.colorized, "\x1b[31mRed\x1b[0m"); 12 | } -------------------------------------------------------------------------------- /examples/cli-utils/tests/test_simple.rs: -------------------------------------------------------------------------------- 1 | 2 | #[test] 3 | fn test_simple() { 4 | println!("hello!"); 5 | //assert!(true); 6 | } -------------------------------------------------------------------------------- /lab.md: -------------------------------------------------------------------------------- 1 | # Create a Rust library 2 | 3 | In this lab, you will create a library in Rust to reinforce the concepts covered in the last lesson. You can choose one of the following library ideas, or you are free to create one on your own. You will add code to the lib.rs file, document your code, and utilize tools like Makefile and Cargo. The end result will be a GitHub repository containing the complete code for your chosen library. 4 | 5 | ## Learning Objectives: 6 | - Gain experience in creating a library and organizing code in Rust. 7 | - Practice documenting code using comments and Rust's documentation conventions. 8 | - Understand how to use a Makefile to automate build tasks and simplify compilation. 9 | - Explore public and private modules in Rust and define appropriate access levels for functions. 10 | 11 | ## Steps: 12 | 13 | 1. 1. Create a new repository in your account for your Rust project. Use the [Rust template repository](https://github.com/alfredodeza/rust-template) to quickly generate one for your own account. Use this link to [create it in one step](https://github.com/alfredodeza/rust-template/generate). 14 | 1. Use the [example code](https://github.com/alfredodeza/applied-rust/tree/main/examples/cli-utils) used for this week as a starting point 15 | 1. Use one of the library ideas below or implement one from your own 16 | 17 | **Bonus:** Try publishing your documented library to crates.io so that you can share it with others as a crate. 18 | 19 | ## Library Ideas 20 | 21 | 1. Library Example: MathUtils 22 | **Description:** Create a library that provides basic mathematical utility functions. Include functions like calculating the factorial of a number, finding the greatest common divisor (GCD) of two numbers, and checking if a number is prime. 23 | 24 | 1. Library Example: StringUtils 25 | **Description:** Build a library that offers string manipulation utilities. Include functions to check if a string is a palindrome, count the occurrence of a specific character in a string, and reverse a string. 26 | 27 | 1. Library Example: DateUtils 28 | **Description:** Develop a library that provides date and time manipulation functionalities. Include functions to calculate the difference between two dates, validate a date format, and format dates in different styles (e.g., DD/MM/YYYY, YYYY-MM-DD). 29 | 30 | 1. Library Example: FileIOUtils 31 | **Description:** Construct a library that simplifies file input/output operations. Include functions to read a file and return its contents as a string, write a string to a file, and append content to an existing file. 32 | 33 | 34 | By completing this lab, you will gain practical experience in building real-world libraries in Rust. You will apply your knowledge of library development, documentation, testing, and code organization to create functional libraries that can be utilized by other Rust developers. The resulting GitHub repository will demonstrate your ability to apply the concepts covered in the last lesson to create simple yet useful libraries in Rust. 35 | 36 | 37 | --------------------------------------------------------------------------------