1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
# shippit-coding-challenge
My submission to the Shippit Coding Challenge, implemented in Ruby v3.3.5, is a small application to manage the following family tree of King Arthur and Queen Margaret:

The application accepts an action file where each line denotes an action to perform on the family tree.
Example: `./ruby family_tree.rb /path/to/actions.txt`
**Supported Actions**
- `ADD_CHILD [MOTHER'S NAME] [CHILD'S NAME] [CHILD'S GENDER]`
- `GET_RELATIONSHIP [PERSON'S NAME] [RELATIONSHIP TYPE]`
> Note that you can only add a child via the mother
**Supported Genders**
- `MALE`
- `FEMAL`
**Supported Relationship Types**
- `MOTHER`
- `FATHER`
- `SIBLINGS`
- `CHILD`
- `DAUGHTER`
- `SON`
- `PATERNAL-UNCLE`
- `MATERNAL-UNCLE`
- `PATERNAL-AUNT`
- `MATERNAL-AUNT`
- `SISTER-IN-LAW`
- `BROTHER-IN-LAW`
**Comments and Blank Lines**
Blank lines and lines starting with `#` are ignored.
**Example `actions.txt` File**
Based on the family tree of King Arthur and Queen Margaret, here is an example action file:
```txt
# Adding Children
ADD_CHILD "Queen Margaret" "Jonathan" "Male"
ADD_CHILD Ginerva "St John" "Male"
# Getting relationships
GET_RELATIONSHIP Remus Maternal-Aunt
```
> Note that quotation marks are only required if the name of the person has a space in it, if quotation marks are ommitted the action will fail.\
> Also, note that the **gender** and **relationship-types** are **case-insensitive**.
**Output**
Based on the family tree, here are the expected outputs for commoon scenarios:
| Action | Output | Comments |
| ----------------------------------------------- | ----------------------- | --------------------------- |
| `ADD_CHILD "Queen Margaret" "Jonathan" "Male"` | `CHILD_ADDED` | Successful |
| `ADD_CHILD "Betty" "Jonathan" "Male"` | `PERSON_NOT_FOUND` | Betty doesn't exist |
| `ADD_CHILD "Queen Margaret" "Jonathan" "Other"` | `CHILD_ADDITION_FAILED` | Invalid gender |
| `ADD_CHILD "King Arthur" "Jonathan" "Other"` | `CHILD_ADDITION_FAILED` | Father's name provided |
| `ADD_CHILD "King Arthur"` | _no output_ | Invalid number of arguments |
| `ADD_CHILD "King Arthur" "Jonathan"` | _no output_ | Invalid number of arguments |
| `ADD_PET "King Arthur" "Poodles"` | _no output_ | Invalid action, `ADD_PET` |
| `GET_RELATIONSHIP "Percy" "Child"` | `Molly Lucy` | Names of children |
| `GET_RELATIONSHIP "Charlie" "Child"` | `NONE` | Charlie has no children |
| `GET_RELATIONSHIP "Betty" "Child"` | `PERSON_NOT_FOUND` | Betty doesn't exist |
| `GET_RELATIONSHIP "King Arthur" "Pets"` | _no output_ | Invalid relationship type |
| `GET_RELATIONSHIP "King Arthur"` | _no output_ | Invalid number of arguments |
## Approach
### Data Model
The data model revolves around four primary classes: `FamilyTree`, `FamilyFactory`, `Family`, and `Person`.
#### `FamilyTree`
Represents the entire family tree and ensures a single instance throughout the application using the Singleton pattern.\\
It manages a collection of `Family` objects and the retrieval of various family relationships such as parents, uncles, aunts, and children.
#### `FamilyFactory`
Responsible for creating and initializing predefined families. It uses helper methods to find or create individuals and establish relationships between them.
#### `RelationshipManager`
Manages the relationships between individuals, ensuring that connections like spouses, parents, and siblings are correctly established and maintained.
#### `Family`
Represents a family unit which is made up of a mother (`Person`), father (`Person`), and children (an array of `Person` objects).
#### `Person`
Represents an individual within the family tree, holding personal information and a reference to their spouse. A `Person` can exist in multiple families - as a **child** of one and as a **parent** (mother or father) of another.
## Dependencies
This project requires the following dependencies:
- Ruby 3.3.5
- Bundler (for managing gem dependencies)
Make sure to install Bundler if you haven't already:
```sh
gem install bundler
```
## Usage
To run the application with a custom `actions.txt` file, you can specify the path to your custom file. For example:
```sh
ruby ./bin/family_tree.rb ./path/to/your/actions.txt
```
This will execute the actions specified in your custom `actions.txt` file.
Alternatively, you can use the Rake task `rake run` to run the application with the included `./data/actions.txt` file:
```sh
rake run
```
## Testing
To run the tests, you can use the Rake tasks defined in the `Rakefile`. Use the following command to run all tests:
```sh
rake test
```
This will execute all the RSpec tests in the `spec` directory.
|