dsu 2.0.8 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -3,7 +3,8 @@
3
3
  module Dsu
4
4
  module Support
5
5
  module CommandOptions
6
- module TimeMneumonics
6
+ module TimeMnemonics
7
+ # TODO: I18n.
7
8
  TODAY = %w[n today].freeze
8
9
  TOMORROW = %w[t tomorrow].freeze
9
10
  YESERDAY = %w[y yesterday].freeze
@@ -10,6 +10,7 @@ module Dsu
10
10
  module TimeFormatable
11
11
  module_function
12
12
 
13
+ # TODO: I18n.
13
14
  def formatted_time(time:)
14
15
  time = time.localtime if time.utc?
15
16
 
@@ -28,10 +29,12 @@ module Dsu
28
29
  time.strftime("%A, (#{today_yesterday_or_tomorrow}) %Y-%m-%d #{time_zone}")
29
30
  end
30
31
 
32
+ # TODO: I18n.
31
33
  def mm_dd(time:, separator: '/')
32
34
  time.strftime("%m#{separator}%d")
33
35
  end
34
36
 
37
+ # TODO: I18n.
35
38
  def mm_dd_yyyy(time:, separator: '/')
36
39
  time.strftime("%m#{separator}%d#{separator}%Y")
37
40
  end
@@ -40,6 +43,16 @@ module Dsu
40
43
  time.zone
41
44
  end
42
45
 
46
+ # TODO: I18n.
47
+ def yyyy_mm_dd_or_through_for(times:)
48
+ return yyyy_mm_dd(time: times[0]) if times.one?
49
+
50
+ times = [yyyy_mm_dd(time: times.min), yyyy_mm_dd(time: times.max)]
51
+
52
+ I18n.t('information.dates.through', from: times[0], to: times[1])
53
+ end
54
+
55
+ # TODO: I18n.
43
56
  def yyyy_mm_dd(time:, separator: '-')
44
57
  time.strftime("%Y#{separator}%m#{separator}%d")
45
58
  end
@@ -28,8 +28,10 @@ module Dsu
28
28
  return if description.length.between?(2, 256)
29
29
 
30
30
  if description.length < 2
31
+ # TODO: I18n.
31
32
  record.errors.add(:description, "is too short: \"#{record.short_description}\" (minimum is 2 characters).")
32
33
  elsif description.length > 256
34
+ # TODO: I18n.
33
35
  record.errors.add(:description, "is too long: \"#{record.short_description}\" (maximum is 256 characters).")
34
36
  end
35
37
  end
@@ -46,6 +46,7 @@ module Dsu
46
46
 
47
47
  non_unique_descriptions = descriptions.select { |description| descriptions.count(description) > 1 }.uniq
48
48
  non_unique_descriptions.each do |non_unique_description|
49
+ # TODO: I18n.
49
50
  record.errors.add(:entries,
50
51
  "array contains duplicate entry: \"#{short_description(non_unique_description)}\".",
51
52
  type: Support::FieldErrors::FIELD_DUPLICATE_ERROR)
data/lib/dsu/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Dsu
4
4
  VERSION_REGEX = /\A\d+\.\d+\.\d+(\.alpha\.\d+)?\z/
5
- VERSION = '2.0.8'
5
+ VERSION = '2.1.2'
6
6
  end
@@ -11,6 +11,7 @@ require_relative '../shared/warning'
11
11
  module Dsu
12
12
  module Views
13
13
  module ColorTheme
14
+ # TODO: I18n this class.
14
15
  class Show
15
16
  include Support::ColorThemable
16
17
 
@@ -6,6 +6,7 @@ require_relative '../../models/entry_group'
6
6
  module Dsu
7
7
  module Views
8
8
  module EntryGroup
9
+ # TODO: I18n this class.
9
10
  class Edit
10
11
  def initialize(entry_group:, options: {})
11
12
  raise ArgumentError, 'entry_group is nil' if entry_group.nil?
@@ -98,7 +99,7 @@ module Dsu
98
99
  end
99
100
 
100
101
  def previous_entry_group?
101
- previous_entry_group.entries.present?
102
+ previous_entry_group&.entries&.present?
102
103
  end
103
104
 
104
105
  def previous_entry_group
@@ -21,8 +21,9 @@ module Dsu
21
21
  @options = options || {}
22
22
  end
23
23
 
24
+ # TODO: I18n.
24
25
  def render
25
- entry_group_times.sort!
26
+ times.sort!
26
27
  time_range = "#{formatted_time(time: times.first)} " \
27
28
  "through #{formatted_time(time: times.last)}"
28
29
  message = "(nothing to display for #{time_range})"
@@ -31,6 +32,8 @@ module Dsu
31
32
 
32
33
  private
33
34
 
35
+ attr_reader :times, :options
36
+
34
37
  def color_theme
35
38
  @color_theme ||= Models::ColorTheme.current_or_default
36
39
  end
@@ -10,6 +10,7 @@ module Dsu
10
10
  raise ArgumentError, 'model is nil' if model.nil?
11
11
  raise ArgumentError, "model is the wrong object type: \"#{model}\"" unless model.is_a?(ActiveModel::Model)
12
12
 
13
+ # TODO: I18n.
13
14
  header = options[:header] || 'The following ERRORS were encountered; changes could not be saved:'
14
15
  super(messages: model.errors.full_messages, header: header, options: options)
15
16
 
data/lib/dsu.rb CHANGED
@@ -2,9 +2,13 @@
2
2
 
3
3
  require 'active_support/core_ext/hash/indifferent_access'
4
4
  require 'active_support/core_ext/object/blank'
5
+ require 'i18n'
5
6
  require 'thor'
6
7
  require 'time'
7
8
 
9
+ I18n.load_path += Dir[File.join(__dir__, 'locales/**/*', '*.yml')]
10
+ # I18n.default_locale = :en # (note that `en` is already the default!)
11
+
8
12
  Dir.glob("#{__dir__}/core/**/*.rb").each do |file|
9
13
  require file
10
14
  end
@@ -24,7 +28,7 @@ if !(Dsu.env.test? || Dsu.env.development?) && Dsu::Migration::Service.run_migra
24
28
  begin
25
29
  Dsu::Migration::Service.new.call
26
30
  rescue StandardError => e
27
- puts "Error running migrations: #{e.message}"
31
+ puts I18n.t('errors.migration.error', message: e.message)
28
32
  exit 1
29
33
  end
30
34
  end
@@ -0,0 +1,8 @@
1
+ en:
2
+ activerecord:
3
+ errors:
4
+ models:
5
+ some_model:
6
+ attributes:
7
+ some_attribute:
8
+ some_error: Some error
@@ -0,0 +1,136 @@
1
+ # lib/dsu/cli.rb
2
+ #
3
+ # NOTE:
4
+ #
5
+ # Commands should have the following layout:
6
+ #
7
+ # en:
8
+ # commands:
9
+ # my_command:
10
+ # key_mappings: thor key mappings
11
+ # desc: thor command description
12
+ # usage: thor command usage
13
+ # long_desc: thor long description
14
+ #
15
+ # Place key_mappings: at the top of the command entries:
16
+ #
17
+ # en:
18
+ # commands:
19
+ # my_command:
20
+ # key_mappings: m # Single mapping
21
+ # key_mappings: # Array of mappings
22
+ # - 'm'
23
+ # - '-m'
24
+ en:
25
+ commands:
26
+ add:
27
+ key_mappings: a
28
+ desc: add|a [OPTIONS] DESCRIPTION
29
+ usage: Adds a DSU entry having DESCRIPTION to the date associated with the given OPTION
30
+ long_desc: |
31
+ Will add a DSU entry having DESCRIPTION to the date associated with the given OPTION.
32
+
33
+ $ dsu add [-d DATE|-n|-t|-y] DESCRIPTION
34
+
35
+ $ dsu a [-d DATE|-n|-t|-y] DESCRIPTION
36
+
37
+ OPTIONS:
38
+
39
+ -d DATE: Adds a DSU entry having DESCRIPTION to the DATE.
40
+
41
+ %{date_option_description}
42
+
43
+ -n: Adds a DSU entry having DESCRIPTION to today's date (`Time.now`).
44
+
45
+ -t: Adds a DSU entry having DESCRIPTION to tomorrow's date (`Time.new.tomorrow`).
46
+
47
+ -y: Adds a DSU entry having DESCRIPTION to yesterday's date (`Time.new.yesterday`).
48
+
49
+ DESCRIPTION
50
+
51
+ Must be be between 2 and 256 characters (inclusive) in length.
52
+ config:
53
+ key_mappings: c
54
+ desc: config|c SUBCOMMAND
55
+ usage: Manage configuration file for this gem
56
+ delete:
57
+ key_mappings: c
58
+ desc: delete|d SUBCOMMAND
59
+ usage: Delete DSU entries for the given SUBCOMMAND
60
+ edit:
61
+ desc: edit|e SUBCOMMAND
62
+ usage: Edit DSU entries for the given SUBCOMMAND
63
+ key_mappings: e
64
+ info:
65
+ key_mappings: i
66
+ desc: info|i
67
+ usage: Displays information about this DSU release
68
+ info: |
69
+ Dsu Info
70
+ --------------------------------------------------
71
+ Dsu version: %{dsu_version}
72
+ Configuration version: %{configuration_version}
73
+ Entry group version: %{entry_group_version}
74
+ Color theme version: %{color_theme_version}
75
+
76
+ Config folder: %{config_folder}
77
+ Root folder: %{root_folder}
78
+ Entries folder: %{entries_folder}
79
+ Themes folder: %{themes_folder}
80
+ Gem folder: %{gem_folder}
81
+ Temp folder: %{temp_folder}
82
+
83
+ Migration version folder: %{migration_version_folder}
84
+ Migration file folder: %{migration_file_folder}
85
+ list:
86
+ key_mappings: l
87
+ desc: list|l SUBCOMMAND
88
+ usage: Displays DSU entries for the given SUBCOMMAND
89
+ theme:
90
+ key_mappings: t
91
+ desc: theme|t SUBCOMMAND
92
+ usage: Manage DSU themes
93
+ version:
94
+ key_mappings:
95
+ - v
96
+ - '-v'
97
+ desc: version|v|-v
98
+ usage: Displays the DSU version for this gem
99
+ # Should these options go under their respective commands
100
+ # (e.g. commands.options.date.name, commands.options.today.aliases, etc.)?
101
+ options:
102
+ date:
103
+ aliases: -d
104
+ name: 'date'
105
+ today:
106
+ aliases: -n
107
+ name: 'today'
108
+ tomorrow:
109
+ aliases: -t
110
+ name: 'tomorrow'
111
+ yesterday:
112
+ aliases: -y
113
+ name: 'yesterday'
114
+ include_all: Include dates that have no DSU entries
115
+ date_option_description: |
116
+ DATE
117
+
118
+ This may be any date string that can be parsed using `Time.parse`.
119
+ Consequently, you may use also use '/' as date separators,
120
+ as well as omit the year if the date you want to display is the
121
+ current year (e.g. <month>/<day>, or 1/31). For example: `require 'time';
122
+ Time.parse('01/02/2023'); Time.parse('1/2') # etc.`
123
+ mnemonic_option_description: |
124
+ MNEMONIC
125
+
126
+ This may be any of the following: n|today|t|tomorrow|y|yesterday|+n|-n.
127
+
128
+ Where n, t, y are aliases for today, tomorrow, and yesterday, respectively.
129
+
130
+ Where +n, -n are relative date mnemonics (RDMs). Generally speaking,
131
+ RDMs are relative to the current date. For example, a RDM of +1 would be
132
+ equal to `Time.now + 1.day` (tomorrow), and a RDM of -1 would be equal to
133
+ `Time.now - 1.day` (yesterday).
134
+
135
+ In some cases the behavior RDMs have on some commands are context dependent;
136
+ in such cases the behavior will be noted.
@@ -0,0 +1,23 @@
1
+ en:
2
+ configuration:
3
+ errors:
4
+ theme_file_missing: Theme file "%{theme_path}" does not exist.
5
+ errors:
6
+ error: "Error: %{message}"
7
+ from_option_invalid: Option -f, [--from=DATE|MNEMONIC] value is invalid ["%{from_option}"]
8
+ to_option_invalid: Option -t, [--to=DATE|MNEMONIC] value is invalid ["%{to_option}"]
9
+ migration:
10
+ error: "Error running migrations: %{message}"
11
+ headers:
12
+ entry:
13
+ could_not_be_added: "An error was encountered; the entry could not be added:"
14
+ messages:
15
+ configuration_file:
16
+ already_exists: Configuration file (%{configuration_file}) already exists.
17
+ created: Configuration file (%{configuration_file}) created.
18
+ deleted: Configuration file (%{configuration_file}) deleted.
19
+ destination_folder_does_not_exist: "Destination folder for configuration file (%{configuration_folder}) does not exist."
20
+ does_not_exist: "Configuration file (%{configuration_file}) does not exist."
21
+ information:
22
+ dates:
23
+ through: "%{from} thru %{to}"
@@ -0,0 +1,19 @@
1
+ en:
2
+ presenters:
3
+ color_theme_presenter:
4
+ headers:
5
+ color_themes: Color Themes
6
+ current_theme: "* current theme"
7
+ color_theme_show_presenter:
8
+ headers:
9
+ number: No.
10
+ color: Color
11
+ values: Values
12
+ viewing_color_theme: "Viewing color theme: %{theme_name}"
13
+ footer_example: Footer example
14
+ configuration_presenter:
15
+ headers:
16
+ file_contents: "Configuration file contents (%{config_path})"
17
+ entry_group_presenter:
18
+ headers:
19
+ no_entries_available: (no entries available for this day)
@@ -0,0 +1,10 @@
1
+ en:
2
+ services:
3
+ editor_service:
4
+ errors:
5
+ temp_file_error: |
6
+ Failed to open temporary file in editor '%{editor}'; the system error returned was: '%{status}'.
7
+ Either set the EDITOR environment variable or set the dsu editor configuration option (`$ dsu config info`).
8
+ Run `$ dsu help config` for more information.
9
+ messages:
10
+ editing: "Editing entry group %{formatted_time}..."