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
@@ -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}..."