A arquitetura MVC
Vamos fazer um Task Manager
require 'sqlite3' # precisamos disso para usar os comandos SQLite
require_relative 'router'
# inicializamos a constante que irá referenciar nosso BD
db_path = File.join(File.dirname(__FILE__), "db/tasks.sqlite")
DB = SQLite3::Database.new(db_path)
# inicia uma instacia de router e põe pra rodar
router = Router.new
router.run
class Router
# inicializamos o router colocando uma variável para controlar o loop
def initialize
@running = true
end
# método do loop, para mostrar as opções, pegar o input e delegar uma
# ação ao controller
def run
puts "============================"
puts "====== TASK MANAGER ======"
puts "============================"
while @running
show_options
opt = gets.chomp.to_i
print `clear`
run_option(opt)
end
end
# método para mostrar as opções (chamado pelo run)
def show_options
puts 'What would you like to do?'
puts '1 - ?????'
puts '2 - ?????'
puts '3 - ?????'
puts '4 - ?????'
puts '5 - ?????'
puts '0 - exit the task manager'
end
# método para delegar uma opção ao controller ou parar o app
def run_option(opt)
case opt
when 0
puts 'See you later!'
@running = false
else
puts 'Invalid option...'
end
end
end
# como faremos um TASK manager, um modelo interessante seria o próprio task
# Para simplicidade, teremos apenas seu Id, a descrição da task e um boolean
# indicando se a task foi realizada ou não
# lib/models/task.rb
class Task
# não queremos que ações externas alterem o id ou se foi feito
attr_reader :id, :done
# queremos poder alterar a descrição da task
attr_accessor :desc
def initialize(attrs = {})
@id = attrs['id']
@desc = attrs['desc']
@done = attrs['done'] || false
end
# queremos ter um método para marcar a task como feita
def mark_as_done!
@done = true
end
end
# precisamos de um controller para as ações em cima de uma task. Damos a esse
# o nome de TaskController.
# lib/controllers/task_controller.rb
# Como iremos utilizar o modelo, precisamos 'importá-lo'
require_relative '../models/task'
class TaskController
# ação para listar todas as tasks que já temos
def list_all
# 1. pegue as tasks do BD
rows = DB.execute('SELECT * FROM tasks')
# 2. para cada linha recuperada, crie um novo Task. Guarde todos os
# tasks numa array
tasks = rows.map do |row|
# 'done' será 0 ou 1 (no BD). Para transformá-lo em boolean...
row['done'] = !row['done'].zero?
Task.new(row)
end
# 3. Mostre-o na tela para o usuário
???
end
end# precisamos de uma view para interagir com o usuário (dependendo da ação
# do controller)
# lib/views/task_view.rb
class TaskView
# ação para listar todas as tasks que já temos
# essa ação espera receber uma array de tasks (para mostrá-las na tela)
def show_all(tasks)
puts '====== Your tasks ======='
tasks.each do |task|
done = task.done ? '[X]' : '[ ]'
puts "#{task.id}: #{done} #{task.desc}"
end
puts '========================='
end
end# para chamarmos o método da view no controller, precisamos 'importá-lo'
# lib/controllers/task_controller.rb
require_relative '../models/task'
require_relative '../views/task_view' # importando a view
class TaskController
# para não termos que criar uma View toda vez que formos usar
# criamos uma variável de instância que utilizaremos toda hora
def initialize
@view = TaskView.new
end
# ação para listar todas as tasks que já temos
def list_all
# ...
# 3. Mostre-o na tela para o usuário (passando as tasks geradas para
# a view
@view.show_tasks(tasks)
end
end# para delegarmos ações ao controller, precisamos chamá-lo aqui no router
# para chamarmos o controller, precisamos 'importá-lo'
# lib/router.rb
require_relative 'controllers/task_controller'
class Router
# inicializamos o router colocando uma variável para controlar o loop
# e outra para guardar o controller o qual delegaremos ações baseados
# na ação do usuário
def initialize
@controller = TaskController.new # criando um controller pra usar
@running = true
end
# ...
# método para mostrar as opções (chamado pelo run)
def show_options
puts 'What would you like to do?'
puts '1 - List all my tasks' # nova opção liberada!!
puts '2 - ?????'
puts '3 - ?????'
puts '4 - ?????'
puts '5 - ?????'
puts '0 - exit the task manager'
end
# método para delegar uma opção ao controller ou parar o app
def run_option(opt)
case opt
when 0
puts 'See you later!'
@running = false
when 1
@controller.list_all # fala pro controller o que fazer
else
puts 'Invalid option...'
end
end
end
# Para refatoração, os controllers são criados no app.rb e então
# passados (como parâmetro) para o router
require 'sqlite3' # precisamos disso para usar os comandos SQLite
require_relative 'router'
require_relative 'controllers/task_controller' # precisamos 'importá-lo'
# inicializamos a constante que irá referenciar nosso BD
db_path = File.join(File.dirname(__FILE__), "db/tasks.sqlite")
DB = SQLite3::Database.new(db_path)
# inicia o controller
task_controller = TaskController.new
# inicia uma instacia de router e põe pra rodar
router = Router.new(task_controller) # passamos o task_controller pro router
router.run
# lib/router.rb
require_relative 'controllers/task_controller'
class Router
# inicializamos o router colocando uma variável para controlar o loop
# e outra para guardar o controller o qual delegaremos ações baseados
# na ação do usuário
def initialize(controller) # esperamos receber os controllers
@controller = controller # instanciamos o controller
@running = true
end
# ...
endComplete o Task Manager! Existem mais quatro coisas que podemos fazer na aplicação:
Pense em como saber interagir com o usuário (view), tanto para mostrar quanto para receber informação.
Pense em como interagir com o Banco de Dados (controller), manipulando modelos e salvando as alterações, inserções e remoções (dica: BD.execute() )