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

@ -1,23 +1,31 @@
class Person
attr_accessor :id, :git
attr_accessor :id, :git, :name
def initialize(args = {})
@id = args[:id] || nil
@id = args[:id]
@git = args[:git]
@name = args[:name]
raise ArgumentError, "Git link is required" unless git_present?
raise ArgumentError, "At least one contact (phone, telegram, or email) is required" unless contact_present?
raise ArgumentError, "ID должен быть числом" if @id && !@id.is_a?(Integer)
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
def set_contacts(phone: nil, telegram: nil, email: nil)
@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
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
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
def self.valid_phone_number?(phone)
@ -45,18 +53,20 @@ class Person
end
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
def contact_info
return "Phone: #{@phone}" if @phone
return "Telegram: #{@telegram}" if @telegram
return "Email: #{@email}" if @email
'No contact available'
'Контактная информация отсутствует'
end
private
attr_reader :phone, :telegram, :email
attr_writer :phone, :telegram, :email
end
end

@ -1,92 +1,132 @@
require_relative 'person'
class Student < Person
attr_accessor :surname, :name, :patronymic
def initialize(args = {})
super(args)
@surname = args.fetch(:surname)
raise ArgumentError, "Invalid surname format: #{@surname}" unless self.class.valid_name?(@surname)
@name = args.fetch(:name)
raise ArgumentError, "Invalid name format: #{@name}" unless self.class.valid_name?(@name)
@patronymic = args.fetch(:patronymic)
raise ArgumentError, "Invalid patronymic format: #{@patronymic}" unless self.class.valid_name?(@patronymic)
set_contacts(
phone: args[:phone],
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
attr_accessor :surname, :name, :patronymic
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}"
end
end
students
end
def initialize(args = {})
super(args)
def self.write_to_txt(file_path, students)
raise ArgumentError, "Expected an array of Student objects" unless students.is_a?(Array) && students.all? { |s| s.is_a?(Student) }
File.open(file_path, 'w') do |file|
students.each do |student|
file.puts student.to_s
end
end
puts "Data successfully written to #{file_path}"
rescue IOError => e
puts "An error occurred while writing to the file: #{e.message}"
end
def surname_and_initials
"#{@surname} #{name[0]}.#{patronymic[0]}."
@surname = args.fetch(:surname) { raise ArgumentError, "Surname is required" }
raise ArgumentError, "Invalid surname format: #{@surname}" unless self.class.valid_name?(@surname)
@name = args.fetch(:name) { raise ArgumentError, "Name is required" }
raise ArgumentError, "Invalid name format: #{@name}" unless self.class.valid_name?(@name)
@patronymic = args.fetch(:patronymic) { raise ArgumentError, "Patronymic is required" }
raise ArgumentError, "Invalid patronymic format: #{@patronymic}" unless self.class.valid_name?(@patronymic)
set_contacts(
phone: args[:phone],
telegram: args[:telegram],
email: args[:email]
)
end
def self.from_string(student_string)
raise ArgumentError, "Input string cannot be nil or empty" if student_string.nil? || student_string.strip.empty?
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
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'}"
fio_part = parts[0]
raise ArgumentError, "FIO part is empty" if fio_part.nil? || fio_part.strip.empty?
fio_elements = fio_part.split(' ')
raise ArgumentError, "Expected Surname Name Patronymic in '#{fio_part}'" unless fio_elements.size == 3
surname, name, patronymic = fio_elements
id_part = parts[1]
raise ArgumentError, "ID part is empty or invalid" if id_part.nil? || !id_part.include?('ID:')
id_str = id_part.split(': ').last
raise ArgumentError, "ID value is missing in '#{id_part}'" if id_str.nil? || id_str.strip.empty?
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
def get_info
"#{surname_and_initials}, Git: #{git_info}, Contact: #{contact_info}"
students
end
def self.write_to_txt(file_path, students)
raise ArgumentError, "Expected an array of Student objects" unless students.is_a?(Array) && students.all? { |s| s.is_a?(Student) }
File.open(file_path, 'w') do |file|
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

@ -1,31 +1,86 @@
require_relative 'person'
class StudentShort < Person
attr_reader :surname_initials, :contact
def initialize(student)
super(id: student.id, git: student.git_info)
@surname_initials = student.surname_and_initials
@contact = student.contact_info
attr_reader :surname_initials, :contact
def initialize(student)
# Проверяем наличие необходимых методов и данных у student
raise ArgumentError, "Объект student не имеет метод id" unless student.respond_to?(:id)
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
def self.from_string(id, info_string)
parts = info_string.split(', ').map(&:strip)
surname_initials = parts[0]
git = parts[1].split(': ').last
contact = parts[2].split(': ').last
new_instance = allocate
new_instance.send(:initialize_from_data, id, surname_initials, git, contact)
new_instance
@contact = student.contact_info
raise ArgumentError, "Контактная информация не может быть пустой" if @contact.nil? || @contact.strip.empty?
end
def self.from_string(id, info_string)
raise ArgumentError, "info_string не может быть пустой" if info_string.nil? || info_string.strip.empty?
parts = info_string.split(', ').map(&:strip)
# Ожидается три части: Фамилия и инициалы, Git, Контакт
unless parts.size == 3
raise ArgumentError, "Строка info_string должна содержать три части разделённые запятой: '#{info_string}'"
end
private
def initialize_from_data(id, surname_initials, git, contact)
@id = id
@surname_initials = surname_initials
@git = git
@contact = contact
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
private
def initialize_from_data(id, surname_initials, git, contact)
raise ArgumentError, "ID должен быть числом" if id && !id.is_a?(Integer)
@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

Loading…
Cancel
Save