students_list_yaml_ligostaev 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 +7 -0
- data/LICENSE +21 -0
- data/README.md +63 -0
- data/lib/abstract_student_list.rb +227 -0
- data/lib/data_list.rb +46 -0
- data/lib/data_list_student_short.rb +21 -0
- data/lib/data_table.rb +21 -0
- data/lib/student.rb +113 -0
- data/lib/student_short.rb +25 -0
- data/lib/students_list_yaml.rb +31 -0
- data/lib/super_student.rb +36 -0
- metadata +52 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 13e5773e64d50df3e40fb1631027bed51c6874af405f4f51de6b3c99f67064f9
|
|
4
|
+
data.tar.gz: ef201b10620bbf2eb1e9538b76059f6e30c99cb196c8e6199ccb3db8fd295740
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 91e6ab9aaa6e7c49848ed7af32c87354efd91439b981c9bb2dd684698da7981c419d80d3f11db56af2ba617b717c070f528cc019a7a758fe865097428b113bb1
|
|
7
|
+
data.tar.gz: 1dc0e16f13553b1645eb318cb48326e2497898f906db72d68171c5a32ed3e846be6174985d8b09eeb04f0690bc8af3d2f87fc6f9ed2f4d4192dde7f9317cfb8c
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Laboratory Work 4
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# students_list_yaml
|
|
2
|
+
|
|
3
|
+
Простой гем для работы со списками студентов в YAML формате.
|
|
4
|
+
|
|
5
|
+
## Установка
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
gem 'students_list_yaml', path: './students_list_yaml_gem'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Или в Gemfile проекта:
|
|
12
|
+
```ruby
|
|
13
|
+
gemspec path: './students_list_yaml_gem'
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Использование
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
require 'students_list_yaml'
|
|
20
|
+
|
|
21
|
+
# Создать объект для работы с YAML файлом
|
|
22
|
+
list = Students_list_YAML.new('students.yaml')
|
|
23
|
+
|
|
24
|
+
# Получить количество студентов
|
|
25
|
+
count = list.get_student_short_count
|
|
26
|
+
|
|
27
|
+
# Получить студента по ID
|
|
28
|
+
student = list.get_student_by_id(1)
|
|
29
|
+
|
|
30
|
+
# Добавить студента
|
|
31
|
+
new_student = Student.new(...)
|
|
32
|
+
list.add_student(new_student)
|
|
33
|
+
|
|
34
|
+
# Получить страницу (5 студентов, 1-я страница)
|
|
35
|
+
page = list.get_k_n_student_short_list(5, 1)
|
|
36
|
+
|
|
37
|
+
# Сортировать по фамилии и инициалам
|
|
38
|
+
list.sort_by_last_name_initials
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Методы
|
|
42
|
+
|
|
43
|
+
- `initialize(file_path)` - создать объект
|
|
44
|
+
- `load_file()` - загрузить студентов из файла
|
|
45
|
+
- `save_file()` - сохранить в файл
|
|
46
|
+
- `get_student_by_id(id)` - получить студента по ID
|
|
47
|
+
- `add_student(student)` - добавить студента
|
|
48
|
+
- `replace_student_by_id(id, new_student)` - заменить студента
|
|
49
|
+
- `remove_student_by_id(id)` - удалить студента
|
|
50
|
+
- `sort_by_last_name_initials()` - сортировать
|
|
51
|
+
- `get_student_short_count()` - количество студентов
|
|
52
|
+
- `get_k_n_student_short_list(k, n)` - получить k студентов со страницы n
|
|
53
|
+
|
|
54
|
+
## Зависимости
|
|
55
|
+
|
|
56
|
+
Требует наличие классов:
|
|
57
|
+
- Student
|
|
58
|
+
- StudentShort
|
|
59
|
+
- DataList
|
|
60
|
+
- DataListStudentShort
|
|
61
|
+
- AbstractStudentList
|
|
62
|
+
|
|
63
|
+
Эти классы должны быть загружены перед использованием гема.
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
require_relative 'student'
|
|
2
|
+
require_relative 'student_short'
|
|
3
|
+
require_relative 'data_list_student_short'
|
|
4
|
+
|
|
5
|
+
# AbstractStudentList — базовый класс для конкретных реализаций хранения списка студентов (JSON, YAML).
|
|
6
|
+
#
|
|
7
|
+
# Содержит общую логику работы со списком студентов:
|
|
8
|
+
# - преобразование хэша в объект Student и наоборот,
|
|
9
|
+
# - добавление/удаление/замена записи по id,
|
|
10
|
+
# - получение страницы StudentShort в виде DataListStudentShort,
|
|
11
|
+
# - сортировка по фамилии + инициалам (last_name_initials),
|
|
12
|
+
# - универсальный read_all/write_all (вызывают реализацию подкласса для записи/чтения массивов).
|
|
13
|
+
#
|
|
14
|
+
# @abstract
|
|
15
|
+
# @example Создание подкласса
|
|
16
|
+
# class StudentListJSON < AbstractStudentList
|
|
17
|
+
# private
|
|
18
|
+
# def load_from_file(content)
|
|
19
|
+
# # реализация для JSON
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# def write_raw_array(array)
|
|
23
|
+
# # реализация для JSON
|
|
24
|
+
# end
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# @see StudentListJSON
|
|
28
|
+
# @see StudentListYAML
|
|
29
|
+
class AbstractStudentList
|
|
30
|
+
# Путь к файлу JSON/YAML
|
|
31
|
+
# @return [String]
|
|
32
|
+
attr_reader :path
|
|
33
|
+
|
|
34
|
+
# Открывает и при необходимости создает файл
|
|
35
|
+
#
|
|
36
|
+
# @param path [String] путь до файла
|
|
37
|
+
# @example
|
|
38
|
+
# list = StudentListJSON.new('students.json')
|
|
39
|
+
def initialize(path)
|
|
40
|
+
@path = path
|
|
41
|
+
@array_list = []
|
|
42
|
+
ensure_file
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Читает все записи с файла
|
|
46
|
+
#
|
|
47
|
+
# @return [Array<Student>] массив объектов Student
|
|
48
|
+
# @example
|
|
49
|
+
# students = list.read_all
|
|
50
|
+
# students.each { |s| puts s.last_name_initials }
|
|
51
|
+
def read_all
|
|
52
|
+
file_content = File.read(@path)
|
|
53
|
+
if file_content.strip.empty?
|
|
54
|
+
@array_list = []
|
|
55
|
+
return @array_list
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
parsed_array = load_from_file(file_content)
|
|
59
|
+
@array_list = parsed_array.map { |element| Student.new(**element) }
|
|
60
|
+
@array_list
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Записывает или перезаписывает всех студентов в файл
|
|
64
|
+
#
|
|
65
|
+
# @return [void]
|
|
66
|
+
# @example
|
|
67
|
+
# students = list.read_all
|
|
68
|
+
# list.write_all
|
|
69
|
+
def write_all
|
|
70
|
+
new_data = @array_list.map(&:to_hash)
|
|
71
|
+
write_raw_array(new_data)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Получает объект класса Student по ID, или nil, если не найден
|
|
75
|
+
#
|
|
76
|
+
# @param id [Integer] идентификатор студента
|
|
77
|
+
# @return [Student, nil] объект Student или nil если не найден
|
|
78
|
+
# @example
|
|
79
|
+
# student = list.get_student_by_id(1)
|
|
80
|
+
# puts student.last_name if student
|
|
81
|
+
def get_student_by_id(id)
|
|
82
|
+
@array_list.find { |element| element.id == id }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Получает список k по счету n объектов StudentShort в виде DataListStudentShort
|
|
86
|
+
#
|
|
87
|
+
# @param k [Integer] размер страницы
|
|
88
|
+
# @param n [Integer] номер страницы
|
|
89
|
+
# @param existing_data_list [DataListStudentShort, nil] если передан,
|
|
90
|
+
# то метод заполнит или заменит объекты в нем
|
|
91
|
+
# @return [DataListStudentShort] список студентов для отображения
|
|
92
|
+
# @example
|
|
93
|
+
# data_list = list.get_k_n_student_short_list(5, 1)
|
|
94
|
+
# data_list.elements.each { |s| puts s.last_name_initials }
|
|
95
|
+
def get_k_n_student_short_list(k, n, existing_data_list = nil)
|
|
96
|
+
sorted_students = @array_list.sort_by { |s| s.last_name_initials }
|
|
97
|
+
start_index = k * (n - 1)
|
|
98
|
+
selected_students = sorted_students[start_index, k] || []
|
|
99
|
+
student_shorts = selected_students.map { |student| StudentShort.from_student(student) }
|
|
100
|
+
|
|
101
|
+
if existing_data_list
|
|
102
|
+
existing_data_list.elements = student_shorts
|
|
103
|
+
existing_data_list
|
|
104
|
+
else
|
|
105
|
+
new_data_list = DataListStudentShort.new(student_shorts)
|
|
106
|
+
new_data_list
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Сортирует элементы по last_name_initials и сохраняет в файл
|
|
111
|
+
#
|
|
112
|
+
# @return [void]
|
|
113
|
+
# @example
|
|
114
|
+
# list.sort_by_last_name_initials
|
|
115
|
+
# # Теперь студенты отсортированы по ФИО
|
|
116
|
+
def sort_by_last_name_initials
|
|
117
|
+
@array_list.sort_by! { |student| student.last_name_initials }
|
|
118
|
+
write_all
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Добавляет объект класса Student в список, генерируя новый ID
|
|
122
|
+
#
|
|
123
|
+
# @param student [Student] студент
|
|
124
|
+
# @return [Student] добавленный объект с назначенным ID
|
|
125
|
+
# @raise [ArgumentError] если студент с такими данными уже существует
|
|
126
|
+
# @example
|
|
127
|
+
# student = Student.new(first_name: 'Иван', last_name: 'Петров', git: 'https://github.com/ivanov')
|
|
128
|
+
# added = list.add_student(student)
|
|
129
|
+
def add_student(student)
|
|
130
|
+
if duplicate?(student)
|
|
131
|
+
raise ArgumentError, "Студент с такими контактными данными уже существует"
|
|
132
|
+
end
|
|
133
|
+
existing_ids = @array_list.map(&:id).compact
|
|
134
|
+
new_id = existing_ids.empty? ? 1 : existing_ids.max + 1
|
|
135
|
+
student.instance_variable_set(:@id, new_id)
|
|
136
|
+
@array_list << student
|
|
137
|
+
write_all
|
|
138
|
+
student
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Заменяет элемент списка по ID на новый Student
|
|
142
|
+
#
|
|
143
|
+
# @param id [Integer] идентификатор заменяемого студента
|
|
144
|
+
# @param new_student [Student] новые данные студента
|
|
145
|
+
# @return [Boolean] true если заменено, false если id не найден
|
|
146
|
+
# @raise [ArgumentError] если новый студент дублирует существующего
|
|
147
|
+
# @example
|
|
148
|
+
# new_student = Student.new(first_name: 'Обновленное', last_name: 'Имя', git: 'https://github.com/updated')
|
|
149
|
+
# success = list.replace_by_id(1, new_student)
|
|
150
|
+
def replace_by_id(id, new_student)
|
|
151
|
+
index = @array_list.index { |student| student.id == id }
|
|
152
|
+
return false unless index
|
|
153
|
+
|
|
154
|
+
if duplicate?(new_student, exclude: id)
|
|
155
|
+
raise ArgumentError, "Студент с такими контактными данными уже существует"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
new_student.instance_variable_set(:@id, id)
|
|
159
|
+
@array_list[index] = new_student
|
|
160
|
+
write_all
|
|
161
|
+
true
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Удаляет элемент по ID
|
|
165
|
+
#
|
|
166
|
+
# @param id [Integer] идентификатор удаляемого студента
|
|
167
|
+
# @return [Boolean] true если удалено, false если не найден
|
|
168
|
+
# @example
|
|
169
|
+
# if list.delete_by_id(5)
|
|
170
|
+
# puts "Студент с ID 5 удален"
|
|
171
|
+
# end
|
|
172
|
+
def delete_by_id(id)
|
|
173
|
+
deleted = @array_list.reject! { |student| student.id == id }
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Возвращает количество элементов
|
|
177
|
+
#
|
|
178
|
+
# @return [Integer] количество студентов в списке
|
|
179
|
+
# @example
|
|
180
|
+
# count = list.get_student_short_count
|
|
181
|
+
# puts "Всего студентов: #{count}"
|
|
182
|
+
def get_student_short_count
|
|
183
|
+
@array_list.length
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
private
|
|
187
|
+
|
|
188
|
+
# Загружает данные из файла
|
|
189
|
+
#
|
|
190
|
+
# @abstract
|
|
191
|
+
# @param content [String] содержимое файла
|
|
192
|
+
# @return [Array<Hash>] массив данных
|
|
193
|
+
# @raise [NotImplementedError] если метод не реализован в подклассе
|
|
194
|
+
def load_from_file(content)
|
|
195
|
+
raise NotImplementedError, "load_from_file должен быть реализован в подклассе"
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Записывает массив в файл
|
|
199
|
+
#
|
|
200
|
+
# @abstract
|
|
201
|
+
# @param array [Array<Hash>] массив данных для записи
|
|
202
|
+
# @return [void]
|
|
203
|
+
# @raise [NotImplementedError] если метод не реализован в подклассе
|
|
204
|
+
def write_raw_array(array)
|
|
205
|
+
raise NotImplementedError, "write_raw_array должен быть реализован в подклассе"
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Проверяет существует ли дубликат студента
|
|
209
|
+
#
|
|
210
|
+
# @param student [Student] объект класса Student для проверки
|
|
211
|
+
# @param exclude [Integer, nil] ID студента исключаемого из проверки (при замене)
|
|
212
|
+
# @return [Boolean] true если найден дубликат, false если нет
|
|
213
|
+
def duplicate?(student, exclude: nil)
|
|
214
|
+
@array_list.any? do |other|
|
|
215
|
+
next if exclude && other.id == exclude
|
|
216
|
+
student == other
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Проверяет существует ли файл, в противном случае создает его с пустым массивом
|
|
221
|
+
#
|
|
222
|
+
# @return [void]
|
|
223
|
+
def ensure_file
|
|
224
|
+
return if File.exist?(@path) && File.size?(@path)
|
|
225
|
+
File.write(@path, '[]')
|
|
226
|
+
end
|
|
227
|
+
end
|
data/lib/data_list.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require_relative 'data_table'
|
|
2
|
+
class DataList
|
|
3
|
+
def initialize(elements = [])
|
|
4
|
+
@elements = elements
|
|
5
|
+
@selected = []
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
attr_reader :elements
|
|
9
|
+
|
|
10
|
+
def elements=(new_elements)
|
|
11
|
+
@elements = new_elements
|
|
12
|
+
@selected.clear
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def select(number)
|
|
16
|
+
if number >= 0 && number < @elements.size
|
|
17
|
+
@selected << number unless @selected.include?(number)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def get_selected
|
|
22
|
+
@selected.map { |index| @elements[index].id }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def clear_selected
|
|
26
|
+
@selected.clear
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def get_names
|
|
30
|
+
["№ по порядку"] + attribute_headers
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def get_data
|
|
34
|
+
DataTable.new(student_arr)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def attribute_headers
|
|
40
|
+
raise NotImplementedError, "метод attribute_headers должен быть реализован в подклассе"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def student_arr
|
|
44
|
+
raise NotImplementedError, "метод student_arr должен быть реализован в подклассе"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require_relative 'data_list'
|
|
2
|
+
require_relative 'student_short'
|
|
3
|
+
require_relative 'data_table'
|
|
4
|
+
|
|
5
|
+
class DataListStudentShort < DataList
|
|
6
|
+
private
|
|
7
|
+
def attribute_headers
|
|
8
|
+
["ФИО", "Контакт", "Git"]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def student_arr
|
|
12
|
+
@elements.each_with_index.map do |student, index|
|
|
13
|
+
[
|
|
14
|
+
index + 1,
|
|
15
|
+
student.last_name_initials,
|
|
16
|
+
student.contact || "",
|
|
17
|
+
student.git || ""
|
|
18
|
+
]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/data_table.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class DataTable
|
|
2
|
+
def initialize(two_dimensional_array)
|
|
3
|
+
@data = two_dimensional_array
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def get(row, col)
|
|
7
|
+
raise IndexError, "Индекс строки вне диапазона" if row < 0 || row >= rows_count
|
|
8
|
+
raise IndexError, "Индекс столбца вне диапазона" if col < 0 || col >= cols_count
|
|
9
|
+
@data[row][col]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def rows_count
|
|
13
|
+
@data.length
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def cols_count
|
|
17
|
+
return 0 if @data.empty?
|
|
18
|
+
@data[0].length
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
data/lib/student.rb
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
require_relative 'super_student.rb'
|
|
2
|
+
|
|
3
|
+
class Student < SuperStudent
|
|
4
|
+
include Comparable
|
|
5
|
+
attr_reader :last_name, :first_name, :patronymic, :git
|
|
6
|
+
|
|
7
|
+
def initialize(id: nil, last_name:, first_name:, patronymic: nil, phone: nil, telegram: nil, email: nil, git: nil)
|
|
8
|
+
raise ArgumentError, "Неверный формат гита #{git}" unless self.class.valid_git?(git)
|
|
9
|
+
super(id:id, git: git)
|
|
10
|
+
self.last_name = last_name
|
|
11
|
+
self.first_name = first_name
|
|
12
|
+
self.patronymic = patronymic
|
|
13
|
+
self.contact = {phone: phone, telegram: telegram, email: email}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def <=>(other)
|
|
17
|
+
[first_name, last_name, patronymic || nil] <=> [other.first_name, other.last_name, other.patronymic || nil]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def contact
|
|
21
|
+
if @telegram && !@telegram.empty?
|
|
22
|
+
"telegram - #{@telegram}"
|
|
23
|
+
elsif @email && !@email.empty?
|
|
24
|
+
"email - #{@email}"
|
|
25
|
+
elsif @phone && !@phone.empty?
|
|
26
|
+
"phone - #{@phone}"
|
|
27
|
+
else
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def contact=(contacts)
|
|
33
|
+
contacts.each do |type, value|
|
|
34
|
+
validator = "valid_#{type}?".to_sym
|
|
35
|
+
raise ArgumentError, "Неверный формат #{type}" unless self.class.send(validator, value)
|
|
36
|
+
instance_variable_set("@#{type}", value)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def last_name_initials
|
|
41
|
+
initials = "#{last_name} #{first_name[0]}."
|
|
42
|
+
initials += " #{patronymic[0]}." if patronymic
|
|
43
|
+
initials
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.validated_attr_writer(attribute, validation_method)
|
|
47
|
+
define_method("#{attribute}=") do |value|
|
|
48
|
+
raise ArgumentError unless self.class.send(validation_method, value)
|
|
49
|
+
instance_variable_set("@#{attribute}", value)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
validated_attr_writer :first_name, :valid_name?
|
|
54
|
+
validated_attr_writer :last_name, :valid_name?
|
|
55
|
+
validated_attr_writer :patronymic, :valid_name?
|
|
56
|
+
validated_attr_writer :git, :valid_git?
|
|
57
|
+
|
|
58
|
+
def to_s
|
|
59
|
+
info = []
|
|
60
|
+
info << "ID: #{@id}" if @id
|
|
61
|
+
info << "Фамилия: #{@last_name}"
|
|
62
|
+
info << "Имя: #{@first_name}"
|
|
63
|
+
info << "Отчество: #{@patronymic}" if @patronymic
|
|
64
|
+
info << "Телефон: #{@phone}" if @phone
|
|
65
|
+
info << "Телеграм: #{@telegram}" if @telegram
|
|
66
|
+
info << "Почта: #{@email}" if @email
|
|
67
|
+
info << "Гит: #{@git}" if @git
|
|
68
|
+
info.join("\n")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.valid_name?(name)
|
|
72
|
+
name.nil? || name.is_a?(String) && name.match?(/^([А-ЯЁ][а-яё\-]+|[A-Z][a-z\-]+)$/)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.valid_phone?(phone)
|
|
76
|
+
phone.nil? || (phone.is_a?(String) && phone.match?(/^(\+7|8)?[\s\-\(]?(\d{3})[\s\-\)]?(\d{3})[\s\-]?(\d{2})[\s\-]?(\d{2})$/))
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def self.valid_telegram?(telegram)
|
|
80
|
+
telegram.nil? || (telegram.is_a?(String) && telegram.match?(/^@[a-zA-Z0-9_]{5,32}$/))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def self.valid_email?(email)
|
|
84
|
+
email.nil? || (email.is_a?(String) && email.match?(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.valid_git?(git)
|
|
88
|
+
git.nil? || (git.is_a?(String) && git.match?(/^https:\/\/(github|gitlab)\.com\/[a-zA-Z0-9_-]+\/?$/))
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def to_hash
|
|
93
|
+
hash = {
|
|
94
|
+
id: @id,
|
|
95
|
+
first_name: @first_name,
|
|
96
|
+
last_name: @last_name
|
|
97
|
+
}
|
|
98
|
+
hash[:patronymic] = @patronymic if @patronymic
|
|
99
|
+
hash[:phone] = @phone if @phone && !@phone.empty?
|
|
100
|
+
hash[:telegram] = @telegram if @telegram && !@telegram.empty?
|
|
101
|
+
hash[:email] = @email if @email && !@email.empty?
|
|
102
|
+
hash[:git] = @git if @git
|
|
103
|
+
hash
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def ==(other)
|
|
107
|
+
return false unless other.is_a?(Student)
|
|
108
|
+
@phone == other.instance_variable_get(:@phone) &&
|
|
109
|
+
@telegram == other.instance_variable_get(:@telegram) &&
|
|
110
|
+
@email == other.instance_variable_get(:@email) &&
|
|
111
|
+
@git == other.git
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require_relative 'student.rb'
|
|
2
|
+
require_relative 'super_student.rb'
|
|
3
|
+
|
|
4
|
+
class StudentShort < SuperStudent
|
|
5
|
+
attr_reader :id, :last_name_initials, :contact, :git
|
|
6
|
+
|
|
7
|
+
def initialize(id:, last_name_initials:, contact: nil, git: nil)
|
|
8
|
+
super(id: id, git: git)
|
|
9
|
+
@last_name_initials = last_name_initials
|
|
10
|
+
@contact = contact
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.from_student(student)
|
|
14
|
+
raise ArgumentError, "Отсутствует ID" unless student.id
|
|
15
|
+
new(
|
|
16
|
+
id: student.id,
|
|
17
|
+
last_name_initials: student.last_name_initials,
|
|
18
|
+
contact: student.contact,
|
|
19
|
+
git: student.git
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
def to_s
|
|
23
|
+
short_info
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
|
|
3
|
+
module StudentsListYaml
|
|
4
|
+
VERSION = "1.0.0"
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require_relative 'super_student'
|
|
8
|
+
require_relative 'student'
|
|
9
|
+
require_relative 'student_short'
|
|
10
|
+
require_relative 'data_table'
|
|
11
|
+
require_relative 'data_list'
|
|
12
|
+
require_relative 'data_list_student_short'
|
|
13
|
+
require_relative 'abstract_student_list'
|
|
14
|
+
|
|
15
|
+
class Students_list_YAML < AbstractStudentList
|
|
16
|
+
def initialize(path)
|
|
17
|
+
super(path)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def load_from_file(content)
|
|
23
|
+
array = YAML.safe_load(content, permitted_classes: [Symbol], symbolize_names: true)
|
|
24
|
+
raise RuntimeError, "Файл должен содержать YAML массив" unless array.is_a?(Array)
|
|
25
|
+
array
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def write_raw_array(array)
|
|
29
|
+
File.write(@path, array.to_yaml)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class SuperStudent
|
|
2
|
+
|
|
3
|
+
attr_reader :id, :git
|
|
4
|
+
|
|
5
|
+
def initialize(id: nil, git: nil)
|
|
6
|
+
@id = id
|
|
7
|
+
@git = git
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def short_info
|
|
11
|
+
info = []
|
|
12
|
+
info << "ID: #{id}" if id
|
|
13
|
+
info << "ФИО: #{last_name_initials}"
|
|
14
|
+
info << "Контакт: #{contact}" if contact
|
|
15
|
+
info << "Гит: #{git}" if git
|
|
16
|
+
info.join("\n")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def has_git?
|
|
20
|
+
!@git.nil? && !@git.empty?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def has_contact?
|
|
24
|
+
!contact.nil? && !contact.empty?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
protected
|
|
28
|
+
|
|
29
|
+
def last_name_initials
|
|
30
|
+
raise NotImplementedError
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def contact
|
|
34
|
+
raise NotImplementedError
|
|
35
|
+
end
|
|
36
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: students_list_yaml_ligostaev
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Ligostaev
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: Provides Students_list_YAML class for managing student data with YAML
|
|
13
|
+
persistence. Includes support for student records with validation, sorting, and
|
|
14
|
+
pagination.
|
|
15
|
+
email:
|
|
16
|
+
- contact@example.com
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- LICENSE
|
|
22
|
+
- README.md
|
|
23
|
+
- lib/abstract_student_list.rb
|
|
24
|
+
- lib/data_list.rb
|
|
25
|
+
- lib/data_list_student_short.rb
|
|
26
|
+
- lib/data_table.rb
|
|
27
|
+
- lib/student.rb
|
|
28
|
+
- lib/student_short.rb
|
|
29
|
+
- lib/students_list_yaml.rb
|
|
30
|
+
- lib/super_student.rb
|
|
31
|
+
homepage: https://github.com/ligostaev/students_list_yaml_gem
|
|
32
|
+
licenses:
|
|
33
|
+
- MIT
|
|
34
|
+
metadata: {}
|
|
35
|
+
rdoc_options: []
|
|
36
|
+
require_paths:
|
|
37
|
+
- lib
|
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
- - ">="
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '2.6'
|
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
requirements: []
|
|
49
|
+
rubygems_version: 3.7.1
|
|
50
|
+
specification_version: 4
|
|
51
|
+
summary: YAML-based storage for student lists
|
|
52
|
+
test_files: []
|