feat: implement persistence strategy for student list management with JSON, TXT, and YAML support

lab4
Artem-Darius Weber 2 months ago
parent 828ab3a5cb
commit 7896de3c3e

@ -0,0 +1,9 @@
module PersistenceStrategy
def load(filename)
raise NotImplementedError, "Метод load должен быть реализован в стратегии"
end
def save(filename, students)
raise NotImplementedError, "Метод save должен быть реализован в стратегии"
end
end

@ -0,0 +1,92 @@
require_relative '../student'
require_relative '../student_short'
require_relative '../data_list_student_short'
require_relative '../data_table'
class StudentsList
attr_reader :students
def initialize(filename, persistence_strategy)
@filename = filename
@persistence_strategy = persistence_strategy
@students = []
end
# Загрузка студентов через выбранную стратегию.
def load
@students = @persistence_strategy.load(@filename)
self
end
# Сохранение студентов через выбранную стратегию.
def save
@persistence_strategy.save(@filename, @students)
self
end
# Получить объект Student по ID.
def get_student_by_id(id)
@students.find { |s| s.id.to_s == id.to_s }
end
# Получить список из k студентов (страница n) в виде объекта DataList.
def get_k_n_student_short_list(k, n, data_list = nil)
start_index = (n - 1) * k
sorted_students = @students.sort_by { |s| s.surname_initials }
selected_students = sorted_students[start_index, k] || []
short_objects = selected_students.map { |s| StudentShort.from_student(s) }
if data_list && data_list.is_a?(DataList)
if data_list.respond_to?(:items=)
data_list.items = short_objects
else
data_list = DataListStudentShort.new(short_objects)
end
data_list
else
DataListStudentShort.new(short_objects)
end
end
# Сортировка студентов по фамилии и инициалам.
def sort_students!
@students.sort_by! { |s| s.surname_initials }
end
# Добавление студента с автоматическим присвоением нового ID.
def add_student(student)
new_id = if @students.empty?
1
else
max_id = @students.map { |s| s.id.to_i }.max
max_id + 1
end
student.id = new_id.to_s
@students << student
student
end
# Обновление студента по ID.
def update_student_by_id(id, new_student)
index = @students.find_index { |s| s.id.to_s == id.to_s }
if index
new_student.id = @students[index].id
@students[index] = new_student
true
else
false
end
end
# Удаление студента по ID.
def delete_student_by_id(id)
initial_count = @students.size
@students.reject! { |s| s.id.to_s == id.to_s }
initial_count != @students.size
end
# Получить количество студентов.
def get_student_short_count
@students.size
end
end

@ -1,34 +1,33 @@
require 'json' require 'json'
require 'date' require 'date'
require_relative 'students_list_base'
require_relative '../student' require_relative '../student'
require_relative 'persistence_strategy'
class StudentsListJSON < StudentsListBase class JSONPersistenceStrategy
def load_from_file include PersistenceStrategy
if File.exist?(@filename)
file_content = File.read(@filename) def load(filename)
if File.exist?(filename)
file_content = File.read(filename)
begin begin
data = JSON.parse(file_content) data = JSON.parse(file_content)
@students = data.map { |student_hash| hash_to_student(student_hash) } data.map { |student_hash| hash_to_student(student_hash) }
rescue JSON::ParserError => e rescue JSON::ParserError => e
warn "Ошибка парсинга JSON: #{e.message}" warn "Ошибка парсинга JSON: #{e.message}"
@students = [] []
end end
else else
@students = [] []
end end
self
end end
def save_to_file def save(filename, students)
data = @students.map { |student| student_to_hash(student) } data = students.map { |student| student_to_hash(student) }
File.open(@filename, 'w') do |file| File.open(filename, 'w') do |file|
file.write(JSON.pretty_generate(data)) file.write(JSON.pretty_generate(data))
end end
self
rescue IOError => e rescue IOError => e
warn "Ошибка при записи в файл: #{e.message}" warn "Ошибка при записи в файл: #{e.message}"
self
end end
private private

@ -1,11 +1,13 @@
require_relative 'students_list_base'
require_relative '../student' require_relative '../student'
require_relative 'persistence_strategy'
class StudentsListTXT < StudentsListBase class TXTPersistenceStrategy
def load_from_file include PersistenceStrategy
if File.exist?(@filename)
File.open(@filename, 'r') do |file| def load(filename)
@students = file.each_line.map do |line| if File.exist?(filename)
File.open(filename, 'r') do |file|
file.each_line.map do |line|
line.strip! line.strip!
next if line.empty? next if line.empty?
begin begin
@ -17,17 +19,15 @@ class StudentsListTXT < StudentsListBase
end.compact end.compact
end end
else else
@students = [] []
end end
self
end end
def save_to_file def save(filename, students)
File.open(@filename, 'w') do |file| File.open(filename, 'w') do |file|
@students.each do |student| students.each do |student|
file.puts student.to_s file.puts student.to_s
end end
end end
self
end end
end end

@ -1,34 +1,32 @@
# students_list_yaml.rb
require 'yaml' require 'yaml'
require 'date' require 'date'
require_relative 'students_list_base'
require_relative '../student' require_relative '../student'
require_relative 'persistence_strategy'
class StudentsListYAML < StudentsListBase class YAMLPersistenceStrategy
def load_from_file include PersistenceStrategy
if File.exist?(@filename)
def load(filename)
if File.exist?(filename)
begin begin
data = YAML.load_file(@filename) data = YAML.load_file(filename)
@students = data.map { |student_hash| hash_to_student(student_hash) } data.map { |student_hash| hash_to_student(student_hash) }
rescue StandardError => e rescue StandardError => e
warn "Ошибка при загрузке YAML: #{e.message}" warn "Ошибка при загрузке YAML: #{e.message}"
@students = [] []
end end
else else
@students = [] []
end end
self
end end
def save_to_file def save(filename, students)
data = @students.map { |student| student_to_hash(student) } data = students.map { |student| student_to_hash(student) }
File.open(@filename, 'w') do |file| File.open(filename, 'w') do |file|
file.write(data.to_yaml) file.write(data.to_yaml)
end end
self
rescue IOError => e rescue IOError => e
warn "Ошибка при записи в YAML: #{e.message}" warn "Ошибка при записи в YAML: #{e.message}"
self
end end
private private

@ -1,6 +1,7 @@
require 'minitest/autorun' require 'minitest/autorun'
require 'json' require 'json'
require 'date' require 'date'
require_relative '../providers/students_list'
require_relative '../providers/students_list_json' require_relative '../providers/students_list_json'
require_relative '../student' require_relative '../student'
require_relative '../student_short' require_relative '../student_short'
@ -11,7 +12,7 @@ class TestStudentsListJSON < Minitest::Test
def setup def setup
# Удаляем временный файл перед каждым тестом, если он существует # Удаляем временный файл перед каждым тестом, если он существует
File.delete(TEMP_FILE) if File.exist?(TEMP_FILE) File.delete(TEMP_FILE) if File.exist?(TEMP_FILE)
@students_list = StudentsListJSON.new(TEMP_FILE) @students_list = StudentsList.new(TEMP_FILE, JSONPersistenceStrategy.new)
# Создаём несколько объектов Student для тестирования # Создаём несколько объектов Student для тестирования
@student1 = Student.new( @student1 = Student.new(
@ -61,11 +62,11 @@ class TestStudentsListJSON < Minitest::Test
def test_save_and_load_from_file def test_save_and_load_from_file
# Сохраняем текущий список в файл # Сохраняем текущий список в файл
@students_list.save_to_file @students_list.save
# Создаём новый объект, который загрузит данные из файла # Создаём новый объект, который загрузит данные из файла
new_list = StudentsListJSON.new(TEMP_FILE) new_list = StudentsList.new(TEMP_FILE, JSONPersistenceStrategy.new)
new_list.load_from_file new_list.load
# Проверяем, что количество студентов совпадает # Проверяем, что количество студентов совпадает
assert_equal @students_list.get_student_short_count, new_list.get_student_short_count assert_equal @students_list.get_student_short_count, new_list.get_student_short_count

@ -1,11 +1,13 @@
require 'date' require 'date'
require_relative '../providers/students_list'
require_relative '../providers/students_list_txt' require_relative '../providers/students_list_txt'
require_relative '../student' require_relative '../student'
require_relative '../student_short' require_relative '../student_short'
def run_tests def run_tests
filename = 'students_test.txt' filename = 'students_test.txt'
students_list = StudentsListTXT.new(filename) # Инициализируем список студентов с TXT-стратегией
students_list = StudentsList.new(filename, TXTPersistenceStrategy.new)
# 1. Добавление студентов. Передаём временный ID '0', который будет заменён. # 1. Добавление студентов. Передаём временный ID '0', который будет заменён.
student1 = Student.new( student1 = Student.new(
@ -23,8 +25,8 @@ def run_tests
puts "Добавленные студенты:\n#{students_list.students.map(&:to_s).join("\n")}" puts "Добавленные студенты:\n#{students_list.students.map(&:to_s).join("\n")}"
# 2. Сохранение и загрузка из файла # 2. Сохранение и загрузка из файла
students_list.save_to_file students_list.save
students_list.load_from_file students_list.load
puts "\nЗагруженные студенты из файла:\n#{students_list.students.map(&:to_s).join("\n")}" puts "\nЗагруженные студенты из файла:\n#{students_list.students.map(&:to_s).join("\n")}"

@ -1,6 +1,7 @@
require 'minitest/autorun' require 'minitest/autorun'
require 'yaml' require 'yaml'
require 'date' require 'date'
require_relative '../providers/students_list'
require_relative '../providers/students_list_yaml' require_relative '../providers/students_list_yaml'
require_relative '../student' require_relative '../student'
require_relative '../student_short' require_relative '../student_short'
@ -11,7 +12,7 @@ class TestStudentsListYAML < Minitest::Test
def setup def setup
# Удаляем временный файл перед каждым тестом, если он существует # Удаляем временный файл перед каждым тестом, если он существует
File.delete(TEMP_FILE) if File.exist?(TEMP_FILE) File.delete(TEMP_FILE) if File.exist?(TEMP_FILE)
@students_list = StudentsListYAML.new(TEMP_FILE) @students_list = StudentsList.new(TEMP_FILE, YAMLPersistenceStrategy.new)
# Создаём несколько объектов Student для тестирования # Создаём несколько объектов Student для тестирования
@student1 = Student.new( @student1 = Student.new(
@ -61,11 +62,11 @@ class TestStudentsListYAML < Minitest::Test
def test_save_and_load_from_file def test_save_and_load_from_file
# Сохраняем список в YAML-файл # Сохраняем список в YAML-файл
@students_list.save_to_file @students_list.save
# Создаём новый объект, который загрузит данные из файла # Создаём новый объект, который загрузит данные из файла
new_list = StudentsListYAML.new(TEMP_FILE) new_list = StudentsList.new(TEMP_FILE, YAMLPersistenceStrategy.new)
new_list.load_from_file new_list.load
# Проверяем, что количество студентов совпадает # Проверяем, что количество студентов совпадает
assert_equal @students_list.get_student_short_count, new_list.get_student_short_count assert_equal @students_list.get_student_short_count, new_list.get_student_short_count

Loading…
Cancel
Save