feat: enhance Student and Person classes with contact information validation

lab2
Artem-Darius Weber 1 month ago
parent cbd9231784
commit a9b27d76c5

@ -12,9 +12,12 @@ begin
name: 'Артем-Дариус', name: 'Артем-Дариус',
patronymic: 'Вебер', patronymic: 'Вебер',
id: 1, id: 1,
git: 'https://github.com/space-creator' git: 'https://github.com/space-creator',
# Передаём контакты сразу, чтобы не было ошибок при инициализации
phone: '+79891242223'
) )
# Можно обновить контакты при необходимости
student1.set_contacts( student1.set_contacts(
phone: '+79891242223', phone: '+79891242223',
telegram: '@alstroemeria22', telegram: '@alstroemeria22',
@ -26,12 +29,16 @@ begin
puts "Git Info: #{student1.git_info}" puts "Git Info: #{student1.git_info}"
puts "Contact Info: #{student1.contact_info}" puts "Contact Info: #{student1.contact_info}"
# Исправляем создание student2: добавляем git и контакт
student2 = Student.new( student2 = Student.new(
surname: 'Норакет', surname: 'Норакет',
name: 'Норакет', name: 'Норакет',
patronymic: 'Фамилия' patronymic: 'Фамилия',
git: 'https://github.com/noraket',
phone: '+70000000001'
) )
# Можно обновить контакты, если нужно другой номер
student2.set_contacts( student2.set_contacts(
phone: '+70000000000' phone: '+70000000000'
) )
@ -40,7 +47,6 @@ begin
puts '-' * 40 puts '-' * 40
puts student2 puts student2
student_short_from_student = StudentShort.new(student1) student_short_from_student = StudentShort.new(student1)
puts "StudentShort from Student object:" puts "StudentShort from Student object:"
puts "ID: #{student_short_from_student.id}" puts "ID: #{student_short_from_student.id}"

@ -1,23 +1,31 @@
class Person class Person
attr_accessor :id, :git attr_accessor :id, :git, :name
def initialize(args = {}) def initialize(args = {})
@id = args[:id] || nil @id = args[:id]
@git = args[:git] @git = args[:git]
@name = args[:name]
raise ArgumentError, "Git link is required" unless git_present? raise ArgumentError, "ID должен быть числом" if @id && !@id.is_a?(Integer)
raise ArgumentError, "At least one contact (phone, telegram, or email) is required" unless contact_present?
raise ArgumentError, "Требуется ссылка на GitHub" unless git_present?
raise ArgumentError, "Некорректная ссылка на GitHub: #{@git}" unless self.class.valid_git?(@git)
raise ArgumentError, "Требуется имя" if @name.nil? || @name.strip.empty?
raise ArgumentError, "Некорректный формат имени: #{@name}" unless self.class.valid_name?(@name)
end end
def set_contacts(phone: nil, telegram: nil, email: nil) def set_contacts(phone: nil, telegram: nil, email: nil)
@phone = phone @phone = phone
raise ArgumentError, "Invalid phone number format: #{@phone}" if @phone && !self.class.valid_phone_number?(@phone) raise ArgumentError, "Некорректный формат номера телефона: #{@phone}" if @phone && !self.class.valid_phone_number?(@phone)
@telegram = telegram @telegram = telegram
raise ArgumentError, "Invalid telegram format: #{@telegram}" if @telegram && !self.class.valid_telegram?(@telegram) raise ArgumentError, "Некорректный формат Telegram: #{@telegram}" if @telegram && !self.class.valid_telegram?(@telegram)
@email = email @email = email
raise ArgumentError, "Invalid email format: #{@email}" if @email && !self.class.valid_email?(@email) raise ArgumentError, "Некорректный формат email: #{@email}" if @email && !self.class.valid_email?(@email)
raise ArgumentError, "Требуется хотя бы один контакт (телефон, телеграм или email)" unless contact_present?
end end
def self.valid_phone_number?(phone) def self.valid_phone_number?(phone)
@ -45,14 +53,16 @@ class Person
end end
def contact_present? def contact_present?
!(@phone.nil? || @phone.empty?) || !(@telegram.nil? || @telegram.empty?) || !(@email.nil? || @email.empty?) !(@phone.nil? || @phone.empty?) ||
!(@telegram.nil? || @telegram.empty?) ||
!(@email.nil? || @email.empty?)
end end
def contact_info def contact_info
return "Phone: #{@phone}" if @phone return "Phone: #{@phone}" if @phone
return "Telegram: #{@telegram}" if @telegram return "Telegram: #{@telegram}" if @telegram
return "Email: #{@email}" if @email return "Email: #{@email}" if @email
'No contact available' 'Контактная информация отсутствует'
end end
private private

@ -1,92 +1,132 @@
require_relative 'person' require_relative 'person'
class Student < Person class Student < Person
attr_accessor :surname, :name, :patronymic attr_accessor :surname, :name, :patronymic
def initialize(args = {}) def initialize(args = {})
super(args) super(args)
@surname = args.fetch(:surname)
raise ArgumentError, "Invalid surname format: #{@surname}" unless self.class.valid_name?(@surname)
@name = args.fetch(:name) @surname = args.fetch(:surname) { raise ArgumentError, "Surname is required" }
raise ArgumentError, "Invalid name format: #{@name}" unless self.class.valid_name?(@name) raise ArgumentError, "Invalid surname format: #{@surname}" unless self.class.valid_name?(@surname)
@patronymic = args.fetch(:patronymic) @name = args.fetch(:name) { raise ArgumentError, "Name is required" }
raise ArgumentError, "Invalid patronymic format: #{@patronymic}" unless self.class.valid_name?(@patronymic) raise ArgumentError, "Invalid name format: #{@name}" unless self.class.valid_name?(@name)
set_contacts( @patronymic = args.fetch(:patronymic) { raise ArgumentError, "Patronymic is required" }
phone: args[:phone], raise ArgumentError, "Invalid patronymic format: #{@patronymic}" unless self.class.valid_name?(@patronymic)
telegram: args[:telegram],
email: args[:email]
)
end
def self.from_string(student_string)
parts = student_string.split('|').map(&:strip)
surname, name, patronymic = parts[0].split(' ')
id = parts[1].split(': ').last.to_i
phone = parts[2].split(': ').last
telegram = parts[3].split(': ').last
email = parts[4].split(': ').last
git = parts[5].split(': ').last
new(
surname: surname,
name: name,
patronymic: patronymic,
id: id,
phone: phone,
telegram: telegram,
email: email,
git: git
)
end
def self.read_from_txt(file_path)
raise IOError, "File path is invalid or file does not exist: #{file_path}" unless File.exist?(file_path)
students = []
File.foreach(file_path) do |line| set_contacts(
line.strip! phone: args[:phone],
next if line.empty? telegram: args[:telegram],
email: args[:email]
)
end
begin def self.from_string(student_string)
student = from_string(line) raise ArgumentError, "Input string cannot be nil or empty" if student_string.nil? || student_string.strip.empty?
students << student
rescue ArgumentError => e
puts "Error processing line: '#{line}'. Reason: #{e.message}"
end
end
students parts = student_string.split('|').map(&:strip)
# Ожидается формат: "Фамилия Имя Отчество | ID: X | Phone: ... | Telegram: ... | Email: ... | Git: ..."
# Проверяем, что частей как минимум 6: ФИО, ID, Phone, Telegram, Email, Git
unless parts.size == 6
raise ArgumentError, "Expected 6 parts separated by '|', got #{parts.size} in '#{student_string}'"
end end
def self.write_to_txt(file_path, students) fio_part = parts[0]
raise ArgumentError, "Expected an array of Student objects" unless students.is_a?(Array) && students.all? { |s| s.is_a?(Student) } raise ArgumentError, "FIO part is empty" if fio_part.nil? || fio_part.strip.empty?
File.open(file_path, 'w') do |file| fio_elements = fio_part.split(' ')
students.each do |student| raise ArgumentError, "Expected Surname Name Patronymic in '#{fio_part}'" unless fio_elements.size == 3
file.puts student.to_s surname, name, patronymic = fio_elements
end
end id_part = parts[1]
raise ArgumentError, "ID part is empty or invalid" if id_part.nil? || !id_part.include?('ID:')
puts "Data successfully written to #{file_path}" id_str = id_part.split(': ').last
rescue IOError => e raise ArgumentError, "ID value is missing in '#{id_part}'" if id_str.nil? || id_str.strip.empty?
puts "An error occurred while writing to the file: #{e.message}" id = id_str.to_i
raise ArgumentError, "ID must be a valid integer: '#{id_str}'" if id == 0 && id_str != "0"
phone_part = parts[2]
raise ArgumentError, "Phone part is invalid or missing" if phone_part.nil? || !phone_part.include?('Phone:')
phone = phone_part.split(': ').last
phone = nil if phone == 'N/A'
telegram_part = parts[3]
raise ArgumentError, "Telegram part is invalid or missing" if telegram_part.nil? || !telegram_part.include?('Telegram:')
telegram = telegram_part.split(': ').last
telegram = nil if telegram == 'N/A'
email_part = parts[4]
raise ArgumentError, "Email part is invalid or missing" if email_part.nil? || !email_part.include?('Email:')
email = email_part.split(': ').last
email = nil if email == 'N/A'
git_part = parts[5]
raise ArgumentError, "Git part is invalid or missing" if git_part.nil? || !git_part.include?('Git:')
git = git_part.split(': ').last
git = nil if git == 'N/A'
new(
surname: surname,
name: name,
patronymic: patronymic,
id: id,
phone: phone,
telegram: telegram,
email: email,
git: git
)
end
def self.read_from_txt(file_path)
raise IOError, "File path is invalid or file does not exist: #{file_path}" unless File.exist?(file_path)
students = []
File.foreach(file_path) do |line|
line.strip!
next if line.empty?
begin
student = from_string(line)
students << student
rescue ArgumentError => e
puts "Error processing line: '#{line}'. Reason: #{e.message}"
rescue StandardError => e
puts "An unexpected error occurred while processing line: '#{line}'. Reason: #{e.message}"
end
end end
def surname_and_initials students
"#{@surname} #{name[0]}.#{patronymic[0]}." end
end
def to_s def self.write_to_txt(file_path, students)
"#{@surname} #{@name} #{@patronymic} | ID: #{@id || 'N/A'} | " \ raise ArgumentError, "Expected an array of Student objects" unless students.is_a?(Array) && students.all? { |s| s.is_a?(Student) }
"Phone: #{@phone || 'N/A'} | Telegram: #{@telegram || 'N/A'} | " \
"Email: #{@email || 'N/A'} | Git: #{@git || 'N/A'}"
end
def get_info File.open(file_path, 'w') do |file|
"#{surname_and_initials}, Git: #{git_info}, Contact: #{contact_info}" students.each do |student|
file.puts student.to_s
end
end end
puts "Data successfully written to #{file_path}"
rescue IOError => e
puts "An error occurred while writing to the file: #{e.message}"
rescue StandardError => e
puts "An unexpected error occurred while writing to the file: #{e.message}"
end
def surname_and_initials
"#{@surname} #{name[0]}.#{patronymic[0]}."
end
def to_s
"#{@surname} #{@name} #{@patronymic} | ID: #{@id || 'N/A'} | " \
"Phone: #{@phone || 'N/A'} | Telegram: #{@telegram || 'N/A'} | " \
"Email: #{@email || 'N/A'} | Git: #{@git || 'N/A'}"
end
def get_info
"#{surname_and_initials}, Git: #{git_info}, Contact: #{contact_info}"
end
end end

@ -1,31 +1,86 @@
require_relative 'person' require_relative 'person'
class StudentShort < Person class StudentShort < Person
attr_reader :surname_initials, :contact attr_reader :surname_initials, :contact
def initialize(student) def initialize(student)
super(id: student.id, git: student.git_info) # Проверяем наличие необходимых методов и данных у student
@surname_initials = student.surname_and_initials raise ArgumentError, "Объект student не имеет метод id" unless student.respond_to?(:id)
@contact = student.contact_info raise ArgumentError, "Объект student не имеет метод git_info" unless student.respond_to?(:git_info)
raise ArgumentError, "Объект student не имеет метод surname_and_initials" unless student.respond_to?(:surname_and_initials)
raise ArgumentError, "Объект student не имеет метод contact_info" unless student.respond_to?(:contact_info)
super(id: student.id, git: student.git_info)
@surname_initials = student.surname_and_initials
raise ArgumentError, "Поле surname_initials не может быть пустым" if @surname_initials.nil? || @surname_initials.strip.empty?
# Дополнительная проверка на формат имен, если требуется
# Если формат @surname_initials может быть сложным (например, "Иванов И.И."),
# то можно добавить отдельную проверку формата:
unless valid_surname_initials?(@surname_initials)
raise ArgumentError, "Некорректный формат фамилии и инициалов: #{@surname_initials}"
end end
def self.from_string(id, info_string) @contact = student.contact_info
parts = info_string.split(', ').map(&:strip) raise ArgumentError, "Контактная информация не может быть пустой" if @contact.nil? || @contact.strip.empty?
surname_initials = parts[0] end
git = parts[1].split(': ').last
contact = parts[2].split(': ').last def self.from_string(id, info_string)
raise ArgumentError, "info_string не может быть пустой" if info_string.nil? || info_string.strip.empty?
new_instance = allocate parts = info_string.split(', ').map(&:strip)
new_instance.send(:initialize_from_data, id, surname_initials, git, contact) # Ожидается три части: Фамилия и инициалы, Git, Контакт
new_instance unless parts.size == 3
raise ArgumentError, "Строка info_string должна содержать три части разделённые запятой: '#{info_string}'"
end end
private surname_initials = parts[0]
raise ArgumentError, "Не удалось извлечь фамилию и инициалы" if surname_initials.nil? || surname_initials.empty?
git_part = parts[1]
raise ArgumentError, "Не удалось извлечь Git-данные" if git_part.nil? || !git_part.include?(': ')
git = git_part.split(': ').last
raise ArgumentError, "Некорректная строка для Git: '#{git_part}'" if git.nil? || git.empty?
contact_part = parts[2]
raise ArgumentError, "Не удалось извлечь контактные данные" if contact_part.nil? || !contact_part.include?(': ')
contact = contact_part.split(': ').last
raise ArgumentError, "Некорректная строка для контакта: '#{contact_part}'" if contact.nil? || contact.empty?
new_instance = allocate
new_instance.send(:initialize_from_data, id, surname_initials, git, contact)
new_instance
end
def initialize_from_data(id, surname_initials, git, contact) private
@id = id
@surname_initials = surname_initials def initialize_from_data(id, surname_initials, git, contact)
@git = git raise ArgumentError, "ID должен быть числом" if id && !id.is_a?(Integer)
@contact = contact @id = id
@surname_initials = surname_initials
raise ArgumentError, "Поле surname_initials не может быть пустым" if @surname_initials.nil? || @surname_initials.strip.empty?
unless valid_surname_initials?(@surname_initials)
raise ArgumentError, "Некорректный формат фамилии и инициалов: #{@surname_initials}"
end end
@git = git
raise ArgumentError, "Git ссылка не может быть пустой" if @git.nil? || @git.strip.empty?
raise ArgumentError, "Некорректная ссылка на GitHub: #{@git}" unless self.class.valid_git?(@git)
@contact = contact
raise ArgumentError, "Контактная информация не может быть пустой" if @contact.nil? || @contact.strip.empty?
# Инициализация родительского класса для валидации полей
# Если необходимо, можно повторно вызвать super или же доверять валидации из Person при отдельном создании
# В данном случае super уже вызывается в инициализаторе, а тут мы лишь готовим данные.
end
def valid_surname_initials?(string)
# Пример простой проверки: фамилия и инициалы могут содержать буквы и точки.
# Формат: "Иванов И.И." или "Petrov P.P."
# Условно: первая часть - фамилия, затем инициалы через пробел.
# Можно настроить по необходимости.
string.match?(/\A[А-Яа-яЁёA-Za-z]+(\s+[А-Яа-яЁёA-Za-z]\.[А-Яа-яЁёA-Za-z]\.)?\z/)
end
end end
Loading…
Cancel
Save