I am trying to learn how to build a very basic MVC structure before jumping on rails and other frameworks. I am working from a .txt file, and I organized a project into four parts: a model, a view, a controller, and a runner. .txt file pattern:line1 -> questionline2 -> answerline3 ->  #blank lineline4 -> questionline5 -> answerline6 -> and so on.runner.rb:require_relative 'view'require_relative 'model'require_relative 'controller'file = 'flashcard_samples.txt'go = Controller.new(file)view.rbrequire_relative 'model'class View  def initialize(question)    @question = question    puts Question:  + question  endendcontroller.rbrequire_relative 'model'class Controller  def initialize(filename)    a = Model.new(filename)    a.play  endendmodel.rbrequire_relative 'view'class Model  attr_reader :data, :questions, :answers, :punchline  def initialize(filename)    @data = []    @questions = []    @answers = []    @score = 0    @file = File.open(filename)  end  def play    welcome_message    parse    startquestions  end  def parse    @file.each_line do |line|      @data << line    end  end  def checkanswer    @goodanswer = false    @oneanswer == @useranswer ? @goodanswer = true && @score += 1: @goodanswer = false && score += 0  end  def displaypunchline    if @goodanswer == true      puts well done    else      puts the good answer was #{@oneanswer}    end  end  def displayscore    puts Your score is now:  + @score.to_s  end  def display_separation    puts --------------------------------------------------------------------------  end  def getuserinput    @useranswer = gets.chomp  end  def crazygameloop    @counter = 1    loop do      break if @counter >= @data.length - 1        @questions = @data.unshift[@counter-1].tr(\n,)        @oneanswer = @data.unshift[@counter].tr(\n,)        @onequestion = View.new(@questions)        @data.unshift[@counter+1]        @counter += 3      getuserinput      checkanswer      displaypunchline      displayscore      display_separation    end  end  def startquestions    crazygameloop  end  def welcome_message    puts welcome in my shitty game    puts |||||||||||||||||||||||||  endendSo far it's working but it's un-DRY, not very readable and probably a bad/incomplete MVC implementation. I'm looking for advice on how I should re-organize my model in order to increase my view responsibilities and optimize my controller in case I would add other features. Any input appreciated.
MVC flash card application
ruby;mvc;quiz
All the parts are here, but your model is taking on too much work. First, let's tackle one of the three hardest things in computer programming: Naming things.Naming Classes in an MVC ApplicationYou have three classes, called aptly Controller, View and Model. I know you are trying to learn the MVC pattern, but an important aspect or learning this pattern is that names should make sense beyond telling you which layer in MVC they go. A convention for naming things is a must.The Rails way of naming things all starts with the model. In your case, your Model class contains data about a quiz, so Quiz is a perfect name for that class. The controller that handles user interaction for Quiz objects should be called QuizesController -- note that Quiz is pluralized, because the controller object handles all quizes, not just one.After that, a QuizView seems like a good name for the view object.Really if you think about it, a quiz is composed of two other things: quiz questions and quiz answers. We need to properly model a quiz before anything else. The Model layer in MVC is the foundation -- the bedrock of your application.Know Your Domain: Properly Modeling Your QuizWe actually have a need for 3 model classes:QuizQuizQuestionQuizAnswerA quiz has one or more questions. An answer requires a question. We need to model this in Ruby.class Quiz  attr_reader :questions  def initialize(questions)    @questions = questions    @grade = 0  end  def answer_question(question, answer_text)    question = questions[question_number - 1]    question.answer answer_text  end  def grade    return @grade if @grade > 0    number_correct = 0    questions.each do |question|      number_correct += 1 if question.answered_correctly?    end    @grade = calculate_grade number_correct  end  def retake    @grade = 0    questions.each do |question|      question.remove_answer    end  end  def quesion_count    questions.count  endprivate  def calculate_grade(number_correct)    number_correct / questions.count  endendA Quiz is a tad more complex, but it just needs a list of QuizQuestions in its constructor. All other operations on the quiz are public methods, some of which are delegated to the QuizQuestion class.class QuizQuestion  attr_reader :text, :answer, :expected_answer  def initialize(text, expected_answer)    @text = text    @expected_answer = expected_answer  end  def answer(answer_text)    @answer = QuizAnswer.new self, answer_text  end  def answered_correctly?    return @answer.nil? ? false : @answer.correct?  end  def remove_answer    @answer = nil  endendThe QuizQuestion class glues the quiz together with the answer, which we will see in a moment. Again, the constructor doesn't do much, except take in the data it needs in order to exist: The question text and the expected answer. The answer method creates the QuizAnswer object and returns it. The logic of retaking a quiz is also delegated to the remove_answer method.class QuizAnswer  attr_reader :question, :text  def initialize(question, text)    @question = question    @text = text  end  def correct?    return question.expected_answer == text  end  def question_text    question.text  endendLastly the QuizAnswer class glues together the quiz question and the user's answer, along with the logic for testing the answer.Now that we've properly modeled our domain, the Quiz, QuizQuestion and QuizAnswer classes become our Domain Models combining data with business logic (taking a quiz). Next, we will take a step up from the foundation of our application to explore the data access layer, or Repository.The Data Access Layer (Repository)The Repository Pattern decouples the data access from your model and controller. What your controller needs is a QuizRepository object that does all the data access.Since you are going with flat file storage, we want to extract this behavior into its own layer.class QuizRepository  def initialize(filename)    @filename = filename  end  def all    return @quizes unless @quizes.nil?    load    @quizes  end  def find(index)    return nil if index < 0 || index > all.count    return all[index]  end  def reload    @quizes = nil  endprivate  def filename    @filename  end  def load    questions = []    index = 0    question_text =     expected_answer =     file = File.open filename    file.each_line do |line|      if index % 2 == 0        question_text = line      else        expected_answer = line        questions << QuizQuestion.new question_text, expected_answer      end      index += 1    end    @quizes << Quiz.new questions  endendThe QuizRepository class needs a filename, and it lazy loads the quiz objects only when you need to get them.Notice that there is no console interaction. This should be encapsulated by the Controller.Handling User Interaction and Displaying InformationKnowledge of the console, and what to display is the realm of the controller and views.class QuizesController  def initialize(quiz_repository)    @quiz_repository = quiz_repository  end  def run    counter = 1    quiz = @quiz_repository.all.first    puts Welcome to the Quiz!    puts --------------------    quiz.questions.each do |question|      puts QuizQuestionView.new question, counter      answer_text = gets.chomp      answer = quiz.answer_question question, answer_text      puts QuizAnswerView.new quiz, answer      counter += 1    end  endendThe main loop is inside the controller, since the controller in MVC responds to user input. The controller needs a quiz repository which is the only argument in its constructor. You'll also notice there are 2 views: QuizQuestionView and QuizAnswerView.class QuizQuestionView  def initialize(question, question_number)    @question = question    @question_number = question_number  end  def to_s    Question \##{@question_number}: #{@question.text}  endendclass QuizAnswerView  def initialize(quiz, answer)    @quiz = quiz    @answer = answer  end  def to_s    text = if answer.correct?             well done           else             the correct answer is #{answer.question_text}           end    text + \nYour score is now #{@quiz.grade}         + \n--------------------------------------------------------------------------  endendAlso notice that there are no calls to gets or puts in the view classes. These classes are responsible for output only. The fact that you are outputting to a console is the responsibility of the Controller, since the Controller knows you are interacting with the user via the console. The to_s method is defined, which returns a string that the Controller then prints to the standard output of the console.Putting All The Layers TogetherNow we actually need to run the program:#!/bin/env rubyquiz_repository = QuizRepository.new /data/quiz.txtcontroller = QuizController.new quiz_repositorycontroller.runThe whole application is started, run and exits in three lines of code.