Skip to content

Commit

Permalink
Project model specs and dsu project delete subcommad wip
Browse files Browse the repository at this point in the history
  • Loading branch information
gangelo committed Jan 26, 2024
1 parent 67959f7 commit e6688df
Show file tree
Hide file tree
Showing 10 changed files with 462 additions and 50 deletions.
6 changes: 6 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,9 @@ RSpec/NotToNot:
SupportedStyles:
- to_not
- not_to

RSpec/MultipleExpectations:
Max: 3

RSpec/MultipleMemoizedHelpers:
Max: 6
68 changes: 51 additions & 17 deletions lib/dsu/models/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ def ==(other)
end
alias eql? ==

def can_delete?
self.class.can_delete?(project_name: project_name)
end

def create
self.class.create(project_name: project_name, description: description)
end
Expand All @@ -74,16 +78,16 @@ def default!
end

def default_project?
project_name == self.class.default_project_name
self.class.default_project?(project_name: project_name)
end

# def delete
# self.class.delete(project_name: project_name)
# end
def delete
self.class.delete(project_name: project_name)
end

# def delete!
# self.class.delete!(time: time)
# end
def delete!
self.class.delete!(project_name: project_name)
end

def hash
[project_name, description, version].map(&:hash).hash
Expand Down Expand Up @@ -132,6 +136,21 @@ def all
# project_metadata.any?
# end

def can_delete?(project_name:)
exist?(project_name: project_name) &&
# Cannot delete the last project.
count > 1 &&
# Do not allow the project to be deleted if it
# is currently the default project.
# The user needs to change to another default
# project before they can delete this project.
!default_project?(project_name: project_name)
end

def count
project_metadata.count
end

def create(project_name:, description: nil, options: {})
Models::Project.new(project_name: project_name, description: description, options: options).tap do |project|
project.validate!
Expand Down Expand Up @@ -166,17 +185,32 @@ def default_project
find(project_name: default_project_name)
end

# def delete(project_name:)
# # TODO: read all entry groups and delete them
# # TODO: delete the project folder
# # superclass.delete(file_path: project_folder_for(project_name: project_name))
# end
def default_project?(project_name:)
project_name == default_project_name
end

# def delete!(project_name:)
# # TODO: read all entry groups and delete them
# # TODO: delete the project folder
# # superclass.delete!(file_path: project_folder_for(project_name: project_name))
# end
def delete(project_name:)
return false unless can_delete?(project_name: project_name)

project_folder = project_folder_for(project_name: project_name)
FileUtils.rm_rf(project_folder)

true
end

def delete!(project_name:)
unless exist?(project_name: project_name)
raise I18n.t('models.project.errors.does_not_exist', project_name: project_name)
end

raise I18n.t('models.project.errors.delete_only_project', project_name: project_name) unless count > 1

if default_project?(project_name: project_name)
raise I18n.t('models.project.errors.delete_default_project', project_name: project_name)
end

delete(project_name: project_name)
end

def find(project_name:)
unless project_folder_exist?(project_name: project_name)
Expand Down
93 changes: 93 additions & 0 deletions lib/dsu/presenters/project/delete_presenter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# frozen_string_literal: true

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

module Dsu
module Presenters
module Project
class UsePresenter < BasePresenterEx
attr_writer :project_name_or_number

def initialize(project_name_or_number:, options: {})
super(options: options)

@project_name_or_number = project_name_or_number
end

def respond(response:)
return false unless response

project.delete! if project&.present?
end

def project_name_or_number
return project_name if delete_by_project_name?
return project_number if delete_by_project_number?

Models::Project.default_project_name
end

def project_description
return unless project&.present?

project.description
end

def project_does_not_exist?
!project&.exist?
end

def project_errors
return [] unless project_errors?

project.errors.full_messages
end

def delete_by_project_name?
!delete_by_project_number? && !delete_by_project_default?
end

def delete_by_project_number?
/\A\d+\z/.match?(@project_name_or_number.to_s)
end

def delete_by_project_default?
@project_name_or_number.blank?
end

private

attr_reader :options

def project
return @project if defined?(@project)

@project = if delete_by_project_name? && Dsu::Models::Project.project_initialized?(project_name: project_name)
Dsu::Models::Project.find(project_name: project_name)
elsif delete_by_project_number?
Dsu::Models::Project.find_by_number(project_number: project_number)
elsif delete_by_project_default?
Dsu::Models::Project.default_project
end
end

def project_errors?
project&.invalid?
end

def project_name
return unless delete_by_project_name?

@project_name_or_number
end

def project_number
return -1 unless delete_by_project_number?

@project_name_or_number.to_i
end
end
end
end
end
10 changes: 6 additions & 4 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/delete_presenter'
require_relative '../presenters/project/list_presenter'
require_relative '../presenters/project/use_presenter'
require_relative '../views/project/create'
Expand Down Expand Up @@ -33,11 +34,12 @@ def create

desc I18n.t('subcommands.project.delete.desc'), I18n.t('subcommands.project.delete.usage')
long_desc I18n.t('subcommands.project.delete.long_desc')
option :project_name, type: :string, required: true, aliases: '-n', banner: 'PROJECT_NAME'
option :prompts, type: :hash, default: {}, hide: true, aliases: '-p'
def delete
# Views::Import.new(presenter: all_presenter(import_file_path: options[:import_file],
# options: options)).render
def delete(project_name_or_number = nil)
options = configuration.to_h.merge(self.options).with_indifferent_access
presenter = Presenters::Project::DeletePresenter.new(project_name_or_number: project_name_or_number,
options: options)
Views::Project::Delete.new(presenter: presenter, options: options).render
end

desc I18n.t('subcommands.project.list.desc'), I18n.t('subcommands.project.list.usage')
Expand Down
94 changes: 94 additions & 0 deletions lib/dsu/views/project/delete.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# frozen_string_literal: true

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

module Dsu
module Views
module Project
class Delete
include Support::Ask
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
return display_project_does_not_exists if presenter.project_does_not_exist?
return display_project_errors if presenter.project_errors.any?

response = display_project_delete_prompt
if presenter.respond response: response
display_deleted_project_message
else
display_delete_project_cancelled_message
end
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 display_project_delete_prompt
response = ask_while(prompt_with_options(prompt: delete_prompt,
options: delete_prompt_options), options: options) do |input|
message = I18n.t('information.input.try_again', options: delete_prompt_options.join(','))
puts apply_theme(message, theme_color: color_theme.info) unless delete_prompt_options.include?(input)
delete_prompt_options.include?(input)
end
response == delete_prompt_options.first
end

def display_delete_project_cancelled_message
message = I18n.t('subcommands.project.messages.cancelled', project_name: presenter.project_name_or_number)
puts apply_theme(message, theme_color: color_theme.info)
end

def display_project_errors
errors = presenter.project_errors.join("\n")
puts apply_theme(errors, theme_color: color_theme.error)
end

def display_project_does_not_exists
message = if presenter.delete_by_project_number?
I18n.t('subcommands.project.messages.number_does_not_exist',
project_number: presenter.project_name_or_number)
else
I18n.t('subcommands.project.messages.does_not_exist',
project_name: presenter.project_name_or_number)
end
puts apply_theme(message, theme_color: color_theme.error)
end

def display_deleted_project_message
message = I18n.t('subcommands.project.delete.messages.using_project',
project_name: presenter.project_name_or_number)
puts apply_theme(message, theme_color: color_theme.success)
end

def delete_prompt
I18n.t('subcommands.project.delete.prompts.delete_confirm',
project_name: presenter.project_name_or_number, description: presenter.project_description)
end

def delete_prompt_options
I18n.t('subcommands.project.delete.prompts.delete_options')
end

def theme_name
@theme_name ||= options.fetch(:theme_name, Models::Configuration.new.theme_name)
end
end
end
end
end
2 changes: 2 additions & 0 deletions lib/locales/en/active_record.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ en:
errors:
already_exists: "Project '%{project_name}' already exists."
does_not_exist: "Project '%{project_name}' does not exist."
delete_default_project: "Project '%{project_name}' is the default project. Change to a different default project before deleting this project."
delete_only_project: "Project '%{project_name}' is the only project and cannot be deleted."
project_file_not_exist: "Project file '%{project_file}' does not exist."
activerecord:
errors:
Expand Down
2 changes: 1 addition & 1 deletion spec/dsu/crud/json_file_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def to_h
end
end

context 'when the validation fails' do # rubocop:disable RSpec/MultipleMemoizedHelpers
context 'when the validation fails' do
subject(:json_file_write) { json_file.write! }

let(:file_data) { nil }
Expand Down
Loading

0 comments on commit e6688df

Please sign in to comment.