Search code examples
rubyloopsuser-input

Ruby loops with user input


I am writing a program that takes an employee wages and hours worked, and outputs the yearly salary of each employee, which employee works the most, which employee makes the most, etc.

Here's what I have so far:

puts "Name of your employee"
employee_1 = gets.chomp!

puts "How much does #{employee_1} make per hour?"
employee_1_wage = gets.chomp!

puts "How many hours does #{employee_1} work per day?"
employee_1_hours = gets.chomp!

puts "Do you have another employee you would like to enter? If 
yes, press ENTER"

pause = STDIN.gets

puts "Name of your employee"
employee_2 = gets.chomp!

puts "How much does #{employee_2} make per hour?"
employee_2_wage = gets.chomp!

puts "How many hours does #{employee_2} work per day?"
employee_2_hours = gets.chomp!

puts "Do you have another employee you would like to enter? If 
yes, press ENTER"

pause = STDIN.gets

I want to make this a loop, but I don't even know where to start. And how would a loop automatically assign the first input as employee_1, second as employee_1_wage, and so on? Then for the second loop as employee_2, etc? Because later on I want to reference these in order to calculate the yearly salary for each employee, etc.


Solution

  • This is kind of a weird case. Because, first off, your instinct to loop is a good one. But you're in kind of an awkward situation because you haven't gotten to persisting data yet, which always makes these intro-level Ruby examples kind of hard to learn. At least in my opinion.

    But, this one actually might be kind of fun so I'm going to try and provide you with a solution that I hope will make sense. Disclosure: this will be very long and you may not understand what's going on. I will do my best to try and break it down line-by-line, but you might still be frustrated by some aspects of my answer. Because in reality, there's maybe something simpler out there that you can understand. But if you follow what I've written, play with it, and really try to understand it I think you will be in a really good spot to understand how Ruby conventions work moving forward. Be patient and be open.

    Copy what I've added at the bottom into your text editor and save it. Run the file by running: ruby whatever_you_named_the_file.rb

    Run through it a few times, enter in one employee then enter in the data for multiple employees. See how you can make it break. then look at the code change stuff around to see how it changes the output.

    To address your point of "how would a loop automatically assign the input as employee_1?" The answer is, it won't. A loop has to be agnostic to the variables it assigns. Meaning all of the assignments will simply be to employee, and each "instance" of a loop will only deal with one employee.

    Anyway, here's the full code. Beneath this I'll try to break down each section and add comments throughout:

    Here's the full code which you can put in an editor to mess around with:

    $employees_array = []
    
    def get_employee_data
      puts "Name of your employee"
      employee = gets.chomp!
    
      puts "How much does #{employee} make per hour?"
      employee_wage = gets.chomp!
    
      puts "How many hours does #{employee} work per day?"
      employee_hours = gets.chomp!
    
      add_employee(employee, employee_wage, employee_hours)
    
      puts "Do you have another employee you would like to enter?"
      response = gets.chomp!
    
      if response.downcase == "no"
        display_employee_salaries
      else
        get_employee_data
      end
    end
    
    def add_employee(employee, employee_wage, employee_hours)
      employee_hash = {
        name: employee,
        wage: employee_wage.to_i,
        hours: employee_hours.to_i,
      }
      $employees_array << employee_hash
    end
    
    def display_employee_salaries
      $employees_array.each do |employee|
        puts "Employee #{employee[:name]} makes $#{employee[:wage]} per hour and worked #{employee[:hours]}. That means their annual salary is: $#{ employee_salary(employee) } "
      end
    end
    
    def employee_salary(employee)
      employee[:wage] * employee[:hours] * 261 # 261 is the number of working days per year
    end
    
    get_employee_data
    

    Now, to try and break that down:

    $employees_array = [] # This is a global variable that will simulate a database for us so we can keep track of our employees.
    
    def get_employee_data #the first half of this is largely similar to what you have. It will prompt the user for information.
      puts "Name of your employee"
      employee = gets.chomp!
    
      puts "How much does #{employee} make per hour?"
      employee_wage = gets.chomp!
    
      puts "How many hours does #{employee} work per day?"
      employee_hours = gets.chomp!
    
      # Now we should hand this data off to another method, so that we can continue our loop and get more employees.
      add_employee(employee, employee_wage, employee_hours) # this is a call to a method we define below. It passes all of the information gathered in the first loop so we can add another employee.
    
      puts "Do you have another employee you would like to enter?"
      response = gets.chomp!
    
      # Now we decide if we want to loop again or return the output based on what the user says
      if response.downcase == "no" #if the user says no, that's when we know to break the loop and calculate our salary data.
        display_employee_salaries # this is another method that we've defined below, it is the final step to the loop.
      else
        get_employee_data # if a user says *anything* other than "no", we call this method, which will restart this loop. This might be confusing, that's because this is known as recursion--which can be a difficult concept to grasp. Be patient.
      end
    end
    

    This is the first new method we need to define. What this does is creates a Hash of all of the data we gathered for one employee, it contains a "name", "wage", and "hours" based on what the user gave us in the previous method (above).

    def add_employee(employee, employee_wage, employee_hours)
      employee_hash = {
        name: employee,
        wage: employee_wage.to_i,
        hours: employee_hours.to_i,
      }
    end
    

    Remember the global variable at the top of the file? Now we just add this hash to the global Array.

    $employees_array << employee_hash
    

    The first time this runs the array will be empty, i.e.: []

    The second time this runs the array will have an employee_hash inside: [employee_hash]

    If another employee is entered, this line is executed again so the array will have [employee_hash, employee_hash]

    This can happen for as many employees as you enter. So if you enter an employee 5 times the array will look like: [employee_hash, employee_hash, employee_hash, employee_hash, employee_hash]

    You may be wondering "aren't those all the same? how does it know the difference?" The variable names are the same, the contents of the Hash are different. It doesn't know the difference. But it doesn't have to.


    The second method we define is below. This gets called if the user answers "no" when asked "Do you have another employee you would like to enter?"

    The responsibility of this method is to print out the employee salaries once all the employees have been entered.

    To do this, we iterate (loop) through the global array of employees, and for each entry in that array, we do a puts command to print out our data. This is happening when we call ".each". It's saying, "For each item in this array, call it an "employee", and perform these actions". Once the array runs out of items, the loop ends and the program exits.

    def display_employee_salaries
      $employees_array.each do |employee|
        puts "Employee #{employee[:name]} makes $#{employee[:wage]} per hour and worked #{employee[:hours]}. That means their annual salary is: $#{ employee_salary(employee) } "
      end
    end
    

    Couple things to note: If you're unfamiliar with hash lookups- this is an example: employee[:name] what this is doing, is it's looking for a "name" key in a hash called "employee". If there is a "name" key, then it will return to us the value. So if "employee" is a hash that looks like this:

    { name: "ActiveModel_Dirty", wage: "40", hours: "8" }

    then employee[:name] will return "ActiveModel_Dirty", employee[:wage] will return "40", and so forth.

    You may be wondering: "Hey, we called that hash employee_hash earlier, why are we suddenly referring to it as "employee"? Good question. after the .each do below you'll see |employee|. "employee" here can be whatever you want. it is how we refer to the current item we're iterating over only while inside this loop, it has no bearing on anything other than a reference point.

    Lastly, you will notice a call to employee_salary towards the end of the puts command. This is calling another method that we define below.


    The final method is used to do math——calculate an annual salary based on the information that the user gave us about an employee. It recieves an instance of an employee as an argument (that's what the (employee)) is.

    It will calculate the wage, multiplied by the employee hours, multiplied by the working days in a year. Once it performs this calculation Ruby by default will return whatever it came up with. Which we then print to the console in the 'puts' statement above.

    This method returns a number, that number is the value for the annual salary

    def employee_salary(employee)
      employee[:wage] * employee[:hours] * 261 # 261 is the number of working days per year
    end
    

    I really hope that helps you out and I hope it's not overwhelming. No one says you need to know how all of it works right now. Process as much as you can and then come back to it if you need to.