Lesson 4
Managing Employee Records: Nested Hashes and Arrays
Introduction

Welcome! Today, we’re diving into an exciting project that involves managing employee records within a company. Specifically, we’ll use nested hashes and arrays in Ruby to add projects and tasks for employees and retrieve those tasks as needed. This exercise will help you understand how to manipulate nested data structures effectively in Ruby.

Introducing Methods to Implement

We'll implement three methods in our EmployeeRecords class:

  • add_project(employee_id, project_name) - Adds a new project to an employee's list of projects. If the project already exists for that employee, the method returns false. Otherwise, it adds the project and returns true.
  • add_task(employee_id, project_name, task) - Adds a new task to a specified project for an employee. If the project does not exist for that employee, the method returns false. If the task is added successfully, it returns true.
  • get_tasks(employee_id, project_name) - Retrieves all tasks for a specified project of an employee. If the project does not exist for that employee, the method returns nil. Otherwise, it returns the list of tasks.
Step 1: Basic Class Structure

Let’s start by building the basic structure of our EmployeeRecords class and initializing our data storage.

Ruby
1class EmployeeRecords 2 def initialize 3 @records = {} # Stores employee data as a hash 4 end 5end 6 7# Instantiate the class to ensure it initializes correctly 8records = EmployeeRecords.new

In this initial setup, we define the EmployeeRecords class and create an instance variable @records, which is an empty hash. This hash will store employee records, with each key being an employee ID and each value being another hash that holds the employee's projects.

Step 2: Implementing `add_project` Method

Next, let’s implement the add_project method to add projects to an employee's record.

Ruby
1class EmployeeRecords 2 def initialize 3 @records = {} 4 end 5 6 def add_project(employee_id, project_name) 7 @records[employee_id] ||= {} # Initialize employee record if it doesn't exist 8 if @records[employee_id].key?(project_name) 9 false # Return false if project already exists 10 else 11 @records[employee_id][project_name] = [] # Initialize an empty task list 12 true # Return true to confirm project was added 13 end 14 end 15end 16 17# Example usage and testing 18records = EmployeeRecords.new 19puts records.add_project("E123", "ProjectA") # Output: true 20puts records.add_project("E123", "ProjectA") # Output: false

The add_project method checks if employee_id exists in the @records hash. If not, it initializes a new hash for that employee. It then checks if the project_name already exists for that employee. If it does, the method returns false. Otherwise, it initializes an empty array for the project (to hold tasks) and returns true.

Step 3: Implementing `add_task` Method

Now, we’ll implement the add_task method. This method relies on the availability of an existing project.

Ruby
1class EmployeeRecords 2 def initialize 3 @records = {} 4 end 5 6 def add_project(employee_id, project_name) 7 @records[employee_id] ||= {} 8 if @records[employee_id].key?(project_name) 9 false 10 else 11 @records[employee_id][project_name] = [] 12 true 13 end 14 end 15 16 def add_task(employee_id, project_name, task) 17 # Check if employee and project exist 18 return false unless @records[employee_id] && @records[employee_id][project_name] 19 20 @records[employee_id][project_name] << task # Add task to the project’s task list 21 true # Return true to confirm task was added 22 end 23end 24 25# Example usage and testing 26records = EmployeeRecords.new 27records.add_project("E123", "ProjectA") 28puts records.add_task("E123", "ProjectA", "Task1") # Output: true 29puts records.add_task("E123", "NonExistentProject", "Task3") # Output: false

The add_task method checks whether employee_id and project_name exist in the @records hash. If not, it returns false. Otherwise, it appends the task to the array of tasks for the specified project and returns true.

Step 4: Implementing `get_tasks` Method

Lastly, let’s implement the get_tasks method to retrieve tasks from a specified project for an employee.

Ruby
1class EmployeeRecords 2 def initialize 3 @records = {} 4 end 5 6 def add_project(employee_id, project_name) 7 @records[employee_id] ||= {} 8 if @records[employee_id].key?(project_name) 9 false 10 else 11 @records[employee_id][project_name] = [] 12 true 13 end 14 end 15 16 def add_task(employee_id, project_name, task) 17 return false unless @records[employee_id] && @records[employee_id][project_name] 18 19 @records[employee_id][project_name] << task 20 true 21 end 22 23 def get_tasks(employee_id, project_name) 24 # Return nil if employee or project doesn't exist 25 return nil unless @records[employee_id] && @records[employee_id][project_name] 26 27 @records[employee_id][project_name] # Return the list of tasks 28 end 29end

The get_tasks method checks if employee_id and project_name exist in the @records hash. If either is missing, it returns nil. Otherwise, it returns the array of tasks for the specified project.

Example Usage for Employee Records Methods

Below are examples demonstrating how to use the methods in the EmployeeRecords class:

Ruby
1# Creating a new EmployeeRecords instance 2records = EmployeeRecords.new 3 4# Adding projects for employees 5puts records.add_project("E123", "ProjectA") # Output: true 6puts records.add_project("E123", "ProjectA") # Output: false 7puts records.add_project("E124", "ProjectB") # Output: true 8 9# Adding tasks to projects 10puts records.add_task("E123", "ProjectA", "Task1") # Output: true 11puts records.add_task("E123", "ProjectA", "Task2") # Output: true 12puts records.add_task("E123", "NonExistentProject", "Task3") # Output: false 13puts records.add_task("E125", "ProjectC", "Task1") # Output: false 14 15# Retrieving tasks for a project 16puts records.get_tasks("E123", "ProjectA").inspect # Output: ["Task1", "Task2"] 17puts records.get_tasks("E123", "NonExistentProject").inspect # Output: nil 18puts records.get_tasks("E124", "ProjectB").inspect # Output: [] 19 20# Final state of the records 21puts records.inspect 22# Output: {"E123"=>{"ProjectA"=>["Task1", "Task2"]}, "E124"=>{"ProjectB"=>[]}}

These examples showcase how to manage projects and tasks for employees, including adding projects, assigning tasks, and retrieving task lists effectively.

Final Solution

Here's the complete EmployeeRecords class with all methods implemented.

Ruby
1require 'set' 2 3class EmployeeRecords 4 def initialize 5 @records = {} 6 end 7 8 def add_project(employee_id, project_name) 9 @records[employee_id] ||= {} 10 if @records[employee_id].key?(project_name) 11 false 12 else 13 @records[employee_id][project_name] = [] 14 true 15 end 16 end 17 18 def add_task(employee_id, project_name, task) 19 return false unless @records[employee_id] && @records[employee_id][project_name] 20 21 @records[employee_id][project_name] << task 22 true 23 end 24 25 def get_tasks(employee_id, project_name) 26 return nil unless @records[employee_id] && @records[employee_id][project_name] 27 28 @records[employee_id][project_name] 29 end 30end 31 32# Example usage: 33records = EmployeeRecords.new 34records.add_project("E123", "ProjectA") 35records.add_task("E123", "ProjectA", "Task1") 36puts records.get_tasks("E123", "ProjectA") # Output: ["Task1"] 37puts records.get_tasks("E123", "NonExistentProject") # Output: nil

This final solution combines all previous methods into one cohesive class, allowing us to add projects, add tasks to those projects, and retrieve tasks effectively.

Lesson Summary

In this lesson, we implemented the EmployeeRecords class for managing projects and tasks for employees using nested hashes and arrays in Ruby. We created methods to add projects, add tasks to those projects, and retrieve tasks, enhancing our skills with nested data structures.

Understanding how to work with nested data structures in Ruby allows you to efficiently manage complex data hierarchies, strengthening your programming skills and problem-solving abilities. Practice similar challenges to reinforce what you've learned today.

Keep coding and exploring new challenges!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.