students_list_yaml_gems 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 24550a4c94d1481f0231db32635e5f6065ce116bb1db7d2617780e1f2f31f6eb
4
+ data.tar.gz: 20753b23b4029e82c7f6b1be5a44a31e45c5db36b7e883b6d0ac71a3bbac7ba5
5
+ SHA512:
6
+ metadata.gz: 75df2aa0f5c7f3cf46b0cdfcdc978c40ad522dbaab586ded7caf2748d02256f064fde1fe1a0c88a98ba562e5d99d1b8570944b0c118b22a5a190f117ef25522c
7
+ data.tar.gz: 621f9b6c890d1c4ff44d6fb5b997753c84a88107d6733bb3546ed996f5e19a075ac50a9f5f7519b1428cb9861d43ede8b35d3c17e3cd78f8024299beab11e8a9
data/lib/data_list.rb ADDED
@@ -0,0 +1,42 @@
1
+ require_relative 'data_table'
2
+ class Data_list
3
+ def initialize(array)
4
+ @selected = []
5
+ @elements = array
6
+ end
7
+
8
+ def select(number)
9
+ @selected << @elements[number]
10
+ end
11
+
12
+ def get_selected
13
+ @selected.map{ |x| x.id }
14
+ end
15
+
16
+ def get_names
17
+ get_names = ["№ по порядку"] + template_get_names()
18
+ end
19
+
20
+ def get_data
21
+ get_data = []
22
+ @elements.each_with_index do |item, index|
23
+ get_data << [index] + template_get_data(item)
24
+ end
25
+ Data_table.new(get_data)
26
+ end
27
+
28
+ def clear_selected
29
+ @selected.clear
30
+ end
31
+
32
+ protected
33
+
34
+ def template_get_data(item)
35
+ raise 'NotImplementedError'
36
+ end
37
+
38
+ def template_get_names
39
+ raise 'NotImplementedError'
40
+ end
41
+
42
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'data_list'
2
+ require_relative 'student_short'
3
+ class Data_list_student_short < Data_list
4
+
5
+ def array=(array)
6
+ @array = array
7
+ end
8
+
9
+ def initialize(array)
10
+ super
11
+ self.array=array
12
+ end
13
+
14
+ private
15
+
16
+ def template_get_names
17
+ names = [ "Last name initialize", "Contact", "Git" ]
18
+ end
19
+
20
+ def template_get_data(value)
21
+ data = [ value.last_name_initials, value.contact || "", value.git || "" ]
22
+ end
23
+
24
+ end
data/lib/data_table.rb ADDED
@@ -0,0 +1,24 @@
1
+ class Data_table
2
+ def initialize(array)
3
+ @elements = []
4
+ array.each do |item|
5
+ @elements << item
6
+ end
7
+ end
8
+
9
+ def to_s
10
+ @elements
11
+ end
12
+
13
+ def get_element(i, j)
14
+ @elements[i][j].dup
15
+ end
16
+
17
+ def get_count_rows
18
+ @elements.length.dup
19
+ end
20
+
21
+ def get_count_column
22
+ @elements[0].length.dup
23
+ end
24
+ end
data/lib/logger.rb ADDED
@@ -0,0 +1,63 @@
1
+ class Logger
2
+ LOG_LEVELS = {
3
+ debug: 0,
4
+ info: 1,
5
+ warn: 2,
6
+ error: 3,
7
+ fatal: 4
8
+ }
9
+
10
+ def initialize(log_file = 'application.log', level = :info)
11
+ @log_file = log_file
12
+ @level = LOG_LEVELS[level] || LOG_LEVELS[:info]
13
+ @mutex = Mutex.new
14
+ ensure_log_file
15
+ end
16
+
17
+ def debug(message)
18
+ log(:debug, message) if @level <= LOG_LEVELS[:debug]
19
+ end
20
+
21
+ def info(message)
22
+ log(:info, message) if @level <= LOG_LEVELS[:info]
23
+ end
24
+
25
+ def warn(message)
26
+ log(:warn, message) if @level <= LOG_LEVELS[:warn]
27
+ end
28
+
29
+ def error(message)
30
+ log(:error, message) if @level <= LOG_LEVELS[:error]
31
+ end
32
+
33
+ def fatal(message)
34
+ log(:fatal, message) if @level <= LOG_LEVELS[:fatal]
35
+ end
36
+
37
+ def level=(new_level)
38
+ @level = LOG_LEVELS[new_level] || LOG_LEVELS[:info]
39
+ end
40
+
41
+ private
42
+
43
+ def ensure_log_file
44
+ return if File.exist?(@log_file)
45
+ File.write(@log_file, '')
46
+ end
47
+
48
+ def log(level, message)
49
+ @mutex.synchronize do
50
+ timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")
51
+ log_entry = "[#{timestamp}] #{level.to_s.upcase}: #{message}\n"
52
+
53
+ File.open(@log_file, 'a') do |file|
54
+ file.write(log_entry)
55
+ end
56
+
57
+ # Также выводим в консоль для отладки
58
+ puts log_entry.strip if @level <= LOG_LEVELS[:info]
59
+ end
60
+ rescue => e
61
+ STDERR.puts "Ошибка записи в лог: #{e.message}"
62
+ end
63
+ end
data/lib/student.rb ADDED
@@ -0,0 +1,131 @@
1
+ require_relative 'student_superclass'
2
+
3
+ class Student < StudentSuper
4
+ include Comparable
5
+ attr_reader :last_name, :first_name, :patronymic, :phone, :telegram, :email
6
+
7
+ # Основной конструктор
8
+ def initialize(last_name:, first_name:, patronymic: nil, id: nil, phone: nil, telegram: nil, email: nil, git: nil)
9
+ raise ArgumentError, "Неверный git: #{git}" unless self.class.valid_git?(git)
10
+
11
+ super(id: id, git: git)
12
+
13
+ self.last_name = last_name
14
+ self.first_name = first_name
15
+ self.patronymic = patronymic
16
+ set_contact(phone: phone, telegram: telegram, email: email)
17
+ end
18
+
19
+ # Конструктор из хеша (Задание 2.5)
20
+ def self.from_hash(hash)
21
+ new(
22
+ id: hash['id'] || hash[:id],
23
+ last_name: hash['last_name'] || hash[:last_name],
24
+ first_name: hash['first_name'] || hash[:first_name],
25
+ patronymic: hash['patronymic'] || hash[:patronymic] || hash['middle_name'] || hash[:middle_name],
26
+ phone: hash['phone'] || hash[:phone],
27
+ telegram: hash['telegram'] || hash[:telegram],
28
+ email: hash['email'] || hash[:email],
29
+ git: hash['git'] || hash[:git]
30
+ )
31
+ end
32
+
33
+ def self.validated_attr_writer(attribute, validation_method)
34
+ define_method("#{attribute}=") do |value|
35
+ raise ArgumentError unless self.class.send(validation_method, value)
36
+ instance_variable_set("@#{attribute}", value)
37
+ end
38
+ end
39
+
40
+ validated_attr_writer :first_name, :valid_name?
41
+ validated_attr_writer :last_name, :valid_name?
42
+ validated_attr_writer :patronymic, :valid_name?
43
+ validated_attr_writer :git, :valid_git?
44
+
45
+ def <=>(other)
46
+ [last_name, first_name, patronymic || nil] <=> [other.last_name, other.first_name, other.patronymic || nil]
47
+ end
48
+
49
+ def contact
50
+ return "telegram - #{@telegram}" if @telegram and !@telegram.empty?
51
+ return "email - #{@email}" if @email and !@email.empty?
52
+ return "phone - #{@phone}" if @phone and !@phone.empty?
53
+ nil
54
+ end
55
+
56
+ def set_contact(phone: nil, telegram: nil, email: nil)
57
+ @phone = phone if phone && self.class.valid_phone?(phone)
58
+ @telegram = telegram if telegram && self.class.valid_telegram?(telegram)
59
+ @email = email if email && self.class.valid_email?(email)
60
+ end
61
+
62
+ def contact=(contacts)
63
+ contacts.each do |type, value|
64
+ validator = "valid_#{type}?".to_sym
65
+ raise ArgumentError, "Неверный формат #{type}" unless self.class.send(validator, value)
66
+ instance_variable_set("@#{type}", value)
67
+ end
68
+ end
69
+
70
+ def last_name_initials
71
+ initials = ""
72
+ if first_name and patronymic
73
+ initials = "#{first_name[0]}. #{patronymic[0]}." if first_name and patronymic
74
+ elsif first_name
75
+ initials = "#{first_name[0]}."
76
+ else
77
+ initials = ""
78
+ end
79
+ "#{last_name} #{initials}".strip
80
+ end
81
+
82
+ def to_s
83
+ info = []
84
+ info << "ID: #{id}" if id
85
+ info << "Фамилия: #{last_name}"
86
+ info << "Имя: #{first_name}"
87
+ info << "Отчество: #{patronymic}" if patronymic
88
+ info << "Телефон: #{@phone}" if @phone
89
+ info << "Telegram: #{@telegram}" if @telegram
90
+ info << "Email: #{@email}" if @email
91
+ info << "Git: #{git}" if git
92
+ info.join(", ")
93
+ end
94
+
95
+ def to_hash
96
+ {
97
+ id: @id,
98
+ last_name: @last_name,
99
+ first_name: @first_name,
100
+ patronymic: @patronymic,
101
+ phone: @phone,
102
+ telegram: @telegram,
103
+ email: @email,
104
+ git: @git
105
+ }
106
+ end
107
+
108
+ def self.valid_name?(name)
109
+ name.nil? || name.is_a?(String) && name.match?(/\A[A-ZА-ЯЁ][a-zа-яё]+\z/)
110
+ end
111
+
112
+ def self.valid_phone?(phone)
113
+ return true if phone.nil? or phone.empty?
114
+ phone.match?(/^(\+7|8)?[\s\-\(]?(\d{3})[\s\-\)]?(\d{3})[\s\-]?(\d{2})[\s\-]?(\d{2})$/)
115
+ end
116
+
117
+ def self.valid_telegram?(telegram)
118
+ return true if telegram.nil? or telegram.empty?
119
+ telegram.match?(/^@[a-zA-Z0-9_]{5,32}$/)
120
+ end
121
+
122
+ def self.valid_email?(email)
123
+ return true if email.nil? or email.empty?
124
+ email.match?(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)
125
+ end
126
+
127
+ def self.valid_git?(git)
128
+ return true if git.nil? or git.empty?
129
+ git.match?(/^https:\/\/(github|gitlab)\.com\/[a-zA-Z0-9_-]+\/?$/)
130
+ end
131
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'student'
2
+ require_relative 'student_superclass'
3
+ class StudentShort < StudentSuper
4
+ attr_reader :last_name_initials, :contact
5
+ def initialize(id:, last_name_initials:, contact: nil, git: nil)
6
+ super(id: id, git: git)
7
+ @last_name_initials = last_name_initials
8
+ @contact = contact
9
+ end
10
+
11
+ def self.from_student(student)
12
+ raise ArgumentError, "Student must not be nil" unless student
13
+
14
+ raise ArgumentError, "ID not found" unless student.id
15
+
16
+ new(
17
+ id: student.id,
18
+ last_name_initials: student.last_name_initials,
19
+ contact: student.contact,
20
+ git: student.git
21
+ )
22
+ end
23
+ end
@@ -0,0 +1,40 @@
1
+ class StudentSuper
2
+ attr_reader :id, :git
3
+
4
+ def initialize(id: nil, git: nil)
5
+ @id = id
6
+ @git = git
7
+ end
8
+
9
+ def to_s
10
+ short_info
11
+ end
12
+
13
+ def short_info
14
+ info = []
15
+ info << "ID: #{id}" if id
16
+ info << "ФИО: #{last_name_initials}"
17
+ info << contact if contact
18
+ info << "Git: #{git}" if git
19
+ info
20
+ end
21
+
22
+ def has_git?
23
+ !@git.nil? and !@git.empty?
24
+ end
25
+
26
+ def has_contact?
27
+ !@contact.nil? and !@contact.empty?
28
+ end
29
+
30
+ protected
31
+
32
+ def contact
33
+ raise 'NotImplementedError'
34
+ end
35
+
36
+ def last_name_initials
37
+ raise 'NotImplementedError'
38
+ end
39
+
40
+ end
@@ -0,0 +1,149 @@
1
+ require_relative 'student'
2
+ require_relative 'student_short'
3
+ require_relative 'data_list_student_short'
4
+
5
+ class Students_list_base
6
+ def initialize
7
+ @students = []
8
+ @filename = nil
9
+ @logger = Logger.new
10
+ end
11
+
12
+ # Абстрактные методы
13
+ def read_from_file(filename)
14
+ raise NotImplementedError, "Метод read_from_file должен быть реализован в подклассе"
15
+ end
16
+
17
+ def write_to_file(filename)
18
+ raise NotImplementedError, "Метод write_to_file должен быть реализован в подклассе"
19
+ end
20
+
21
+ # Получить объект класса Student по ID
22
+ def get_student_by_id(id)
23
+ @logger.debug("Поиск студента с ID: #{id}")
24
+ student = @students.find { |s| s.id == id }
25
+ if student
26
+ @logger.debug("Найден студент: #{student.last_name_initials}")
27
+ else
28
+ @logger.debug("Студент с ID #{id} не найден")
29
+ end
30
+ student
31
+ end
32
+
33
+ # Получить список k по счету n объектов класса Student_short
34
+ def get_k_n_student_short_list(k, n, existing_list = nil)
35
+ @logger.debug("Получение списка: страница #{k}, элементов #{n}")
36
+
37
+ # Сортируем по ФамилияИнициалы
38
+ sorted_students = @students.sort_by(&:last_name_initials)
39
+
40
+ # Преобразуем в Student_short
41
+ short_students = sorted_students.map { |s| StudentShort.from_student(s) }
42
+
43
+ # Вычисляем диапазон
44
+ start_index = (k - 1) * n
45
+ end_index = start_index + n - 1
46
+
47
+ # Получаем срез
48
+ result_data = short_students[start_index..end_index] || []
49
+
50
+ # Возвращаем или изменяем существующий список
51
+ if existing_list
52
+ existing_list.instance_variable_set(:@elements, result_data)
53
+ @logger.debug("Обновлен существующий список, элементов: #{result_data.size}")
54
+ existing_list
55
+ else
56
+ @logger.debug("Создан новый список, элементов: #{result_data.size}")
57
+ Data_list_student_short.new(result_data)
58
+ end
59
+ end
60
+
61
+ # Сортировать элементы по набору ФамилияИнициалы
62
+ def sort_by_name
63
+ @logger.info("Сортировка списка студентов по ФамилияИнициалы")
64
+ @students.sort_by!(&:last_name_initials)
65
+ end
66
+
67
+ # Добавить объект класса Student в список (при добавлении сформировать новый ID)
68
+ def add_student(student)
69
+ @logger.info("Добавление нового студента: #{student.last_name}")
70
+
71
+ # Генерация нового ID
72
+ new_id = @students.empty? ? 1 : @students.map(&:id).compact.max + 1
73
+
74
+ # Создаем нового студента с новым ID
75
+ new_student = Student.new(
76
+ id: new_id,
77
+ last_name: student.last_name,
78
+ first_name: student.first_name,
79
+ patronymic: student.patronymic,
80
+ phone: student.phone,
81
+ telegram: student.telegram,
82
+ email: student.email,
83
+ git: student.git
84
+ )
85
+
86
+ @students << new_student
87
+ save_changes
88
+ @logger.info("Студент добавлен с ID: #{new_id}")
89
+ new_id
90
+ end
91
+
92
+ # Заменить элемент списка по ID
93
+ def replace_student(id, student)
94
+ @logger.info("Замена студента с ID: #{id}")
95
+
96
+ index = @students.find_index { |s| s.id == id }
97
+
98
+ if index
99
+ updated_student = Student.new(
100
+ id: id,
101
+ last_name: student.last_name,
102
+ first_name: student.first_name,
103
+ patronymic: student.patronymic,
104
+ phone: student.phone,
105
+ telegram: student.telegram,
106
+ email: student.email,
107
+ git: student.git
108
+ )
109
+
110
+ @students[index] = updated_student
111
+ save_changes
112
+ @logger.info("Студент с ID #{id} успешно заменен")
113
+ true
114
+ else
115
+ @logger.warn("Студент с ID #{id} не найден")
116
+ false
117
+ end
118
+ end
119
+
120
+ # Удалить элемент списка по ID
121
+ def delete_student(id)
122
+ @logger.info("Удаление студента с ID: #{id}")
123
+
124
+ initial_size = @students.size
125
+ @students.reject! { |student| student.id == id }
126
+
127
+ if @students.size < initial_size
128
+ save_changes
129
+ @logger.info("Студент с ID #{id} успешно удален")
130
+ true
131
+ else
132
+ @logger.warn("Студент с ID #{id} не найден")
133
+ false
134
+ end
135
+ end
136
+
137
+ # Получить количество элементов
138
+ def get_student_short_count
139
+ count = @students.size
140
+ @logger.debug("Текущее количество студентов: #{count}")
141
+ count
142
+ end
143
+
144
+ private
145
+
146
+ def save_changes
147
+ write_to_file(@filename) if @filename
148
+ end
149
+ end
@@ -0,0 +1,60 @@
1
+ require 'yaml'
2
+ require_relative 'students_list_base'
3
+ require_relative 'logger'
4
+
5
+ class Students_list_YAML < Students_list_base
6
+ def initialize
7
+ super
8
+ @logger = Logger.new('students_yaml.log', :debug)
9
+ end
10
+
11
+ # a. Чтение всех значений из файла
12
+ def read_from_file(filename)
13
+ @logger.info("Чтение из YAML файла: #{filename}")
14
+ @filename = filename
15
+
16
+ begin
17
+ if File.exist?(filename)
18
+ data_array = YAML.load_file(filename)
19
+
20
+ @students = data_array.map do |hash|
21
+ Student.from_hash(hash)
22
+ end
23
+
24
+ @logger.info("Успешно загружено #{@students.size} студентов")
25
+ else
26
+ @students = []
27
+ @logger.warn("Файл #{filename} не существует. Создан пустой список.")
28
+ end
29
+ rescue Psych::SyntaxError => e
30
+ @logger.error("Ошибка парсинга YAML: #{e.message}")
31
+ @students = []
32
+ rescue => e
33
+ @logger.error("Ошибка чтения файла: #{e.message}")
34
+ @students = []
35
+ end
36
+ end
37
+
38
+ # b. Запись всех значений в файл
39
+ def write_to_file(filename)
40
+ @logger.info("Запись в YAML файл: #{filename}")
41
+
42
+ begin
43
+ data_array = @students.map(&:to_hash)
44
+ yaml_data = YAML.dump(data_array)
45
+ File.write(filename, yaml_data)
46
+ @logger.info("Успешно записано #{@students.size} студентов")
47
+ rescue => e
48
+ @logger.error("Ошибка записи в файл: #{e.message}")
49
+ raise
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def save_changes
56
+ return unless @filename
57
+ @logger.debug("Автосохранение изменений")
58
+ write_to_file(@filename)
59
+ end
60
+ end
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: students_list_yaml_gems
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Мари
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-01-10 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/data_list.rb
20
+ - lib/data_list_student_short.rb
21
+ - lib/data_table.rb
22
+ - lib/logger.rb
23
+ - lib/student.rb
24
+ - lib/student_short.rb
25
+ - lib/student_superclass.rb
26
+ - lib/students_list_base.rb
27
+ - lib/students_list_yaml.rb
28
+ homepage:
29
+ licenses:
30
+ - MIT
31
+ metadata: {}
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubygems_version: 3.4.20
48
+ signing_key:
49
+ specification_version: 4
50
+ summary: Управление списками студентов в YAML
51
+ test_files: []