1

I am writing a flash card CLI game.

class Intro
  def self.display
    while 1
      puts "Welcome player! Choose one of the following!"
      puts "1. Create a new flash card?"
      puts "2. View all flash cards?"
      puts "3. Edit a flashcard?"
      puts "4. Delete a flashcard?"
      puts "5. View score and answers?"
      input = gets.chomp.to_i
      if (1..5).include? input
        self.select input
        break
      else
        puts "Invalid option." 
      end
    end
  end
  def self.select number
    @number = number
    puts "#{@number} selected!"
    puts "#{@back}"
  end
end
Intro.display

It seems redundant to consistently use if/else for many answers unless that's the only way.

How would I write cleaner code that compares the input of the user and the call to a class? If there is another method to do so, I'd appreciate it.

4
  • This may be better suited as a question on SE code review. Also as a side note, use two-spaces for indentation in Ruby. Commented May 23, 2017 at 22:26
  • Welcome to Stack Overflow. We don't care what your experience level is, we want well researched and concise questions. Please read "How to Ask" and "minimal reproducible example" and their linked pages for more information. Idiomatic Ruby code can best be learned by reading the code for various popular Ruby projects on github. Rails is actually full of Ruby's deeper magic so I recommend spending a lot of time with Ruby alone first. Sinatra and Padrino are a great starting point, then step into Rails. Commented May 23, 2017 at 22:40
  • @theTinMan That's a pretty general answer when it comes to experience levels, can be understandable to a degree as well. Though, I post my experience level to make sure people know how to approach giving answers. This site and so are the visitors make up various experience levels, it is a good thing if you can understand how to communicate with people properly rather than being on separate pages. Commented May 23, 2017 at 22:52
  • It's important to understand that SO isn't an "answer my question" site. Instead it's a "here's a specific programming problem and how to fix it site". As such, the question asked has to have certain information in it that will help future searchers looking to solve the same problem. It has to be written clearly and concisely and address one, or at them most two, closely related questions. "How do I improve my code" is wide open, and very open to opinion, and, as such, isn't a good fit for SO. Code Review might be a better choice, determined by you reading their question requirements. Commented May 23, 2017 at 23:27

2 Answers 2

1

Cleanliness is somewhat subjective, but this might be something you're looking for.

class Intro

  def self.display
    input = nil
    until (1..5).include? input
      puts "Welcome player! Choose one of the following!"
      puts "1. Create a new flash card?"
      puts "2. View all flash cards?"
      puts "3. Edit a flashcard?"
      puts "4. Delete a flashcard?"
      puts "5. View score and answers?"
      input = gets.chomp.to_i
      puts "Invalid option." unless (1..5).include? input
    end
    self.select(input)
  end

  def self.select(number)
    @number = number
    puts "#{@number} selected!"
    puts "#{@back}" # @back is uninitialized
  end
end

Intro.display

Edit:

If you want to be able to have multiple answers then one way to go about it would be to create instances of your Intro class each with a instance variable containing the answer.

So, instead of calling display on the class itself you would call it on an instance of the class.

The class Intro would have an initialize function that is automatically called whenever a new instance of the Intro class is instantiated.

class Intro

  def initialize(answer)
    @answer = answer
  end

  #[...]

This would mean that by calling

new_game = Intro.new(7)

you are creating an instance of the Intro class that has its instance variable @answer set to seven and you are storing that instance in the variable new_game. And from there you can call instance methods on new_game.

Sign up to request clarification or add additional context in comments.

3 Comments

That is better than what I currently have. But what about a better way to call on class.methods when it comes to multiple answers?
Well, in that case you'd want to create instances of your class Intro each containing a different answer as a instance variable.
Don't use "edit" or "update" tags when you change things. Instead, incorporate the change as if it'd been there initially. We can see what changed and when if we need to. meta.stackoverflow.com/a/255685/128421
1

Your question is very broad because there are many ways to write it. As a first pass I'd do:

class Intro
  CHOICES = {
    1 => 'Create a new flash card',
    2 => 'View all flash cards',
    3 => 'Edit a flashcard',
    4 => 'Delete a flashcard',
    5 => 'View score and answers',
  }

  def self.display
    loop do
      puts "Welcome player! Choose one of the following!"
      CHOICES.each do |h|
        puts '%d. %s?' % h
      end

      input = gets.to_i

      return input if CHOICES[input]
      puts 'Invalid option.' 
    end
  end

  def self.select number
    puts "#{number} selected!"
  end
end

choice = Intro.display
Intro.select(choice)

Your choice of gets.chomp.to_i is better written as gets.to_i.

(1..5).include? input is fine but forces you to edit your code if you add or remove options. Instead, compute the maximum value based on the list of choices, so you only have to add or delete them and everything adjusts.

self.select input probably shouldn't be a separate method. It probably shouldn't be called by display either, but that's mostly a programmer-choice.

Using a class for such a simple piece of code is overkill. It could be simplified to:

CHOICES = {
  1 => 'Create a new flash card',
  2 => 'View all flash cards',
  3 => 'Edit a flashcard',
  4 => 'Delete a flashcard',
  5 => 'View score and answers',
}

def display
  loop do
    puts "Welcome player! Choose one of the following!"
    CHOICES.each do |h|
      puts '%d. %s?' % h
    end

    input = gets.to_i

    return input if CHOICES[input]
    puts 'Invalid option.' 
  end
end

def select number
  puts "#{number} selected!"
end

choice = display
select(choice)

Using a class to encapsulate the methods, without using it to have instances of the class gets old very quickly. Ruby allows us to write code using classes, or without. Think of what is concise and simple to understand as you write. Sometimes we start simply and have to back up a little and take another run at it because we decide using classes makes more sense. I usually let the complexity of the program determine that.

Using a series of if/elsif/then statements is sometimes useful. We often can use case/when to clean the code up even more than using if chains:

CHOICES = [
  'Create a new flash card',
  'View all flash cards',
  'Edit a flashcard',
  'Delete a flashcard',
  'View score and answers',
]

def display
  loop do
    puts "Welcome player! Choose one of the following!"
    CHOICES.each.with_index(1) do |s, i|
      puts '%d. %s?' % [i, s]
    end

    input = gets.to_i

    case input
    when 1 .. CHOICES.size
      return input
    else
      puts 'Invalid option.' 
    end
  end
end

Replace the previous methods with these and experiment.


...how ('%d. %s?' % [i, s]) [works]

Notice that '%d. %s?' is a String. That'd make % a method of String.

See String#%

2 Comments

Oh. That. Heh. I was going to remove the instance variable. Removed.
Case is definitely great. I appreciate the response. This actually makes the sheet more fluid. Is there anyway you could possibly iterate on how ('%d. %s?' % [i, s]) I tried googling and didn't find any explanations. I googled each.with_index and thats a pretty handy method, thanks for that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.