Last active
March 7, 2018 14:21
-
-
Save luizfonseca/8e58cad29b27d5a20d2343bba772ed9f to your computer and use it in GitHub Desktop.
BaseRepository example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'csv' | |
# There are a bunch of ways of doing this class | |
# There's not one 'best' way, but different approaches | |
class BaseRepository | |
# This is an initialize method that is | |
# Common for 90% of the Repositories | |
# It just takes a CSV file, and creates | |
# @elements empty list (array) | |
def initialize(csv_file) | |
@elements = [] | |
@csv_file = csv_file | |
end | |
# Nothing, just return all elements, that's it | |
def all | |
@elements | |
end | |
# Take a look in the documentation, find | |
# returns the object that matched with the condition | |
# inside (in this case, the ID of the MEAL to be equal to the ID in | |
# the method definition) | |
def find(id) | |
@elements.find { |el| el.id == id } | |
end | |
# Just add the element(meal, customer, employee, whatever) | |
# To the elements array and setup the next id | |
# I removed the sync from here, because it's up to the | |
# child repository to find out if he wants to use it | |
# That's why we can call SUPER on the CHILDREN, it will just | |
# execute these 2 lines, then give the control back to you | |
def add(element) | |
element.id = next_id | |
@elements << element | |
end | |
private | |
# Just finding out the next_id, | |
# If @elements is empty, 1 | |
# If @elements has (meals/customer/employee), | |
# get the last ID from the item | |
def next_id | |
@elements.empty? ? 1 : @elements.last.id + 1 | |
end | |
# This is a weird thing, right? | |
# It's just a method that receives one argument: a CLASS itself | |
# Not a string, not an array, but a class | |
# So we can call .NEW on it - pretty cool, right? | |
# Look, the name in the method definition is up to you | |
# I decided for klass, but you can call it class_name and | |
# it will work the same way | |
def sync_csv(klass) | |
CSV.open(@csv_file, 'wb') do |csv| | |
# This line just find all instance variables and returns them as strings | |
# Inside an array (['@name', '@price']) | |
# We just remove the "@" from the string ([1..-1] instead of [0..-1]) | |
csv << klass.new.instance_variables.map { |x| x[1..-1] } | |
@elements.each do |element| | |
# This is tricky right? | |
# YIELD is quite simple once you understand it. | |
# If you use `DO` on this method | |
# E.g.: `sync_csv DO |some_variable|` | |
# This will call yield - and because we passed a variable to yield | |
# We have access to this variable (to do whatever we want) all the | |
# way up there in the children class | |
# So we are just converting this yield to whatever we pass | |
# INSIDE the block there in the children. | |
# This will be converted to whatever you want, | |
# In our case, it's ["Something", "Something", "Something"] | |
# Look at the child class (MealRepository, CustomerRepository) | |
csv << yield(element) | |
end | |
end | |
end | |
# Again, we receive a CLASS as an argument when we call it | |
# it's just a variable name, call whatever you want | |
# This method only is only used if we need to convert the rows | |
# to a Ruby format | |
# Like "true" to true (boolean) and "1" to 1 (integer) | |
def load_csv(klass) | |
csv_options = { headers: :first_row, header_converters: :symbol } | |
# We dont run anything, just skip - if the file doesnt exist | |
return unless File.exist?(@csv_file) | |
CSV.foreach(@csv_file, csv_options) do |row| | |
row[:id] = row[:id].to_i | |
# Again, if you use DO on this method | |
# E.g.: `load_csv(Meal) do |some_variable|` | |
# It will replace the value of yield with the value | |
# inside your DO block | |
# BLOCK_GIVEN? means: only run this line if we use `DO` on this | |
# method | |
yield(row) if block_given? | |
@elements << klass.new(row) | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_relative '../models/customer' | |
require_relative 'base_repository' | |
require 'csv' | |
# We are inheriting from the Base repository | |
# That has ALL methods that we need | |
# We are only overriding the ones we actually | |
# need to change | |
class CustomerRepository < BaseRepository | |
def initialize(csv) | |
super(csv) | |
load_csv Customer | |
end | |
def add(element) | |
super | |
sync_csv Customer do |customer| | |
[customer.id, customer.name, customer.address] | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_relative "../models/meal" | |
require_relative 'base_repository' | |
require 'csv' | |
class MealRepository < BaseRepository | |
def initialize(csv) | |
super(csv) | |
load_csv Meal do |row| | |
row[:price] = row[:price].to_i | |
end | |
end | |
def add(element) | |
super | |
sync_csv Meal do |meal| | |
[meal.id, meal.name, meal.price] | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment