Compare commits
55 Commits
@ -0,0 +1 @@
|
|||||||
|
lab2/tests/students_test.txt
|
@ -1,16 +0,0 @@
|
|||||||
require_relative '../src/02_user_interface.rb'
|
|
||||||
|
|
||||||
RSpec.describe "Main" do
|
|
||||||
before do
|
|
||||||
allow(STDIN).to receive(:gets).and_return("ruby\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "greets the user and checks Ruby as language" do
|
|
||||||
expect { main() }.to output("Hello my catgirl test_user! \nWhat is your love language?\nruby\nc++\npy\nПодлиза \n").to_stdout
|
|
||||||
end
|
|
||||||
|
|
||||||
it "handles unknown language input" do
|
|
||||||
allow(STDIN).to receive(:gets).and_return("java\n")
|
|
||||||
expect { main() }.to output(/Неизвестный язык: java/).to_stdout
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,2 +0,0 @@
|
|||||||
puts "Hello, world!"
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
|||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
LANGUAGES = [
|
|
||||||
"ruby",
|
|
||||||
"c++",
|
|
||||||
"py"
|
|
||||||
]
|
|
||||||
|
|
||||||
def main()
|
|
||||||
user_name = ARGV[0]
|
|
||||||
puts "Hello my catgirl #{user_name}! \nWhat is your love language?"
|
|
||||||
LANGUAGES.each { |language| puts "#{language}", " " }
|
|
||||||
|
|
||||||
user_lang = STDIN.gets.chomp
|
|
||||||
|
|
||||||
case user_lang
|
|
||||||
when "ruby"
|
|
||||||
puts "Подлиза \n"
|
|
||||||
when "c++"
|
|
||||||
puts "MATLAB скушал? \n"
|
|
||||||
when "TS/JS"
|
|
||||||
puts "Фронтендер, Фууу! \n"
|
|
||||||
when "py"
|
|
||||||
puts "Девопсер, иди ДАГИ писать \n"
|
|
||||||
else
|
|
||||||
puts "Неизвестный язык: #{user_lang}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
main()
|
|
@ -1,39 +0,0 @@
|
|||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
LANGUAGES = [
|
|
||||||
"ruby",
|
|
||||||
"c++",
|
|
||||||
"py"
|
|
||||||
]
|
|
||||||
|
|
||||||
def main()
|
|
||||||
user_name = ARGV[0]
|
|
||||||
puts "Hello my catgirl #{user_name}! \nWhat is your love language?"
|
|
||||||
LANGUAGES.each { |language| puts "#{language}", " " }
|
|
||||||
|
|
||||||
user_lang = STDIN.gets.chomp
|
|
||||||
case user_lang
|
|
||||||
when "ruby"
|
|
||||||
puts "Подлиза \n"
|
|
||||||
when "c++"
|
|
||||||
puts "MATLAB скушал? \n"
|
|
||||||
when "TS/JS"
|
|
||||||
puts "Фронтендер, Фууу! \n"
|
|
||||||
when "py"
|
|
||||||
puts "Девопсер, иди ДАГИ писать \n"
|
|
||||||
end
|
|
||||||
|
|
||||||
puts "Введите команду на языке Ruby для выполнения:"
|
|
||||||
ruby_command = STDIN.gets.chomp
|
|
||||||
begin
|
|
||||||
eval(ruby_command)
|
|
||||||
rescue Exception => e
|
|
||||||
puts "Ошибка выполнения команды Ruby: #{e.message}"
|
|
||||||
end
|
|
||||||
|
|
||||||
puts "Введите команду операционной системы для выполнения:"
|
|
||||||
os_command = STDIN.gets.chomp
|
|
||||||
system(os_command)
|
|
||||||
end
|
|
||||||
|
|
||||||
main()
|
|
@ -1,68 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
def find_min_element_for(arr)
|
|
||||||
min_element = arr[0]
|
|
||||||
for element in arr
|
|
||||||
min_element = element if element < min_element
|
|
||||||
end
|
|
||||||
min_element
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def find_min_element_while(arr)
|
|
||||||
min_element = arr[0]
|
|
||||||
index = 0
|
|
||||||
while index < arr.size
|
|
||||||
min_element = arr[index] if arr[index] < min_element
|
|
||||||
index += 1
|
|
||||||
end
|
|
||||||
min_element
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def find_first_positive_index_for(arr)
|
|
||||||
for index in 0...arr.size
|
|
||||||
return index if arr[index] > 0
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def find_first_positive_index_while(arr)
|
|
||||||
index = 0
|
|
||||||
while index < arr.size
|
|
||||||
return index if arr[index] > 0
|
|
||||||
index += 1
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def find_first_positive_for(arr)
|
|
||||||
for element in arr
|
|
||||||
return element if element > 0
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def find_first_positive_while(arr)
|
|
||||||
index = 0
|
|
||||||
while index < arr.size
|
|
||||||
return arr[index] if arr[index] > 0
|
|
||||||
index += 1
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# INPUT
|
|
||||||
array = [-10, -5, 0, 3, 5, -2]
|
|
||||||
|
|
||||||
puts "Минимальный элемент (for): #{find_min_element_for(array)}"
|
|
||||||
puts "Минимальный элемент (while): #{find_min_element_while(array)}"
|
|
||||||
|
|
||||||
puts "Индекс первого положительного элемента (for): #{find_first_positive_index_for(array)}"
|
|
||||||
puts "Индекс первого положительного элемента (while): #{find_first_positive_index_while(array)}"
|
|
||||||
|
|
||||||
puts "Первый положительный элемент (for): #{find_first_positive_for(array)}"
|
|
||||||
puts "Первый положительный элемент (while): #{find_first_positive_while(array)}"
|
|
@ -1,62 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
def find_min_element(arr)
|
|
||||||
min_element = arr[0]
|
|
||||||
arr.each do |element|
|
|
||||||
min_element = element if element < min_element
|
|
||||||
end
|
|
||||||
min_element
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def find_first_positive_index(arr)
|
|
||||||
arr.each_with_index do |element, index|
|
|
||||||
return index if element > 0
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def find_first_positive(arr)
|
|
||||||
arr.each do |element|
|
|
||||||
return element if element > 0
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def main
|
|
||||||
method_name = ARGV[0]
|
|
||||||
file_path = ARGV[1]
|
|
||||||
|
|
||||||
if method_name.nil? || file_path.nil?
|
|
||||||
puts "Неправльный формат ввода. Использование: ruby program.rb <method_name> <file_path>"
|
|
||||||
puts "method_name: 'min', 'first_positive_index' или 'first_positive'"
|
|
||||||
exit
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
|
||||||
array = File.read(file_path).split.map(&:to_i)
|
|
||||||
rescue Errno::ENOENT
|
|
||||||
puts "Файл не найден: #{file_path}"
|
|
||||||
exit
|
|
||||||
end
|
|
||||||
|
|
||||||
case method_name
|
|
||||||
when 'min'
|
|
||||||
result = find_min_element(array)
|
|
||||||
puts "Минимальный элемент: #{result}"
|
|
||||||
when 'first_positive_index'
|
|
||||||
result = find_first_positive_index(array)
|
|
||||||
puts "Индекс первого положительного элемента: #{result.nil? ? 'Нет положительного элемента' : result}"
|
|
||||||
when 'first_positive'
|
|
||||||
result = find_first_positive(array)
|
|
||||||
puts "Первый положительный элемент: #{result.nil? ? 'Нет положительного элемента' : result}"
|
|
||||||
else
|
|
||||||
puts "Неизвестный метод: #{method_name}"
|
|
||||||
puts "Доступные методы: 'min', 'first_positive_index', 'first_positive'"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
main if __FILE__ == $0
|
|
@ -1 +0,0 @@
|
|||||||
-10 -5 0 3 5 -2
|
|
@ -1,4 +1,163 @@
|
|||||||
# Lab 2
|
# Lab 2
|
||||||
|
|
||||||
> "И тут я обнаружил что случайно сделал 3-5 задачи в 1-2"
|
|
||||||
|
## Диаграмма классов:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
classDiagram
|
||||||
|
class PersistenceStrategy {
|
||||||
|
+ load(filename : String) : Raise
|
||||||
|
+ save(filename : String, students : Students) : Raise
|
||||||
|
}
|
||||||
|
|
||||||
|
class StudentsListBase {
|
||||||
|
+ initialize(filename : String)
|
||||||
|
+ load_from_file() : Raise
|
||||||
|
+ save_to_file() : Raise
|
||||||
|
+ get_student_by_id(id : String) : Student
|
||||||
|
+ get_k_n_student_short_list(k : Int, n : Int, data_list = nil) : List<Student>
|
||||||
|
+ sort_students() : List<Student>
|
||||||
|
+ add_student(student : Student) : Student
|
||||||
|
+ update_student_by_id(id : Int, new_stodent : Student) : Bool
|
||||||
|
+ delete_student_by_id(id : Int)
|
||||||
|
+ get_student_short_count() : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class StudentsListDB {
|
||||||
|
+ initialize()
|
||||||
|
+ get_student_by_id(id : Int) : nil | Student
|
||||||
|
+ get_k_n_student_short_list(k : Int, n : Int) : List<Student>
|
||||||
|
+ add_student(student : Student) : Student
|
||||||
|
+ update_student_by_id(id : Int, new_student : Student)
|
||||||
|
+ delete_student_by_id(id : Int)
|
||||||
|
+ get_student_short_count() : Int
|
||||||
|
- row_to_student(row : Student)
|
||||||
|
- escape(value : any)
|
||||||
|
}
|
||||||
|
|
||||||
|
class JSONPersistenceStrategy {
|
||||||
|
+ load(filename : String) : List<>
|
||||||
|
+ save(filename : String, students : List<Student>)
|
||||||
|
- student_to_hash(student : Student)
|
||||||
|
- hash_to_student(hash : String)
|
||||||
|
}
|
||||||
|
|
||||||
|
class TXTPersistenceStrategy {
|
||||||
|
+ load(filename : String) : List<>
|
||||||
|
+ save(filename : String, students : List<Student>)
|
||||||
|
}
|
||||||
|
|
||||||
|
class YAMLPersistenceStrategy {
|
||||||
|
+ load(filename : String) : List<>
|
||||||
|
+ save(filename : String, students : List<Student>)
|
||||||
|
- student_to_hash(student : Student)
|
||||||
|
- hash_to_student(hash : String)
|
||||||
|
}
|
||||||
|
|
||||||
|
class StudentsList {
|
||||||
|
+ initialize(filename : String, persistence_strategy)
|
||||||
|
+ load() : self
|
||||||
|
+ save() : self
|
||||||
|
+ get_student_by_id(id : Int) : Student
|
||||||
|
+ get_k_n_student_short_list(k : Int, n : Int, data_list = nil) : DataListStudentShort
|
||||||
|
+ sort_students() : List<Student>
|
||||||
|
add_student(student : Student) : Student
|
||||||
|
+ update_student_by_id(id : Int, new_student : Student) : Bool
|
||||||
|
+ delete_student_by_id(id : Int) : Bool
|
||||||
|
+ get_student_short_count() : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class DatabaseConnection {
|
||||||
|
+ initialize()
|
||||||
|
+ client()
|
||||||
|
+ query(sql : String)
|
||||||
|
}
|
||||||
|
|
||||||
|
class BinarySearchTree {
|
||||||
|
- root : Node
|
||||||
|
+ add(student : Student) : void
|
||||||
|
+ each(&block) : void
|
||||||
|
- insert(node : Node, student : Student) : Node
|
||||||
|
- in_order_traversal(node : Node, &block) : void
|
||||||
|
}
|
||||||
|
|
||||||
|
class Node {
|
||||||
|
- student : Student
|
||||||
|
- left : Node
|
||||||
|
- right : Node
|
||||||
|
+ Node(student : Student)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Person {
|
||||||
|
- id : String
|
||||||
|
- git : String
|
||||||
|
- phone : String?
|
||||||
|
- telegram : String?
|
||||||
|
- email : String?
|
||||||
|
+ Person(id : String, git : String, phone: String, telegram: String, email: String)
|
||||||
|
+ phone=(String) : Boolean
|
||||||
|
+ telegram=(String) : Boolean
|
||||||
|
+ email=(String) : Boolean
|
||||||
|
+ surname_initials() : NotImplementedError
|
||||||
|
+ valid_phone_number() : Boolean <<class>>
|
||||||
|
+ valid_telegram() : Boolean <<class>>
|
||||||
|
+ valid_email() : Boolean <<class>>
|
||||||
|
+ git_present() : Boolean
|
||||||
|
+ contact_present() : Boolean
|
||||||
|
+ get_first_contact() : String
|
||||||
|
+ git=(git : String) : void
|
||||||
|
+ validate_id(id: String) : void <<class>>
|
||||||
|
+ validate_git(git : String) : void <<class>>
|
||||||
|
- valid_git?(git : String) : Boolean
|
||||||
|
- valid_id?(id : String) : Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
class StudentRepository {
|
||||||
|
+ read_from_txt(file_path : String) : List~Student~ <<class>>
|
||||||
|
+ write_to_txt(file_path : String, students : List~Student~) <<class>>
|
||||||
|
}
|
||||||
|
|
||||||
|
class StudentShort {
|
||||||
|
- surname_initials : String
|
||||||
|
+ get_surname_initials() : String
|
||||||
|
+ StudentShort(id : String, surname_initials : String, phone: String, telegram: String, email: String)
|
||||||
|
+ from_student(student : Student) : StudentShort <<class>>
|
||||||
|
+ from_string(id : String, info_string : String) : StudentShort <<class>>
|
||||||
|
+ to_s() : String
|
||||||
|
- parse_contact_string(contact_string: String) : Array<String> <<class>>
|
||||||
|
}
|
||||||
|
|
||||||
|
class Student {
|
||||||
|
- surname : String
|
||||||
|
- name : String
|
||||||
|
- patronymic : String
|
||||||
|
- birth_date : Date
|
||||||
|
- const NAME_REGEX : String
|
||||||
|
+ Student(id : String, git : String, phone: String, telegram: String, email: String, surname : String, name : String, patronymic : String, birth_date : Date)
|
||||||
|
+ from_string(student_string : String) : Student <<class>>
|
||||||
|
+ surname_initials() : String
|
||||||
|
+ to_s() : String
|
||||||
|
+ get_info() : String
|
||||||
|
+ surname=(surname : String)
|
||||||
|
+ name=(name : String)
|
||||||
|
+ patronymic=(patronymic : String)
|
||||||
|
+ birth_date=(birthdate : String)
|
||||||
|
+ valid_name?(name : String) : Boolean <<class>>
|
||||||
|
- name_initial(name : String) : String
|
||||||
|
- patronymic(patronymic : String) : String
|
||||||
|
}
|
||||||
|
|
||||||
|
BinarySearchTree o-- Node
|
||||||
|
Node o-- Student
|
||||||
|
StudentsList o-- Student
|
||||||
|
StudentsListBase o-- Student
|
||||||
|
StudentsListDB o-- DatabaseConnection
|
||||||
|
DatabaseConnection <.. Singleton
|
||||||
|
JSONPersistenceStrategy o-- PersistenceStrategy
|
||||||
|
TXTPersistenceStrategy o-- PersistenceStrategy
|
||||||
|
YAMLPersistenceStrategy o-- PersistenceStrategy
|
||||||
|
Person <|-- Student
|
||||||
|
Person <|-- StudentShort
|
||||||
|
Student <.. StudentRepository
|
||||||
|
```
|
||||||
|
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
class BinarySearchTree
|
||||||
|
include Enumerable
|
||||||
|
|
||||||
|
class Node
|
||||||
|
attr_accessor :student, :left, :right
|
||||||
|
|
||||||
|
def initialize(student)
|
||||||
|
@student = student
|
||||||
|
@left = nil
|
||||||
|
@right = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@root = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def add(student)
|
||||||
|
@root = insert(@root, student)
|
||||||
|
end
|
||||||
|
|
||||||
|
def each(&block)
|
||||||
|
in_order_traversal(@root, &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def insert(node, student)
|
||||||
|
return Node.new(student) if node.nil?
|
||||||
|
|
||||||
|
if student.birth_date < node.student.birth_date
|
||||||
|
node.left = insert(node.left, student)
|
||||||
|
else
|
||||||
|
node.right = insert(node.right, student)
|
||||||
|
end
|
||||||
|
node
|
||||||
|
end
|
||||||
|
|
||||||
|
def in_order_traversal(node, &block)
|
||||||
|
return if node.nil?
|
||||||
|
|
||||||
|
in_order_traversal(node.left, &block)
|
||||||
|
yield node.student
|
||||||
|
in_order_traversal(node.right, &block)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,20 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
container_name: mysql_container
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: rootpassword
|
||||||
|
MYSQL_DATABASE: project_db
|
||||||
|
MYSQL_USER: project_user
|
||||||
|
MYSQL_PASSWORD: project_password
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
volumes:
|
||||||
|
- mysql_data:/var/lib/mysql
|
||||||
|
- ./db/migrations:/docker-entrypoint-initdb.d # Автоматическая инициализация базы (скрипты миграций)
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql_data:
|
@ -0,0 +1,61 @@
|
|||||||
|
require_relative './data_table'
|
||||||
|
|
||||||
|
class DataListStudentShort < DataList
|
||||||
|
def initialize(items)
|
||||||
|
column_names = ['№', 'Фамилия и инициалы', 'Телефон', 'Telegram', 'Email']
|
||||||
|
filtered = items.select { |item| item.is_a?(StudentShort) }
|
||||||
|
super(filtered, column_names)
|
||||||
|
end
|
||||||
|
|
||||||
|
def items=(new_items)
|
||||||
|
filtered = new_items.select { |item| item.is_a?(StudentShort) }
|
||||||
|
@items = filtered.dup
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_names
|
||||||
|
column_names
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_data
|
||||||
|
data = prepare_table_data
|
||||||
|
DataTable.new(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def column_names
|
||||||
|
['№', 'Фамилия и инициалы', 'Телефон', 'Telegram', 'Email']
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_table_data
|
||||||
|
@items.each_with_index.map do |item, index|
|
||||||
|
prepare_row(item, index)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_row(item, index)
|
||||||
|
[
|
||||||
|
index + 1, # id
|
||||||
|
item.surname_initials, # Фамилия и инициалы
|
||||||
|
item.phone || '-', # Телефон (или прочерк)
|
||||||
|
item.telegram || '-', # Telegram (или прочерк)
|
||||||
|
item.email || '-' # Email (или прочерк)
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
def extract_surname_initials(item)
|
||||||
|
item.respond_to?(:surname_initials) ? item.surname_initials : 'N/A'
|
||||||
|
end
|
||||||
|
|
||||||
|
def extract_phone(item)
|
||||||
|
item.respond_to?(:phone) ? item.phone : nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def extract_telegram(item)
|
||||||
|
item.respond_to?(:telegram) ? item.telegram : nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def extract_email(item)
|
||||||
|
item.respond_to?(:email) ? item.email : nil
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,64 @@
|
|||||||
|
class DataTable
|
||||||
|
def initialize(data)
|
||||||
|
@data = data.map { |row| row.dup.freeze }.freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def item(row, col)
|
||||||
|
return nil unless valid_row?(row) && valid_col?(col)
|
||||||
|
@data[row][col]
|
||||||
|
end
|
||||||
|
|
||||||
|
def rows_count
|
||||||
|
@data.size
|
||||||
|
end
|
||||||
|
|
||||||
|
def columns_count
|
||||||
|
return 0 if @data.empty?
|
||||||
|
@data.first.size
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def valid_row?(row)
|
||||||
|
row.between?(0, rows_count - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_col?(col)
|
||||||
|
col.between?(0, columns_count - 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class DataList
|
||||||
|
def initialize(items, column_names = [])
|
||||||
|
@items = items.dup.freeze
|
||||||
|
@selected = []
|
||||||
|
@column_names = column_names
|
||||||
|
end
|
||||||
|
|
||||||
|
def select(number)
|
||||||
|
index = number.to_i
|
||||||
|
toggle_selection(index) if valid_index?(index)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_selected
|
||||||
|
@selected.dup
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_names
|
||||||
|
@column_names
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_data
|
||||||
|
raise NotImplementedError, "Implement this method in a subclass"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def valid_index?(index)
|
||||||
|
index.between?(0, @items.size - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def toggle_selection(index)
|
||||||
|
@selected.include?(index) ? @selected.delete(index) : @selected << index
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,11 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS student (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
git VARCHAR(255) NOT NULL,
|
||||||
|
surname VARCHAR(100) NOT NULL,
|
||||||
|
name VARCHAR(100) NOT NULL,
|
||||||
|
patronymic VARCHAR(100) NOT NULL,
|
||||||
|
birth_date DATE NOT NULL,
|
||||||
|
phone VARCHAR(20),
|
||||||
|
telegram VARCHAR(50),
|
||||||
|
email VARCHAR(100)
|
||||||
|
);
|
@ -0,0 +1,4 @@
|
|||||||
|
INSERT INTO student (git, surname, name, patronymic, birth_date, phone, telegram, email)
|
||||||
|
VALUES
|
||||||
|
('https://github.com/example', 'Иванов', 'Иван', 'Иванович', '2000-01-01', '+123456789', '@telegram', 'email@example.com'),
|
||||||
|
('https://github.com/example2', 'Петров', 'Петр', 'Петрович', '1999-05-15', '+987654321', '@petrov', 'petrov@example.com');
|
@ -0,0 +1,23 @@
|
|||||||
|
require 'mysql2'
|
||||||
|
require 'singleton'
|
||||||
|
|
||||||
|
class DatabaseConnection
|
||||||
|
include Singleton
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@client = Mysql2::Client.new(
|
||||||
|
host: 'localhost',
|
||||||
|
username: 'project_user',
|
||||||
|
password: 'project_password',
|
||||||
|
database: 'project_db'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def client
|
||||||
|
@client
|
||||||
|
end
|
||||||
|
|
||||||
|
def query(sql)
|
||||||
|
@client.query(sql)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,9 @@
|
|||||||
|
module PersistenceStrategy
|
||||||
|
def load(filename)
|
||||||
|
raise NotImplementedError, "Метод load должен быть реализован в стратегии"
|
||||||
|
end
|
||||||
|
|
||||||
|
def save(filename, students)
|
||||||
|
raise NotImplementedError, "Метод save должен быть реализован в стратегии"
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,87 @@
|
|||||||
|
require_relative '../student'
|
||||||
|
require_relative '../student_short'
|
||||||
|
require_relative '../data_list_student_short'
|
||||||
|
require_relative '../data_table'
|
||||||
|
|
||||||
|
class StudentsList
|
||||||
|
attr_reader :students
|
||||||
|
|
||||||
|
def initialize(filename, persistence_strategy)
|
||||||
|
@filename = filename
|
||||||
|
@persistence_strategy = persistence_strategy
|
||||||
|
@students = []
|
||||||
|
end
|
||||||
|
|
||||||
|
# Загрузка студентов через выбранную стратегию
|
||||||
|
def load
|
||||||
|
@students = @persistence_strategy.load(@filename)
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Сохранение студентов через выбранную стратегию
|
||||||
|
def save
|
||||||
|
@persistence_strategy.save(@filename, @students)
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_student_by_id(id)
|
||||||
|
@students.find { |s| s.id.to_s == id.to_s }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Получить список из k студентов (страница n) в виде объекта DataList
|
||||||
|
def get_k_n_student_short_list(k, n, data_list = nil)
|
||||||
|
start_index = (n - 1) * k
|
||||||
|
sorted_students = @students.sort_by { |s| s.surname_initials }
|
||||||
|
selected_students = sorted_students[start_index, k] || []
|
||||||
|
short_objects = selected_students.map { |s| StudentShort.from_student(s) }
|
||||||
|
|
||||||
|
if data_list && data_list.is_a?(DataList)
|
||||||
|
if data_list.respond_to?(:items=)
|
||||||
|
data_list.items = short_objects
|
||||||
|
else
|
||||||
|
data_list = DataListStudentShort.new(short_objects)
|
||||||
|
end
|
||||||
|
data_list
|
||||||
|
else
|
||||||
|
DataListStudentShort.new(short_objects)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Сортировка студентов по фамилии и инициалам
|
||||||
|
def sort_students!
|
||||||
|
@students.sort_by! { |s| s.surname_initials }
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_student(student)
|
||||||
|
new_id = if @students.empty?
|
||||||
|
1
|
||||||
|
else
|
||||||
|
max_id = @students.map { |s| s.id.to_i }.max
|
||||||
|
max_id + 1
|
||||||
|
end
|
||||||
|
student.id = new_id.to_s
|
||||||
|
@students << student
|
||||||
|
student
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_student_by_id(id, new_student)
|
||||||
|
index = @students.find_index { |s| s.id.to_s == id.to_s }
|
||||||
|
if index
|
||||||
|
new_student.id = @students[index].id
|
||||||
|
@students[index] = new_student
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_student_by_id(id)
|
||||||
|
initial_count = @students.size
|
||||||
|
@students.reject! { |s| s.id.to_s == id.to_s }
|
||||||
|
initial_count != @students.size
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_student_short_count
|
||||||
|
@students.size
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,84 @@
|
|||||||
|
require_relative '../student'
|
||||||
|
require_relative '../student_short'
|
||||||
|
require_relative '../data_list_student_short'
|
||||||
|
require_relative '../data_table'
|
||||||
|
|
||||||
|
class StudentsListBase
|
||||||
|
attr_reader :students
|
||||||
|
|
||||||
|
def initialize(filename)
|
||||||
|
@filename = filename
|
||||||
|
@students = []
|
||||||
|
end
|
||||||
|
|
||||||
|
# Абстрактный метод
|
||||||
|
def load_from_file
|
||||||
|
raise NotImplementedError, "Метод load_from_file должен быть реализован в подклассе"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Абстрактный метод
|
||||||
|
def save_to_file
|
||||||
|
raise NotImplementedError, "Метод save_to_file должен быть реализован в подклассе"
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_student_by_id(id)
|
||||||
|
@students.find { |s| s.id.to_s == id.to_s }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Получить список из k студентов (страница n) в виде объекта DataList
|
||||||
|
def get_k_n_student_short_list(k, n, data_list = nil)
|
||||||
|
start_index = (n - 1) * k
|
||||||
|
sorted_students = @students.sort_by { |s| s.surname_initials }
|
||||||
|
selected_students = sorted_students[start_index, k] || []
|
||||||
|
short_objects = selected_students.map { |s| StudentShort.from_student(s) }
|
||||||
|
|
||||||
|
if data_list && data_list.is_a?(DataList)
|
||||||
|
if data_list.respond_to?(:items=)
|
||||||
|
data_list.items = short_objects
|
||||||
|
else
|
||||||
|
data_list = DataListStudentShort.new(short_objects)
|
||||||
|
end
|
||||||
|
data_list
|
||||||
|
else
|
||||||
|
DataListStudentShort.new(short_objects)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Сортировать список студентов по ФамилияИнициалы
|
||||||
|
def sort_students!
|
||||||
|
@students.sort_by! { |s| s.surname_initials }
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_student(student)
|
||||||
|
new_id = if @students.empty?
|
||||||
|
1
|
||||||
|
else
|
||||||
|
max_id = @students.map { |s| s.id.to_i }.max
|
||||||
|
max_id + 1
|
||||||
|
end
|
||||||
|
student.id = new_id.to_s
|
||||||
|
@students << student
|
||||||
|
student
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_student_by_id(id, new_student)
|
||||||
|
index = @students.find_index { |s| s.id.to_s == id.to_s }
|
||||||
|
if index
|
||||||
|
new_student.id = @students[index].id
|
||||||
|
@students[index] = new_student
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_student_by_id(id)
|
||||||
|
initial_count = @students.size
|
||||||
|
@students.reject! { |s| s.id.to_s == id.to_s }
|
||||||
|
initial_count != @students.size
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_student_short_count
|
||||||
|
@students.size
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,96 @@
|
|||||||
|
require_relative '../db_connection'
|
||||||
|
require_relative '../student'
|
||||||
|
require_relative '../student_short'
|
||||||
|
require_relative '../data_list_student_short'
|
||||||
|
require 'date'
|
||||||
|
|
||||||
|
class StudentsListDB
|
||||||
|
def initialize
|
||||||
|
@db = DatabaseConnection.instance
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_student_by_id(id)
|
||||||
|
result = @db.query("SELECT * FROM student WHERE id = #{id} LIMIT 1")
|
||||||
|
row = result.first
|
||||||
|
row ? row_to_student(row) : nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_k_n_student_short_list(k, n)
|
||||||
|
offset = (n - 1) * k
|
||||||
|
results = @db.query("SELECT * FROM student ORDER BY surname, name, patronymic LIMIT #{k} OFFSET #{offset}")
|
||||||
|
student_shorts = results.map { |row| StudentShort.from_student(row_to_student(row)) }
|
||||||
|
DataListStudentShort.new(student_shorts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_student(student)
|
||||||
|
sql = <<~SQL
|
||||||
|
INSERT INTO student (git, surname, name, patronymic, birth_date, phone, telegram, email)
|
||||||
|
VALUES (
|
||||||
|
'#{escape(student.git)}',
|
||||||
|
'#{escape(student.surname)}',
|
||||||
|
'#{escape(student.name)}',
|
||||||
|
'#{escape(student.patronymic)}',
|
||||||
|
'#{student.birth_date}',
|
||||||
|
#{student.phone ? "'#{escape(student.phone)}'" : "NULL"},
|
||||||
|
#{student.telegram ? "'#{escape(student.telegram)}'" : "NULL"},
|
||||||
|
#{student.email ? "'#{escape(student.email)}'" : "NULL"}
|
||||||
|
)
|
||||||
|
SQL
|
||||||
|
|
||||||
|
@db.query(sql)
|
||||||
|
new_id = @db.query("SELECT LAST_INSERT_ID() as id").first['id']
|
||||||
|
student.id = new_id.to_s
|
||||||
|
student
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_student_by_id(id, new_student)
|
||||||
|
sql = <<~SQL
|
||||||
|
UPDATE student SET
|
||||||
|
git = '#{escape(new_student.git)}',
|
||||||
|
surname = '#{escape(new_student.surname)}',
|
||||||
|
name = '#{escape(new_student.name)}',
|
||||||
|
patronymic = '#{escape(new_student.patronymic)}',
|
||||||
|
birth_date = '#{new_student.birth_date}',
|
||||||
|
phone = #{new_student.phone ? "'#{escape(new_student.phone)}'" : "NULL"},
|
||||||
|
telegram = #{new_student.telegram ? "'#{escape(new_student.telegram)}'" : "NULL"},
|
||||||
|
email = #{new_student.email ? "'#{escape(new_student.email)}'" : "NULL"}
|
||||||
|
WHERE id = #{id}
|
||||||
|
SQL
|
||||||
|
|
||||||
|
@db.query(sql)
|
||||||
|
@db.client.affected_rows > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_student_by_id(id)
|
||||||
|
@db.query("DELETE FROM student WHERE id = #{id}")
|
||||||
|
@db.client.affected_rows > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_student_short_count
|
||||||
|
result = @db.query("SELECT COUNT(*) as count FROM student")
|
||||||
|
result.first['count']
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Преобразование строки результата в объект Student
|
||||||
|
|
||||||
|
def row_to_student(row)
|
||||||
|
Student.new(
|
||||||
|
id: row['id'].to_s,
|
||||||
|
git: row['git'],
|
||||||
|
surname: row['surname'],
|
||||||
|
name: row['name'],
|
||||||
|
patronymic: row['patronymic'],
|
||||||
|
birth_date: Date.parse(row['birth_date'].to_s),
|
||||||
|
phone: row['phone'],
|
||||||
|
telegram: row['telegram'],
|
||||||
|
email: row['email']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Метод для экранирования строк
|
||||||
|
def escape(value)
|
||||||
|
@db.client.escape(value.to_s)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,62 @@
|
|||||||
|
require 'json'
|
||||||
|
require 'date'
|
||||||
|
require_relative '../student'
|
||||||
|
require_relative 'persistence_strategy'
|
||||||
|
|
||||||
|
class JSONPersistenceStrategy
|
||||||
|
include PersistenceStrategy
|
||||||
|
|
||||||
|
def load(filename)
|
||||||
|
if File.exist?(filename)
|
||||||
|
file_content = File.read(filename)
|
||||||
|
begin
|
||||||
|
data = JSON.parse(file_content)
|
||||||
|
data.map { |student_hash| hash_to_student(student_hash) }
|
||||||
|
rescue JSON::ParserError => e
|
||||||
|
warn "Ошибка парсинга JSON: #{e.message}"
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def save(filename, students)
|
||||||
|
data = students.map { |student| student_to_hash(student) }
|
||||||
|
File.open(filename, 'w') do |file|
|
||||||
|
file.write(JSON.pretty_generate(data))
|
||||||
|
end
|
||||||
|
rescue IOError => e
|
||||||
|
warn "Ошибка при записи в файл: #{e.message}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def student_to_hash(student)
|
||||||
|
{
|
||||||
|
'id' => student.id,
|
||||||
|
'git' => student.git,
|
||||||
|
'surname' => student.surname,
|
||||||
|
'name' => student.name,
|
||||||
|
'patronymic' => student.patronymic,
|
||||||
|
'birth_date' => student.birth_date.to_s,
|
||||||
|
'phone' => student.phone,
|
||||||
|
'telegram' => student.telegram,
|
||||||
|
'email' => student.email
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def hash_to_student(hash)
|
||||||
|
Student.new(
|
||||||
|
id: hash['id'],
|
||||||
|
git: hash['git'],
|
||||||
|
surname: hash['surname'],
|
||||||
|
name: hash['name'],
|
||||||
|
patronymic: hash['patronymic'],
|
||||||
|
birth_date: Date.parse(hash['birth_date']),
|
||||||
|
phone: hash['phone'],
|
||||||
|
telegram: hash['telegram'],
|
||||||
|
email: hash['email']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,33 @@
|
|||||||
|
require_relative '../student'
|
||||||
|
require_relative 'persistence_strategy'
|
||||||
|
|
||||||
|
class TXTPersistenceStrategy
|
||||||
|
include PersistenceStrategy
|
||||||
|
|
||||||
|
def load(filename)
|
||||||
|
if File.exist?(filename)
|
||||||
|
File.open(filename, 'r') do |file|
|
||||||
|
file.each_line.map do |line|
|
||||||
|
line.strip!
|
||||||
|
next if line.empty?
|
||||||
|
begin
|
||||||
|
Student.from_string(line)
|
||||||
|
rescue ArgumentError => e
|
||||||
|
warn "Ошибка при парсинге строки: #{line}. #{e.message}"
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end.compact
|
||||||
|
end
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def save(filename, students)
|
||||||
|
File.open(filename, 'w') do |file|
|
||||||
|
students.each do |student|
|
||||||
|
file.puts student.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,61 @@
|
|||||||
|
require 'yaml'
|
||||||
|
require 'date'
|
||||||
|
require_relative '../student'
|
||||||
|
require_relative 'persistence_strategy'
|
||||||
|
|
||||||
|
class YAMLPersistenceStrategy
|
||||||
|
include PersistenceStrategy
|
||||||
|
|
||||||
|
def load(filename)
|
||||||
|
if File.exist?(filename)
|
||||||
|
begin
|
||||||
|
data = YAML.load_file(filename)
|
||||||
|
data.map { |student_hash| hash_to_student(student_hash) }
|
||||||
|
rescue StandardError => e
|
||||||
|
warn "Ошибка при загрузке YAML: #{e.message}"
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def save(filename, students)
|
||||||
|
data = students.map { |student| student_to_hash(student) }
|
||||||
|
File.open(filename, 'w') do |file|
|
||||||
|
file.write(data.to_yaml)
|
||||||
|
end
|
||||||
|
rescue IOError => e
|
||||||
|
warn "Ошибка при записи в YAML: #{e.message}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def student_to_hash(student)
|
||||||
|
{
|
||||||
|
'id' => student.id,
|
||||||
|
'git' => student.git,
|
||||||
|
'surname' => student.surname,
|
||||||
|
'name' => student.name,
|
||||||
|
'patronymic' => student.patronymic,
|
||||||
|
'birth_date' => student.birth_date.to_s,
|
||||||
|
'phone' => student.phone,
|
||||||
|
'telegram' => student.telegram,
|
||||||
|
'email' => student.email
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def hash_to_student(hash)
|
||||||
|
Student.new(
|
||||||
|
id: hash['id'],
|
||||||
|
git: hash['git'],
|
||||||
|
surname: hash['surname'],
|
||||||
|
name: hash['name'],
|
||||||
|
patronymic: hash['patronymic'],
|
||||||
|
birth_date: Date.parse(hash['birth_date']),
|
||||||
|
phone: hash['phone'],
|
||||||
|
telegram: hash['telegram'],
|
||||||
|
email: hash['email']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,39 @@
|
|||||||
|
require_relative 'student'
|
||||||
|
|
||||||
|
class StudentRepository
|
||||||
|
def self.read_from_txt(file_path)
|
||||||
|
raise IOError, "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 = Student.from_string(line)
|
||||||
|
students << student
|
||||||
|
rescue ArgumentError => e
|
||||||
|
puts "Error processing line: '#{line}'. Reason: #{e.message}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
students
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.write_to_txt(file_path, students)
|
||||||
|
unless students.is_a?(Array) && students.all? { |s| s.is_a?(Student) }
|
||||||
|
raise ArgumentError, 'Expected an array of Student objects'
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
end
|
@ -1,31 +1,59 @@
|
|||||||
require_relative 'person'
|
require_relative 'person'
|
||||||
|
|
||||||
class StudentShort < Person
|
class StudentShort < Person
|
||||||
attr_reader :surname_initials, :contact
|
attr_reader :surname_initials
|
||||||
|
|
||||||
def initialize(student)
|
def initialize(id:, surname_initials:, phone: nil, telegram: nil, email: nil)
|
||||||
super(id: student.id, git: student.git_info)
|
super(id: id, phone: phone, telegram: telegram, email: email)
|
||||||
@surname_initials = student.surname_and_initials
|
@surname_initials = surname_initials
|
||||||
@contact = student.contact_info
|
freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_student(student)
|
||||||
|
new(
|
||||||
|
id: student.id,
|
||||||
|
surname_initials: student.surname_initials,
|
||||||
|
phone: student.phone,
|
||||||
|
telegram: student.telegram,
|
||||||
|
email: student.email
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.from_string(id, info_string)
|
def self.from_string(id, info_string)
|
||||||
parts = info_string.split(', ').map(&:strip)
|
parts = info_string.split(',').map(&:strip)
|
||||||
|
raise ArgumentError, 'Invalid info string format' if parts.size < 2
|
||||||
|
|
||||||
surname_initials = parts[0]
|
surname_initials = parts[0]
|
||||||
git = parts[1].split(': ').last
|
contact_string = parts[1].split(': ', 2).last.strip
|
||||||
contact = parts[2].split(': ').last
|
|
||||||
|
phone, telegram, email = parse_contact_string(contact_string)
|
||||||
|
|
||||||
new_instance = allocate
|
new(
|
||||||
new_instance.send(:initialize_from_data, id, surname_initials, git, contact)
|
id: id,
|
||||||
new_instance
|
surname_initials: surname_initials,
|
||||||
|
phone: phone,
|
||||||
|
telegram: telegram,
|
||||||
|
email: email
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
contact_info = get_first_contact()
|
||||||
|
"#{@surname_initials}, Contact: #{contact_info}"
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def initialize_from_data(id, surname_initials, git, contact)
|
def self.parse_contact_string(contact_string)
|
||||||
@id = id
|
case contact_string
|
||||||
@surname_initials = surname_initials
|
when /\APhone: (.+)\z/i
|
||||||
@git = git
|
[Regexp.last_match(1).strip, nil, nil]
|
||||||
@contact = contact
|
when /\ATelegram: (.+)\z/i
|
||||||
|
[nil, Regexp.last_match(1).strip, nil]
|
||||||
|
when /\AEmail: (.+)\z/i
|
||||||
|
[nil, nil, Regexp.last_match(1).strip]
|
||||||
|
else
|
||||||
|
raise ArgumentError, "Invalid contact string format: #{contact_string}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -0,0 +1,39 @@
|
|||||||
|
require_relative '../data_table'
|
||||||
|
|
||||||
|
data = [
|
||||||
|
[1, "Alice", 25],
|
||||||
|
[2, "Bob", 30],
|
||||||
|
[3, "Charlie", 35]
|
||||||
|
]
|
||||||
|
|
||||||
|
data_table = DataTable.new(data)
|
||||||
|
|
||||||
|
puts "Количество строк: #{data_table.rows_count}" # Ожидаем 3
|
||||||
|
puts "Количество столбцов: #{data_table.columns_count}" # Ожидаем 3
|
||||||
|
puts "Элемент в строке 1, столбце 2: #{data_table.item(1, 2)}" # Ожидаем 30
|
||||||
|
puts "Элемент в строке 0, столбце 1: #{data_table.item(0, 1)}" # Ожидаем "Alice"
|
||||||
|
puts "Элемент за пределами таблицы: #{data_table.item(10, 10)}" # Ожидаем nil
|
||||||
|
|
||||||
|
items = [
|
||||||
|
{ id: 1, name: "Alice", age: 25 },
|
||||||
|
{ id: 2, name: "Bob", age: 30 },
|
||||||
|
{ id: 3, name: "Charlie", age: 35 }
|
||||||
|
]
|
||||||
|
|
||||||
|
data_list = DataList.new(items)
|
||||||
|
|
||||||
|
data_list.select(0)
|
||||||
|
data_list.select(2)
|
||||||
|
puts "Выбранные элементы: #{data_list.get_selected.inspect}"
|
||||||
|
|
||||||
|
begin
|
||||||
|
data_list.get_names
|
||||||
|
rescue NotImplementedError => e
|
||||||
|
puts "Ошибка: #{e.message}" # Ожидаем "Implement this method in a subclass"
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
data_list.get_data
|
||||||
|
rescue NotImplementedError => e
|
||||||
|
puts "Ошибка: #{e.message}" # Ожидаем "Implement this method in a subclass"
|
||||||
|
end
|
Loading…
Reference in new issue