Простые тесты на ruby для web

в 10:05, , рубрики: ruby, sinatra, метки: ,

Для изучения ruby был выбран учебный проект в котором простая задача, написания тестов для web. Ввиду отсутствия знаний и опыта было решено использовать упрощенный фреймворк sinatra. В результате, в моем решении этой задачи всего два файла. Первый это mutaAlim.json, в котором у нас база данных в json формате.

Рассмотрим структуру этого файла на примере нескольких вопросов:

[
    {
        "id" : 1,
        "question" : "Ассаламу Алейкум!",
        "answers" : ["Ваалейкум Ассалам", "Привет", "Здорово", "Хай"]
    },
    { 
        "id" : 2,
        "question" : "Как дела?",
        "answers" : ["альхамдуЛилягь", "Плохо", "хорошо", "шикарно"]
    }, …..(другие вопросы в таком же порядке) 
]

У нас таким образом в json массив из хеш элементов.
Ответы в массиве по ключу answers, в котором первый вариант ответа является правильным.

Второй файл mutaAlim.rb в котором код приложения.

Рассмотрим его поближе. Первые строчки подключают гемы sinatra и json:

require 'sinatra'
require 'json'

Для перехода на страницу приветствия следующий код

get '/' do 
    erb :index
end

При переходе по адресу у нас откроется страничка, которая описана в том же файле:

@@index
<!DOCTYPE html>
<html>
    <head>
        <title>Главная</title>
    </head>
    <body>
        <h1> Ассаламу гIалайкум ва раhматуЛлаhи ва баракатуhу!</h1>    
        <h1> Мира вам, Милости и Благославления Всевышнего!</h1>    
        <h1> Сайт для тестирования базовых знаний</h1>    
        <h2>Описание </h2>
        <div>
            <p>    Этот сайт предназначен для тех кто хочет проверить свои знания. </p> 
        </div>
        <input  value="Начать тест" name="test_begin" onclick="location.href='/test'" type="button">
    </body>
</html>

Простая страничка с кнопкой для перехода на страничку тестов. Далее в коде у нас переменные необходимые для работы приложения:

#хеш с тестами
@@test_hash
#количество тестов
@@kol_testov = 13
#массив из случайно выбранных неповторяющихся вопросов
@@mas_test_number = Array.new(@@kol_testov)
#массив с ответами, -1 если не ответили на вопрос иначе номер ответа
@@mas_test_answer

#считываем файл с тестами 
test_file = File.open('mutaAlim.json',"rb")
@@test_hash = JSON.parse(test_file.read)
test_file.close

#для таблицы результатов
@@not_answer = "Вы не дали ответ"
#количество ответов
@@answers
#количество правильных ответов
@@ball
#процент правильных ответов
@@procent_tru_answers 
#массив в котором хранится

Как вы заметили пришлось все переменные объявить в классе, иначе на вывод в erb были ошибки, которые я не смог понять и исправить. Далее основной элемент приложения это код странички тестов:

# страничка тестов
get '/test' do 
    if params[:var] == nil
        @@mas_test_answer = Array.new(@@kol_testov) { |i| -1}
        # заносим случайные вопросы в массив @@mas_test_number
        @@mas_test_number[0] = Random.rand(@@test_hash.length)
        @@mas_test_number.each_index do |i| 
            begin
                flag = true
                buf = Random.rand(@@test_hash.length)
                0..i.times do |j|
                    if @@mas_test_number[j]==buf
                        flag = false
                    end
                end
                if flag
                    @@mas_test_number[i] = buf
                end
            end until flag==true
        end
        @@test_number = 0;
        
        # заносим случайные варианты ответов в массив @@mas_random_variants
        @@mas_random_variants =  Array.new(@@kol_testov)
        @@mas_random_variants.each_index do |i| 
            @@mas_random_variants[i] = Array.new(@@test_hash[@@mas_test_number[i]]["answers"].size)
        end
        @@mas_random_variants.each_index do |i|
            @@mas_random_variants[i][0] = Random.rand(@@test_hash[@@mas_test_number[i]]["answers"].size)
            @@mas_random_variants[i].each_index do |j|
                begin
                    flag = true
                    buf = Random.rand(@@test_hash[@@mas_test_number[i]]["answers"].size)
                    0..j.times do |k|
                        if @@mas_random_variants[i][k]==buf
                            flag = false
                        end
                    end
                    if flag
                        @@mas_random_variants[i][j] = buf
                    end
                end until flag==true
            end
        end
    else
        #сохраняем выбранный вариант ответа в массив @@mas_test_answer
        @@mas_test_answer[@@test_number] = params[:var].to_i
        #если возможно выдаем след вопрос
        if @@test_number != @@kol_testov - 1
            @@test_number += 1
        end
    end
    erb :test
end

По условию params[:var] == nil мы определяем что пользователь впервые на страничке и «готовим» все необходимое(случайно выбираем тесты из базы, случайно «перемешиваем» варианты ответов и создаем массив для хранения ответов), иначе записываем выбранный пользователем ответ в массив. Весь функционал приложения построен на get запросах, а много путаницы в следствии того, что писалось оно в режиме «лишь бы работало». К примеру если пользователь переходит по ссылке http://localhost:4567/test?var=0 то в массиве ответов на текущий вопрос будет установлено значение 0.

Рассмотрим код странички тестов

@@test
<!DOCTYPE html>
<html>
    <head>
        <title>Тесты</title>
    </head>
    <body>
        <div>
            <h2> Вопрос №<%= @@test_number +1 %> <h2>
            <h3>
                <%= @@test_hash[@@mas_test_number[@@test_number]]["question"] %>
            </h3>    
        </div>
        <p> 
            <form method="get" action="/test">
                <% @@test_hash[@@mas_test_number[@@test_number]]["answers"].each_index do |i| %>
                    <input type="radio" name="var" value="<%= @@mas_random_variants[@@test_number][i] %>">
                        <%= @@test_hash[@@mas_test_number[@@test_number]]["answers"][@@mas_random_variants[@@test_number][i]] %>
                <% end %>
                <input type="submit" value="Ответить"/>
            </form>
        </p>
        
        <div>
            <input type="button" name="next_question" value="Предыдущий вопрос" onclick="location.href='/test/pred'">
            <% @@mas_test_number.each_index do |i| %>
                <a href='/test/question/<%= i + 1 %>'> № <%= i + 1 %> </a>
            <% end %>
            <input type="button" name="pred_question" value="Следующий вопрос" onclick="location.href='/test/next'"> 
 
 
        </div>
        
        <input type="button" name="result" value="Завершить тестирование" onclick="location.href='/test/result'">
    </body>
</html>

Как вы заметили вставка кода на страничку проиcходит при помощи erb следующим образом <%= #код с выводом данных %> и <% код без вывода данных %> . На самой страничке вопрос, варианты ответов(radiobutton), ссылки на все вопросы. кнопки навигации по тестам и кнопка завершения тестирования, которая направляет пользователя на страничку результатов теста.

Работа кнопок навигации и ссылок на вопросы:

# ссылки на каждый вопрос
get '/test/question/:id' do
    @@test_number = params[:id].to_i - 1
    erb :test
end

# следующий вопрос
get '/test/next' do
    if @@test_number != @@kol_testov - 1
            @@test_number += 1
    end
    erb :test
end

# предыдущий вопрос
get '/test/pred' do
    if @@test_number != 0
            @@test_number -= 1
    end
    erb :test
end
Осталось разобрать код странички результатов теста которая подсчитывает итоги

# страничка результатов
get '/test/result' do
    @@ball = 0
    @@answers = 0
    #подсчет правильных ответов 
    @@mas_test_answer.each do |i| 
        if i == 0 
            @@ball += 1 
        end
        if i != -1 
            @@answers += 1 
        end
    end
    @@procent_tru_answers = (100/@@kol_testov) * @@ball
    
    erb :result
end

И код на html + erb

@@result
<!DOCTYPE html>
<html>
    <head>
        <title>Результат</title>
    </head>
    <body>
        <h1> Результаты вашего теста </h1>    
        
        <div>
            <table  cellspacing="2" border="1" cellpadding="5">
                <tr> <td> № </td> <td> Вопрос </td> <td> Ваш ответ </td> <td> Правильный ответ </td> <tr>
                <% @@mas_test_answer.each_index do |i| %>
                    <tr> 
                        <td> <%= i+1 %> </td> 
                        <td> <%= @@test_hash[@@mas_test_number[i]]["question"] %> </td> 
                        <td> <%=     if (@@mas_test_answer[i] == -1)  
                                        @@not_answer 
                                    else @@test_hash[@@mas_test_number[i]]["answers"][@@mas_test_answer[i]] end %> </td>
                        <td> <%= @@test_hash[@@mas_test_number[i]]["answers"][0] %> </td> 
                    <tr>
                <% end %>
            </table>
        </div>
        <div>
            <h3> Количество тестов =                  <%= @@kol_testov %> </h3>
            <h3> Количество ответов =      <%= @@answers %> </h3>
            <h3> Количество правильных ответов =      <%= @@ball %> </h3>
            <h3> Процент правильных ответов =          <%= @@procent_tru_answers %> %</h3>
        <div>
        <div>
            <p>    Этот сайт предназначен для тех кто хочет проверить свои знания.
            </p> 
        </div>
        <input  value="Пройти снова" name="test_begin" onclick="location.href='/test'" type="button">
    </body>
</html>

Я понимаю что данное приложение легче написать с нуля и правильно, нежели понять или сопровождать это. Язык ruby я начал изучать на этом приложении ровно как движок sinatra, язык разметки erb и формат json, поэтому прошу строго не судить за то, что и как использовал.
В дальнейшем планируется переход от sinatra к ror, от json к полноценной базе данных, от erb к haml, от однотипных вопросов(radiobutton) к вопросам 5-6 типов, от тестов к игре и плюс дизайн с версткой.

Приложение в рабочем виде можно увидеть на сайте.
Репозиторий на гитхабе.

Автор: Kaspsoft

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js