shnaider_code 1.1.6 → 2.0.1

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/lib/shnaider_code/version.rb +2 -2
  3. data/lib/shnaider_code.rb +1 -1
  4. data/lib/source/attr_limited_regex_accessor.rb +43 -0
  5. data/lib/source/controllers/create_student_controller.rb +8 -0
  6. data/lib/source/controllers/edit_student_controller.rb +10 -0
  7. data/lib/source/controllers/view_controller.rb +106 -0
  8. data/lib/source/data_construct_pattern/data_construct_pattarn.rb +25 -0
  9. data/lib/source/data_list.rb +59 -0
  10. data/lib/source/data_list_student_short.rb +28 -0
  11. data/lib/source/data_table.rb +21 -0
  12. data/lib/source/database/scripts/create_table.sql +10 -0
  13. data/lib/source/database/scripts/fill_data.sql +14 -0
  14. data/lib/source/database/students_db.rb +78 -0
  15. data/lib/source/database/students_list_db.rb +36 -0
  16. data/lib/source/student/abstract_student.rb +26 -0
  17. data/lib/source/student/student.rb +120 -0
  18. data/lib/source/student/student_short.rb +59 -0
  19. data/lib/source/student_list_format.rb +50 -0
  20. data/lib/source/students_list.rb +43 -0
  21. data/lib/source/students_list_adapter.rb +89 -0
  22. data/lib/source/students_list_format_strategy.rb +59 -0
  23. data/shnaider_code-2.0.0.gem +0 -0
  24. data/shnaider_code.gemspec +1 -1
  25. metadata +21 -25
  26. data/Gemfile +0 -13
  27. data/lib/source/controllers/student_input_form/student_input_form_controller_create.rb +0 -59
  28. data/lib/source/controllers/student_input_form/student_input_form_controller_edit.rb +0 -68
  29. data/lib/source/controllers/tab_students_controller.rb +0 -82
  30. data/lib/source/db_config/config.yaml +0 -5
  31. data/lib/source/db_config/migrations/001_create_table_student.sql +0 -12
  32. data/lib/source/db_config/mock_data/fill_student.sql +0 -6
  33. data/lib/source/models/student.rb +0 -103
  34. data/lib/source/models/student_base.rb +0 -100
  35. data/lib/source/models/student_short.rb +0 -50
  36. data/lib/source/repositories/adapters/db_source_adapter.rb +0 -54
  37. data/lib/source/repositories/adapters/file_source_adapter.rb +0 -37
  38. data/lib/source/repositories/containers/data_list.rb +0 -74
  39. data/lib/source/repositories/containers/data_list_student_short.rb +0 -18
  40. data/lib/source/repositories/containers/data_table.rb +0 -35
  41. data/lib/source/repositories/data_sources/db_data_source.rb +0 -37
  42. data/lib/source/repositories/data_sources/file_data_source.rb +0 -75
  43. data/lib/source/repositories/data_sources/transformers/data_transformer_base.rb +0 -15
  44. data/lib/source/repositories/data_sources/transformers/data_transformer_json.rb +0 -16
  45. data/lib/source/repositories/data_sources/transformers/data_transformer_yaml.rb +0 -16
  46. data/lib/source/repositories/student_repository.rb +0 -32
  47. data/lib/source/util/logger_holder.rb +0 -24
  48. data/shnaider_code-1.1.4.gem +0 -0
  49. data/sig/shnaider_code.rbs +0 -4
@@ -1,100 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class StudentBase
4
- # Запрещаем создание базового класса (он "абстрактный")
5
- private_class_method :new
6
-
7
- # Валидаторы для полей
8
- def self.valid_name?(name)
9
- name.match(/(^[А-Я][а-я]+$)|(^[A-Z][a-z]+$)/)
10
- end
11
-
12
- def self.valid_phone?(phone)
13
- phone.match(/^\+?[78] ?[(-]?\d{3} ?[)-]?[ -]?\d{3}[ -]?\d{2}[ -]?\d{2}$/)
14
- end
15
-
16
- def self.valid_profile_name?(profile_name)
17
- profile_name.match(/^[a-zA-Z0-9_.]+$/)
18
- end
19
-
20
- def self.valid_email?(email)
21
- email.match(/^(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/)
22
- end
23
-
24
- # Стандартные геттеры и сеттеры для полей
25
-
26
- protected
27
-
28
- attr_writer :id
29
- attr_reader :phone, :telegram, :email
30
-
31
- public
32
-
33
- attr_reader :id, :git
34
-
35
- # Стандартный конструктор
36
- def initialize(id: nil, phone: nil, telegram: nil, email: nil, git: nil)
37
- self.id = id
38
- self.phone = phone
39
- self.telegram = telegram
40
- self.email = email
41
- self.git = git
42
- end
43
-
44
- # Краткая информация о первом доступном контакте пользователя
45
- def short_contact
46
- contact = {}
47
- %i[telegram email phone].each do |attr|
48
- attr_val = send(attr)
49
- next if attr_val.nil?
50
-
51
- contact[:type] = attr
52
- contact[:value] = attr_val
53
- return contact
54
- end
55
-
56
- nil
57
- end
58
-
59
- protected
60
-
61
- # Сеттеры с валидацией перед присваиванием
62
- def phone=(new_phone)
63
- raise ArgumentError, "Invalid argument: phone=#{new_phone}" unless new_phone.nil? || StudentBase.valid_phone?(new_phone)
64
-
65
- @phone = new_phone
66
- end
67
-
68
- def telegram=(new_telegram)
69
- raise ArgumentError, "Invalid argument: telegram=#{new_telegram}" unless new_telegram.nil? || StudentBase.valid_profile_name?(new_telegram)
70
-
71
- @telegram = new_telegram
72
- end
73
-
74
- def git=(new_git)
75
- raise ArgumentError, "Invalid argument: git=#{new_git}" unless new_git.nil? || StudentBase.valid_profile_name?(new_git)
76
-
77
- @git = new_git
78
- end
79
-
80
- def email=(new_email)
81
- raise ArgumentError, "Invalid argument: email=#{new_email}" unless new_email.nil? || StudentBase.valid_email?(new_email)
82
-
83
- @email = new_email
84
- end
85
-
86
- public
87
-
88
- # Валидаторы объекта
89
- def has_contacts?
90
- !phone.nil? || !telegram.nil? || !email.nil?
91
- end
92
-
93
- def has_git?
94
- !git.nil?
95
- end
96
-
97
- def valid?
98
- has_contacts? && has_git?
99
- end
100
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class StudentShort < StudentBase
4
- # Делаем new предка публичным
5
- public_class_method :new
6
-
7
- # Стандартные геттеры и сеттеры
8
-
9
- private
10
-
11
- attr_writer :last_name_and_initials, :contact
12
-
13
- public
14
-
15
- attr_reader :last_name_and_initials, :contact
16
-
17
- # Конструктор из Student
18
- def self.from_student(student)
19
- raise ArgumentError, 'Student ID is required' if student.id.nil?
20
-
21
- StudentShort.new(student.id, student.short_info)
22
- end
23
-
24
- # Стандартный конструктор
25
- def initialize(id, info_str)
26
- params = JSON.parse(info_str, { symbolize_names: true })
27
- raise ArgumentError, 'Fields required: last_name_and_initials' if !params.key?(:last_name_and_initials) || params[:last_name_and_initials].nil?
28
-
29
- self.id = id
30
- self.last_name_and_initials = params[:last_name_and_initials]
31
- self.contact = params[:contact]
32
- self.git = params[:git]
33
-
34
- options = {}
35
- options[:id] = id
36
- options[:git] = git
37
- options[contact[:type].to_sym] = contact[:value] if contact
38
- super(**options)
39
- end
40
-
41
- # Методы приведения объекта к строке
42
- def to_s
43
- result = last_name_and_initials
44
- %i[id contact git].each do |attr|
45
- attr_val = send(attr)
46
- result += ", #{attr}=#{attr_val}" unless attr_val.nil?
47
- end
48
- result
49
- end
50
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'source/repositories/data_sources/db_data_source'
4
- require 'source/models/student'
5
- require 'source/models/student_short'
6
- require 'source/repositories/containers/data_list_student_short'
7
-
8
- class DBSourceAdapter
9
- def initialize
10
- @db = DBDataSource.instance
11
- end
12
-
13
- def student_by_id(student_id)
14
- hash = @db.prepare_exec('SELECT * FROM student WHERE id = ?', student_id).first
15
- return nil if hash.nil?
16
-
17
- Student.from_hash(hash)
18
- end
19
-
20
- def paginated_short_students(page, count, existing_data_list = nil)
21
- offset = (page - 1) * count
22
- students = @db.prepare_exec('SELECT * FROM student LIMIT ?, ?', offset, count)
23
- slice = students.map { |h| StudentShort.from_student(Student.from_hash(h)) }
24
- return DataListStudentShort.new(slice) if existing_data_list.nil?
25
-
26
- existing_data_list.replace_objects(slice)
27
- existing_data_list
28
- end
29
-
30
- def add_student(student)
31
- template = 'INSERT INTO student(last_name, first_name, father_name, phone, telegram, email, git) VALUES (?, ?, ?, ?, ?, ?, ?)'
32
- @db.prepare_exec(template, *student_fields(student))
33
- @db.query('SELECT LAST_INSERT_ID()').first.first[1]
34
- end
35
-
36
- def replace_student(student_id, student)
37
- template = 'UPDATE student SET last_name=?, first_name=?, father_name=?, phone=?, telegram=?, email=?, git=? WHERE id=?'
38
- @db.prepare_exec(template, *student_fields(student), student_id)
39
- end
40
-
41
- def remove_student(student_id)
42
- @db.prepare_exec('DELETE FROM student WHERE id = ?', student_id)
43
- end
44
-
45
- def student_count
46
- @db.query('SELECT COUNT(id) FROM student').first.first[1]
47
- end
48
-
49
- private
50
-
51
- def student_fields(student)
52
- [student.last_name, student.first_name, student.father_name, student.phone, student.telegram, student.email, student.git]
53
- end
54
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class FileSourceAdapter
4
- def initialize(data_transformer, file_path)
5
- @file_path = file_path
6
- @file_source = FileDataSource.new(data_transformer)
7
- @file_source.load_from_file(file_path)
8
- end
9
-
10
- def student_by_id(student_id)
11
- @file_source.student_by_id(student_id)
12
- end
13
-
14
- def paginated_short_students(page, count, existing_data_list = nil)
15
- @file_source.paginated_short_students(page, count, existing_data_list)
16
- end
17
-
18
- def add_student(student)
19
- added_id = @file_source.add_student(student)
20
- @file_source.save_to_file(@file_path)
21
- added_id
22
- end
23
-
24
- def replace_student(student_id, student)
25
- @file_source.replace_student(student_id, student)
26
- @file_source.save_to_file(@file_path)
27
- end
28
-
29
- def remove_student(student_id)
30
- @file_source.remove_student(student_id)
31
- @file_source.save_to_file(@file_path)
32
- end
33
-
34
- def student_count
35
- @file_source.student_count
36
- end
37
- end
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'source/repositories/containers/data_table'
4
-
5
- class DataList
6
- # Это "абстрактный" класс
7
- private_class_method :new
8
-
9
- attr_writer :objects
10
-
11
- # Конструктор, принимает массив любых объектов
12
- def initialize(objects)
13
- self.objects = objects
14
- @listeners = []
15
- end
16
-
17
- def add_listener(listener)
18
- @listeners << listener
19
- end
20
-
21
- def remove_listener(listener)
22
- @listeners.delete(listener)
23
- end
24
-
25
- def notify
26
- @listeners.each { |lst| lst.on_datalist_changed(data_table) }
27
- end
28
-
29
- # Выбрать элемент по номеру
30
- def select_element(number)
31
- self.selected_num = number < objects.size ? number : nil
32
- end
33
-
34
- def selected_id
35
- objects[selected_num].id
36
- end
37
-
38
- # Получить DataTable со всеми элементами.
39
- def data_table
40
- result = []
41
- counter = 0
42
- objects.each do |obj|
43
- row = []
44
- row << counter
45
- row.push(*table_fields(obj))
46
- result << row
47
- counter += 1
48
- end
49
- DataTable.new(result)
50
- end
51
-
52
- # Добавить элементы в конец списка
53
- def replace_objects(objects)
54
- self.objects = objects.dup
55
- notify
56
- end
57
-
58
- protected
59
-
60
- # Список значений полей для DataTable. Переопределить в наследниках
61
- def table_fields(_obj)
62
- []
63
- end
64
-
65
- # Имена атрибутов объектов по порядку. Переопределить в наследниках
66
- def column_names
67
- []
68
- end
69
-
70
- private
71
-
72
- attr_reader :objects
73
- attr_accessor :selected_num
74
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'data_list'
4
-
5
- class DataListStudentShort < DataList
6
- # Делаем приватный new предка публичным
7
- public_class_method :new
8
-
9
- def column_names
10
- ['Фамилия И. О.', 'Гит', 'Контакт']
11
- end
12
-
13
- protected
14
-
15
- def table_fields(obj)
16
- [obj.last_name_and_initials, obj.git, obj.contact]
17
- end
18
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class DataTable
4
- attr_reader :rows_count, :cols_count
5
-
6
- # Конструктор, принимает 2D Array
7
- def initialize(table)
8
- self.rows_count = table.size
9
- max_cols = 0
10
- table.each { |row| max_cols = row.size if row.size > max_cols }
11
- self.cols_count = max_cols
12
- self.table = table
13
- end
14
-
15
- # Получить значение в ячейке [row, col]
16
- def get_item(row, col)
17
- return nil if row >= rows_count
18
- return nil if col >= cols_count
19
-
20
- table[row][col].dup
21
- end
22
-
23
- def to_2d_array
24
- table.dup
25
- end
26
-
27
- def to_s
28
- "DataTable (#{rows_count}x#{cols_count})"
29
- end
30
-
31
- private
32
-
33
- attr_accessor :table
34
- attr_writer :rows_count, :cols_count
35
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'mysql2'
4
-
5
- class DBDataSource
6
- private_class_method :new
7
- @instance_mutex = Mutex.new
8
-
9
- def initialize
10
- #тут изменить путь к своему конфигу
11
- db_config = YAML.load_file('C:\Users\ASUS\Desktop\PatternsLabs\LabStudents\gemka\lib\source\db_config\config.yaml').transform_keys(&:to_sym)
12
- @client = Mysql2::Client.new(db_config)
13
- @client.query_options.merge!(symbolize_keys: true)
14
- end
15
-
16
- def self.instance
17
- return @instance if @instance
18
-
19
- @instance_mutex.synchronize do
20
- @instance ||= new
21
- end
22
-
23
- @instance
24
- end
25
-
26
- def prepare_exec(statement, *params)
27
- @client.prepare(statement).execute(*params)
28
- end
29
-
30
- def query(statement)
31
- @client.query(statement)
32
- end
33
-
34
- def last_id
35
- @client.last_id
36
- end
37
- end
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'source/models/student'
4
- require 'source/models/student_short'
5
- require 'source/repositories/containers/data_list_student_short'
6
-
7
- class FileDataSource
8
- attr_writer :data_transformer
9
-
10
- def initialize(data_transformer)
11
- self.students = []
12
- self.seq_id = 1
13
- self.data_transformer = data_transformer
14
- end
15
-
16
- def load_from_file(file_path)
17
- hash_list = data_transformer.str_to_hash_list(File.read(file_path))
18
- self.students = hash_list.map { |h| Student.from_hash(h) }
19
- update_seq_id
20
- end
21
-
22
- def save_to_file(file_path)
23
- hash_list = students.map(&:to_hash)
24
- File.write(file_path, data_transformer.hash_list_to_str(hash_list))
25
- end
26
-
27
- def student_by_id(student_id)
28
- students.detect { |s| s.id == student_id }
29
- end
30
-
31
- # Получить page по счету count элементов (страница начинается с 1)
32
- def paginated_short_students(page, count, existing_data_list = nil)
33
- offset = (page - 1) * count
34
- slice = students[offset, count].map { |s| StudentShort.from_student(s) }
35
-
36
- return DataListStudentShort.new(slice) if existing_data_list.nil?
37
-
38
- existing_data_list.replace_objects(slice)
39
- existing_data_list
40
- end
41
-
42
- def sorted
43
- students.sort_by(&:last_name_and_initials)
44
- end
45
-
46
- def add_student(student)
47
- student.id = seq_id
48
- students << student
49
- self.seq_id += 1
50
- student.id
51
- end
52
-
53
- def replace_student(student_id, student)
54
- idx = students.find_index { |s| s.id == student_id }
55
- students[idx] = student
56
- end
57
-
58
- def remove_student(student_id)
59
- students.reject! { |s| s.id == student_id }
60
- end
61
-
62
- def student_count
63
- students.count
64
- end
65
-
66
- private
67
-
68
- # Метод для актуализации seq_id
69
- def update_seq_id
70
- self.seq_id = students.max_by(&:id).id + 1
71
- end
72
-
73
- attr_reader :data_transformer
74
- attr_accessor :students, :seq_id
75
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class DataTransformerBase
4
- private_class_method :new
5
-
6
- protected
7
-
8
- def str_to_hash_list(str)
9
- raise NotImplementedError('Should be implemented in child')
10
- end
11
-
12
- def hash_list_to_str(hash_list)
13
- raise NotImplementedError('Should be implemented in child')
14
- end
15
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'data_transformer_base'
4
- require 'json'
5
-
6
- class DataTransformerJSON < DataTransformerBase
7
- public_class_method :new
8
-
9
- def str_to_hash_list(str)
10
- JSON.parse(str, { symbolize_names: true })
11
- end
12
-
13
- def hash_list_to_str(hash_list)
14
- JSON.pretty_generate(hash_list)
15
- end
16
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'data_transformer_base'
4
- require 'yaml'
5
-
6
- class DataTransformerYAML < DataTransformerBase
7
- public_class_method :new
8
-
9
- def str_to_hash_list(str)
10
- YAML.safe_load(str).map { |h| h.transform_keys(&:to_sym) }
11
- end
12
-
13
- def hash_list_to_str(hash_list)
14
- hash_list.map { |h| h.transform_keys(&:to_s) }.to_yaml
15
- end
16
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class StudentRepository
4
- def initialize(data_source_adapter)
5
- @data_source_adapter = data_source_adapter
6
- end
7
-
8
- def student_by_id(student_id)
9
- @data_source_adapter.student_by_id(student_id)
10
- end
11
-
12
- # Получить page по счету count элементов (страница начинается с 1)
13
- def paginated_short_students(page, count, existing_data_list = nil)
14
- @data_source_adapter.paginated_short_students(page, count, existing_data_list)
15
- end
16
-
17
- def add_student(student)
18
- @data_source_adapter.add_student(student)
19
- end
20
-
21
- def replace_student(student_id, student)
22
- @data_source_adapter.replace_student(student_id, student)
23
- end
24
-
25
- def remove_student(student_id)
26
- @data_source_adapter.remove_student(student_id)
27
- end
28
-
29
- def student_count
30
- @data_source_adapter.student_count
31
- end
32
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'logger'
4
-
5
- class LoggerHolder
6
- private_class_method :new
7
- @instance_mutex = Mutex.new
8
-
9
- attr_reader :logger
10
-
11
- def initialize
12
- @logger = Logger.new(STDOUT)
13
- end
14
-
15
- def self.instance
16
- return @instance.logger if @instance
17
-
18
- @instance_mutex.synchronize do
19
- @instance ||= new
20
- end
21
-
22
- @instance.logger
23
- end
24
- end
Binary file
@@ -1,4 +0,0 @@
1
- module Shnaider
2
- VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
- end