├── books.json ├── logo.png ├── nameable.rb ├── Gemfile ├── rentals.json ├── capitalize_decorator.rb ├── people.json ├── trimer_decorator.rb ├── decorator.rb ├── rental.rb ├── book.rb ├── classroom.rb ├── teacher.rb ├── options.rb ├── main.rb ├── option_handler.rb ├── student.rb ├── solver.rb ├── rspec_test ├── teacher_rspec.rb ├── student_rspec.rb ├── classroom_rspec.rb ├── rental_rspec.rb ├── book_rspec.rb ├── person_rspec.rb └── solver_rspec.rb ├── .github └── workflows │ └── linters.yml ├── person.rb ├── Gemfile.lock ├── LICENSE ├── test.rb ├── .rubocop.yml ├── data_manager.rb ├── app.rb └── README.md /books.json: -------------------------------------------------------------------------------- 1 | [{"title":"Kite Runner","author":"Mahdi"}] 2 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noelfoka/library-school/HEAD/logo.png -------------------------------------------------------------------------------- /nameable.rb: -------------------------------------------------------------------------------- 1 | class Nameable 2 | def correct_name 3 | raise NotImplementedError 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rspec', '~> 3.4' 4 | gem 'rubocop', '>= 1.0', '< 2.0' 5 | -------------------------------------------------------------------------------- /rentals.json: -------------------------------------------------------------------------------- 1 | [{"date":"2023","book":{"title":"Kite Runner","author":"Mahdi"},"person":{"id":10,"type":"Teacher","age":"19","name":"Noel","parent_permission":true}}] 2 | -------------------------------------------------------------------------------- /capitalize_decorator.rb: -------------------------------------------------------------------------------- 1 | require_relative 'decorator' 2 | 3 | class CapitalizeDecorator < NameDecorator 4 | def correct_name 5 | @nameable.correct_name.capitalize 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /people.json: -------------------------------------------------------------------------------- 1 | [{"type":"Student","age":"Mahdi","name":"Unknown","parent_permision":true,"specialization":null},{"type":"Teacher","age":"19","name":"Noel","parent_permision":true,"specialization":"Computer Science"}] 2 | -------------------------------------------------------------------------------- /trimer_decorator.rb: -------------------------------------------------------------------------------- 1 | require_relative 'decorator' 2 | 3 | class TrimmerDecorator < NameDecorator 4 | def correct_name 5 | name = @nameable.correct_name 6 | name.length > 10 ? name[0..9] : name 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /decorator.rb: -------------------------------------------------------------------------------- 1 | require_relative 'nameable' 2 | 3 | class NameDecorator < Nameable 4 | attr_accessor :nameable 5 | 6 | def initialize(nameable) 7 | super() 8 | @nameable = nameable 9 | end 10 | 11 | def correct_name 12 | @nameable.correct_name 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /rental.rb: -------------------------------------------------------------------------------- 1 | class Rental 2 | attr_accessor :date, :book, :person 3 | 4 | def initialize(date, book, person) 5 | super() 6 | @date = date 7 | 8 | @book = book 9 | book.rentals << self 10 | @person = person 11 | person.rentals << self 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /book.rb: -------------------------------------------------------------------------------- 1 | class Book 2 | attr_accessor :title, :author, :rentals 3 | 4 | def initialize(title, author) 5 | @title = title 6 | @author = author 7 | @rentals = [] 8 | end 9 | 10 | def add_rental(person, date) 11 | Rental.new(date, self, person) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /classroom.rb: -------------------------------------------------------------------------------- 1 | class Classroom 2 | attr_accessor :label 3 | attr_reader :students 4 | 5 | def initialize(label) 6 | @label = label 7 | @students = [] 8 | end 9 | 10 | def add_student(student) 11 | @students.push(student) 12 | student.classroom = self 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /teacher.rb: -------------------------------------------------------------------------------- 1 | require_relative 'person' 2 | 3 | class Teacher < Person 4 | attr_accessor :specialization 5 | 6 | def initialize(specialization, age, name = 'Unknown', parent_permission: true) 7 | super(age, name, parent_permission: parent_permission) 8 | @specialization = specialization 9 | end 10 | 11 | def can_use_services? 12 | true 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /options.rb: -------------------------------------------------------------------------------- 1 | # Show option implementation 2 | class ShowOptions 3 | def show_options 4 | puts 'Please choose an option by entering a number:' 5 | puts '1 - List all books' 6 | puts '2 - List all people' 7 | puts '3 - Create a person' 8 | puts '4 - Create a book' 9 | puts '5 - Create a rental' 10 | puts '6 - List all rentals for a given person id' 11 | puts '7 - Exit' 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /main.rb: -------------------------------------------------------------------------------- 1 | require_relative 'app' 2 | require_relative 'option_handler' 3 | require_relative 'options' 4 | 5 | def prompt 6 | puts 'Welcome to the School Library App!' 7 | app = App.new 8 | option_handler = OptionHandler.new(app) 9 | options = ShowOptions.new 10 | 11 | loop do 12 | options.show_options 13 | option = gets.chomp.to_i 14 | break if option == 7 15 | 16 | option_handler.call_option(option) 17 | end 18 | end 19 | 20 | prompt 21 | -------------------------------------------------------------------------------- /option_handler.rb: -------------------------------------------------------------------------------- 1 | require_relative 'app' 2 | 3 | class OptionHandler 4 | def initialize(app) 5 | @app = app 6 | end 7 | 8 | def call_option(option) 9 | case option 10 | when 1 11 | @app.list_books 12 | when 2 13 | @app.list_people 14 | when 3 15 | @app.create_person 16 | when 4 17 | @app.create_book 18 | when 5 19 | @app.create_rental 20 | when 6 21 | @app.list_rentals 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /student.rb: -------------------------------------------------------------------------------- 1 | require_relative 'person' 2 | 3 | class Student < Person 4 | attr_reader :classroom 5 | 6 | def initialize(classroom, age, name = 'Unknown', parent_permission: true) 7 | super(age, name, parent_permission: parent_permission) 8 | @classroom = classroom 9 | end 10 | 11 | def classroom=(classroom) 12 | @classroom = classroom 13 | classroom.students.push(self) unless classroom.students.include?(self) 14 | end 15 | 16 | def play_hooky 17 | '¯\(ツ)/¯' 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /solver.rb: -------------------------------------------------------------------------------- 1 | class Solver 2 | def factorial(num) 3 | raise ArgumentError, 'N must be a non-negatve integer' if num.negative? 4 | return 1 if num.zero? 5 | 6 | (1..num).reduce(:*) 7 | end 8 | 9 | def reverse(word) 10 | reversed_word = '' 11 | i = word.length - 1 12 | while i >= 0 13 | reversed_word += word[i] 14 | i -= 1 15 | end 16 | reversed_word 17 | end 18 | 19 | def fizzbuzz(num) 20 | result = '' 21 | result += 'fizz' if (num % 3).zero? 22 | result += 'buzz' if (num % 5).zero? 23 | result = n.to_s if result == '' 24 | result 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /rspec_test/teacher_rspec.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require_relative '../teacher' 3 | 4 | describe Teacher do 5 | let(:teacher) { Teacher.new('Math', 40) } 6 | 7 | context 'initialized with data' do 8 | it 'should inherit age, name from Person' do 9 | expect(teacher.age).to eq(40) 10 | expect(teacher.name).to eq('Unknown') 11 | end 12 | 13 | it 'should have a specialization' do 14 | expect(teacher.specialization).to eq('Math') 15 | end 16 | end 17 | 18 | context 'using services' do 19 | it 'can use services' do 20 | expect(teacher.can_use_services?).to be(true) 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /.github/workflows/linters.yml: -------------------------------------------------------------------------------- 1 | name: Linters 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | rubocop: 7 | name: Rubocop 8 | runs-on: ubuntu-22.04 9 | 10 | steps: 11 | - uses: actions/checkout@v3 12 | - uses: actions/setup-ruby@v1 13 | with: 14 | ruby-version: ">=3.1.x" 15 | - name: Setup Rubocop 16 | run: | 17 | gem install --no-document rubocop -v '>= 1.0, < 2.0' # https://docs.rubocop.org/en/stable/installation/ 18 | [ -f .rubocop.yml ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/ruby/.rubocop.yml 19 | - name: Rubocop Report 20 | run: rubocop --color 21 | -------------------------------------------------------------------------------- /person.rb: -------------------------------------------------------------------------------- 1 | require_relative 'nameable' 2 | require_relative 'capitalize_decorator' 3 | require_relative 'trimer_decorator' 4 | 5 | class Person < Nameable 6 | attr_reader :id, :specialization 7 | attr_accessor :name, :age, :rentals, :parent_permission 8 | 9 | def initialize(age, name = 'Unknown', parent_permission: true) 10 | super() 11 | @id = Random.rand(1..1000) 12 | @name = name 13 | @age = age 14 | @parent_permission = parent_permission 15 | @rentals = [] 16 | end 17 | 18 | def correct_name 19 | name 20 | end 21 | 22 | def can_use_services? 23 | of_age? || @parent_permission 24 | end 25 | 26 | def add_rentals(book, date) 27 | Rental.new(date, book, self) 28 | end 29 | 30 | private 31 | 32 | def of_age? 33 | @age >= 18 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /rspec_test/student_rspec.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require_relative '../student' 3 | require_relative '../classroom' 4 | 5 | describe Student do 6 | let(:classroom) { Classroom.new('Math') } 7 | let(:student) { Student.new(classroom, 16, 'Alice') } 8 | 9 | context 'student is initialized with data' do 10 | it 'should inherit age, name, and parent_permission from Person' do 11 | expect(student.age).to eq(16) 12 | expect(student.name).to eq('Alice') 13 | end 14 | 15 | it 'should initialize a classroom' do 16 | expect(student.classroom).to eq(classroom) 17 | end 18 | end 19 | 20 | context 'attr accessors' do 21 | it 'classroom is changeable' do 22 | new_classroom = Classroom.new('History') 23 | student.classroom = new_classroom 24 | expect(student.classroom).to eq(new_classroom) 25 | end 26 | end 27 | 28 | context 'methods' do 29 | it 'play_hooky method should return an emoji' do 30 | expect(student.play_hooky).to eq('¯\\(ツ)/¯') 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | ast (2.4.2) 5 | base64 (0.1.1) 6 | json (2.6.3) 7 | language_server-protocol (3.17.0.3) 8 | parallel (1.23.0) 9 | parser (3.2.2.3) 10 | ast (~> 2.4.1) 11 | racc 12 | racc (1.7.1) 13 | rainbow (3.1.1) 14 | regexp_parser (2.8.1) 15 | rexml (3.2.6) 16 | rubocop (1.56.4) 17 | base64 (~> 0.1.1) 18 | json (~> 2.3) 19 | language_server-protocol (>= 3.17.0) 20 | parallel (~> 1.10) 21 | parser (>= 3.2.2.3) 22 | rainbow (>= 2.2.2, < 4.0) 23 | regexp_parser (>= 1.8, < 3.0) 24 | rexml (>= 3.2.5, < 4.0) 25 | rubocop-ast (>= 1.28.1, < 2.0) 26 | ruby-progressbar (~> 1.7) 27 | unicode-display_width (>= 2.4.0, < 3.0) 28 | rubocop-ast (1.29.0) 29 | parser (>= 3.2.1.0) 30 | ruby-progressbar (1.13.0) 31 | unicode-display_width (2.5.0) 32 | 33 | PLATFORMS 34 | x64-mingw-ucrt 35 | 36 | DEPENDENCIES 37 | rubocop (>= 1.0, < 2.0) 38 | 39 | BUNDLED WITH 40 | 2.4.20 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 NOEL NOMGNE FOKA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test.rb: -------------------------------------------------------------------------------- 1 | require_relative 'student' 2 | require_relative 'classroom' 3 | require_relative 'rental' 4 | require_relative 'book' 5 | 6 | student1 = Student.new('Unknown', 13, 'Mahdi') 7 | student2 = Student.new('Unknown', 17, 'Noel') 8 | student3 = Student.new('Unknown', 14, 'Joel') 9 | 10 | class1 = Classroom.new('Literature & Travels') 11 | 12 | book1 = Book.new('Learn JavaScript', 'Author1') 13 | book2 = Book.new('Learn React', 'Author2') 14 | book3 = Book.new('Learrn Ruby', 'Author3') 15 | 16 | Rental.new('2017-12-07', book1, student1) 17 | Rental.new('2018-03-07', book2, student2) 18 | Rental.new('2019-08-07', book2, student1) 19 | Rental.new('2022-02-09', book3, student3) 20 | 21 | puts class1.add_student(student1) 22 | puts student1.classroom.label 23 | puts student2.classroom 24 | puts class1.students.count 25 | puts student2.classroom = class1 26 | puts class1.students.count 27 | 28 | puts book1.rentals 29 | puts book2.rentals 30 | puts book3.rentals 31 | 32 | puts student1.rentals.count 33 | puts student2.rentals.count 34 | puts student3.rentals.count 35 | puts book1.rentals.count 36 | puts book2.rentals.count 37 | puts book3.rentals.count 38 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | NewCops: enable 3 | Exclude: 4 | - 'Guardfile' 5 | - 'Rakefile' 6 | - 'node_modules/**/*' 7 | 8 | DisplayCopNames: true 9 | 10 | Layout/LineLength: 11 | Max: 120 12 | Metrics/MethodLength: 13 | Max: 20 14 | Metrics/AbcSize: 15 | Max: 50 16 | Metrics/ClassLength: 17 | Max: 150 18 | Metrics/BlockLength: 19 | IgnoredMethods: ['describe'] 20 | Max: 30 21 | 22 | Style/Documentation: 23 | Enabled: false 24 | Style/ClassAndModuleChildren: 25 | Enabled: false 26 | Style/EachForSimpleLoop: 27 | Enabled: false 28 | Style/AndOr: 29 | Enabled: false 30 | Style/DefWithParentheses: 31 | Enabled: false 32 | Style/FrozenStringLiteralComment: 33 | EnforcedStyle: never 34 | 35 | Layout/HashAlignment: 36 | EnforcedColonStyle: key 37 | Layout/ExtraSpacing: 38 | AllowForAlignment: false 39 | Layout/MultilineMethodCallIndentation: 40 | Enabled: true 41 | EnforcedStyle: indented 42 | Lint/RaiseException: 43 | Enabled: false 44 | Lint/StructNewOverride: 45 | Enabled: false 46 | Style/HashEachMethods: 47 | Enabled: false 48 | Style/HashTransformKeys: 49 | Enabled: false 50 | Style/HashTransformValues: 51 | Enabled: false 52 | -------------------------------------------------------------------------------- /rspec_test/classroom_rspec.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require_relative '../classroom' 3 | require_relative '../student' 4 | 5 | describe Classroom do 6 | let(:classroom) { Classroom.new('Classroom 1') } 7 | let(:student) { Student.new('John Doe', 'Math', 15) } 8 | 9 | context '#label' do 10 | it 'returns the classroom label' do 11 | expect(classroom.label).to eq('Classroom 1') 12 | end 13 | end 14 | 15 | context '#attr_accesor' do 16 | it 'label instance can be changed' do 17 | classroom.label = 'new label' 18 | expect(classroom.label).to eq('new label') 19 | end 20 | 21 | context '#students' do 22 | it 'returns an empty array by default' do 23 | expect(classroom.students).to be_empty 24 | end 25 | end 26 | 27 | context '#add_student' do 28 | it 'adds a student to the classroom' do 29 | classroom.add_student(student) 30 | expect(classroom.students).to include(student) 31 | end 32 | 33 | it 'sets the student classroom to the classroom' do 34 | classroom.add_student(student) 35 | expect(student.classroom).to eq(classroom) 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /rspec_test/rental_rspec.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require_relative '../rental' 3 | require_relative '../person' 4 | require_relative '../book' 5 | 6 | describe Rental do 7 | let(:book) { Book.new('The Formula', 'Author Name') } 8 | let(:person) { Person.new('Okari', 25) } 9 | let(:rental) { Rental.new('2004-05-20', book, person) } 10 | 11 | context 'rental is initialized with data' do 12 | it 'should initialize a date' do 13 | expect(rental.date).to eq('2004-05-20') 14 | end 15 | 16 | it 'should initialize a book' do 17 | expect(rental.book).to be_an_instance_of(Book) 18 | end 19 | 20 | it 'should initialize a person' do 21 | expect(rental.person).to be_an_instance_of(Person) 22 | end 23 | end 24 | 25 | context 'attr accessors' do 26 | it 'date is changeable' do 27 | rental.date = '2009-08-17' 28 | expect(rental.date).to eq('2009-08-17') 29 | end 30 | 31 | it 'book is changeable' do 32 | new_book = Book.new('New Book', 'New Author') 33 | rental.book = new_book 34 | expect(rental.book).to eq(new_book) 35 | end 36 | 37 | it 'person is changeable' do 38 | new_person = Person.new('Nyandika', 20) 39 | rental.person = new_person 40 | expect(rental.person).to eq(new_person) 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /rspec_test/book_rspec.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require 'date' 3 | 4 | require_relative '../book' 5 | require_relative '../rental' 6 | require_relative '../person' 7 | 8 | describe Book do 9 | let(:book) { Book.new('Title', 'Author') } 10 | let(:person) { Person.new('Mahdi', 25) } 11 | let(:date) { Date.new(2023, 10, 11) } 12 | 13 | context 'Initialization' do 14 | it 'should initialize with a title' do 15 | expect(book.title).to eq('Title') 16 | end 17 | 18 | it 'should initialize with an author' do 19 | expect(book.author).to eq('Author') 20 | end 21 | 22 | it 'should initialize with an empty rentals array' do 23 | expect(book.rentals).to be_empty 24 | end 25 | end 26 | 27 | context 'Attribute Accessors' do 28 | it 'should allow updating the title' do 29 | book.title = 'New Title' 30 | expect(book.title).to eq('New Title') 31 | end 32 | 33 | it 'should allow updating the author' do 34 | book.author = 'New Author' 35 | expect(book.author).to eq('New Author') 36 | end 37 | end 38 | 39 | context 'add_rental method' do 40 | it 'should add a rental to the rentals array' do 41 | rental = book.add_rental(person, date) 42 | expect(book.rentals).to include(rental) 43 | end 44 | 45 | it 'should create a new Rental object' do 46 | rental = book.add_rental(person, date) 47 | expect(rental).to be_an_instance_of(Rental) 48 | expect(rental.book).to eq(book) 49 | expect(rental.person).to eq(person) 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /rspec_test/person_rspec.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require 'date' 3 | require_relative '../book' 4 | require_relative '../person' 5 | require_relative '../rental' 6 | 7 | describe Person do 8 | let(:person) { Person.new(18, 'Noel') } 9 | 10 | context '#add_rentals' do 11 | it 'adds a new rental to the rental list of a person' do 12 | person = Person.new(25) 13 | book = Book.new('Book 1', 'Author 1') 14 | date = Date.today 15 | 16 | person.add_rentals(book, date) 17 | 18 | expect(person.rentals).to include(Rental.new(date, book, person)) 19 | end 20 | end 21 | 22 | context '#using_services' do 23 | it 'returns true if the person is of age' do 24 | person = Person.new(14) 25 | expect(person.can_use_services?).to be true 26 | end 27 | 28 | it 'returns true if the person has parent permission' do 29 | person = Person.new(16, parent_permission: true) 30 | expect(person.can_use_services?).to be true 31 | end 32 | 33 | it 'returns false if the person is not of age and does not have parent permission' do 34 | person = Person.new(16, parent_permission: false) 35 | expect(person.can_use_services?).to be false 36 | end 37 | end 38 | 39 | context '#correct_name' do 40 | it 'returns the actual name' do 41 | person = Person.new(14, 'Okari') 42 | expect(person.correct_name).to eq 'Okari' 43 | end 44 | 45 | context '#private methods' do 46 | context '#of_age?' do 47 | it 'returns true if the person is 18 years old or older' do 48 | expect(person.send(:of_age?)).to be true 49 | end 50 | 51 | it 'returns false if the person is younger than 18 years old' do 52 | person.age = 17 53 | expect(person.send(:of_age?)).to be false 54 | end 55 | end 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /rspec_test/solver_rspec.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require_relative '../solver' 3 | 4 | describe Solver do 5 | let(:solver) { Solver.new } 6 | describe '#factorial' do 7 | it 'Returns the factorial of 5' do 8 | expect(solver.factorial(5)).to eq(120) 9 | end 10 | it 'Returns the factorial of 0' do 11 | expect(solver.factorial(0)).to eq(1) 12 | end 13 | it 'returns the factorial of 1' do 14 | expect(solver.factorial(1)).to eq(1) 15 | end 16 | it 'returns the factorial of 10' do 17 | expect(solver.factorial(10)).to eq(3_628_800) 18 | end 19 | it 'riases an error when a negative number is passed' do 20 | expect { solver.factorial(-1) }.to raise_error(ArgumentError, 'N must be a non-negatve integer') 21 | end 22 | end 23 | 24 | describe '#reverse' do 25 | it 'returns the reverse of "hello"' do 26 | expect(solver.reverse('hello')).to eq('olleh') 27 | end 28 | it 'returns the reverse of "world"' do 29 | expect(solver.reverse('world')).to eq('dlrow') 30 | end 31 | it 'returns the reverse of an empty string' do 32 | expect(solver.reverse('')).to eq('') 33 | end 34 | it 'returns the reverse of a string with one character' do 35 | expect(solver.reverse('a')).to eq('a') 36 | end 37 | end 38 | describe '#fizzbuzz' do 39 | it 'returns "fizz" for numbers divisible by 3' do 40 | expect(solver.fizzbuzz(3)).to eq('fizz') 41 | expect(solver.fizzbuzz(6)).to eq('fizz') 42 | end 43 | it 'returns "buzz" for numbers divisible by 5' do 44 | expect(solver.fizzbuzz(5)).to eq('buzz') 45 | expect(solver.fizzbuzz(10)).to eq('buzz') 46 | end 47 | it 'returns "fizzbuzz" for numbers divisible by 3 and 5' do 48 | expect(solver.fizzbuzz(15)).to eq('fizzbuzz') 49 | expect(solver.fizzbuzz(30)).to eq('fizzbuzz') 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /data_manager.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | class DataManager 4 | attr_accessor :books, :rentals, :people 5 | 6 | def initialize 7 | @books = [] 8 | @rentals = [] 9 | @people = [] 10 | end 11 | 12 | def load_data 13 | load_books 14 | load_people 15 | load_rentals 16 | end 17 | 18 | def save_data 19 | save_books 20 | save_people 21 | save_rentals 22 | puts 'Books Saved!' 23 | rescue StandardError => e 24 | puts "Error Saving Data: #{e.message}" 25 | end 26 | 27 | def save_rentals 28 | File.open('rentals.json', 'w') do |file| 29 | file.puts @rentals.map { |rental| 30 | { 31 | 'date' => rental.date, 32 | 'book' => { 33 | 'title' => rental.book.title, 34 | 'author' => rental.book.author 35 | }, 36 | 'person' => { 37 | 'id' => rental.person.id, 38 | 'type' => rental.person.class.name, 39 | 'age' => rental.person.age, 40 | 'name' => rental.person.name, 41 | 'parent_permission' => rental.person.parent_permission 42 | } 43 | } 44 | }.to_json 45 | end 46 | end 47 | 48 | def save_books 49 | File.open('books.json', 'w') do |file| 50 | file.puts @books.map { |book| 51 | { 52 | 'title' => book.title, 53 | 'author' => book.author 54 | } 55 | }.to_json 56 | end 57 | end 58 | 59 | def save_people 60 | File.open('people.json', 'w') do |file| 61 | file.puts @people.map { |person| 62 | { 63 | 'type' => person.class.name, 64 | 'age' => person.age, 65 | 'name' => person.name, 66 | 'parent_permision' => person.parent_permission, 67 | 'specialization' => person.specialization 68 | } 69 | }.to_json 70 | end 71 | end 72 | 73 | private 74 | 75 | def load_books 76 | return unless File.exist?('books.json') 77 | 78 | json_str = File.read('books.json') 79 | @books = JSON.parse(json_str).map do |book_data| 80 | Book.new(book_data['title'], book_data['author']) 81 | end 82 | end 83 | 84 | def load_people 85 | return unless File.exist?('people.json') 86 | 87 | json_str = File.read('people.json') 88 | @people = JSON.parse(json_str).map do |person_data| 89 | if person_data['type'] == 'Student' 90 | Student.new(person_data['age'], person_data['name'], person_data['parent_permission']) 91 | elsif person_data['type'] == 'Teacher' 92 | Teacher.new(person_data['age'], person_data['specialization'], person_data['name']) 93 | else 94 | raise "Invalid person type: #{person_data['type']}" 95 | end 96 | end 97 | end 98 | 99 | def load_rentals 100 | return unless File.exist?('rentals.json') 101 | 102 | json_str = File.read('rentals.json') 103 | data = JSON.parse(json_str) 104 | @rentals = data.map do |rental_data| 105 | book = Book.new(rental_data['book']['title'], rental_data['book']['author']) 106 | person = case rental_data['person']['type'] 107 | when 'Student' 108 | Student.new(rental_data['person']['age'].to_i, rental_data['person']['name'], 109 | parent_permission: rental_data['person']['parent_permission']) 110 | when 'Teacher' 111 | Teacher.new(rental_data['person']['age'].to_i, rental_data['person']['specialization'], 112 | rental_data['person']['name']) 113 | end 114 | Rental.new(rental_data['date'], book, person) 115 | end 116 | @rentals 117 | end 118 | end 119 | -------------------------------------------------------------------------------- /app.rb: -------------------------------------------------------------------------------- 1 | require_relative 'book' 2 | require_relative 'classroom' 3 | require_relative 'person' 4 | require_relative 'rental' 5 | require_relative 'student' 6 | require_relative 'teacher' 7 | require_relative 'data_manager' 8 | 9 | class App 10 | attr_accessor :books, :people, :rentals 11 | 12 | def initialize 13 | @books = [] 14 | @rentals = [] 15 | @people = [] 16 | 17 | @data_manager = DataManager.new 18 | @data_manager.load_data 19 | @books = @data_manager.books 20 | @people = @data_manager.people 21 | end 22 | 23 | def save_data 24 | @data_manager.save_books 25 | puts 'Book Save Successfully!' 26 | end 27 | 28 | def list_books 29 | @books.each { |book| puts "Title: \"#{book.title}\", Author: #{book.author}" } 30 | end 31 | 32 | def list_books_with_index 33 | @books.each_with_index { |book, i| puts "#{i}) Title: \"#{book.title}\", Author: #{book.author}" } 34 | end 35 | 36 | def list_people 37 | @people.each do |person| 38 | puts "[#{person.class.name}] Name: \"#{person.name}\", ID: #{person.id}, Age: #{person.age}" 39 | end 40 | end 41 | 42 | def list_people_with_index 43 | @people.each_with_index do |person, i| 44 | puts "#{i}) [#{person.class.name}] Name: \"#{person.name}\", ID: #{person.id}, Age: #{person.age}" 45 | end 46 | end 47 | 48 | def create_person 49 | print 'Do you want to create a Student (1) or a Teacher (2)? [Input the number]: ' 50 | option = gets.chomp 51 | print 'Age: ' 52 | age = gets.chomp 53 | print 'Name: ' 54 | name = gets.chomp 55 | case option 56 | when '1' 57 | print 'Has parent permission? [Y/N]: ' 58 | permission = gets.chomp.downcase 59 | @people << Student.new(age, name, parent_permission: (permission == 'y')) 60 | when '2' 61 | print 'Specialization: ' 62 | specialization = gets.chomp 63 | @people << Teacher.new(age, specialization, name) 64 | end 65 | puts 'Person Created Successfully' 66 | 67 | @data_manager.people = @people 68 | @data_manager.save_people 69 | end 70 | 71 | def create_book 72 | print 'Title: ' 73 | title = gets.chomp.to_s 74 | 75 | print 'Author: ' 76 | author = gets.chomp.to_s 77 | 78 | @books.push(Book.new(title, author)) 79 | puts 'Book created successfully' 80 | 81 | @data_manager.save_books 82 | end 83 | 84 | def create_rental 85 | book = select_book 86 | return unless book 87 | 88 | person = select_person 89 | return unless person 90 | 91 | print 'Date: ' 92 | date = gets.chomp.to_s 93 | 94 | create_and_save_rental(date, book, person) 95 | end 96 | 97 | def select_book 98 | puts 'Select a book from the following list by number' 99 | list_books_with_index 100 | book_index = gets.chomp.to_i 101 | unless (0...@books.length).include?(book_index) 102 | puts "Error adding a record. Book #{book_index} doesn't exist" 103 | return 104 | end 105 | @books[book_index] 106 | end 107 | 108 | def select_person 109 | puts "\nSelect a person from the following list by number (not id)" 110 | list_people_with_index 111 | person_index = gets.chomp.to_i 112 | unless (0...@people.length).include?(person_index) 113 | puts "Error adding a record. Person #{person_index} doesn't exist" 114 | return 115 | end 116 | @people[person_index] 117 | end 118 | 119 | def create_and_save_rental(date, book, person) 120 | @rentals.push(Rental.new(date, book, person)) 121 | puts 'Rental created successfully' 122 | 123 | @data_manager.rentals = @rentals 124 | @data_manager.save_rentals 125 | end 126 | 127 | def list_rentals 128 | print 'ID of person: ' 129 | id = gets.chomp.to_i 130 | selected = @rentals.find_all { |rental| rental.person.id == id } 131 | if selected.empty? 132 | puts "Person with given id #{id} does not exist" 133 | return 134 | end 135 | puts 'Rentals:' 136 | selected.map { |rental| puts "Date: #{rental.date}, Book \"#{rental.book.title}\" by #{rental.book.author}" } 137 | end 138 | 139 | def run 140 | prompt 141 | save_data 142 | end 143 | end 144 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | logo 6 |
7 | 8 |

OOP school library

9 | 10 |
11 | 12 | 13 | 14 | # 📗 Table of Contents 15 | 16 | - [📗 Table of Contents](#-table-of-contents) 17 | - [📖 OOP school library ](#-oop-school-library-) 18 | - [🛠 Built With ](#-built-with-) 19 | - [Tech Stack ](#tech-stack-) 20 | - [Key Features ](#key-features-) 21 | - [💻 Getting Started ](#-getting-started-) 22 | - [Prerequisites](#prerequisites) 23 | - [Setup](#setup) 24 | - [Install](#install) 25 | - [👥 Authors ](#-authors-) 26 | - [🔭 Future Features ](#-future-features-) 27 | - [🤝 Contributing ](#-contributing-) 28 | - [⭐️ Show your support ](#️-show-your-support-) 29 | - [🙏 Acknowledgments ](#-acknowledgments-) 30 | - [📝 License ](#-license-) 31 | 32 | 33 | 34 | # 📖 OOP school library 35 | 36 | **OOP school library** is a simple ruby project, starting by create three classes, Person, Student and Teacher are inherents to Person with an extra parameter for each children class. 37 | 38 | ## 🛠 Built With 39 | 40 | ### Tech Stack 41 | 42 |
43 | Back-End 44 | 47 |
48 | 49 | 50 |
51 | Database 52 | 55 |
56 | 57 | 58 | 59 | ### Key Features 60 | 61 | - **Create a class** 62 | - **Create the instance vars class** 63 | 64 |

(back to top)

65 | 66 | 67 | 68 | ## 💻 Getting Started 69 | 70 | To get a local copy up and running, follow these steps. 71 | 72 | ### Prerequisites 73 | 74 | In order to run this project you need: 75 | 76 | ```sh 77 | gem install 78 | ``` 79 | 80 | ### Setup 81 | 82 | Clone this repository to your desired folder: 83 | 84 | ```sh 85 | cd library-school 86 | git clone git@github.com:noelfoka/library-school.git 87 | ``` 88 | 89 | ### Install 90 | 91 | Install this project with: 92 | 93 | ```sh 94 | cd library-school 95 | gem install 96 | ``` 97 | 98 | 99 | 100 | ## 👥 Authors 101 | 102 | 👤 **Noel FOKA** 103 | 104 | - GitHub: [@noelfoka](https://github.com/noelfoka) 105 | - Twitter: [@noelnomgne](https://twitter.com/noelnomgne) 106 | - LinkedIn: [noelfoka](https://linkedin.com/in/noelfoka) 107 | 108 | 109 | 👤 **Mohammad Mahdi Niazi** 110 | - GitHub: [@Mahdi-Niazi](https://github.com/Mahdi-Niazi) 111 | - Twitter: [@mahdinazi1](https://twitter.com/mahdiniazi1) 112 | - LinkedIn: [Mohammad Mahdi Niazi](https://www.linkedin.com/in/mohammad-mahdi-niazi/) 113 | 114 |

(back to top)

115 | 116 | 117 | 118 | ## 🔭 Future Features 119 | 120 | - [ ] **Unit Test Done** 121 | 122 |

(back to top)

123 | 124 | 125 | 126 | ## 🤝 Contributing 127 | 128 | Contributions, issues, and feature requests are welcome! 129 | 130 | Feel free to check the [issues page](../../issues/). 131 | 132 |

(back to top)

133 | 134 | 135 | 136 | ## ⭐️ Show your support 137 | 138 | If you like this project, give me a 🌟. 139 | 140 |

(back to top)

141 | 142 | 143 | 144 | ## 🙏 Acknowledgments 145 | 146 | I would like to thank Microverse and my partener Nelson Menendez 147 | 148 |

(back to top)

149 | 150 | 151 | 152 | ## 📝 License 153 | 154 | This project is [MIT](./LICENSE) licensed. 155 | 156 |

(back to top)

--------------------------------------------------------------------------------