Skip to content

Commit

Permalink
✨ (concepts) Add new concept exercise phone-number-analysis
Browse files Browse the repository at this point in the history
This is inspired by the same in csharp track. Provides a gentle introduction to tuples.
  • Loading branch information
devkabiir committed May 1, 2023
1 parent 796f2ca commit 08c5c99
Show file tree
Hide file tree
Showing 11 changed files with 320 additions and 0 deletions.
14 changes: 14 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@
},
"exercises": {
"concept": [
{
"slug": "phone-number-analysis",
"uuid": "eabea697-cc15-472f-ab4e-5b2720a180d1",
"name": "Phone Number Analysis",
"difficulty": 1,
"concepts": [
"tuples"
],
"prerequisites": [
"strings",
"booleans"
],
"status": "wip"
},
{
"slug": "lucians-luscious-lasagna",
"uuid": "29a2d3bd-eec8-454d-9dba-4b2d7d071925",
Expand Down
27 changes: 27 additions & 0 deletions exercises/concept/phone-number-analysis/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Hints

## General

- [Tuples][tuples]: shows how to define and use tuples.

## 1. Analyze a phone number

- Make sure the tuple has values at the right place.
- Tuples are passed as a [return value][tuples-return].

- Use `.split_at()` method on a string to split it and get a tuple of its parts.
```rust
let str = "Per Martin-Löf";

let (first, last) = str.split_at(3);

first // => "Per"
last // => " Martin-Löf"
```

## 2. Detect if a phone number is fake prefix code (555)

- You can extract the value of a field with the same sort of dot syntax as you employ with `struct`s or `class`s.

[tuples]: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
[tuples-return]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#tuples-as-method-return-values
32 changes: 32 additions & 0 deletions exercises/concept/phone-number-analysis/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Instructions

This exercise has you analyze phone numbers.

You are asked to implement 2 features.

Phone numbers passed to the routines are guaranteed to be in the form
NNN-NNN-NNNN e.g. 212-515-9876.

## 1. Analyze a phone number

Your analysis should return 3 pieces of data

1. An indication of whether the number has a New York dialing code ie. 212 as the first 3 digits
2. An indication of whether the number is fake having 555 as a prefix code in positions 5 to 7 (numbering from 1)
3. The last 4 digits of the number.

Implement the function `analyze()` to produce the phone number info.

```rust
analyze("631-555-1234");
// => (false, true, "1234")
```

## 2. Detect if a phone number has a fake prefix code (555)

Implement the function `is_fake()` to detect whether the phone number is fake using the phone number info produced in task 1.

```rust
is_fake(analyze("631-555-1234"));
// => true
```
115 changes: 115 additions & 0 deletions exercises/concept/phone-number-analysis/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Introduction

## Tuples

A _tuple_ is a general way of grouping together a number of values with a variety of types into one compound type. Tuples have a fixed length: once declared, they cannot grow or shrink in size.

We create a tuple by writing a comma-separated list of values inside parentheses. Each position in the tuple has a type, and the types of the different values in the tuple don’t have to be the same.
We’ve added optional type annotations in this example:

```rust
let my_tuple: (i32, f64, u8) = (500, 6.4, 1);
```

The variable `my_tuple` binds to the entire tuple because a tuple is considered
a single compound element.
To get the individual values out of a tuple, we can use pattern matching to
destructure a tuple value, like this:

```rust
let (x, y, z) = my_tuple;

println!("{}", y);
// => 6.4

```

This program first creates a tuple and binds it to the variable `my_tuple`.
It then uses a pattern with let to take `my_tuple` and turn it into three separate variables, `x`, `y`, and `z`.
This is called _destructuring_ because it breaks the single tuple into three
parts.
Finally, the program prints the value of `y`, which is `6.4`.

Sometimes, when _destructuring_ a tuple, some values might not be important or
needed, these can be discarded by labeling them with "`_`" (underscore).

```rust
let (_, y, _) = my_tuple;

println!("{}", y);
// => 6.4

```

We can also access a tuple element directly by using a period (.) followed by the index of the value we want to access.
For example:

```rust
let my_tuple: (i32, f64, u8) = (500, 6.4, 1);

let five_hundred = my_tuple.0;

let six_point_four = my_tuple.1;

let one = my_tuple.2;
```

This program creates the tuple x and then accesses each element of the tuple
using their respective indices. As with most programming languages, the first
index in a tuple is 0.

A tuple can contain 0, or upto 12 elements. A tuple with zero elements has a
special name, _unit_.

```rust
let my_zero_tuple = ();
let my_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
```



### Calling methods
One can call any methods on a value held by a tuple by either first
destructuring that value out of the tuple or accessing it using it's index.
```rust
let my_tuple = (12, "hello");

let (my_num, my_str) = my_tuple;

my_str.to_uppercase();

// OR

my_tuple.1.to_uppercase();
```

### Functions can accept a tuple as a parameter.
Accepting a tuple as a parameter requires to explicitly define its type. The
following example illustrates that.
```rust
fn my_function(my_tuple: (i32, &str)) {
// Do something with my_tuple
}
```

### Functions can return tuple as a result.
Returning a tuple as a result requires to explicitly define its type. The
following example illustrates that.
```rust
fn make_tuple(an_int: i32, a_string: &str) -> (i32, &str) {
return (an_int, a_string);
}
```

### Methods can return tuple as a result.
Methods on various types sometimes return a tuple as a result. Consider the
following example of a `&str` variable's `.split_at()` method.

```rust
let str = "Per Martin-Löf";

let (first, last) = str.split_at(3);

first // => "Per"
last // => " Martin-Löf"
```
8 changes: 8 additions & 0 deletions exercises/concept/phone-number-analysis/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Generated by Cargo
# will have compiled files and executables
/target/
**/*.rs.bk

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock
18 changes: 18 additions & 0 deletions exercises/concept/phone-number-analysis/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"authors": [
"devkabiir"
],
"files": {
"solution": [
"src/lib.rs",
"Cargo.toml"
],
"test": [
"tests/phone-number-analysis.rs"
],
"exemplar": [
".meta/exemplar.rs"
]
},
"blurb": "Learn about tuples by analysing phone numbers."
}
23 changes: 23 additions & 0 deletions exercises/concept/phone-number-analysis/.meta/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Design

## Learning objectives

- Know of the existence of tuples.
- Know how to assigne a tuple.
- Know how to access a value held by a tuple.
- Know how to return a tuple as a result.
- Know how to destructure tuple values into variables.
- Know how to accept a tuple as a parameter.

## Out of scope


## Concepts

- `tuples`

## Prerequisites

- `strings`
- `if-statements`
- `booleans`
13 changes: 13 additions & 0 deletions exercises/concept/phone-number-analysis/.meta/exemplar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pub fn analyze(phone_number: &str) -> (bool, bool, &str) {
let (dial_code, number) = phone_number.split_at(3);

let (prefix_code, last_4_with_dash) = number.split_at(4);

let (_, last_4) = last_4_with_dash.split_at(1);

(dial_code == "212", prefix_code == "-555", last_4)
}

pub fn is_fake(info: (bool, bool, &str)) -> bool {
info.1
}
4 changes: 4 additions & 0 deletions exercises/concept/phone-number-analysis/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
name = "phone_number_analysis"
version = "0.1.0"
edition = "2021"
7 changes: 7 additions & 0 deletions exercises/concept/phone-number-analysis/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub fn analyze(_phone_number: &str) -> (bool, bool, &str) {
unimplemented!("Implement analyze")
}

pub fn is_fake(_info: (bool, bool, &str)) -> bool {
unimplemented!("Implement is_fake")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#[test]
pub fn analyze_non_fake_non_newyork() {
assert_eq!(
(false, false, "1234"),
phone_number_analysis::analyze("631-502-1234")
);
}

#[test]
#[ignore]
pub fn analyze_fake_non_newyork() {
assert_eq!(
(false, true, "1234"),
phone_number_analysis::analyze("631-555-1234")
);
}

#[test]
#[ignore]
pub fn analyze_non_fake_newyork() {
assert_eq!(
(true, false, "1234"),
phone_number_analysis::analyze("212-502-1234")
);
}

#[test]
#[ignore]
pub fn analyze_fake_newyork() {
assert_eq!(
(true, true, "1234"),
phone_number_analysis::analyze("212-555-1234")
);
}

#[test]
#[ignore]
pub fn analyze_fake_fake() {
assert_eq!(
(false, false, "1234"),
phone_number_analysis::analyze("515-212-1234")
);
}

#[test]
#[ignore]
pub fn is_fake_fake() {
assert!(phone_number_analysis::is_fake(
phone_number_analysis::analyze("212-555-1234")
));
}

#[test]
#[ignore]
pub fn is_fake_non_fake() {
assert!(!phone_number_analysis::is_fake(
phone_number_analysis::analyze("555-212-1234")
));
}

0 comments on commit 08c5c99

Please sign in to comment.