diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml new file mode 100644 index 0000000..0e5efbd --- /dev/null +++ b/.github/workflows/linters.yml @@ -0,0 +1,20 @@ +name: Linters + +on: pull_request + +jobs: + rubocop: + name: Rubocop + runs-on: ubuntu-18.04 + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-ruby@v1 + with: + ruby-version: ">=3.0.x" + - name: Setup Rubocop + run: | + gem install --no-document rubocop -v '>= 1.0, < 2.0' # https://docs.rubocop.org/en/stable/installation/ + [ -f .rubocop.yml ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/ruby/.rubocop.yml + - name: Rubocop Report + run: rubocop --color \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..7401a9e --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,19 @@ +name: Tests + +on: pull_request + +jobs: + rspec: + name: RSpec + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-ruby@v1 + with: + ruby-version: 3.0.x + - name: Setup RSpec + run: | + [ -f Gemfile ] && bundle + gem install --no-document rspec -v '>=3.0, < 4.0' + - name: RSpec Report + run: rspec --force-color --format documentation \ No newline at end of file diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..4948d48 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,52 @@ +AllCops: + NewCops: enable + Exclude: + - "Guardfile" + - "Rakefile" + - "node_modules/**/*" + + DisplayCopNames: true + +Layout/LineLength: + Max: 120 +Metrics/MethodLength: + Max: 20 +Metrics/AbcSize: + Max: 50 +Metrics/ClassLength: + Max: 150 +Metrics/BlockLength: + IgnoredMethods: ['describe'] + Max: 30 + + +Style/Documentation: + Enabled: false +Style/ClassAndModuleChildren: + Enabled: false +Style/EachForSimpleLoop: + Enabled: false +Style/AndOr: + Enabled: false +Style/DefWithParentheses: + Enabled: false +Style/FrozenStringLiteralComment: + EnforcedStyle: never + +Layout/HashAlignment: + EnforcedColonStyle: key +Layout/ExtraSpacing: + AllowForAlignment: false +Layout/MultilineMethodCallIndentation: + Enabled: true + EnforcedStyle: indented +Lint/RaiseException: + Enabled: false +Lint/StructNewOverride: + Enabled: false +Style/HashEachMethods: + Enabled: false +Style/HashTransformKeys: + Enabled: false +Style/HashTransformValues: + Enabled: false \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..3fe9350 --- /dev/null +++ b/Gemfile @@ -0,0 +1,2 @@ +source 'https://rubygems.org' +gem 'rubocop', '>= 1.0', '< 2.0' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..1c9955c --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,32 @@ +GEM + remote: https://rubygems.org/ + specs: + ast (2.4.2) + parallel (1.21.0) + parser (3.0.2.0) + ast (~> 2.4.1) + rainbow (3.0.0) + regexp_parser (2.1.1) + rexml (3.2.5) + rubocop (1.23.0) + parallel (~> 1.10) + parser (>= 3.0.0.0) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml + rubocop-ast (>= 1.12.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.13.0) + parser (>= 3.0.1.1) + ruby-progressbar (1.11.0) + unicode-display_width (2.1.0) + +PLATFORMS + x64-mingw32 + +DEPENDENCIES + rubocop (>= 1.0, < 2.0) + +BUNDLED WITH + 2.2.22 diff --git a/README.md b/README.md index 6637131..bbcc2ce 100644 --- a/README.md +++ b/README.md @@ -1 +1,33 @@ -# school-library \ No newline at end of file +## School-library +Imagine that you are the librarian of OOP University, and you need a tool to record what books are in the library and who borrows them. This app that I created will make your library the best organized one. +This app allows you to: +- Add new students or teachers. +- Add new books. +- Save records of who borrowed a given book and when. +![WebImages](./images/p0.JPG) + +![WebImages](./images/p1.JPG) +![WebImages](./images/p2.JPG) +![WebImages](./images/p3.JPG) +![WebImages](./images/p4.JPG) +## Built With +- Ruby +- OOP +- rubocop + +## Author +👤 **Olipliche Mavoungou Paka** +- GitHub: [https://github.com/OLIPLICHE) +- LinkedIn: [LinkedIn](https://www.linkedin.com/in/olipliche/) + +## 🤝 Contributing +Contributions, Issues, and feature requests are welcome! + +## Show your support +Give a ⭐️ if you like this project +## Acknowledgments +- Hat tip to anyone whose code was used +- Inspiration + +## 📝 License +This project is [Microverse](https://www.microverse.org/) licensed. diff --git a/book.rb b/book.rb new file mode 100644 index 0000000..662bcfb --- /dev/null +++ b/book.rb @@ -0,0 +1,15 @@ +class Book + attr_accessor :title, :author + attr_reader :rentals + + def initialize(title, author) + @title = title + @author = author + @rentals = [] + end + + def add_rental(rental) + @rentals << rental + rental.book = self + end +end diff --git a/classroom.rb b/classroom.rb new file mode 100644 index 0000000..6fde1a5 --- /dev/null +++ b/classroom.rb @@ -0,0 +1,14 @@ +class Classroom + attr_accessor :label + attr_reader :students + + def initialize(label) + @label = label + @students = [] + end + + def add_student(student) + @students << student + student.classroom = self + end +end diff --git a/corrector.rb b/corrector.rb new file mode 100644 index 0000000..a5179de --- /dev/null +++ b/corrector.rb @@ -0,0 +1,11 @@ +class Corrector + def correct_name(name) + get_name = name.strip.capitalize + + if get_name.length > 10 + get_name[0, 10] + else + get_name + end + end +end diff --git a/images/p0.JPG b/images/p0.JPG new file mode 100644 index 0000000..00eb1f0 Binary files /dev/null and b/images/p0.JPG differ diff --git a/images/p1.JPG b/images/p1.JPG new file mode 100644 index 0000000..671c8af Binary files /dev/null and b/images/p1.JPG differ diff --git a/images/p2.JPG b/images/p2.JPG new file mode 100644 index 0000000..36b6934 Binary files /dev/null and b/images/p2.JPG differ diff --git a/images/p3.JPG b/images/p3.JPG new file mode 100644 index 0000000..d6aec06 Binary files /dev/null and b/images/p3.JPG differ diff --git a/images/p4.JPG b/images/p4.JPG new file mode 100644 index 0000000..52c4ce3 Binary files /dev/null and b/images/p4.JPG differ diff --git a/main.rb b/main.rb new file mode 100644 index 0000000..477c5b5 --- /dev/null +++ b/main.rb @@ -0,0 +1,184 @@ +require './person' +require './book' +require './classroom' +require './corrector' +require './rental' +require './student' +require './teacher' + +class App + attr_accessor :books, :persons, :rentals + + def initialize + @books = [] + @people = [] + @rentals = [] + @class = Classroom.new('Grade 7') + end + + def run + print 'Welcome to School Library App!' + sleep 0.75 + menu + end + + def menu + puts + puts 'Please choose on option by entering a number' + puts '1 - List all books' + puts '2 - List all people' + puts '3 - Create a person' + puts '4 - Create a book' + puts '5 - Create a rental' + puts '6 - List all rentals for a given person id' + puts '7 - Exit' + option = gets.chomp + + get_option option + end + + # rubocop:disable Metrics/CyclomaticComplexity + def get_option(input) + case input + when '1' + list_all_books + when '2' + list_all_people + when '3' + create_a_person + when '4' + create_a_book + when '5' + create_a_rental + when '6' + list_rentals_by_person_id + when '7' + puts 'Thank you for using this app!' + else + puts 'Please enter a number between 1 and 7' + end + end + # rubocop:enable Metrics/CyclomaticComplexity + + def list_all_books + puts 'There are no books yet! Kindly add books.' if @books.empty? + + @books.each { |book| puts "Title: #{book.title}, Author: #{book.author}" } + sleep 0.75 + menu + end + + def list_all_people + puts 'There are no people yet! Kindly add a student or teacher.' if @people.empty? + @people.map { |person| puts "[#{person.class}] Name: #{person.name}, ID: #{person.id}, Age: #{person.age}" } + sleep 0.75 + menu + end + + def create_a_person + print 'Do you want to create a student (1) or teacher (2) [Input a number]: ' + option = gets.chomp + + case option + when '1' + create_a_student + when '2' + create_a_teacher + else + puts 'Invalid input. Kindly type 1 or 2' + end + end + + def create_a_student + print 'Age: ' + age = gets.chomp.to_i + + print 'Name: ' + name = gets.chomp + + print 'Has parent permission? [Y/N]: ' + parent_permission = gets.chomp.downcase + + student = Student.new(age, @class, name, parent_permission) + @people << student + + puts 'Student created successfully' + sleep 0.75 + menu + end + + def create_a_teacher + print 'Age: ' + age = gets.chomp.to_i + + print 'Name: ' + name = gets.chomp + + print 'Specialization: ' + specialization = gets.chomp + + teacher = Teacher.new(specialization, age, name) + @people << teacher + + puts 'Teacher created successfully' + sleep 0.75 + menu + end + + def create_a_book + print 'Title: ' + title = gets.chomp + + print 'Author: ' + author = gets.chomp + + book = Book.new(title, author) + @books << book + + puts 'Book added successfully' + sleep 0.75 + menu + end +end + +def create_a_rental + puts 'Select a book from the following list by number' + @books.each_with_index { |book, index| puts "#{index}) Title: #{book.title}, Author: #{book.author}" } + + book_id = gets.chomp.to_i + + puts 'Select a person from the following list by number (not id)' + @people.each_with_index do |person, index| + puts "#{index}) [#{person.class}] Name: #{person.name}, ID: #{person.id}, Age: #{person.age}" + end + + person_id = gets.chomp.to_i + + print 'Date: ' + date = gets.chomp.to_s + + rental = Rental.new(date, @people[person_id], @books[book_id]) + @rentals << rental + + puts 'Rental created successfully' + sleep 0.75 + menu +end + +def list_rentals_by_person_id + print 'ID of person: ' + id = gets.chomp.to_i + + puts 'Rentals:' + @rentals.each do |rental| + puts "Date: #{rental.date}, Book: '#{rental.book.title}' by #{rental.book.author}" if rental.person.id == id + end + sleep 0.75 + menu +end + +def main + app = App.new + app.run +end +main diff --git a/person.rb b/person.rb new file mode 100644 index 0000000..da1a913 --- /dev/null +++ b/person.rb @@ -0,0 +1,36 @@ +# rubocop: disable Style/OptionalBooleanParameter +require './corrector' +class Person + attr_accessor :name, :age + attr_reader :id, :rentals + + def initialize(age, name = 'Unknown', parent_permission = true) + @id = Random.rand(1..1000) + @name = name + @age = age + @parent_permission = parent_permission + @corrector = Corrector.new + @rentals = [] + end + + def of_age? + @age >= 18 + end + + private :of_age? + + def can_use_services? + of_age? || parent_permission == true + end + + def validate_name + validate = @corrector + @name = validate.correct_name(@name) + end + + def add_rental(rental) + @rentals << rental + rental.book = self + end +end +# rubocop: enable Style/OptionalBooleanParameter diff --git a/rental.rb b/rental.rb new file mode 100644 index 0000000..05ad49d --- /dev/null +++ b/rental.rb @@ -0,0 +1,22 @@ +class Rental + attr_accessor :date + attr_reader :book, :person + + def initialize(date, person, book) + @date = date + @book = book + @book.rentals << self + @person = person + person.rentals << self + end + + def book=(book) + @book = book + book.rentals.push(self) unless book.rentals.include?(self) + end + + def person=(person) + @person = person + person.rentals.push(self) unless person.rentals.include?(self) + end +end diff --git a/student.rb b/student.rb new file mode 100644 index 0000000..e1c1af2 --- /dev/null +++ b/student.rb @@ -0,0 +1,20 @@ +# rubocop: disable Style/OptionalBooleanParameter +require './person' +class Student < Person + attr_reader :classroom + + def initialize(age, classroom, name = 'Unknown', parent_permission = true) + super(name, age, parent_permission) + @classroom = classroom + end + + def play_hooky + '¯\(ツ)/¯' + end + + def classroom=(classroom) + @classroom = classroom + classroom.students.push(self) unless classroom.students.include?(self) + end +end +# rubocop: enable Style/OptionalBooleanParameter diff --git a/teacher.rb b/teacher.rb new file mode 100644 index 0000000..1ad5c2b --- /dev/null +++ b/teacher.rb @@ -0,0 +1,13 @@ +# rubocop: disable Style/OptionalBooleanParameter +require './person' +class Teacher < Person + def initialize(specialization, age, name = 'Unknown', parent_permission = true) + super(age, name, parent_permission) + @specialization = specialization + end + + def can_use_services? + true + end +end +# rubocop: enable Style/OptionalBooleanParameter