From 10362d3aaf5c58c4b5451c296e4915d0c3b8fc39 Mon Sep 17 00:00:00 2001 From: Artem Darius Weber Date: Sat, 21 Sep 2024 15:22:45 +0300 Subject: [PATCH 01/10] ref: delete lab1 code from lab2 branch --- lab1/README.md | 67 ------------------- lab1/spec/spec_02.rb | 16 ----- lab1/spec/spec_03.rb | 34 ---------- lab1/src/01_hello_world.rb | 2 - lab1/src/02_user_interface.rb | 30 --------- .../03_fork_02_with_exec_pasted_command.rb | 39 ----------- lab1/src/04_number_funcs.rb | 67 ------------------- 7 files changed, 255 deletions(-) delete mode 100644 lab1/README.md delete mode 100644 lab1/spec/spec_02.rb delete mode 100644 lab1/spec/spec_03.rb delete mode 100644 lab1/src/01_hello_world.rb delete mode 100644 lab1/src/02_user_interface.rb delete mode 100644 lab1/src/03_fork_02_with_exec_pasted_command.rb delete mode 100644 lab1/src/04_number_funcs.rb diff --git a/lab1/README.md b/lab1/README.md deleted file mode 100644 index 21c405d..0000000 --- a/lab1/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# Lab 1 - ---- - -## 01. Hello world - -Task: - -Установить компилятор и текстовый редактор. Реализовать и -вызвать Hello World c комментарием. (ну как всегда) - -```bash -ruby 01_hello_world.rb -``` - -Returns: - -``` -Hello, world! -``` - -## 02. User interface - -Task: - -Принять имя пользователя как аргумент программы. -Поздороваться с пользователем с использованием форматирования -строки. Спросить какой язык у пользователя любимый, в случае, если это -ruby, ответить что пользователь подлиза, иначе обязательно ответить, что -скоро будет ruby и поставить различные комментарии для нескольких -языков. - -```bash -ruby 02_user_interface.rb darius -``` - -## 03. User interface with ruby and os commands execution - -Task: - -3.Продолжение предыдущего задания. Попросить пользователя -ввести команду языка ruby. И команду OC. Выполнить команду руби и -команду операционной системы. - -```bash -ruby 03_fork_02_with_exec_pasted_command.rb darius -``` - -## 04. Number funcations - -Task: - -«Работа с числами». Составить 3 метода для работы с цифрами или делителей числа на основании варианта. Каждый метод отдельный коммит. - -- Метод 1. Найти количество четных чисел, не взаимно простых с данным -- Метод 2. Найти максимальную цифры числа, не делящуюся на 3. -- Метод 3. Найти произведение максимального числа, не взаимно простого с данным, не делящегося на наименьший делитель исходно числа, и суммы цифр числа, меньших 5. - -```bash -ruby 04_number_funcs.rb -``` - ---- - -Author: Artem-Darius Weber - -Licence: MIT \ No newline at end of file diff --git a/lab1/spec/spec_02.rb b/lab1/spec/spec_02.rb deleted file mode 100644 index 44080ff..0000000 --- a/lab1/spec/spec_02.rb +++ /dev/null @@ -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 \ No newline at end of file diff --git a/lab1/spec/spec_03.rb b/lab1/spec/spec_03.rb deleted file mode 100644 index 434b534..0000000 --- a/lab1/spec/spec_03.rb +++ /dev/null @@ -1,34 +0,0 @@ -require_relative '../src/03_fork_02_with_exec_pasted_command.rb' - -RSpec.describe "Main" do - before do - allow(STDIN).to receive(:gets).and_return("ruby\n", "puts 'Hello from Ruby!'\n", "echo 'Hello from shell!'\n") - allow(ARGV).to receive(:[]).with(0).and_return("test_user") - end - - it "greets the user and processes ruby input" do - expect { main() }.to output(/Hello my catgirl test_user! \nWhat is your love language?\nruby\nc++\npy\nПодлиза \n/).to_stdout - end - - it "executes valid ruby command" do - allow(STDIN).to receive(:gets).and_return("ruby\n", "puts 'Hello from Ruby!'\n") - - expect { main() }.to output(/Hello from Ruby!/).to_stdout - end - - it "handles ruby command execution error" do - allow(STDIN).to receive(:gets).and_return("ruby\n", "invalid_ruby_code\n") - - expect { main() }.to output(/Ошибка выполнения команды Ruby: undefined local variable or method `invalid_ruby_code'/).to_stdout - end - - it "executes shell command" do - allow(STDIN).to receive(:gets).and_return("ruby\n", "puts 'Hello from Ruby!'\n", "echo 'Hello from shell!'\n") - expect(main()).to include("Hello from shell!") - end - - it "returns correct output for unknown programming language" do - allow(STDIN).to receive(:gets).and_return("java\n") - expect { main() }.to output(/Неизвестный язык: java/).to_stdout - end -end diff --git a/lab1/src/01_hello_world.rb b/lab1/src/01_hello_world.rb deleted file mode 100644 index 717d507..0000000 --- a/lab1/src/01_hello_world.rb +++ /dev/null @@ -1,2 +0,0 @@ -puts "Hello, world!" - diff --git a/lab1/src/02_user_interface.rb b/lab1/src/02_user_interface.rb deleted file mode 100644 index f68737b..0000000 --- a/lab1/src/02_user_interface.rb +++ /dev/null @@ -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() diff --git a/lab1/src/03_fork_02_with_exec_pasted_command.rb b/lab1/src/03_fork_02_with_exec_pasted_command.rb deleted file mode 100644 index 3d05635..0000000 --- a/lab1/src/03_fork_02_with_exec_pasted_command.rb +++ /dev/null @@ -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() diff --git a/lab1/src/04_number_funcs.rb b/lab1/src/04_number_funcs.rb deleted file mode 100644 index 588e2ec..0000000 --- a/lab1/src/04_number_funcs.rb +++ /dev/null @@ -1,67 +0,0 @@ -require 'prime' - - - - -# @param n [Integer] Число, для которого нужно найти количество четных, не взаимно простых чисел. -# @return [Integer] Количество четных чисел, не взаимно простых с данным числом. -# @example -# count_even_non_coprimes(30) # => 14 -def count_even_non_coprimes(n) - (1...n).count do |num| - num.even? && n.gcd(num) != 1 - end -end - - -# @param n [Integer] Число, цифры которого нужно проверить. -# @return [Integer, nil] Максимальная цифра числа, не делящаяся на 3, или nil, если таких цифр нет. -# @example -# max_digit_not_divisible_by_three(483726) # => 8 -def max_digit_not_divisible_by_three(n) - n.digits.select { |digit| digit % 3 != 0 }.max -end - - -# @param n [Integer] Число, для которого нужно найти наименьший делитель. -# @return [Integer] Наименьший делитель числа. -# @example -# smallest_divisor(30) # => 2 -def smallest_divisor(n) - (2..n).find { |i| n % i == 0 } -end - - -# @param n [Integer] Число, для которого нужно найти подходящее максимальное число. -# @return [Integer, nil] Максимальное число, не взаимно простое с данным, не делящееся на наименьший делитель, или nil, если таких чисел нет. -# @example -# max_non_coprime_not_divisible_by_smallest_divisor(30) # => 28 -def max_non_coprime_not_divisible_by_smallest_divisor(n) - divisor = smallest_divisor(n) - (1...n).select { |num| n.gcd(num) != 1 && num % divisor != 0 }.max -end - - -# @param n [Integer] Число, цифры которого нужно просуммировать. -# @return [Integer] Сумма цифр числа, меньших 5. -# @example -# sum_of_digits_less_than_five(483726) # => 9 -def sum_of_digits_less_than_five(n) - n.digits.select { |digit| digit < 5 }.sum -end - - -# @param n [Integer] Число, для которого проводится вычисление. -# @return [Integer] Произведение максимального числа и суммы цифр числа. -# @example -# product_of_max_and_sum(30) # => 252 -def product_of_max_and_sum(n) - max_number = max_non_coprime_not_divisible_by_smallest_divisor(n) - sum_digits = sum_of_digits_less_than_five(n) - max_number * sum_digits -end - - -puts count_even_non_coprimes(30) # => 14 -puts max_digit_not_divisible_by_three(483726) # => 8 -puts product_of_max_and_sum(30) # => 252 From fca36ccd9d67fd5fecc4fc6dc9bacf7c26e38355 Mon Sep 17 00:00:00 2001 From: Artem Darius Weber Date: Sat, 21 Sep 2024 16:21:02 +0300 Subject: [PATCH 02/10] feat: add field validations to Student class and modify constructor - Added class methods to validate the format of strings for each field: - `valid_name?` for surname, name, and patronymic (only letters allowed). - `valid_phone_number?` for phone number (validates 10-15 digits, optional '+' sign). - `valid_telegram?` for telegram handle (starts with '@' and allows letters, digits, and underscores). - `valid_email?` for email (standard email format validation). - `valid_git?` for Git link (validates GitHub URL format). - Modified the `initialize` constructor: - Integrated validations for all fields with descriptive error messages. - Ensured objects cannot be created with invalid data formats. --- lab2/student.rb | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/lab2/student.rb b/lab2/student.rb index 14f5464..99d3793 100644 --- a/lab2/student.rb +++ b/lab2/student.rb @@ -5,10 +5,31 @@ class Student phone.match?(/\A\+?[0-9]{10,15}\z/) end + def self.valid_name?(name) + name.match?(/\A[А-Яа-яЁёA-Za-z\-]+\z/) + end + + def self.valid_telegram?(telegram) + telegram.nil? || telegram.match?(/\A@[A-Za-z0-9_]{5,32}\z/) + end + + def self.valid_email?(email) + email.nil? || email.match?(/\A[^@\s]+@[^@\s]+\.[^@\s]+\z/) + end + + def self.valid_git?(git) + git.nil? || git.match?(/\Ahttps:\/\/github\.com\/[A-Za-z0-9_\-]+\z/) + end + def initialize(args = {}) @surname = args.fetch(:surname) + raise ArgumentError, "Invalid surname format: #{@surname}" unless Student.valid_name?(@surname) + @name = args.fetch(:name) + raise ArgumentError, "Invalid name format: #{@name}" unless Student.valid_name?(@name) + @patronymic = args.fetch(:patronymic) + raise ArgumentError, "Invalid patronymic format: #{@patronymic}" unless Student.valid_name?(@patronymic) @id = args[:id] || nil @@ -16,10 +37,15 @@ class Student if @phone && !Student.valid_phone_number?(@phone) raise ArgumentError, "Invalid phone number format: #{@phone}" end - - @telegram = args[:telegram] || nil - @email = args[:email] || nil - @git = args[:git] || nil + + @telegram = args[:telegram] + raise ArgumentError, "Invalid telegram format: #{@telegram}" unless Student.valid_telegram?(@telegram) + + @email = args[:email] + raise ArgumentError, "Invalid email format: #{@email}" unless Student.valid_email?(@email) + + @git = args[:git] + raise ArgumentError, "Invalid git format: #{@git}" unless Student.valid_git?(@git) end def to_s @@ -30,4 +56,4 @@ class Student "Email: #{@email || 'N/A'}\n" \ "Git: #{@git || 'N/A'}" end - end \ No newline at end of file +end \ No newline at end of file From c1ca0ea8459f1d202d5a0e058ce1e62d7eacc8dd Mon Sep 17 00:00:00 2001 From: Artem Darius Weber Date: Sat, 21 Sep 2024 16:24:24 +0300 Subject: [PATCH 03/10] feat: add validation methods for Git link and contact presence - Added `validate` method to ensure each Student object has a Git link and at least one contact method (phone, telegram, or email). - Implemented `git_present?` method to check the presence of a Git link. - Implemented `contact_present?` method to check the presence of at least one contact method. - Modified the constructor to call `validate` during object initialization. --- lab2/student.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lab2/student.rb b/lab2/student.rb index 99d3793..e351eb7 100644 --- a/lab2/student.rb +++ b/lab2/student.rb @@ -46,6 +46,21 @@ class Student @git = args[:git] raise ArgumentError, "Invalid git format: #{@git}" unless Student.valid_git?(@git) + + validate + end + + def git_present? + !@git.nil? && !@git.empty? + end + + def contact_present? + !(@phone.nil? || @phone.empty?) || !(@telegram.nil? || @telegram.empty?) || !(@email.nil? || @email.empty?) + end + + def validate + raise ArgumentError, "Git link is required" unless git_present? + raise ArgumentError, "At least one contact (phone, telegram, or email) is required" unless contact_present? end def to_s From 1407d3e6fdf49adb29a7b66965391d43deef6ac8 Mon Sep 17 00:00:00 2001 From: Artem Darius Weber Date: Sat, 21 Sep 2024 16:29:55 +0300 Subject: [PATCH 04/10] feat: Add contact validation and secure modification for Student class - Implemented `set_contacts` method to safely set phone, telegram, and email fields. - Made contact fields (`phone`, `telegram`, `email`) private and accessible only through `set_contacts`. - Added validation within `set_contacts` to ensure contact fields are correctly formatted. - Modified the `initialize` method to utilize `set_contacts` for setting contact values during object creation. - Added checks in the `validate` method to ensure Git presence and at least one contact method. - Updated test cases in `main.rb` to demonstrate correct and incorrect uses of contact modifications. - Ensured that contact fields cannot be modified directly, maintaining data integrity. --- lab2/main.rb | 46 ++++++++++--------- lab2/student.rb | 116 ++++++++++++++++++++++++++---------------------- 2 files changed, 90 insertions(+), 72 deletions(-) diff --git a/lab2/main.rb b/lab2/main.rb index b426934..8233460 100644 --- a/lab2/main.rb +++ b/lab2/main.rb @@ -1,27 +1,33 @@ require_relative 'student' begin - student1 = Student.new( - surname: 'Алексеевич', - name: 'Артем-Дариус', - patronymic: 'Вебер', - id: 1, - phone: '+79891242223', - telegram: '@alstroemeria22', - email: 'no-replay@djft.ru', - git: 'https://git.djft.ru' - ) + student1 = Student.new( + surname: 'Алексеевич', + name: 'Артем-Дариус', + patronymic: 'Вебер', + id: 1, + git: 'https://git.djft.ru' + ) - student2 = Student.new( - surname: 'nil', - name: 'Норакет', - patronymic: 'nil' - ) + student1.set_contacts( + phone: '+79891242223', + telegram: '@alstroemeria22', + email: 'no-replay@djft.ru' + ) - puts student1 - puts '-' * 40 - puts student2 + student2 = Student.new( + surname: 'Норакет', + name: 'Норакет', + patronymic: 'Фамилия' + ) + + student2.set_contacts( + phone: '+70000000000' + ) + + puts student1 + puts '-' * 40 + puts student2 rescue ArgumentError => e - puts "Err.: #{e.message}" + puts "Ошибка: #{e.message}" end - diff --git a/lab2/student.rb b/lab2/student.rb index e351eb7..83dd59a 100644 --- a/lab2/student.rb +++ b/lab2/student.rb @@ -1,74 +1,86 @@ class Student - attr_accessor :id, :surname, :name, :patronymic, :phone, :telegram, :email, :git - + attr_accessor :id, :surname, :name, :patronymic, :git + def self.valid_phone_number?(phone) - phone.match?(/\A\+?[0-9]{10,15}\z/) + phone.match?(/\A\+?[0-9]{10,15}\z/) end - + def self.valid_name?(name) - name.match?(/\A[А-Яа-яЁёA-Za-z\-]+\z/) + name.match?(/\A[А-Яа-яЁёA-Za-z\-]+\z/) end - + def self.valid_telegram?(telegram) - telegram.nil? || telegram.match?(/\A@[A-Za-z0-9_]{5,32}\z/) + telegram.nil? || telegram.match?(/\A@[A-Za-z0-9_]{5,32}\z/) end - + def self.valid_email?(email) - email.nil? || email.match?(/\A[^@\s]+@[^@\s]+\.[^@\s]+\z/) + email.nil? || email.match?(/\A[^@\s]+@[^@\s]+\.[^@\s]+\z/) end - + def self.valid_git?(git) - git.nil? || git.match?(/\Ahttps:\/\/github\.com\/[A-Za-z0-9_\-]+\z/) + git.nil? || git.match?(/\Ahttps:\/\/github\.com\/[A-Za-z0-9_\-]+\z/) end - + def initialize(args = {}) - @surname = args.fetch(:surname) - raise ArgumentError, "Invalid surname format: #{@surname}" unless Student.valid_name?(@surname) - - @name = args.fetch(:name) - raise ArgumentError, "Invalid name format: #{@name}" unless Student.valid_name?(@name) - - @patronymic = args.fetch(:patronymic) - raise ArgumentError, "Invalid patronymic format: #{@patronymic}" unless Student.valid_name?(@patronymic) - - @id = args[:id] || nil - - @phone = args[:phone] - if @phone && !Student.valid_phone_number?(@phone) - raise ArgumentError, "Invalid phone number format: #{@phone}" - end - - @telegram = args[:telegram] - raise ArgumentError, "Invalid telegram format: #{@telegram}" unless Student.valid_telegram?(@telegram) - - @email = args[:email] - raise ArgumentError, "Invalid email format: #{@email}" unless Student.valid_email?(@email) - - @git = args[:git] - raise ArgumentError, "Invalid git format: #{@git}" unless Student.valid_git?(@git) - - validate + @surname = args.fetch(:surname) + raise ArgumentError, "Invalid surname format: #{@surname}" unless Student.valid_name?(@surname) + + @name = args.fetch(:name) + raise ArgumentError, "Invalid name format: #{@name}" unless Student.valid_name?(@name) + + @patronymic = args.fetch(:patronymic) + raise ArgumentError, "Invalid patronymic format: #{@patronymic}" unless Student.valid_name?(@patronymic) + + @id = args[:id] || nil + + set_contacts( + phone: args[:phone], + telegram: args[:telegram], + email: args[:email] + ) + + @git = args[:git] + raise ArgumentError, "Invalid git format: #{@git}" unless Student.valid_git?(@git) + + validate end - + + def set_contacts(phone: nil, telegram: nil, email: nil) + @phone = phone + raise ArgumentError, "Invalid phone number format: #{@phone}" if @phone && !Student.valid_phone_number?(@phone) + + @telegram = telegram + raise ArgumentError, "Invalid telegram format: #{@telegram}" if @telegram && !Student.valid_telegram?(@telegram) + + @email = email + raise ArgumentError, "Invalid email format: #{@email}" if @email && !Student.valid_email?(@email) + end + def git_present? - !@git.nil? && !@git.empty? + !@git.nil? && !@git.empty? end - + def contact_present? - !(@phone.nil? || @phone.empty?) || !(@telegram.nil? || @telegram.empty?) || !(@email.nil? || @email.empty?) + !(@phone.nil? || @phone.empty?) || !(@telegram.nil? || @telegram.empty?) || !(@email.nil? || @email.empty?) end - + def validate - raise ArgumentError, "Git link is required" unless git_present? - raise ArgumentError, "At least one contact (phone, telegram, or email) is required" unless contact_present? + raise ArgumentError, "Git link is required" unless git_present? + raise ArgumentError, "At least one contact (phone, telegram, or email) is required" unless contact_present? end - + def to_s - "Student: #{@surname} #{@name} #{@patronymic}\n" \ - "ID: #{@id || 'N/A'}\n" \ - "Phone: #{@phone || 'N/A'}\n" \ - "Telegram: #{@telegram || 'N/A'}\n" \ - "Email: #{@email || 'N/A'}\n" \ - "Git: #{@git || 'N/A'}" + "Student: #{@surname} #{@name} #{@patronymic}\n" \ + "ID: #{@id || 'N/A'}\n" \ + "Phone: #{@phone || 'N/A'}\n" \ + "Telegram: #{@telegram || 'N/A'}\n" \ + "Email: #{@email || 'N/A'}\n" \ + "Git: #{@git || 'N/A'}" end + + private + + attr_reader :phone, :telegram, :email + + attr_writer :phone, :telegram, :email end \ No newline at end of file From 8858731565a016e48c72611fc121f6790d52b194 Mon Sep 17 00:00:00 2001 From: Artem Darius Weber Date: Sat, 21 Sep 2024 17:42:33 +0300 Subject: [PATCH 05/10] feat: add constructor for Student class to parse object from string representation - Updated `to_s` method to standardize string representation of Student object. - Added `from_string` constructor that parses a formatted string and initializes the object with parsed data. - Modified `set_contacts` to ensure contacts are only set via the defined method. - Added validation for Git presence and contact details presence, ensuring data integrity. - Updated tests in main.rb to validate the new constructor and string parsing logic. --- lab2/main.rb | 51 +++++++++++++++++++++++++++---------------------- lab2/student.rb | 32 ++++++++++++++++++++++++------- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/lab2/main.rb b/lab2/main.rb index 8233460..021879e 100644 --- a/lab2/main.rb +++ b/lab2/main.rb @@ -1,33 +1,38 @@ require_relative 'student' begin - student1 = Student.new( - surname: 'Алексеевич', - name: 'Артем-Дариус', - patronymic: 'Вебер', - id: 1, - git: 'https://git.djft.ru' - ) + student_string = "Норакет Норакет Норакет | ID: 2 | Phone: +1234567890 | Telegram: @nora | Email: nora@example.com | Git: https://github.com/nora" + student_from_string = Student.from_string(student_string) + puts "Создан объект из строки:\n#{student_from_string}" - student1.set_contacts( - phone: '+79891242223', - telegram: '@alstroemeria22', - email: 'no-replay@djft.ru' - ) - student2 = Student.new( - surname: 'Норакет', - name: 'Норакет', - patronymic: 'Фамилия' - ) + student1 = Student.new( + surname: 'Алексеевич', + name: 'Артем-Дариус', + patronymic: 'Вебер', + id: 1, + git: 'https://git.djft.ru' + ) - student2.set_contacts( - phone: '+70000000000' - ) + student1.set_contacts( + phone: '+79891242223', + telegram: '@alstroemeria22', + email: 'no-replay@djft.ru' + ) - puts student1 - puts '-' * 40 - puts student2 + student2 = Student.new( + surname: 'Норакет', + name: 'Норакет', + patronymic: 'Фамилия' + ) + + student2.set_contacts( + phone: '+70000000000' + ) + + puts student1 + puts '-' * 40 + puts student2 rescue ArgumentError => e puts "Ошибка: #{e.message}" end diff --git a/lab2/student.rb b/lab2/student.rb index 83dd59a..62a14ac 100644 --- a/lab2/student.rb +++ b/lab2/student.rb @@ -44,6 +44,27 @@ class Student validate end + + def self.from_string(student_string) + parts = student_string.split('|').map(&:strip) + surname, name, patronymic = parts[0].split(' ') + id = parts[1].split(': ').last.to_i + phone = parts[2].split(': ').last + telegram = parts[3].split(': ').last + email = parts[4].split(': ').last + git = parts[5].split(': ').last + + new( + surname: surname, + name: name, + patronymic: patronymic, + id: id, + phone: phone, + telegram: telegram, + email: email, + git: git + ) + end def set_contacts(phone: nil, telegram: nil, email: nil) @phone = phone @@ -70,13 +91,10 @@ class Student end def to_s - "Student: #{@surname} #{@name} #{@patronymic}\n" \ - "ID: #{@id || 'N/A'}\n" \ - "Phone: #{@phone || 'N/A'}\n" \ - "Telegram: #{@telegram || 'N/A'}\n" \ - "Email: #{@email || 'N/A'}\n" \ - "Git: #{@git || 'N/A'}" - end + "#{@surname} #{@name} #{@patronymic} | ID: #{@id || 'N/A'} | " \ + "Phone: #{@phone || 'N/A'} | Telegram: #{@telegram || 'N/A'} | " \ + "Email: #{@email || 'N/A'} | Git: #{@git || 'N/A'}" + end private From 611c712b8a068a783ac4325413b5a2bc018e8257 Mon Sep 17 00:00:00 2001 From: Artem Darius Weber Date: Sat, 21 Sep 2024 17:46:44 +0300 Subject: [PATCH 06/10] feat: add `get_info` method and protected access to key student info - Added `get_info` method to return a concise summary of the student, including surname with initials, Git link, and primary contact method. - Implemented individual methods for retrieving surname with initials, Git link, and contact information separately. - Protected contact fields from direct modification; fields can now only be updated via `set_contacts`. - Enhanced string parsing with `from_string` constructor to initialize objects directly from formatted strings. - Updated main file to test new methods and constructor functionality. --- lab2/main.rb | 5 ++++ lab2/student.rb | 69 +++++++++++++++++++++++++++++++------------------ 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/lab2/main.rb b/lab2/main.rb index 021879e..d9848cf 100644 --- a/lab2/main.rb +++ b/lab2/main.rb @@ -20,6 +20,11 @@ begin email: 'no-replay@djft.ru' ) + puts student1.get_info + puts "Surname and Initials: #{student1.surname_and_initials}" + puts "Git Info: #{student1.git_info}" + puts "Contact Info: #{student1.contact_info}" + student2 = Student.new( surname: 'Норакет', name: 'Норакет', diff --git a/lab2/student.rb b/lab2/student.rb index 62a14ac..d02f868 100644 --- a/lab2/student.rb +++ b/lab2/student.rb @@ -44,26 +44,26 @@ class Student validate end - + def self.from_string(student_string) - parts = student_string.split('|').map(&:strip) - surname, name, patronymic = parts[0].split(' ') - id = parts[1].split(': ').last.to_i - phone = parts[2].split(': ').last - telegram = parts[3].split(': ').last - email = parts[4].split(': ').last - git = parts[5].split(': ').last - - new( - surname: surname, - name: name, - patronymic: patronymic, - id: id, - phone: phone, - telegram: telegram, - email: email, - git: git - ) + parts = student_string.split('|').map(&:strip) + surname, name, patronymic = parts[0].split(' ') + id = parts[1].split(': ').last.to_i + phone = parts[2].split(': ').last + telegram = parts[3].split(': ').last + email = parts[4].split(': ').last + git = parts[5].split(': ').last + + new( + surname: surname, + name: name, + patronymic: patronymic, + id: id, + phone: phone, + telegram: telegram, + email: email, + git: git + ) end def set_contacts(phone: nil, telegram: nil, email: nil) @@ -91,14 +91,33 @@ class Student end def to_s - "#{@surname} #{@name} #{@patronymic} | ID: #{@id || 'N/A'} | " \ - "Phone: #{@phone || 'N/A'} | Telegram: #{@telegram || 'N/A'} | " \ - "Email: #{@email || 'N/A'} | Git: #{@git || 'N/A'}" - end + "#{@surname} #{@name} #{@patronymic} | ID: #{@id || 'N/A'} | " \ + "Phone: #{@phone || 'N/A'} | Telegram: #{@telegram || 'N/A'} | " \ + "Email: #{@email || 'N/A'} | Git: #{@git || 'N/A'}" + end + + def get_info + "#{surname_and_initials}, Git: #{git_info}, Contact: #{contact_info}" + end + + def surname_and_initials + "#{@surname} #{name[0]}.#{patronymic[0]}." + end + + def git_info + @git + end + + def contact_info + return "Phone: #{@phone}" if @phone + return "Telegram: #{@telegram}" if @telegram + return "Email: #{@email}" if @email + 'No contact available' + end private attr_reader :phone, :telegram, :email - attr_writer :phone, :telegram, :email -end \ No newline at end of file + end + \ No newline at end of file From 68ca94d4e9ecbaa912d8149556dc9a7a983f3284 Mon Sep 17 00:00:00 2001 From: Artem Darius Weber Date: Sat, 21 Sep 2024 17:51:10 +0300 Subject: [PATCH 07/10] feat: add StudentShort class with immutable fields and constructors - Created StudentShort class with fields: ID, surname initials, git, and contact, which cannot be modified directly. - Implemented two constructors: 1. One that accepts a Student object to initialize fields. 2. Another that accepts ID and a string containing surname initials, git, and contact information. - Updated main.rb to test both constructors of StudentShort, ensuring proper field initialization and immutability. --- lab2/main.rb | 20 ++++++++++++++++++-- lab2/student_short.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 lab2/student_short.rb diff --git a/lab2/main.rb b/lab2/main.rb index d9848cf..e714667 100644 --- a/lab2/main.rb +++ b/lab2/main.rb @@ -1,7 +1,8 @@ require_relative 'student' +require_relative 'student_short' begin - student_string = "Норакет Норакет Норакет | ID: 2 | Phone: +1234567890 | Telegram: @nora | Email: nora@example.com | Git: https://github.com/nora" + student_string = "Норакет Норакет Норакет | ID: 2 | Phone: +1234567890 | Telegram: @noracat | Email: nora@example.com | Git: https://github.com/nora" student_from_string = Student.from_string(student_string) puts "Создан объект из строки:\n#{student_from_string}" @@ -11,7 +12,7 @@ begin name: 'Артем-Дариус', patronymic: 'Вебер', id: 1, - git: 'https://git.djft.ru' + git: 'https://github.com/space-creator' ) student1.set_contacts( @@ -38,6 +39,21 @@ begin puts student1 puts '-' * 40 puts student2 + + + student_short_from_student = StudentShort.new(student1) + puts "StudentShort from Student object:" + puts "ID: #{student_short_from_student.id}" + puts "Surname and Initials: #{student_short_from_student.surname_initials}" + puts "Git: #{student_short_from_student.git}" + puts "Contact: #{student_short_from_student.contact}" + + student_short_from_string = StudentShort.from_string(5, 'Skye A.A., Git: https://github.com/skye, Contact: Phone: +4923467890') + puts "StudentShort from string:" + puts "ID: #{student_short_from_string.id}" + puts "Surname and Initials: #{student_short_from_string.surname_initials}" + puts "Git: #{student_short_from_string.git}" + puts "Contact: #{student_short_from_string.contact}" rescue ArgumentError => e puts "Ошибка: #{e.message}" end diff --git a/lab2/student_short.rb b/lab2/student_short.rb new file mode 100644 index 0000000..85f9762 --- /dev/null +++ b/lab2/student_short.rb @@ -0,0 +1,30 @@ +class StudentShort + attr_reader :id, :surname_initials, :git, :contact + + def initialize(student) + @id = student.id + @surname_initials = student.surname_and_initials + @git = student.git_info + @contact = student.contact_info + end + + def self.from_string(id, info_string) + parts = info_string.split(', ').map(&:strip) + surname_initials = parts[0] + git = parts[1].split(': ').last + contact = parts[2].split(': ').last + + new_instance = allocate + new_instance.send(:initialize_from_data, id, surname_initials, git, contact) + new_instance + end + + private + + def initialize_from_data(id, surname_initials, git, contact) + @id = id + @surname_initials = surname_initials + @git = git + @contact = contact + end +end From d387e12d7db6e04bd77deb13254f5bb5f0e0e2a1 Mon Sep 17 00:00:00 2001 From: Artem Darius Weber Date: Sat, 21 Sep 2024 19:18:36 +0300 Subject: [PATCH 08/10] ref: Extract common functionality into Person superclass - Created a new superclass `Person` to encapsulate common attributes and methods for `Student` and `StudentShort`. - Moved validation methods, contact handling, and common logic from `Student` and `StudentShort` into `Person`. - Updated `Student` to inherit from `Person`, simplifying initialization and validation. - Updated `StudentShort` to inherit from `Person`, reducing redundancy and aligning with the new superclass structure. - Improved code maintainability by eliminating duplicated code and clarifying class responsibilities. --- lab2/person.rb | 65 ++++++++++++++++++++++++++++++++ lab2/student.rb | 87 ++++++------------------------------------- lab2/student_short.rb | 11 +++--- 3 files changed, 82 insertions(+), 81 deletions(-) create mode 100644 lab2/person.rb diff --git a/lab2/person.rb b/lab2/person.rb new file mode 100644 index 0000000..1dc8f9e --- /dev/null +++ b/lab2/person.rb @@ -0,0 +1,65 @@ +class Person + attr_accessor :id, :git + + def initialize(args = {}) + @id = args[:id] || nil + @git = args[:git] + validate + end + + def set_contacts(phone: nil, telegram: nil, email: nil) + @phone = phone + raise ArgumentError, "Invalid phone number format: #{@phone}" if @phone && !self.class.valid_phone_number?(@phone) + + @telegram = telegram + raise ArgumentError, "Invalid telegram format: #{@telegram}" if @telegram && !self.class.valid_telegram?(@telegram) + + @email = email + raise ArgumentError, "Invalid email format: #{@email}" if @email && !self.class.valid_email?(@email) + end + + def self.valid_phone_number?(phone) + phone.match?(/\A\+?[0-9]{10,15}\z/) + end + + def self.valid_name?(name) + name.match?(/\A[А-Яа-яЁёA-Za-z\-]+\z/) + end + + def self.valid_telegram?(telegram) + telegram.nil? || telegram.match?(/\A@[A-Za-z0-9_]{5,32}\z/) + end + + def self.valid_email?(email) + email.nil? || email.match?(/\A[^@\s]+@[^@\s]+\.[^@\s]+\z/) + end + + def self.valid_git?(git) + git.nil? || git.match?(/\Ahttps:\/\/github\.com\/[A-Za-z0-9_\-]+\z/) + end + + def git_present? + !@git.nil? && !@git.empty? + end + + def contact_present? + !(@phone.nil? || @phone.empty?) || !(@telegram.nil? || @telegram.empty?) || !(@email.nil? || @email.empty?) + end + + def validate + raise ArgumentError, "Git link is required" unless git_present? + raise ArgumentError, "At least one contact (phone, telegram, or email) is required" unless contact_present? + end + + def contact_info + return "Phone: #{@phone}" if @phone + return "Telegram: #{@telegram}" if @telegram + return "Email: #{@email}" if @email + 'No contact available' + end + + private + + attr_reader :phone, :telegram, :email + attr_writer :phone, :telegram, :email +end \ No newline at end of file diff --git a/lab2/student.rb b/lab2/student.rb index d02f868..f0a5121 100644 --- a/lab2/student.rb +++ b/lab2/student.rb @@ -1,48 +1,24 @@ -class Student - attr_accessor :id, :surname, :name, :patronymic, :git - - def self.valid_phone_number?(phone) - phone.match?(/\A\+?[0-9]{10,15}\z/) - end - - def self.valid_name?(name) - name.match?(/\A[А-Яа-яЁёA-Za-z\-]+\z/) - end - - def self.valid_telegram?(telegram) - telegram.nil? || telegram.match?(/\A@[A-Za-z0-9_]{5,32}\z/) - end - - def self.valid_email?(email) - email.nil? || email.match?(/\A[^@\s]+@[^@\s]+\.[^@\s]+\z/) - end - - def self.valid_git?(git) - git.nil? || git.match?(/\Ahttps:\/\/github\.com\/[A-Za-z0-9_\-]+\z/) - end +require_relative 'person' + +class Student < Person + attr_accessor :surname, :name, :patronymic def initialize(args = {}) + super(args) @surname = args.fetch(:surname) - raise ArgumentError, "Invalid surname format: #{@surname}" unless Student.valid_name?(@surname) + raise ArgumentError, "Invalid surname format: #{@surname}" unless self.class.valid_name?(@surname) @name = args.fetch(:name) - raise ArgumentError, "Invalid name format: #{@name}" unless Student.valid_name?(@name) + raise ArgumentError, "Invalid name format: #{@name}" unless self.class.valid_name?(@name) @patronymic = args.fetch(:patronymic) - raise ArgumentError, "Invalid patronymic format: #{@patronymic}" unless Student.valid_name?(@patronymic) - - @id = args[:id] || nil + raise ArgumentError, "Invalid patronymic format: #{@patronymic}" unless self.class.valid_name?(@patronymic) set_contacts( phone: args[:phone], telegram: args[:telegram], email: args[:email] ) - - @git = args[:git] - raise ArgumentError, "Invalid git format: #{@git}" unless Student.valid_git?(@git) - - validate end def self.from_string(student_string) @@ -66,28 +42,8 @@ class Student ) end - def set_contacts(phone: nil, telegram: nil, email: nil) - @phone = phone - raise ArgumentError, "Invalid phone number format: #{@phone}" if @phone && !Student.valid_phone_number?(@phone) - - @telegram = telegram - raise ArgumentError, "Invalid telegram format: #{@telegram}" if @telegram && !Student.valid_telegram?(@telegram) - - @email = email - raise ArgumentError, "Invalid email format: #{@email}" if @email && !Student.valid_email?(@email) - end - - def git_present? - !@git.nil? && !@git.empty? - end - - def contact_present? - !(@phone.nil? || @phone.empty?) || !(@telegram.nil? || @telegram.empty?) || !(@email.nil? || @email.empty?) - end - - def validate - raise ArgumentError, "Git link is required" unless git_present? - raise ArgumentError, "At least one contact (phone, telegram, or email) is required" unless contact_present? + def surname_and_initials + "#{@surname} #{name[0]}.#{patronymic[0]}." end def to_s @@ -99,25 +55,4 @@ class Student def get_info "#{surname_and_initials}, Git: #{git_info}, Contact: #{contact_info}" end - - def surname_and_initials - "#{@surname} #{name[0]}.#{patronymic[0]}." - end - - def git_info - @git - end - - def contact_info - return "Phone: #{@phone}" if @phone - return "Telegram: #{@telegram}" if @telegram - return "Email: #{@email}" if @email - 'No contact available' - end - - private - - attr_reader :phone, :telegram, :email - attr_writer :phone, :telegram, :email - end - \ No newline at end of file +end \ No newline at end of file diff --git a/lab2/student_short.rb b/lab2/student_short.rb index 85f9762..1bff260 100644 --- a/lab2/student_short.rb +++ b/lab2/student_short.rb @@ -1,10 +1,11 @@ -class StudentShort - attr_reader :id, :surname_initials, :git, :contact +require_relative 'person' + +class StudentShort < Person + attr_reader :surname_initials, :contact def initialize(student) - @id = student.id + super(id: student.id, git: student.git_info) @surname_initials = student.surname_and_initials - @git = student.git_info @contact = student.contact_info end @@ -27,4 +28,4 @@ class StudentShort @git = git @contact = contact end -end +end \ No newline at end of file From acf69c43856353ad128bbd5c1ec92b503f536f35 Mon Sep 17 00:00:00 2001 From: Artem Darius Weber Date: Sat, 21 Sep 2024 19:22:37 +0300 Subject: [PATCH 09/10] feat: Add read_from_txt method to Student class - Introduced read_from_txt method in Student class to read student data from a text file. --- lab2/student.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lab2/student.rb b/lab2/student.rb index f0a5121..6d2dd9e 100644 --- a/lab2/student.rb +++ b/lab2/student.rb @@ -41,6 +41,26 @@ class Student < Person git: git ) end + + def self.read_from_txt(file_path) + raise IOError, "File path is invalid or file does not exist: #{file_path}" unless File.exist?(file_path) + + students = [] + + File.foreach(file_path) do |line| + line.strip! + next if line.empty? # Пропустить пустые строки + + begin + student = from_string(line) + students << student + rescue ArgumentError => e + puts "Error processing line: '#{line}'. Reason: #{e.message}" + end + end + + students + end def surname_and_initials "#{@surname} #{name[0]}.#{patronymic[0]}." From dc752cdf43360d3aef45d411a975ea100407be54 Mon Sep 17 00:00:00 2001 From: Artem Darius Weber Date: Sat, 21 Sep 2024 19:26:03 +0300 Subject: [PATCH 10/10] feat: add write_txt method to Student class --- lab2/student.rb | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lab2/student.rb b/lab2/student.rb index 6d2dd9e..57d26a7 100644 --- a/lab2/student.rb +++ b/lab2/student.rb @@ -49,7 +49,7 @@ class Student < Person File.foreach(file_path) do |line| line.strip! - next if line.empty? # Пропустить пустые строки + next if line.empty? begin student = from_string(line) @@ -61,6 +61,20 @@ class Student < Person students end + + def self.write_to_txt(file_path, students) + raise ArgumentError, "Expected an array of Student objects" unless students.is_a?(Array) && students.all? { |s| s.is_a?(Student) } + + File.open(file_path, 'w') do |file| + students.each do |student| + file.puts student.to_s + end + end + + puts "Data successfully written to #{file_path}" + rescue IOError => e + puts "An error occurred while writing to the file: #{e.message}" + end def surname_and_initials "#{@surname} #{name[0]}.#{patronymic[0]}."