Skip to content

✨ (concepts) Add new concept exercise phone-number-analysis #1676

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many people would consider that feature 2 would be a standalone test and that feature 1 would reference that test in constructing the feature 1 tuple. It seems that we are looking for feature 2 to return the second element of the feature 1 tuple (i.e. analyze().1) , rather than returning the value of the separate test, simply because the second part of feature 1 relies on feature 2.

Perhaps we should recognize that in the instructions and say (as we do in different exercises) that although you could simply return the value of the standalone test for fake 555 prefix, this exercise asks you to return the value based only on the phone number info produced in task 1.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your concern on clarity, I don't understand how to make it more clear, the following along with the accompanying example should suffice

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

As I understand it, The purpose of second task is to learn how to take tuples as parameters and indexing tuples.


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
```
114 changes: 114 additions & 0 deletions exercises/concept/phone-number-analysis/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# 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 `my_tuple` and then accesses each of its elements 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")
));
}