Skip to content

Commit

Permalink
dsu project list subcommand
Browse files Browse the repository at this point in the history
  • Loading branch information
gangelo committed Jan 24, 2024
1 parent ae8c3dc commit 55613a0
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 8 deletions.
24 changes: 24 additions & 0 deletions lib/dsu/presenters/project/list_presenter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

require_relative '../../models/project'
require_relative '../base_presenter_ex'

module Dsu
module Presenters
module Project
class ListPresenter < BasePresenterEx
def initialize(options: {})
super(options: options)
end

def projects
@projects ||= Dsu::Models::Project.all
end

private

attr_reader :options
end
end
end
end
6 changes: 4 additions & 2 deletions lib/dsu/subcommands/project.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require_relative '../presenters/project/create_presenter'
require_relative '../presenters/project/list_presenter'
require_relative '../presenters/project/use_presenter'
require_relative '../views/project/create'
require_relative '../views/project/use'
Expand Down Expand Up @@ -43,8 +44,9 @@ def delete
long_desc I18n.t('subcommands.project.list.long_desc')
option :prompts, type: :hash, default: {}, hide: true, aliases: '-p'
def list
# Views::Import.new(presenter: all_presenter(import_file_path: options[:import_file],
# options: options)).render
options = configuration.to_h.merge(self.options).with_indifferent_access
presenter = Presenters::Project::ListPresenter.new(options: options)
Views::Project::List.new(presenter: presenter, options: options).render
end

desc I18n.t('subcommands.project.show.desc'), I18n.t('subcommands.project.show.usage')
Expand Down
16 changes: 12 additions & 4 deletions lib/dsu/support/project_file_system.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,7 @@ def project_folder_exist?(project_name:)
end

def project_metadata
Pathname.new(projects_folder).children
.select(&:directory?)
.map(&:basename)
.map(&:to_s).each_with_index.with_object([]) do |(project_name, index), array|
project_folder_names.each_with_index.with_object([]) do |(project_name, index), array|
array << {
project_number: index + 1,
project_name: project_name,
Expand All @@ -107,6 +104,17 @@ def project_number_for(project_name:)
metadata[:project_name] == project_name
end&.[](:project_number) || -1
end

private

def project_folder_names
Pathname.new(projects_folder)
.children
.select(&:directory?)
.map(&:basename)
.map(&:to_s)
.sort { |a, b| a.casecmp(b) }
end
end
end
end
Expand Down
41 changes: 41 additions & 0 deletions lib/dsu/views/base_list_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# frozen_string_literal: true

require_relative '../env'
require_relative '../models/color_theme'
require_relative '../support/color_themable'

module Dsu
module Views
class BaseListView
include Support::ColorThemable

attr_reader :presenter

def initialize(presenter:, options: {})
@presenter = presenter
@options = options&.dup || {}
@color_theme = Models::ColorTheme.find(theme_name: theme_name)
end

def render
yield
rescue StandardError => e
puts apply_theme(e.message, theme_color: color_theme.error)
puts apply_theme(e.backtrace_locations.join("\n"), theme_color: color_theme.error) if Dsu.env.local?
end

private

attr_reader :color_theme, :options

def theme_name
@theme_name ||= options.fetch(:theme_name, Models::Configuration.new.theme_name)
end

def formatted_index(index:)
apply_theme("#{format('%02s', index + 1)}. ",
theme_color: color_theme.index)
end
end
end
end
84 changes: 84 additions & 0 deletions lib/dsu/views/project/list.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# frozen_string_literal: true

require_relative '../base_list_view'

module Dsu
module Views
module Project
class List < Views::BaseListView
DETAIL_HEADER_STRING = "#{'No.'.ljust(4)} " \
"#{'Project'.ljust(15)} " \
"#{'Description'.ljust(10)}".freeze

def render
super do
return display_no_projects if presenter.projects.none?

display_project_list
end
end

private

def display_project_list
display_header
display_detail_header
display_detail
display_footer
end

def display_no_projects
# Should never happen
I18n.t('subcommands.project.messages.no_projects')
puts apply_theme(message, theme_color: color_theme.info)
end

def display_detail
presenter.projects.each_with_index do |project, index|
display_detail_data(
formatted_index(index: index),
project.project_name,
project.description
)
end
end

def display_detail_header
puts apply_theme(DETAIL_HEADER_STRING, theme_color: color_theme.index)
end

def display_detail_data(index, project_name, project_desc)
puts "#{index_detail_data(index)} " \
"#{project_name_detail_data(project_name)} " \
"#{project_desc_detail_data(project_desc)}"
end

def display_footer
footer = "\nTotal projects: #{presenter.projects.count}"
puts apply_theme(footer, theme_color: color_theme.footer)
end

def display_header
header = "Project list\n"
puts apply_theme(header, theme_color: color_theme.subheader)
end

def index_detail_data(value)
apply_theme(value.to_s.ljust(4), theme_color: color_theme.index)
end

def project_name_detail_data(value)
apply_theme(value.to_s.ljust(15), theme_color: color_theme.body.bold!)
end

def project_desc_detail_data(value)
apply_theme(value.to_s.ljust(10), theme_color: color_theme.body)
end

def theme_name
@theme_name ||= options.fetch(:theme_name, Models::Configuration.new.theme_name)
end
end
end
end
end
49 changes: 49 additions & 0 deletions spec/dsu/views/project/list_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

RSpec.describe Dsu::Views::Project::List do
subject(:list_view) do
described_class.new(presenter: presenter, options: options)
end

# before do
# allow($stdin).to receive(:getch).and_return(response)
# end

let(:presenter) do
build(:list_presenter, options: options)
end
let(:options) { nil }

describe '#initialize' do
context 'when the arguments are valid' do
it 'does not raise an error' do
expect { list_view }.to_not raise_error
end
end
end

describe '#render' do
context 'when there are projects to list' do
let(:presenter) do
build(:list_presenter, options: options)
end
let(:expected_project_list) do
default_project = Dsu::Models::Project.default_project
[
"1. #{default_project.project_name} #{default_project.description}",
'2. Test1 Test1 project',
'3. Test2 Test2 project'
]
end

it 'lists the projects' do
expect(strip_escapes(Dsu::Services::StdoutRedirectorService.call do
list_view.render
end.chomp).gsub(/\s{2,}/, ' ')).to include(expected_project_list.join(' '))
end
end

context 'when there are no projects to list' do
end
end
end
36 changes: 36 additions & 0 deletions spec/factories/list_presenters.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

FactoryBot.define do
factory :list_presenter, class: 'Dsu::Presenters::Project::ListPresenter' do
options { {} }

transient do
project_names { %w[Test1 Test2] }
without_projects { false }
end

initialize_with do
new(options: options)
end

after(:build) do |_list_presenter, evaluator|
if evaluator.without_projects
evaluator.project_names.each do |project_name|
Dsu::Models::Project.exist?(project_name: project_name).tap do |exist|
raise "without_projects is false and project '#{project_name}' already exist!" if exist
end
end
else
raise 'project_names must not be empty?' if evaluator.project_names.empty?

evaluator.project_names.each do |project_name|
build(:project,
project_name: project_name,
options: evaluator.options).tap do |project|
project.save! unless project.exist?
end
end
end
end
end
end
2 changes: 1 addition & 1 deletion spec/factories/projects.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
FactoryBot.define do
factory :project, class: 'Dsu::Models::Project' do
project_name { 'default' }
description { 'Project description' }
description { nil }
options { {} }
version { Dsu::Migration::VERSION }

Expand Down
2 changes: 1 addition & 1 deletion spec/fixtures/files/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": 20230613121411,
"project_name": "default",
"description": "Default description"
"description": "Default project"
}

0 comments on commit 55613a0

Please sign in to comment.