File generated from /Users/batate/mastery/lib/mastery/core/quiz.ex by COVER 2019-03-16 at 12:03:51

****************************************************************************

        |  
        |  defmodule Mastery.Core.Quiz do
        |    alias Mastery.Core.{Template, Question, Response}
        |  
     7..|    defstruct title: nil,
        |              mastery: 3,
        |              templates: %{ },
        |              used: [ ],
        |              current_question: nil,
        |              last_response: nil, 
        |              record: %{ },
        |              mastered: [ ]
        |  
        |    def new(fields) do
        |      struct!(__MODULE__, fields)
        |    end
        |  
        |  
        |  
        |    def add_template(quiz, fields) do
        |      template = Template.new(fields)
        |  
        |      templates =
        |        update_in(
        |          quiz.templates,
        |          [template.category],
        |          &add_to_list_or_nil(&1, template)
        |        )
        |  
        |      %__MODULE__{quiz | templates: templates}
        |    end
        |  
        |    defp add_to_list_or_nil(nil, template), do: [template]
        |    defp add_to_list_or_nil(templates, template), do: [template | templates]
        |  
        |  
        |  
        |    def select_question(%__MODULE__{templates: t}) when map_size(t) == 0, do: nil
        |    def select_question(quiz) do
        |      quiz
        |      |> pick_current_question
        |      |> move_template(:used)
        |      |> reset_template_cycle
        |    end
        |  
        |    
        |  
        |    defp pick_current_question(quiz) do
        |      Map.put(
        |        quiz,
        |        :current_question,
        |        select_a_random_question(quiz)
        |      )
        |    end
        |  
        |    defp select_a_random_question(quiz) do
        |      quiz.templates
        |      |> Enum.random
        |      |> elem(1)
        |      |> Enum.random
        |      |> Question.new
        |    end
        |  
        |  
        |  
        |    defp move_template(quiz, field) do
        |      quiz
        |      |> remove_template_from_category
        |      |> add_template_to_field(field)
        |    end
        |    
        |    defp template(quiz), do: quiz.current_question.template
        |  
        |  
        |  
        |    defp remove_template_from_category(quiz) do
        |      template = template(quiz)
        |      new_category_templates =
        |        quiz.templates
        |        |> Map.fetch!(template.category)
        |        |> List.delete(template)
        |  
        |      new_templates =
        |        if new_category_templates == [ ] do
        |          Map.delete(quiz.templates, template.category)
        |        else
        |          Map.put(quiz.templates, template.category, new_category_templates)
        |        end
        |  
        |      Map.put(quiz, :templates, new_templates)
        |    end
        |  
        |  
        |  
        |    defp add_template_to_field(quiz, field) do
        |      template = template(quiz)
        |      list = Map.get(quiz, field)
        |  
        |      Map.put(quiz, field, [template | list])
        |    end
        |  
        |  
        |  
        |    defp reset_template_cycle(%{templates: templates, used: used} = quiz)
        |    when map_size(templates) == 0 do
        |      %__MODULE__{
        |        quiz |
        |        templates: Enum.group_by(used, fn template -> template.category end),
        |        used: [ ]
        |      }
        |    end
        |    defp reset_template_cycle(quiz), do: quiz
        |  
        |  
        |  
        |    def answer_question(quiz, %Response{correct: true}=response) do
        |      new_quiz = 
        |        quiz
        |        |> inc_record
        |        |> save_response(response)
        |      maybe_advance(new_quiz, mastered?(new_quiz))
        |    end
        |    def answer_question(quiz, %Response{correct: false}=response) do
        |      quiz
        |      |> reset_record
        |      |> save_response(response)
        |    end
        |    
        |    def save_response(quiz, response) do
        |      Map.put(quiz, :last_response, response)
        |    end
        |  
        |    def mastered?(quiz) do
        |      score = Map.get(quiz.record, template(quiz).name, 0)
        |      score == quiz.mastery
        |    end
        |  
        |  
        |  
        |    defp inc_record(%{current_question: question}=quiz) do
        |      new_record = Map.update(quiz.record, question.template.name, 1, &(&1 + 1))
        |      Map.put(quiz, :record, new_record)
        |    end
        |  
        |  
        |  
        |    defp maybe_advance(quiz, false = _mastered), do: quiz
        |    defp maybe_advance(quiz, true = _mastered), do: advance(quiz)
        |  
        |    def advance(quiz) do
        |      quiz
        |      |> move_template(:mastered)
        |      |> reset_record
        |      |> reset_used
        |    end
        |  
        |  
        |  
        |    defp reset_record(%{current_question: question} = quiz) do
        |      Map.put(
        |        quiz,
        |        :record,
        |        Map.delete(quiz.record, question.template.name)
        |      )
        |    end
        |  
        |    defp reset_used(%{current_question: question} = quiz) do
        |      Map.put(
        |        quiz,
        |        :used,
        |        List.delete(quiz.used, question.template)
        |      )
        |    end
        |  end
        |