dsu 2.0.8 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -2
  3. data/Gemfile.lock +9 -9
  4. data/README.md +178 -69
  5. data/lib/core/ruby/color_theme_mode.rb +1 -1
  6. data/lib/dsu/base_cli.rb +3 -17
  7. data/lib/dsu/cli.rb +44 -72
  8. data/lib/dsu/command_services/add_entry_service.rb +1 -1
  9. data/lib/dsu/env.rb +4 -0
  10. data/lib/dsu/models/color_theme.rb +2 -2
  11. data/lib/dsu/models/configuration.rb +3 -1
  12. data/lib/dsu/models/entry_group.rb +1 -1
  13. data/lib/dsu/presenters/color_theme_presenter.rb +4 -2
  14. data/lib/dsu/presenters/color_theme_show_presenter.rb +9 -3
  15. data/lib/dsu/presenters/configuration_presenter.rb +2 -2
  16. data/lib/dsu/presenters/entry_group_presenter.rb +2 -2
  17. data/lib/dsu/services/entry_group/counter_service.rb +32 -0
  18. data/lib/dsu/services/entry_group/deleter_service.rb +35 -0
  19. data/lib/dsu/services/entry_group/editor_service.rb +7 -11
  20. data/lib/dsu/subcommands/base_subcommand.rb +0 -2
  21. data/lib/dsu/subcommands/config.rb +17 -74
  22. data/lib/dsu/subcommands/delete.rb +107 -0
  23. data/lib/dsu/subcommands/edit.rb +16 -30
  24. data/lib/dsu/subcommands/list.rb +26 -96
  25. data/lib/dsu/subcommands/theme.rb +50 -79
  26. data/lib/dsu/support/ask.rb +1 -1
  27. data/lib/dsu/support/command_help_colorizeable.rb +7 -0
  28. data/lib/dsu/support/command_hookable.rb +2 -0
  29. data/lib/dsu/support/command_options/dsu_times.rb +10 -10
  30. data/lib/dsu/support/command_options/time.rb +1 -0
  31. data/lib/dsu/support/command_options/time_mnemonic.rb +108 -0
  32. data/lib/dsu/support/command_options/{time_mneumonics.rb → time_mnemonics.rb} +2 -1
  33. data/lib/dsu/support/time_formatable.rb +13 -0
  34. data/lib/dsu/validators/description_validator.rb +2 -0
  35. data/lib/dsu/validators/entries_validator.rb +1 -0
  36. data/lib/dsu/version.rb +1 -1
  37. data/lib/dsu/views/color_theme/show.rb +1 -0
  38. data/lib/dsu/views/entry_group/edit.rb +2 -1
  39. data/lib/dsu/views/entry_group/shared/no_entries_to_display.rb +4 -1
  40. data/lib/dsu/views/shared/model_errors.rb +1 -0
  41. data/lib/dsu.rb +5 -1
  42. data/lib/locales/en/active_record.yml +8 -0
  43. data/lib/locales/en/commands.yml +136 -0
  44. data/lib/locales/en/miscellaneous.yml +23 -0
  45. data/lib/locales/en/presenters.yml +19 -0
  46. data/lib/locales/en/services.yml +10 -0
  47. data/lib/locales/en/subcommands.yml +348 -0
  48. metadata +26 -27
  49. data/exe/dsu_migrate.rb +0 -43
  50. data/lib/dsu/support/command_options/time_mneumonic.rb +0 -108
  51. data/lib/dsu/support/subcommand_help_colorizeable.rb +0 -27
data/lib/dsu/cli.rb CHANGED
@@ -4,6 +4,7 @@ require 'fileutils'
4
4
  require 'time'
5
5
  require_relative 'base_cli'
6
6
  require_relative 'subcommands/config'
7
+ require_relative 'subcommands/delete'
7
8
  require_relative 'subcommands/edit'
8
9
  require_relative 'subcommands/list'
9
10
  require_relative 'subcommands/theme'
@@ -11,53 +12,30 @@ require_relative 'subcommands/theme'
11
12
  module Dsu
12
13
  # The `dsu` command.
13
14
  class CLI < BaseCLI
14
- map %w[a -a] => :add
15
- map %w[c -c] => :config
16
- map %w[e -e] => :edit
17
- map %w[l -l] => :list
18
- map %w[t -t] => :theme
19
- map %w[v -i] => :info
20
- map %w[v -v] => :version
21
-
22
- desc 'add, -a [OPTIONS] DESCRIPTION',
23
- 'Adds a DSU entry having DESCRIPTION to the date associated with the given OPTION'
24
- long_desc <<-LONG_DESC
25
- NAME
26
-
27
- $ dsu add, -a [OPTIONS] DESCRIPTION -- will add a DSU entry having DESCRIPTION to the date associated with the given OPTION.
28
-
29
- SYNOPSIS
30
-
31
- $ dsu add, -a [-d DATE|-n|-t|-y] DESCRIPTION
32
-
33
- OPTIONS:
34
-
35
- -d DATE: Adds a DSU entry having DESCRIPTION to the DATE.
36
-
37
- #{date_option_description}
38
-
39
- -n: Adds a DSU entry having DESCRIPTION to today's date (`Time.now`).
40
-
41
- -t: Adds a DSU entry having DESCRIPTION to tomorrow's date (`Time.new.tomorrow`).
42
-
43
- -y: Adds a DSU entry having DESCRIPTION to yesterday's date (`Time.new.yesterday`).
44
-
45
- DESCRIPTION:
46
-
47
- Must be be between 2 and 256 characters (inclusive) in length.
48
- LONG_DESC
49
- option :date, type: :string, aliases: '-d'
50
- option :tomorrow, type: :boolean, aliases: '-t'
51
- option :yesterday, type: :boolean, aliases: '-y'
52
- option :today, type: :boolean, aliases: '-n', default: true
15
+ map I18n.t('commands.add.key_mappings') => :add
16
+ map I18n.t('commands.config.key_mappings') => :config
17
+ map I18n.t('commands.delete.key_mappings') => :delete
18
+ map I18n.t('commands.edit.key_mappings') => :edit
19
+ map I18n.t('commands.help.key_mappings') => :help
20
+ map I18n.t('commands.info.key_mappings') => :info
21
+ map I18n.t('commands.list.key_mappings') => :list
22
+ map I18n.t('commands.theme.key_mappings') => :theme
23
+ map I18n.t('commands.version.key_mappings') => :version
24
+
25
+ desc I18n.t('commands.add.desc'), I18n.t('commands.add.usage')
26
+ long_desc I18n.t('commands.add.long_desc', date_option_description: date_option_description)
27
+ option I18n.t('options.date.name'), aliases: I18n.t('options.date.aliases'), type: :string
28
+ option I18n.t('options.tomorrow.name'), aliases: I18n.t('options.tomorrow.aliases'), type: :boolean
29
+ option I18n.t('options.yesterday.name'), aliases: I18n.t('options.yesterday.aliases'), type: :boolean
30
+ option I18n.t('options.today.name'), aliases: I18n.t('options.today.aliases'), type: :boolean, default: true
53
31
  def add(description)
54
- time = if options[:date].present?
55
- Time.parse(options[:date])
56
- elsif options[:tomorrow].present?
32
+ time = if options[I18n.t('options.date.name')].present?
33
+ Time.parse(options[I18n.t('options.date.name')])
34
+ elsif options[I18n.t('options.tomorrow.name')].present?
57
35
  Time.now.tomorrow
58
- elsif options[:yesterday].present?
36
+ elsif options[I18n.t('options.yesterday.name')].present?
59
37
  Time.now.yesterday
60
- elsif options[:today].present?
38
+ elsif options[I18n.t('options.today.name')].present?
61
39
  Time.now
62
40
  end
63
41
  entry = Models::Entry.new(description: description)
@@ -65,49 +43,43 @@ module Dsu
65
43
  view_entry_group(time: time)
66
44
  end
67
45
 
68
- desc 'list, -l SUBCOMMAND',
69
- 'Displays DSU entries for the given SUBCOMMAND'
46
+ desc I18n.t('commands.list.desc'), I18n.t('commands.list.usage')
70
47
  subcommand :list, Subcommands::List
71
48
 
72
- desc 'config, -c SUBCOMMAND',
73
- 'Manage configuration file for this gem'
49
+ desc I18n.t('commands.config.desc'), I18n.t('commands.config.usage')
74
50
  subcommand :config, Subcommands::Config
75
51
 
76
- desc 'edit, -e SUBCOMMAND',
77
- 'Edit DSU entries for the given SUBCOMMAND'
52
+ desc I18n.t('commands.delete.desc'), I18n.t('commands.delete.usage')
53
+ subcommand :delete, Subcommands::Delete
54
+
55
+ desc I18n.t('commands.edit.desc'), I18n.t('commands.edit.usage')
78
56
  subcommand :edit, Subcommands::Edit
79
57
 
80
- desc 'theme, -t SUBCOMMAND',
81
- 'Manage DSU themes'
58
+ desc I18n.t('commands.theme.desc'), I18n.t('commands.theme.usage')
82
59
  subcommand :theme, Subcommands::Theme
83
60
 
84
- desc 'info, -i',
85
- 'Displays information about this dsu release'
61
+ desc I18n.t('commands.info.desc'), I18n.t('commands.info.usage')
86
62
  def info
87
63
  configuration_version = Models::Configuration::VERSION
88
64
  entry_group_version = Models::EntryGroup::VERSION
89
65
  color_theme_version = Models::ColorTheme::VERSION
90
- info = <<~INFO
91
- Dsu version: #{dsu_version}
92
- Configuration version: #{configuration_version}
93
- Entry group version: #{entry_group_version}
94
- Color theme version: #{color_theme_version}
95
-
96
- Config path: #{Support::Fileable.config_path}
97
- Root folder: #{Support::Fileable.root_folder}
98
- Entries folder: #{Support::Fileable.entries_folder}
99
- Themes folder: #{Support::Fileable.themes_folder}
100
- Gem folder: #{Support::Fileable.gem_dir}
101
- Temp folder: #{Support::Fileable.temp_folder}
102
-
103
- Migration version folder: #{Support::Fileable.migration_version_folder}
104
- Migration file path: #{Support::Fileable.migration_version_path}
105
- INFO
66
+ info = I18n.t('commands.info.info',
67
+ dsu_version: dsu_version,
68
+ configuration_version: configuration_version,
69
+ entry_group_version: entry_group_version,
70
+ color_theme_version: color_theme_version,
71
+ config_folder: Support::Fileable.config_path,
72
+ root_folder: Support::Fileable.root_folder,
73
+ entries_folder: Support::Fileable.entries_folder,
74
+ themes_folder: Support::Fileable.themes_folder,
75
+ gem_folder: Support::Fileable.gem_dir,
76
+ temp_folder: Support::Fileable.temp_folder,
77
+ migration_version_folder: Support::Fileable.migration_version_folder,
78
+ migration_file_folder: Support::Fileable.migration_version_path)
106
79
  puts apply_theme(info, theme_color: color_theme.body)
107
80
  end
108
81
 
109
- desc 'version, -v',
110
- 'Displays the version for this gem'
82
+ desc I18n.t('commands.version.desc'), I18n.t('commands.version.usage')
111
83
  def version
112
84
  puts apply_theme(dsu_version, theme_color: color_theme.body)
113
85
  end
@@ -38,7 +38,7 @@ module Dsu
38
38
  entry_group.save!
39
39
  entry
40
40
  rescue ActiveModel::ValidationError => e
41
- header = 'An error was encountered; the entry could not be added:'
41
+ header = I18n.t('headers.entry.could_not_be_added')
42
42
  Views::Shared::Error.new(messages: e.message, header: header).render
43
43
  end
44
44
 
data/lib/dsu/env.rb CHANGED
@@ -12,6 +12,10 @@ module Dsu
12
12
  env.fetch('DSU_ENV', nil) == 'development'
13
13
  end
14
14
 
15
+ def local?
16
+ test? || development?
17
+ end
18
+
15
19
  def production?
16
20
  env.fetch('DSU_ENV', 'production') == 'production'
17
21
  end
@@ -88,11 +88,11 @@ module Dsu
88
88
  self.class.class_eval do
89
89
  attr_reader attr
90
90
  attr_writer attr
91
- private "#{attr}="
91
+ private :"#{attr}="
92
92
  end
93
93
  attr_value = theme_hash[attr]
94
94
  attr_value = attr_value.merge_default_colors if default_theme_color_keys.include?(attr)
95
- send("#{attr}=", attr_value)
95
+ send(:"#{attr}=", attr_value)
96
96
  end
97
97
  end
98
98
 
@@ -133,6 +133,7 @@ module Dsu
133
133
  end
134
134
 
135
135
  def merge(hash)
136
+ hash.transform_keys!(&:to_sym)
136
137
  replace!(config_hash: to_h.merge(hash))
137
138
  end
138
139
 
@@ -153,7 +154,8 @@ module Dsu
153
154
  theme_path = themes_path(theme_name: theme_name)
154
155
  return if File.exist?(theme_path)
155
156
 
156
- errors.add(:base, "Theme file \"#{theme_path}\" does not exist")
157
+ i18n_key = 'configuration.errors.theme_file_missing'
158
+ errors.add(:base, I18n.t(i18n_key, theme_path: theme_path))
157
159
  end
158
160
  end
159
161
  end
@@ -193,7 +193,7 @@ module Dsu
193
193
  end
194
194
 
195
195
  def entry_files
196
- Dir.glob("#{entries_folder}/*")
196
+ Dir.glob("#{Support::Fileable.entries_folder}/*")
197
197
  end
198
198
  end
199
199
 
@@ -14,11 +14,13 @@ module Dsu
14
14
  end
15
15
 
16
16
  def header
17
- apply_theme('Color Themes', theme_color: color_theme.subheader)
17
+ header = I18n.t('presenters.color_theme_presenter.headers.color_themes')
18
+ apply_theme(header, theme_color: color_theme.subheader)
18
19
  end
19
20
 
20
21
  def footer
21
- apply_theme('* current theme', theme_color: color_theme.footer)
22
+ header = I18n.t('presenters.color_theme_presenter.headers.current_theme')
23
+ apply_theme(header, theme_color: color_theme.footer)
22
24
  end
23
25
 
24
26
  def detail
@@ -10,7 +10,10 @@ module Dsu
10
10
  end
11
11
 
12
12
  def detail
13
- puts_detail('No.', 'Color', 'Values', header: true)
13
+ headers = [I18n.t('presenters.color_theme_show_presenter.headers.number'),
14
+ I18n.t('presenters.color_theme_show_presenter.headers.color'),
15
+ I18n.t('presenters.color_theme_show_presenter.headers.values')]
16
+ puts_detail(*headers, header: true)
14
17
 
15
18
  Models::ColorTheme::DEFAULT_THEME_COLORS.keys.each_with_index do |color_key, index|
16
19
  index = formatted_index(index: index)
@@ -24,11 +27,14 @@ module Dsu
24
27
  end
25
28
 
26
29
  def footer
27
- apply_theme('Footer example', theme_color: color_theme.footer)
30
+ header = I18n.t('presenters.color_theme_show_presenter.headers.footer_example')
31
+ apply_theme(header, theme_color: color_theme.footer)
28
32
  end
29
33
 
30
34
  def header
31
- apply_theme("Viewing color theme: #{color_theme.theme_name}", theme_color: color_theme.subheader)
35
+ header = I18n.t('presenters.color_theme_show_presenter.headers.viewing_color_theme',
36
+ theme_name: color_theme.theme_name)
37
+ apply_theme(header, theme_color: color_theme.subheader)
32
38
  end
33
39
 
34
40
  private
@@ -15,8 +15,8 @@ module Dsu
15
15
  end
16
16
 
17
17
  def configuration_header
18
- apply_theme("Configuration file contents (#{config_path})",
19
- theme_color: color_theme.header)
18
+ header = I18n.t('presenters.configuration_presenter.headers.file_contents', config_path: config_path)
19
+ apply_theme(header, theme_color: color_theme.header)
20
20
  end
21
21
 
22
22
  def configuration_details
@@ -27,8 +27,8 @@ module Dsu
27
27
  end
28
28
 
29
29
  def no_entries_available
30
- colors = color_theme.info
31
- apply_theme('(no entries available for this day)', theme_color: colors)
30
+ header = I18n.t('presenters.entry_group_presenter.headers.no_entries_available')
31
+ apply_theme(header, theme_color: color_theme.info)
32
32
  end
33
33
  end
34
34
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/entry_group'
4
+
5
+ module Dsu
6
+ module Services
7
+ module EntryGroup
8
+ class CounterService
9
+ def initialize(times:, options: {})
10
+ raise ArgumentError, 'Argument times is nil' if times.nil?
11
+
12
+ @times = times
13
+ @options = options
14
+ end
15
+
16
+ def call
17
+ total_entry_groups = 0
18
+
19
+ times.each do |time|
20
+ total_entry_groups += 1 if Models::EntryGroup.exist?(time: time)
21
+ end
22
+
23
+ total_entry_groups
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :times, :options
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/entry_group'
4
+
5
+ module Dsu
6
+ module Services
7
+ module EntryGroup
8
+ class DeleterService
9
+ def initialize(times:, options: {})
10
+ raise ArgumentError, 'Argument times is nil' if times.nil?
11
+
12
+ @times = times
13
+ @options = options
14
+ end
15
+
16
+ def call
17
+ deleted_entry_groups = 0
18
+
19
+ times.each do |time|
20
+ next unless Models::EntryGroup.exist?(time: time)
21
+
22
+ Models::EntryGroup.delete(time: time)
23
+ deleted_entry_groups += 1
24
+ end
25
+
26
+ deleted_entry_groups
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :times, :options
32
+ end
33
+ end
34
+ end
35
+ end
@@ -40,8 +40,9 @@ module Dsu
40
40
  # Renders the edit view to a string so we can write it to a temporary file
41
41
  # and edit it. The edits will be used to update the entry group.
42
42
  def render_edit_view
43
- puts apply_theme("Editing entry group #{formatted_time(time: entry_group.time)}...",
44
- theme_color: color_theme.header)
43
+ message = I18n.t('services.editor_service.messages.editing',
44
+ formatted_time: formatted_time(time: entry_group.time))
45
+ puts apply_theme(message, theme_color: color_theme.header)
45
46
  # TODO: Call #render_as_string directly below?
46
47
  StdoutRedirectorService.call { Views::EntryGroup::Edit.new(entry_group: entry_group).render }
47
48
  # Views::EntryGroup::Edit.new(entry_group: entry_group).render_as_string
@@ -63,15 +64,10 @@ module Dsu
63
64
 
64
65
  process_entry_group!(entry_group_with_edits)
65
66
  else
66
- puts apply_theme(
67
- [
68
- "Failed to open temporary file in editor '#{configuration.editor}'; " \
69
- "the system error returned was: '#{$CHILD_STATUS}'.",
70
- 'Either set the EDITOR environment variable ' \
71
- 'or set the dsu editor configuration option (`$ dsu config info`).',
72
- 'Run `$ dsu help config` for more information.'
73
- ], theme_color: color_theme.error
74
- )
67
+ message_array = I18n.t('services.editor_service.errors.temp_file_error',
68
+ editor: configuration.editor,
69
+ status: $CHILD_STATUS).split("\n")
70
+ puts apply_theme(message_array, theme_color: color_theme.error)
75
71
  end
76
72
  end
77
73
  end
@@ -2,13 +2,11 @@
2
2
 
3
3
  require_relative '../base_cli'
4
4
  require_relative '../support/ask'
5
- require_relative '../support/subcommand_help_colorizeable'
6
5
 
7
6
  module Dsu
8
7
  module Subcommands
9
8
  class BaseSubcommand < Dsu::BaseCLI
10
9
  include Support::Ask
11
- include Support::SubcommandHelpColorizable
12
10
  end
13
11
  end
14
12
  end
@@ -18,99 +18,40 @@ module Dsu
18
18
  end
19
19
  end
20
20
 
21
- desc 'info', 'Displays information about this gem configuration'
22
- long_desc <<-LONG_DESC
23
- NAME
24
-
25
- `dsu config info` -- Displays information about this gem configuration.
26
-
27
- SYNOPSIS
28
-
29
- dsu config info
30
- LONG_DESC
21
+ desc I18n.t('subcommands.config.info.desc'), I18n.t('subcommands.config.info.usage')
22
+ long_desc I18n.t('subcommands.config.info.long_desc')
31
23
  def info
32
24
  configuration = Models::Configuration.new
33
25
  Views::Configuration::Show.new(config: configuration).call
34
26
  end
35
27
 
36
- if ENV['DEV_ENV']
37
- desc 'init', 'Creates and initializes a .dsu file in your home folder'
38
- long_desc <<-LONG_DESC
39
- NAME
40
-
41
- `dsu config init` -- will create and initialize a .dsu file ("#{Dsu::Support::Fileable.root_folder}/.dsu") that you may edit. Otherwise, the default configuration will be used.
42
-
43
- SYNOPSIS
44
-
45
- dsu config init
46
-
47
- CONFIGURATION FILE OPTIONS
48
-
49
- The following configuration file options are available:
50
-
51
- version:
52
-
53
- The configuration version - DO NOT ALTER THIS VALUE!
54
-
55
- editor:
56
-
57
- The default editor to use when editing entry groups if the EDITOR environment variable on your system is not set. The default is 'nano'. You'll need to change the default editor on Windows systems.
58
-
59
- entries_display_order:
60
-
61
- The order by which entries will be displayed, :asc or :desc (ascending or descending, respectively).
62
-
63
- Default: :desc
64
-
65
- entries_file_name:
66
-
67
- The entries file name format. It is recommended that you do not change this. The file name must include `%Y`, `%m` and `%d` `Time` formatting specifiers to make sure the file name is unique and able to be located by `dsu` functions. For example, the default file name is `%Y-%m-%d.json`; however, something like `%m-%d-%Y.json` or `entry-group-%m-%d-%Y.json` would work as well.
68
-
69
- ATTENTION: Please keep in mind that if you change this value `dsu` will not recognize entry files using a different format. You would (at this time), have to manually rename any existing entry file names to the new format.
70
-
71
- Default: '%Y-%m-%d.json'
72
-
73
- entries_folder:
74
-
75
- This is the folder where `dsu` stores entry files. You may change this to anything you want. `dsu` will create this folder for you, as long as your system's write permissions allow this.
76
-
77
- ATTENTION: Please keep in mind that if you change this value `dsu` will not be able to find entry files in any previous folder. You would (at this time), have to manually mode any existing entry files to this new folder.
78
-
79
- Default: "'#{Dsu::Support::Fileable.root_folder}/dsu/entries'"
80
- LONG_DESC
28
+ if Dsu.env.development?
29
+ desc I18n.t('subcommands.config.init.desc'), I18n.t('subcommands.config.init.usage')
30
+ long_desc I18n.t('subcommands.config.init.long_desc', home_folder: Dsu::Support::Fileable.root_folder)
81
31
  def init
82
32
  exit 1 if configuration_errors_or_wanings?
83
33
 
84
34
  Models::Configuration.default.tap do |configuration|
85
35
  configuration.save!
86
- messages = ["Configuration file (#{Models::Configuration.config_file}) created."]
36
+ messages = [I18n.t('messages.configuration_file.created',
37
+ configuration_file: Models::Configuration.config_file)]
87
38
  Views::Shared::Success.new(messages: messages).render
88
39
  Views::Configuration::Show.new(config: configuration).render
89
40
  end
90
41
  end
91
42
 
92
- desc 'delete', 'Deletes the configuration file'
93
- long_desc <<-LONG_DESC
94
- NAME
95
-
96
- `dsu config delete` -- Deletes the configuration.
97
-
98
- SYNOPSIS
99
-
100
- dsu config delete
101
-
102
- NOTES
103
-
104
- Deleting the dsu configuration file will simply cause dsu to use the default configuration options (`Dsu::Models::Configuration::DEFAULT_CONFIGURATION`).
105
- LONG_DESC
43
+ desc I18n.t('subcommands.config.delete.desc'), I18n.t('subcommands.config.delete.usage')
44
+ long_desc I18n.t('subcommands.config.delete.long_desc')
106
45
  def delete
107
46
  unless Models::Configuration.exist?
108
- messages = ["Configuration file (#{Models::Configuration.config_file}) does not exist."]
47
+ messages = [I18n.t('messages.configuration_file.does_not_exist',
48
+ configuration_file: Models::Configuration.config_file)]
109
49
  Views::Shared::Warning.new(messages: messages).render
110
50
  exit 1
111
51
  end
112
52
  Models::Configuration.delete!
113
- messages = ["Configuration file (#{Models::Configuration.config_file}) deleted."]
53
+ messages = [I18n.t('messages.configuration_file.deleted',
54
+ configuration_file: Models::Configuration.config_file)]
114
55
  Views::Shared::Success.new(messages: messages).render
115
56
  end
116
57
  end
@@ -119,10 +60,12 @@ module Dsu
119
60
 
120
61
  def configuration_errors_or_wanings?
121
62
  if Models::Configuration.exist?
122
- messages = ["Configuration file (#{Models::Configuration.config_file}) already exists"]
63
+ messages = [I18n.t('messages.configuration_file.already_exists',
64
+ configuration_file: Models::Configuration.config_file)]
123
65
  Views::Shared::Warning.new(messages: messages).render
124
66
  elsif !Dir.exist?(Models::Configuration.config_folder)
125
- messages = ["Destination folder for configuration file (#{Models::Configuration.config_folder}) does not exist"] # rubocop:disable Layout/LineLength
67
+ messages = [I18n.t('messages.configuration_file.destination_folder_does_not_exist',
68
+ configuration_file: Models::Configuration.config_file)]
126
69
  Views::Shared::Error.new(messages: messages).render
127
70
  else
128
71
  configuration = Models::Configuration.default
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../services/entry_group/counter_service'
4
+ require_relative '../services/entry_group/deleter_service'
5
+ require_relative '../support/command_options/dsu_times'
6
+ require_relative '../support/command_options/time_mnemonic'
7
+ require_relative '../support/time_formatable'
8
+ require_relative '../views/entry_group/shared/no_entries_to_display'
9
+ require_relative '../views/shared/error'
10
+ require_relative 'base_subcommand'
11
+
12
+ module Dsu
13
+ module Subcommands
14
+ class Delete < BaseSubcommand
15
+ include Support::CommandOptions::TimeMnemonic
16
+ include Support::TimeFormatable
17
+
18
+ map %w[d] => :date
19
+ map %w[dd] => :dates
20
+ map %w[n] => :today
21
+ map %w[t] => :tomorrow
22
+ map %w[y] => :yesterday
23
+
24
+ desc I18n.t('subcommands.delete.today.desc'), I18n.t('subcommands.delete.today.usage')
25
+ long_desc I18n.t('subcommands.delete.today.long_desc')
26
+ option :prompts, type: :hash, default: {}, hide: true, aliases: '-p'
27
+ def today
28
+ delete_entry_groups_if times: [Time.now], options: options
29
+ end
30
+
31
+ desc I18n.t('subcommands.delete.tomorrow.desc'), I18n.t('subcommands.delete.tomorrow.usage')
32
+ long_desc I18n.t('subcommands.delete.tomorrow.long_desc')
33
+ option :prompts, type: :hash, default: {}, hide: true, aliases: '-p'
34
+ def tomorrow
35
+ delete_entry_groups_if times: [Time.now.tomorrow], options: options
36
+ end
37
+
38
+ desc I18n.t('subcommands.delete.yesterday.desc'), I18n.t('subcommands.delete.yesterday.usage')
39
+ long_desc I18n.t('subcommands.delete.yesterday.long_desc')
40
+ option :prompts, type: :hash, default: {}, hide: true, aliases: '-p'
41
+ def yesterday
42
+ delete_entry_groups_if times: [Time.now.yesterday], options: options
43
+ end
44
+
45
+ desc I18n.t('subcommands.delete.date.desc'), I18n.t('subcommands.delete.date.usage')
46
+ long_desc I18n.t('subcommands.delete.date.long_desc',
47
+ date_option_description: date_option_description,
48
+ mnemonic_option_description: mnemonic_option_description)
49
+ option :prompts, type: :hash, default: {}, hide: true, aliases: '-p'
50
+ def date(date_or_mnemonic)
51
+ time = if time_mnemonic?(date_or_mnemonic)
52
+ time_from_mnemonic(command_option: date_or_mnemonic)
53
+ else
54
+ Time.parse(date_or_mnemonic)
55
+ end
56
+ delete_entry_groups_if times: [time], options: options
57
+ rescue ArgumentError => e
58
+ Views::Shared::Error.new(messages: e.message).render
59
+ end
60
+
61
+ desc I18n.t('subcommands.delete.dates.desc'), I18n.t('subcommands.delete.dates.usage')
62
+ long_desc I18n.t('subcommands.delete.dates.long_desc',
63
+ date_option_description: date_option_description,
64
+ mnemonic_option_description: mnemonic_option_description)
65
+ option :from, type: :string, required: true, aliases: '-f', banner: 'DATE|MNEMONIC'
66
+ option :to, type: :string, required: true, aliases: '-t', banner: 'DATE|MNEMONIC'
67
+ option :prompts, type: :hash, default: {}, hide: true, aliases: '-p'
68
+ def dates
69
+ options = configuration.to_h.merge(self.options).with_indifferent_access
70
+ times, errors = Support::CommandOptions::DsuTimes.dsu_times_for(from_option: options[:from], to_option: options[:to]) # rubocop:disable Layout/LineLength
71
+ if errors.any?
72
+ Views::Shared::Error.new(messages: errors).render
73
+ return
74
+ end
75
+
76
+ times = times_sort(times: times, entries_display_order: options[:entries_display_order])
77
+ delete_entry_groups_if times: times, options: options
78
+ rescue ArgumentError => e
79
+ Views::Shared::Error.new(messages: e.message).render
80
+ end
81
+
82
+ private
83
+
84
+ def delete_entry_groups_if(times:, options:)
85
+ prompt_string = I18n.t('subcommands.delete.prompts.are_you_sure',
86
+ dates: yyyy_mm_dd_or_through_for(times: times), count: total_entry_groups_for(times: times))
87
+ prompt = color_theme.prompt_with_options(prompt: prompt_string, options: %w[y N])
88
+ if yes?(prompt, options: options)
89
+ deleted_count = delete_entry_groups_for(times: times)
90
+ message = I18n.t('subcommands.delete.messages.deleted', count: deleted_count)
91
+ Views::Shared::Success.new(messages: message).render
92
+ else
93
+ message = I18n.t('subcommands.delete.messages.canceled')
94
+ Views::Shared::Info.new(messages: message).render
95
+ end
96
+ end
97
+
98
+ def delete_entry_groups_for(times:)
99
+ Services::EntryGroup::DeleterService.new(times: times).call
100
+ end
101
+
102
+ def total_entry_groups_for(times:)
103
+ Services::EntryGroup::CounterService.new(times: times).call
104
+ end
105
+ end
106
+ end
107
+ end