diff --git a/.bundle/config b/.bundle/config new file mode 100644 index 0000000..6d9698e --- /dev/null +++ b/.bundle/config @@ -0,0 +1,2 @@ +--- +BUNDLE_PATH: "ruby-capstone" diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml new file mode 100644 index 0000000..e284163 --- /dev/null +++ b/.github/workflows/linters.yml @@ -0,0 +1,20 @@ +name: Linters + +on: pull_request + +jobs: + rubocop: + name: Rubocop + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-ruby@v1 + with: + ruby-version: ">=3.1.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..f44b191 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,19 @@ +name: Tests + +on: pull_request + +jobs: + rspec: + name: RSpec + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-ruby@v1 + with: + ruby-version: 3.1.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..400e887 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,54 @@ +AllCops: + NewCops: enable + Exclude: + - "Guardfile" + - "Rakefile" + - "node_modules/**/*" + + DisplayCopNames: true + +Layout/LineLength: + Max: 130 +Metrics/MethodLength: + Max: 25 +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 +Layout/EndOfLine: + Enabled: False \ No newline at end of file diff --git a/Database/schema.sql b/Database/schema.sql new file mode 100644 index 0000000..f949bde --- /dev/null +++ b/Database/schema.sql @@ -0,0 +1,64 @@ +-- create catalog of my things database +CREATE DATABASE catalog; + +-- create label table + +CREATE TABLE label ( + id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + title VARCHAR(100) NOT NULL, + color VARCHAR(100) NOT NULL +); + +-- create book table +CREATE TABLE book ( + id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + author_id INT REFERENCES author(id), + published_date DATE, + publisher TEXT, + archived BOOLEAN NOT NULL DEFAULT FALSE, + cover_state VARCHAR(5), + label_id INT REFERENCES label(id) +); + +-- create game table +CREATE TABLE game ( + id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + published_date DATE, + multiplayer BOOLEAN NOT NULL DEFAULT FALSE, + last_played_at DATE, + author_id int REFERENCES author(id), +); + +-- create author table +CREATE TABLE author ( + id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + first_name VARCHAR(100) NOT NULL, + last_name VARCHAR(100) NOT NULL, +); + +-- create genre table +CREATE TABLE Genre( + id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + name VARCHAR(60) NOT NULL +); + +-- create item table + +CREATE TABLE item( + id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + genre_id INT, + author_id INT, + label_id INT, + publish_date Date, + archived BOOLEAN, + FOREIGN KEY(genre_id) REFERENCES Genre(id) ON UPDATE CASCADE, + FOREIGN KEY(author_id) REFERENCES Author(id) ON UPDATE CASCADE, + FOREIGN KEY(label_id) REFERENCES Label(id) ON UPDATE CASCADE +); + +-- create music_album table +CREATE TABLE MusicAlbum( + id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + on_spotify BOOLEAN NOT NULL, + FOREIGN KEY(id) REFERENCES item(id) ON UPDATE CASCADE +); \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..1a22d6d --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' + +gem 'rubocop', '>= 1.0', '< 2.0' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..41ea951 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,34 @@ +GEM + remote: https://rubygems.org/ + specs: + ast (2.4.2) + json (2.6.3) + parallel (1.23.0) + parser (3.2.2.1) + ast (~> 2.4.1) + rainbow (3.1.1) + regexp_parser (2.8.0) + rexml (3.2.5) + rubocop (1.51.0) + json (~> 2.3) + parallel (~> 1.10) + parser (>= 3.2.0.0) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.28.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.28.1) + parser (>= 3.2.1.0) + ruby-progressbar (1.13.0) + unicode-display_width (2.4.2) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + rubocop (>= 1.0, < 2.0) + +BUNDLED WITH + 2.4.13 diff --git a/LICENSE b/LICENSE index f182899..8f1d0fa 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2023 Brhanu Hailu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2023 Brhanu Hailu, Daniel Matama + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 75fc403..bf04f7d 100644 --- a/README.md +++ b/README.md @@ -1 +1,189 @@ -# capstone-ruby-practice \ No newline at end of file + + +# 📗 Table of Contents + +- [📖 About the Project](#about-project) + - [🛠 Built With](#built-with) + - [Tech Stack](#tech-stack) + - [Key Features](#key-features) + - [🚀 Live Demo](#live-demo) +- [💻 Getting Started](#getting-started) + - [Setup](#setup) + - [Prerequisites](#prerequisites) + - [Install](#install) + - [Usage](#usage) + - [Run tests](#run-tests) + - [Deployment](#triangular_flag_on_post-deployment) +- [👥 Authors](#authors) +- [🔭 Future Features](#future-features) +- [🤝 Contributing](#contributing) +- [⭐️ Show your support](#support) +- [🙏 Acknowledgements](#acknowledgements) +- [❓ FAQ (OPTIONAL)](#faq) +- [📝 License](#license) + + + +# 📖 [Catalogue_Of_My_Things] + +**[Catalogue_Of_My_Things]** is a console app that will help to keep a record of different types of things one owns: books, music albums, movies, and games. Everything is based on the UML class diagram. The data is stored in JSON files but we also prepare a database with tables structure analogical the program's class structure. + +## 🛠 Built With + +### Tech Stack + +
+ Server + +
+ +
+Database + +
+ + + +### Key Features + +- **[User Interface]** +- **[Add Database to store the whole data]** +- **[preserve data in json format]** + +

(back to top)

+ + + +## 🚀 Video Link + +> - [Video Link](https://drive.google.com/file/d/1jBsHmWNemll98kqnGH5JWwbRKP6Eb4G9/view?usp=sharing) + + +

(back to top)

+ + + +## 💻 Getting Started + +To get a local copy up and running, follow these steps. + +### Prerequisites + +In order to run this project you need: + +```sh + install sudo apt-get install ruby-full +``` + +### Setup + +Clone this repository to your desired folder: + +```sh + cd my-folder + git clone https://github.com/brhanuhailu/ruby-capstone.git +``` + + +### Install + +Install this project with: + +```sh + cd project + bundle install +``` +### Usage + +To run the project, execute the following command: +```sh + ruby main.rb +``` +### Run tests + +To run Linter tests, run the following command: +```sh + rubocop +``` +### Run unit tests + +To run unit tests, run the following command: +```sh + Rspec +``` +### Deployment + +Not applicable. + + +

(back to top)

+ + + +## 👥 Authors + +👤 **Daniel Matama** + +- GitHub: [@Recillah-Khamala](https://github.com/danielmatama) +- Twitter: [@recillahk](https://twitter.com/danmatama) +- LinkedIn: [Recillah Khamala](https://www.linkedin.com/in/danielmatama-mwebesa/) + +👤 **Brhanu Hailu** + +- GitHub: [@brhanuhailu](https://github.com/brhanuhailu) +- Twitter: [@tigrayfurtune](https://twitter.com/TigrayCountry) +- LinkedIn: [LinkedIn](https://www.linkedin.com/in/brhanu-hailu-85578a246/) + +👤 **Yodit Abebe** + +- GitHub: [@yodit93](https://github.com/yodit93) +- Twitter: [@@yodtwit](https://twitter.com/yodtwit) +- LinkedIn: [LinkedIn](https://www.linkedin.com/in/yodit-abebe-ayalew/) + +

(back to top)

+ + + +## 🔭 Future Features + +- [ ] **[Add more unit tests]** +- [ ] **[Create complete databases]** + +

(back to top)

+ + + +## 🤝 Contributing + +Contributions, issues, and feature requests are welcome! + +Feel free to check the [issues page](https://github.com/brhanuhailu/ruby-capstone/issues). + +

(back to top)

+ + + +## ⭐️ Show your support + +If you like this project give a ⭐️ and We are so excited to accept you feedback to improve our profession. + +

(back to top)

+ + + +## 🙏 Acknowledgments + +we would like to thank Microverse + +

(back to top)

+ + + + +## 📝 License + +This project is [MIT](https://github.com/brhanuhailu/ruby-capstone/blob/dev/LICENSE) licensed. diff --git a/app.rb b/app.rb new file mode 100644 index 0000000..39b089d --- /dev/null +++ b/app.rb @@ -0,0 +1,152 @@ +require_relative 'book' +require_relative 'label' +require_relative 'item' +require_relative 'game' +require_relative './store/preserve_data' +require_relative 'author' +require_relative './src/music/genre' +require_relative './src/music/music_album' +require_relative './handler' +require 'json' +require 'date' + +class App < Handler + def initialize + super + @genres = [] + @music_albums = [] + @store = PreserveData.new + @books = File.empty?('./store/books.json') ? [] : @store.load_data('./store/books.json') + @labels = File.empty?('./store/labels.json') ? [] : @store.load_data('./store/labels.json') + @games = File.empty?('./store/games.json') ? [] : @store.load_data('./store/games.json') + @authors = File.empty?('./store/authors.json') ? [] : @store.load_data('./store/authors.json') + end + + def list_books + @books.each do |book| + puts "#{book['id']} - #{book['author']} - #{book['published_date']}" + end + end + + def list_labels + @labels.each do |label| + puts "#{label['id']} - #{label['title']} - #{label['color']}" + end + end + + def create_book + puts 'Enter author' + author = gets.chomp + puts 'Enter published date (YYYY-MM-DD))' + published_date = gets.chomp + puts 'Enter publisher' + publisher = gets.chomp + puts 'Enter cover state' + cover_state = gets.chomp + puts 'Enter label title' + label_title = gets.chomp + puts 'Enter label color' + label_color = gets.chomp + label = create_label(label_title, label_color) + book = create_book_object(author, published_date, publisher, cover_state, label) + @books << book + @labels << label + @store.save_data(@books, './store/books.json') + @store.save_data(@labels, './store/labels.json') + puts 'Book created successfully' + end + + def create_label(title, color) + label = Label.new(title, color) + { 'id' => label.id, 'title' => label.title, 'color' => label.color } + end + + def create_book_object(author, published_date, publisher, cover_state, label) + book = Book.new(author, published_date, publisher, cover_state, label) + { + 'id' => book.id, + 'author' => book.author, + 'published_date' => book.published_date, + 'publisher' => book.publisher, + 'cover_state' => book.cover_state, + 'label' => book.label + } + end + + def list_games + if @games.empty? + puts 'No games found in the system currently' + else + puts '=================================================================:' + puts 'List of Games:' + puts '=================================================================:' + puts 'ID - Game Name - Last Played Date - Published Date - Multiplayer' + @games.each do |game| + puts "#{game['id']} - #{game['game_name']} - #{game['last_played_at']} - #{game['publish_date']} - #{game['multiplayer']}" + end + puts '=================================================================:' + end + end + + def list_authors + if @authors.empty? + puts 'No authors found in the system currently' + else + puts '=============================================:' + puts 'List of Authors:' + puts '=============================================:' + puts 'ID - First Name - Last Name' + @authors.each do |author| + puts "#{author['id']} - #{author['first_name']} - #{author['last_name']}" + end + puts '=============================================:' + end + end + + def create_games + puts 'write Name of the game' + game_name = gets.chomp + puts 'Write last played date (YYYY-MM-DD))' + last_played_at = gets.chomp + puts 'Enter published date (YYYY-MM-DD))' + publish_date = gets.chomp + puts 'Enter multiplayer (yes/no)' + multiplayer = gets.chomp.downcase == 'yes' + puts 'Enter first name' + first_name = gets.chomp + puts 'Enter last name' + last_name = gets.chomp + author = create_author(first_name, last_name) + @authors << author + @store.save_data(@authors, './store/authors.json') + game = create_game_object(game_name, last_played_at, publish_date, multiplayer) + @games << game + @store.save_data(@games, './store/games.json') + puts 'Game is created successfully' + end + + def create_author(first_name, last_name) + author = Author.new(first_name, last_name) + { + 'id' => author.id, + 'first_name' => author.first_name, + 'last_name' => author.last_name + } + end + + def create_game_object(game_name, last_played_at, publish_date, multiplayer) + game = Game.new(game_name, last_played_at, publish_date, multiplayer) + { + 'id' => game.id, + 'game_name' => game.game_name, + 'last_played_at' => game.last_played_at, + 'publish_date' => game.publish_date, + 'multiplayer' => game.multiplayer + } + end + + def exit_app + puts 'Thanks for using the app!' + exit + end +end diff --git a/author.rb b/author.rb new file mode 100644 index 0000000..473da15 --- /dev/null +++ b/author.rb @@ -0,0 +1,22 @@ +require_relative 'item' + +class Author + attr_reader :id + attr_accessor :first_name, :last_name, :items + + def initialize(first_name, last_name) + @id = Random.rand(1..1000) + @first_name = first_name + @last_name = last_name + @items = [] + end + + def full_name + "#{@first_name} #{@last_name}" + end + + def add_author(item) + @items.push(item) + item.author = self + end +end diff --git a/book.rb b/book.rb new file mode 100644 index 0000000..3aa4727 --- /dev/null +++ b/book.rb @@ -0,0 +1,16 @@ +require_relative 'item' + +class Book < Item + attr_accessor :publisher, :cover_state + + def initialize(author, published_date, publisher, cover_state, label = nil) + super(nil, author, published_date, label) + @publisher = publisher + @cover_state = cover_state + end + + def can_be_archived? + result = super + result || cover_state == 'bad' + end +end diff --git a/game.rb b/game.rb new file mode 100644 index 0000000..19555ea --- /dev/null +++ b/game.rb @@ -0,0 +1,26 @@ +require_relative 'item' +require 'date' + +class Game < Item + attr_accessor :id, :game_name, :multiplayer, :last_played_at, :publish_date + + def initialize(game_name, last_played_at, publish_date, multiplayer) + super(nil, nil, nil, publish_date) + @id = id || Random.rand(1..1000) + @game_name = game_name + @multiplayer = multiplayer + @last_played_at = Date.parse(last_played_at) + @publish_date = Date.parse(publish_date) + end + + def move_to_archive + @archived = true if can_be_archived? + end + + private + + def can_be_archived? + age_in_years = Time.now.year - @last_played_at.year + age_in_years >= 2 + end +end diff --git a/handler.rb b/handler.rb new file mode 100644 index 0000000..5c0151d --- /dev/null +++ b/handler.rb @@ -0,0 +1,70 @@ +require_relative './store' +require_relative 'storage' + +class Handler + include JsonStorage + include Storage + + def add_music_album + puts 'Album name: ' + name = gets.chomp + puts 'Genre: ' + genre_name = gets.chomp + @genres.push(Genre.new(genre_name)) + store_genre_data + + puts 'Date of publish [Enter date in format (yyyy-mm-dd)]' + publish_date = gets.chomp + + puts 'Is it available on Spotify? Y/N' + on_spotify = gets.chomp.downcase + case on_spotify + when 'y' + @music_albums.push(MusicAlbum.new(name, publish_date, true)) + when 'n' + @music_albums.push(MusicAlbum.new(name, publish_date, false)) + end + puts 'Music album created' + store_music_data + end + + def albums + music_data = get_data('./store/music_albums.json') + puts 'No music found' if music_data.empty? + music_data.each do |music_album| + puts "Album_name: #{music_album['music_name']} | On_spotify: #{music_album['music_on_spotify']}" + end + end + + def genres + data = get_data('./store/genres.json') + puts 'No genre found' if data.empty? + data.each do |genre| + puts "Genre name: #{genre['genre_name']}" + end + end + + def store_music_data + array = [] + @music_albums.each do |music| + array << { + music_id: music.id, + music_name: music.name, + music_on_spotify: music.on_spotify + + } + end + update_data(array, './store/music_albums.json') + end + + def store_genre_data + array = [] + @genres.each do |genre| + array << { + genre_id: genre.id, + genre_name: genre.name + } + end + update_data(array, './store/genres.json') + end +end diff --git a/item.rb b/item.rb new file mode 100644 index 0000000..998ec96 --- /dev/null +++ b/item.rb @@ -0,0 +1,39 @@ +require 'date' + +class Item + attr_reader :id, :label, :author, :genre + attr_accessor :published_date, :archived + + def initialize(genre, author, published_date, label = nil) + @id = Random.rand(1..1000) + @genre = genre + @author = author + @label = label + @published_date = published_date + @archived = false + end + + def can_be_archived? + age_in_years = Time.now.year - Date.parse(@published_date).year + age_in_years >= 10 + end + + def move_to_archive + @archived = true if can_be_archived? + end + + def label=(label) + @label = label + label.add_item(self) unless label.items.include?(self) + end + + def author=(author) + @author = author + author.add_author(self) unless author.items.include?(self) + end + + def genre=(genre) + @genre = genre + genre.add_item(self) unless genre.items.include?(self) + end +end diff --git a/label.rb b/label.rb new file mode 100644 index 0000000..8b44ec5 --- /dev/null +++ b/label.rb @@ -0,0 +1,15 @@ +class Label + attr_accessor :title, :color, :items, :id + + def initialize(title, color) + @id = Random.rand(1..1000) + @title = title + @color = color + @items = [] + end + + def add_item(item) + @items << item + item.label = self if item.label.nil? + end +end diff --git a/main.rb b/main.rb new file mode 100644 index 0000000..a6f2d22 --- /dev/null +++ b/main.rb @@ -0,0 +1,95 @@ +require_relative 'app' + +class MainMenu + attr_reader :app + + def initialize(app) + @app = app + end + + def user_options(choice) + menu_options = { + 1 => method(:list_books), + 2 => method(:list_music), + 3 => method(:list_games), + 4 => method(:list_genres), + 5 => method(:list_labels), + 6 => method(:list_authors), + 7 => method(:create_book), + 8 => method(:create_music), + 9 => method(:create_games), + 0 => method(:exit_app) + } + if menu_options.key?(choice) + menu_options[choice].call(app) + else + puts 'Invalid option, please try again!' + end + end + + def display + puts 'Welcome to your library' + puts 'Please choose an option' + puts '1. List all books' + puts '2. List all music albums' + puts '3. List all games' + puts '4. List all genres' + puts '5. List all labels' + puts '6. List all authors' + puts '7. Create a book' + puts '8. Create a music album' + puts '9. Create a game' + puts '0. Exit' + end + + def list_books(app) + app.list_books + end + + def list_music(app) + app.albums + end + + def list_games(app) + app.list_games + end + + def list_genres(app) + app.genres + end + + def list_labels(app) + app.list_labels + end + + def list_authors(app) + app.list_authors + end + + def create_book(app) + app.create_book + end + + def create_music(app) + app.add_music_album + end + + def create_games(app) + app.create_games + end + + def exit_app(app) + app.exit_app + end +end + +def main + app = App.new + main_menu = MainMenu.new(app) + loop do + main_menu.display + choice = gets.chomp.to_i + main_menu.user_options(choice) + end +end +main diff --git a/spec/author_spec.rb b/spec/author_spec.rb new file mode 100644 index 0000000..7eac509 --- /dev/null +++ b/spec/author_spec.rb @@ -0,0 +1,25 @@ +require_relative './spec_helper' +RSpec.describe Author do + describe '#add_author' do + let(:author) { Author.new('John', 'Doe') } + let(:item) { Item.new('gameone', 'hall', '2022-1-2', nil) } + + it 'adds an item to the author' do + author.add_author(item) + expect(author.items).to include(item) + end + + it 'sets the author of the item to the current author' do + author.add_author(item) + expect(item.author).to eq(author) + end + end + + describe '#full_name' do + let(:author) { Author.new('John', 'Doe') } + + it 'returns the full name of the author' do + expect(author.full_name).to eq('John Doe') + end + end +end diff --git a/spec/book_spec.rb b/spec/book_spec.rb new file mode 100644 index 0000000..c6e67ad --- /dev/null +++ b/spec/book_spec.rb @@ -0,0 +1,44 @@ +require_relative './spec_helper' +describe Book do + before(:all) do + label = Label.new('Fiction', 'blue') + @book = Book.new('author', '2020-01-01', 'publisher', 'good', label) + end + + describe '#initialize' do + it 'creates a new Book instance' do + expect(@book).to be_an_instance_of Book + end + + it 'the author of the book should be "author"' do + expect(@book.author).to eq('author') + end + + it 'the publication date of the book should be "2020-01-01"' do + expect(@book.published_date).to eq('2020-01-01') + end + + it 'the publisher of the book should be "publisher"' do + expect(@book.publisher).to eq('publisher') + end + + it 'the cover state of the book should be "good"' do + expect(@book.cover_state).to eq('good') + end + + it 'the label of the book should be a Label instance' do + expect(@book.label).to be_kind_of Label + end + end + + describe '#can_be_archived?' do + it 'should return true for less than 10 years' do + expect(@book.can_be_archived?).to eq(false) + end + + it 'should return false for more than 10 years' do + @book.published_date = '2010-01-01' + expect(@book.can_be_archived?).to eq(true) + end + end +end diff --git a/spec/game_spec.rb b/spec/game_spec.rb new file mode 100644 index 0000000..62e691b --- /dev/null +++ b/spec/game_spec.rb @@ -0,0 +1,59 @@ +RSpec.describe Game do + let(:game) { Game.new('Game Name', '2022-01-01', '2022-01-01', 'Yes') } + + describe '#initialize' do + it 'sets the game_name' do + expect(game.game_name).to eq('Game Name') + end + + it 'sets the multiplayer' do + expect(game.multiplayer).to eq('Yes') + end + + it 'sets the last_played_at' do + expect(game.last_played_at).to eq(Date.parse('2022-01-01')) + end + + it 'sets the publish_date' do + expect(game.publish_date).to eq(Date.parse('2022-01-01')) + end + end + + describe '#move_to_archive' do + context 'when the game is older than 2 years' do + let(:game) { Game.new('Game Name', '2020-01-01', '2022-01-01', 'Yes') } + + it 'moves the game to archive' do + game.move_to_archive + expect(game.archived).to be true + end + end + + context 'when the game is newer than 2 years' do + let(:game) { Game.new('Game Name', '2022-01-01', '2022-01-01', 'Yes') } + + it 'does not move the game to archive' do + game.move_to_archive + expect(game.archived).to be false + end + end + end + + describe '#can_be_archived?' do + context 'when the game is older than 2 years' do + let(:game) { Game.new('Game Name', '2020-01-01', '2022-01-01', 'Yes') } + + it 'returns true' do + expect(game.send(:can_be_archived?)).to be true + end + end + + context 'when the game is newer than 2 years' do + let(:game) { Game.new('Game Name', '2022-01-01', '2022-01-01', 'Yes') } + + it 'returns false' do + expect(game.send(:can_be_archived?)).to be false + end + end + end +end diff --git a/spec/genre_spec.rb b/spec/genre_spec.rb new file mode 100644 index 0000000..d34b4b7 --- /dev/null +++ b/spec/genre_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' +require_relative '../src/music/genre' +RSpec.describe Genre do + let(:name) { 'Action' } + let(:id) { 42 } + item = Item.new('genre', 'name', 'published_date') + subject { Genre.new(name, id: id) } + describe '#initialize' do + it 'sets the name' do + expect(subject.name).to eq(name) + end + it 'sets the id' do + expect(subject.id).to eq(id) + end + it 'initializes an empty items array' do + expect(subject.items).to be_empty + end + end + describe '#add_item' do + it 'adds the item to the items array' do + subject.add_item(item) + expect(subject.items).to include(item) + end + it 'sets the genre on the item' do + expect(item).to receive(:genre=).with(subject) + subject.add_item(item) + end + end +end diff --git a/spec/item_spec.rb b/spec/item_spec.rb new file mode 100644 index 0000000..9a8780d --- /dev/null +++ b/spec/item_spec.rb @@ -0,0 +1,70 @@ +require_relative './spec_helper' +describe Book do + before(:all) do + @label = Label.new('Fiction', 'blue') + @item = Item.new('genre', 'author', '2020-01-01', nil) + end + + describe '#initialize' do + it 'creates a new item instance' do + expect(@item).to be_an_instance_of Item + end + + it 'the genre of the item should be "genre"' do + expect(@item.genre).to eq('genre') + end + + it 'the author of the item should be "author"' do + expect(@item.author).to eq('author') + end + + it 'the publication date of the book should be "2010-01-01"' do + expect(@item.published_date).to eq('2020-01-01') + end + + it 'the label of the book should be a Label instance' do + expect(@item.label).to be nil + end + end + + describe '#can_be_archived?' do + it 'should return false for less than 10 years' do + expect(@item.can_be_archived?).to eq(false) + end + + it 'should return true for more than 10 years' do + @item.published_date = '2010-01-01' + expect(@item.can_be_archived?).to eq(true) + end + end + + describe '#move_to_archive' do + it 'should return true if can_be_archived? is true' do + @item.published_date = '2010-01-01' + expect(@item.move_to_archive).to eq(true) + end + end + + describe '#label=' do + it 'should add the item to the label' do + @item.label = @label + expect(@label.items).to include(@item) + end + end + + describe '#author=' do + it 'should add the item to the author' do + author = Author.new('John', 'Doe') + @item.author = author + expect(author.items).to include(@item) + end + end + + describe '#genre=' do + it 'should add the item to the genre' do + genre = Genre.new('Fiction') + @item.genre = genre + expect(genre.items).to include(@item) + end + end +end diff --git a/spec/label_spec.rb b/spec/label_spec.rb new file mode 100644 index 0000000..b46c754 --- /dev/null +++ b/spec/label_spec.rb @@ -0,0 +1,29 @@ +require_relative './spec_helper' + +describe Label do + before(:all) do + @label = Label.new('Fiction', 'blue') + end + + describe '#initialize' do + it 'creates a new Label instance' do + expect(@label).to be_an_instance_of Label + end + + it 'the title of the label should be "Fiction"' do + expect(@label.title).to eq('Fiction') + end + + it 'the color of the label should be "blue"' do + expect(@label.color).to eq('blue') + end + end + + describe '#add_item' do + it 'should add an item to the label' do + book = Book.new('author', '2020-01-01', 'publisher', 'good', nil) + @label.add_item(book) + expect(@label.items).to include(book) + end + end +end diff --git a/spec/music_album_spec.rb b/spec/music_album_spec.rb new file mode 100644 index 0000000..243482d --- /dev/null +++ b/spec/music_album_spec.rb @@ -0,0 +1,15 @@ +require_relative '../src/music/music_album' +require_relative '../item' +describe MusicAlbum do + context 'Given an instance of the music album class' do + before :each do + @music = MusicAlbum.new('Kaweesi', '2013-09-03', true) + end + it 'creates an instance of the music album class' do + expect(@music).to be_instance_of MusicAlbum + end + it 'return true for the can be archived method' do + expect(@music.can_be_archived?).to be true + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..4416388 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,6 @@ +require_relative '../book' +require_relative '../label' +require_relative '../game' +require_relative '../author' +require_relative '../item' +require_relative '../src/music/genre' diff --git a/src/music/genre.rb b/src/music/genre.rb new file mode 100644 index 0000000..56899a7 --- /dev/null +++ b/src/music/genre.rb @@ -0,0 +1,14 @@ +class Genre + attr_reader :items, :name, :id + + def initialize(name, id: rand(1..1000)) + @id = id + @name = name + @items = [] + end + + def add_item(item) + @items << item + item.genre = self + end +end diff --git a/src/music/music_album.rb b/src/music/music_album.rb new file mode 100644 index 0000000..a93ae7b --- /dev/null +++ b/src/music/music_album.rb @@ -0,0 +1,15 @@ +require_relative '../../item' +class MusicAlbum < Item + attr_accessor :name, :publish_date, :on_spotify + + def initialize(name, publish_date, on_spotify) + @id = Random.rand(1..1000) + super(nil, nil, publish_date, archived) + @name = name + @on_spotify = on_spotify + end + + def can_be_archived? + super && @on_spotify + end +end diff --git a/storage.rb b/storage.rb new file mode 100644 index 0000000..072d0a6 --- /dev/null +++ b/storage.rb @@ -0,0 +1,22 @@ +require 'json' + +module JsonStorage + def update_data(array, file_path) + opts = { + array_nl: "\n", + object_nl: "\n", + indent: ' ', + space_before: ' ', + space: ' ' + } + json = JSON.generate(array, opts) + File.write(file_path, json) + end + + def get_data(file_path) + return [] unless File.exist?(file_path) + + file = File.read(file_path) + JSON.parse(file) + end +end diff --git a/store.rb b/store.rb new file mode 100644 index 0000000..27bf353 --- /dev/null +++ b/store.rb @@ -0,0 +1,14 @@ +require_relative './src/music/music_album' +require_relative './src/music/genre' +require_relative './app' +require 'json' + +module Storage + def save_music_albums; end + + def load_music_albums; end + + def save_genres; end + + def load_genres; end +end diff --git a/store/authors.json b/store/authors.json new file mode 100644 index 0000000..955d61d --- /dev/null +++ b/store/authors.json @@ -0,0 +1,47 @@ +[ + { + "id": 180, + "first_name": "bvcx", + "last_name": "nbcc" + }, + { + "id": 631, + "first_name": "Brhanu", + "last_name": "Hailu" + }, + { + "id": 483, + "first_name": "marki", + "last_name": "msess" + }, + { + "id": 839, + "first_name": "Abebe", + "last_name": "kebede" + }, + { + "id": 868, + "first_name": "kebede", + "last_name": "melaku" + }, + { + "id": 393, + "first_name": "baedd", + "last_name": "dagdg" + }, + { + "id": 113, + "first_name": "mario", + "last_name": "littel" + }, + { + "id": 548, + "first_name": "yodit", + "last_name": "abebe" + }, + { + "id": 753, + "first_name": "first", + "last_name": "last" + } +] \ No newline at end of file diff --git a/store/books.json b/store/books.json new file mode 100644 index 0000000..cd225c4 --- /dev/null +++ b/store/books.json @@ -0,0 +1,134 @@ +[ + { + "id": 535, + "author": "author1", + "published_date": "2010-09-09", + "publisher": "pub", + "cover_state": "good", + "label": { + "id": 476, + "title": "fiction", + "color": "green" + } + }, + { + "id": 256, + "author": "author2", + "published_date": "1998-07-30", + "publisher": "pubmed", + "cover_state": "bad", + "label": { + "id": 84, + "title": "title2", + "color": "orange" + } + }, + { + "id": 345, + "author": "author3", + "published_date": "1765-03-14", + "publisher": "pubmed", + "cover_state": "bad", + "label": { + "id": 170, + "title": "science", + "color": "red" + } + }, + { + "id": 858, + "author": "a", + "published_date": "2017-08-04", + "publisher": "pub", + "cover_state": "good", + "label": { + "id": 181, + "title": "history", + "color": "violet" + } + }, + { + "id": 844, + "author": "yod", + "published_date": "220-09-25", + "publisher": "Biomed", + "cover_state": "good", + "label": { + "id": 157, + "title": "Science", + "color": "yellow" + } + }, + { + "id": 973, + "author": "John", + "published_date": "1990-12-12", + "publisher": "Nasa", + "cover_state": "bad", + "label": { + "id": 918, + "title": "Robotic", + "color": "dark" + } + }, + { + "id": 206, + "author": "a", + "published_date": "1888-02-02", + "publisher": "pub", + "cover_state": "bad", + "label": { + "id": 214, + "title": "iction", + "color": "red" + } + }, + { + "id": 82, + "author": "yodi", + "published_date": "2023-2-1", + "publisher": "puplisher", + "cover_state": "good", + "label": { + "id": 569, + "title": "title", + "color": "color" + } + }, + { + "id": 901, + "author": "dfsdf", + "published_date": "2023-2-2", + "publisher": "ghgh", + "cover_state": "goood", + "label": { + "id": 323, + "title": "trer", + "color": "fgfdg" + } + }, + { + "id": 767, + "author": "a", + "published_date": "2012", + "publisher": "pub", + "cover_state": "bad", + "label": { + "id": 544, + "title": "science", + "color": "red" + } + }, + { + "id": 418, + "author": "e", + "published_date": "56", + "publisher": "p", + "cover_state": "bad", + "label": { + "id": 462, + "title": "la", + "color": "c" + } + } +] \ No newline at end of file diff --git a/store/games.json b/store/games.json new file mode 100644 index 0000000..37d357e --- /dev/null +++ b/store/games.json @@ -0,0 +1,58 @@ +[ + { + "id": 146, + "game_name": "jhkjkk", + "last_played_at": "2023-5-2", + "publish_date": "2022-05-03", + "multiplayer": "jhhjhhj" + }, + { + "id": 395, + "game_name": "valleyball", + "last_played_at": "2023-6-2", + "publish_date": "2022-05-03", + "multiplayer": "vlc" + }, + { + "id": 601, + "game_name": "hwrhawi", + "last_played_at": "1-2-2023", + "publish_date": "2023-06-02", + "multiplayer": "mcccccc" + }, + { + "id": 59, + "game_name": "merseir", + "last_played_at": "1-2-2023", + "publish_date": "2023-02-02", + "multiplayer": true + }, + { + "id": 567, + "game_name": "abeb", + "last_played_at": "2023-02-05", + "publish_date": "2022-04-01", + "multiplayer": true + }, + { + "id": 222, + "game_name": "Gametwo", + "last_played_at": "2023-02-01", + "publish_date": "2023-02-03", + "multiplayer": true + }, + { + "id": 229, + "game_name": "mario", + "last_played_at": "2023-09-01", + "publish_date": "1990-04-03", + "multiplayer": true + }, + { + "id": 826, + "game_name": "game", + "last_played_at": "2010-02-01", + "publish_date": "1998-02-01", + "multiplayer": true + } +] \ No newline at end of file diff --git a/store/genres.json b/store/genres.json new file mode 100644 index 0000000..2e76b1b --- /dev/null +++ b/store/genres.json @@ -0,0 +1,6 @@ +[ + { + "genre_id" : 422, + "genre_name" : "g" + } +] \ No newline at end of file diff --git a/store/labels.json b/store/labels.json new file mode 100644 index 0000000..9617913 --- /dev/null +++ b/store/labels.json @@ -0,0 +1,57 @@ +[ + { + "id": 476, + "title": "fiction", + "color": "green" + }, + { + "id": 84, + "title": "title2", + "color": "orange" + }, + { + "id": 170, + "title": "science", + "color": "red" + }, + { + "id": 181, + "title": "history", + "color": "violet" + }, + { + "id": 157, + "title": "Science", + "color": "yellow" + }, + { + "id": 918, + "title": "Robotic", + "color": "dark" + }, + { + "id": 214, + "title": "iction", + "color": "red" + }, + { + "id": 569, + "title": "title", + "color": "color" + }, + { + "id": 323, + "title": "trer", + "color": "fgfdg" + }, + { + "id": 544, + "title": "science", + "color": "red" + }, + { + "id": 462, + "title": "la", + "color": "c" + } +] \ No newline at end of file diff --git a/store/music_albums.json b/store/music_albums.json new file mode 100644 index 0000000..c44dc44 --- /dev/null +++ b/store/music_albums.json @@ -0,0 +1,3 @@ +[ + +] \ No newline at end of file diff --git a/store/preserve_data.rb b/store/preserve_data.rb new file mode 100644 index 0000000..01aaa88 --- /dev/null +++ b/store/preserve_data.rb @@ -0,0 +1,10 @@ +class PreserveData + def save_data(data, filename) + data = JSON.pretty_generate(data) + File.write(filename, data) + end + + def load_data(filename) + JSON.parse(File.read(filename)) + end +end