dsu 2.0.8 → 2.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -2
- data/Gemfile.lock +9 -9
- data/README.md +178 -69
- data/lib/core/ruby/color_theme_mode.rb +1 -1
- data/lib/dsu/base_cli.rb +3 -17
- data/lib/dsu/cli.rb +44 -72
- data/lib/dsu/command_services/add_entry_service.rb +1 -1
- data/lib/dsu/env.rb +4 -0
- data/lib/dsu/models/color_theme.rb +2 -2
- data/lib/dsu/models/configuration.rb +3 -1
- data/lib/dsu/models/entry_group.rb +1 -1
- data/lib/dsu/presenters/color_theme_presenter.rb +4 -2
- data/lib/dsu/presenters/color_theme_show_presenter.rb +9 -3
- data/lib/dsu/presenters/configuration_presenter.rb +2 -2
- data/lib/dsu/presenters/entry_group_presenter.rb +2 -2
- data/lib/dsu/services/entry_group/counter_service.rb +32 -0
- data/lib/dsu/services/entry_group/deleter_service.rb +35 -0
- data/lib/dsu/services/entry_group/editor_service.rb +7 -11
- data/lib/dsu/subcommands/base_subcommand.rb +0 -2
- data/lib/dsu/subcommands/config.rb +17 -74
- data/lib/dsu/subcommands/delete.rb +107 -0
- data/lib/dsu/subcommands/edit.rb +16 -30
- data/lib/dsu/subcommands/list.rb +26 -96
- data/lib/dsu/subcommands/theme.rb +50 -79
- data/lib/dsu/support/ask.rb +1 -1
- data/lib/dsu/support/command_help_colorizeable.rb +7 -0
- data/lib/dsu/support/command_hookable.rb +2 -0
- data/lib/dsu/support/command_options/dsu_times.rb +10 -10
- data/lib/dsu/support/command_options/time.rb +1 -0
- data/lib/dsu/support/command_options/time_mnemonic.rb +108 -0
- data/lib/dsu/support/command_options/{time_mneumonics.rb → time_mnemonics.rb} +2 -1
- data/lib/dsu/support/time_formatable.rb +13 -0
- data/lib/dsu/validators/description_validator.rb +2 -0
- data/lib/dsu/validators/entries_validator.rb +1 -0
- data/lib/dsu/version.rb +1 -1
- data/lib/dsu/views/color_theme/show.rb +1 -0
- data/lib/dsu/views/entry_group/edit.rb +2 -1
- data/lib/dsu/views/entry_group/shared/no_entries_to_display.rb +4 -1
- data/lib/dsu/views/shared/model_errors.rb +1 -0
- data/lib/dsu.rb +5 -1
- data/lib/locales/en/active_record.yml +8 -0
- data/lib/locales/en/commands.yml +136 -0
- data/lib/locales/en/miscellaneous.yml +23 -0
- data/lib/locales/en/presenters.yml +19 -0
- data/lib/locales/en/services.yml +10 -0
- data/lib/locales/en/subcommands.yml +348 -0
- metadata +26 -27
- data/exe/dsu_migrate.rb +0 -43
- data/lib/dsu/support/command_options/time_mneumonic.rb +0 -108
- data/lib/dsu/support/subcommand_help_colorizeable.rb +0 -27
data/lib/dsu/subcommands/edit.rb
CHANGED
@@ -12,50 +12,36 @@ module Dsu
|
|
12
12
|
map %w[t] => :tomorrow
|
13
13
|
map %w[y] => :yesterday
|
14
14
|
|
15
|
-
desc '
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
desc I18n.t('subcommands.edit.date.desc'), I18n.t('subcommands.edit.date.usage')
|
16
|
+
long_desc I18n.t('subcommands.edit.date.long_desc', date_option_description: date_option_description)
|
17
|
+
def date(date)
|
18
|
+
entry_group = Models::EntryGroup.edit(time: Time.parse(date))
|
19
|
+
Views::EntryGroup::Show.new(entry_group: entry_group).render
|
20
|
+
rescue ArgumentError => e
|
21
|
+
puts apply_theme(I18n.t('errors.error', message: e.message), theme_color: color_theme.error)
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
|
25
|
+
desc I18n.t('subcommands.edit.today.desc'), I18n.t('subcommands.edit.today.usage')
|
26
|
+
long_desc I18n.t('subcommands.edit.today.long_desc')
|
20
27
|
def today
|
21
28
|
entry_group = Models::EntryGroup.edit(time: Time.now)
|
22
29
|
Views::EntryGroup::Show.new(entry_group: entry_group).render
|
23
30
|
end
|
24
31
|
|
25
|
-
desc 'tomorrow, t'
|
26
|
-
|
27
|
-
long_desc <<-LONG_DESC
|
28
|
-
Edits the DSU entries for tomorrow.
|
29
|
-
LONG_DESC
|
32
|
+
desc I18n.t('subcommands.edit.tomorrow.desc'), I18n.t('subcommands.edit.tomorrow.usage')
|
33
|
+
long_desc I18n.t('subcommands.edit.tomorrow.long_desc')
|
30
34
|
def tomorrow
|
31
35
|
entry_group = Models::EntryGroup.edit(time: Time.now.tomorrow)
|
32
36
|
Views::EntryGroup::Show.new(entry_group: entry_group).render
|
33
37
|
end
|
34
38
|
|
35
|
-
desc 'yesterday,
|
36
|
-
|
37
|
-
long_desc <<-LONG_DESC
|
38
|
-
Edits the DSU entries for yesterday.
|
39
|
-
LONG_DESC
|
39
|
+
desc I18n.t('subcommands.edit.yesterday.desc'), I18n.t('subcommands.edit.yesterday.usage')
|
40
|
+
long_desc I18n.t('subcommands.edit.yesterday.long_desc')
|
40
41
|
def yesterday
|
41
42
|
entry_group = Models::EntryGroup.edit(time: Time.now.yesterday)
|
42
43
|
Views::EntryGroup::Show.new(entry_group: entry_group).render
|
43
44
|
end
|
44
|
-
|
45
|
-
desc 'date, d DATE',
|
46
|
-
'Edits the DSU entries for DATE.'
|
47
|
-
long_desc <<-LONG_DESC
|
48
|
-
Edits the DSU entries for DATE.
|
49
|
-
|
50
|
-
\x5 #{date_option_description}
|
51
|
-
LONG_DESC
|
52
|
-
def date(date)
|
53
|
-
entry_group = Models::EntryGroup.edit(time: Time.parse(date))
|
54
|
-
Views::EntryGroup::Show.new(entry_group: entry_group).render
|
55
|
-
rescue ArgumentError => e
|
56
|
-
puts apply_theme("Error: #{e.message}", theme_color: color_theme.error)
|
57
|
-
exit 1
|
58
|
-
end
|
59
45
|
end
|
60
46
|
end
|
61
47
|
end
|
data/lib/dsu/subcommands/list.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative '../services/entry_group/counter_service'
|
3
4
|
require_relative '../support/command_options/dsu_times'
|
4
|
-
require_relative '../support/command_options/
|
5
|
+
require_relative '../support/command_options/time_mnemonic'
|
5
6
|
require_relative '../support/time_formatable'
|
6
7
|
require_relative '../views/entry_group/shared/no_entries_to_display'
|
7
8
|
require_relative '../views/shared/error'
|
@@ -10,7 +11,7 @@ require_relative 'base_subcommand'
|
|
10
11
|
module Dsu
|
11
12
|
module Subcommands
|
12
13
|
class List < BaseSubcommand
|
13
|
-
include Support::CommandOptions::
|
14
|
+
include Support::CommandOptions::TimeMnemonic
|
14
15
|
include Support::TimeFormatable
|
15
16
|
|
16
17
|
map %w[d] => :date
|
@@ -19,57 +20,39 @@ module Dsu
|
|
19
20
|
map %w[t] => :tomorrow
|
20
21
|
map %w[y] => :yesterday
|
21
22
|
|
22
|
-
desc 'today,
|
23
|
-
|
24
|
-
long_desc <<-LONG_DESC
|
25
|
-
Displays the DSU entries for today. This command has no options.
|
26
|
-
LONG_DESC
|
27
|
-
option :include_all, type: :boolean, aliases: '-a', desc: 'Include dates that have no DSU entries'
|
23
|
+
desc I18n.t('subcommands.list.today.desc'), I18n.t('subcommands.list.today.usage')
|
24
|
+
long_desc I18n.t('subcommands.list.today.long_desc')
|
28
25
|
def today
|
29
26
|
time = Time.now
|
30
27
|
times = sorted_dsu_times_for(times: [time.yesterday, time])
|
31
28
|
view_list_for(times: times, options: options)
|
32
29
|
end
|
33
30
|
|
34
|
-
desc 'tomorrow, t'
|
35
|
-
|
36
|
-
long_desc <<-LONG_DESC
|
37
|
-
Displays the DSU entries for tomorrow. This command has no options.
|
38
|
-
LONG_DESC
|
39
|
-
option :include_all, type: :boolean, aliases: '-a', desc: 'Include dates that have no DSU entries'
|
31
|
+
desc I18n.t('subcommands.list.tomorrow.desc'), I18n.t('subcommands.list.tomorrow.usage')
|
32
|
+
long_desc I18n.t('subcommands.list.tomorrow.long_desc')
|
40
33
|
def tomorrow
|
41
34
|
time = Time.now
|
42
35
|
times = sorted_dsu_times_for(times: [time, time.tomorrow])
|
43
36
|
view_list_for(times: times, options: options)
|
44
37
|
end
|
45
38
|
|
46
|
-
desc 'yesterday,
|
47
|
-
|
48
|
-
long_desc <<-LONG_DESC
|
49
|
-
Displays the DSU entries for yesterday. This command has no options.
|
50
|
-
LONG_DESC
|
51
|
-
option :include_all, type: :boolean, aliases: '-a', desc: 'Include dates that have no DSU entries'
|
39
|
+
desc I18n.t('subcommands.list.yesterday.desc'), I18n.t('subcommands.list.yesterday.usage')
|
40
|
+
long_desc I18n.t('subcommands.list.yesterday.long_desc')
|
52
41
|
def yesterday
|
53
42
|
time = Time.now
|
54
43
|
times = sorted_dsu_times_for(times: [time.yesterday, time.yesterday.yesterday])
|
55
44
|
view_list_for(times: times, options: options)
|
56
45
|
end
|
57
46
|
|
58
|
-
desc 'date,
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
#{mneumonic_option_description}
|
66
|
-
LONG_DESC
|
67
|
-
option :include_all, type: :boolean, aliases: '-a', desc: 'Include dates that have no DSU entries'
|
68
|
-
def date(date_or_mneumonic)
|
69
|
-
time = if time_mneumonic?(date_or_mneumonic)
|
70
|
-
time_from_mneumonic(command_option: date_or_mneumonic)
|
47
|
+
desc I18n.t('subcommands.list.date.desc'), I18n.t('subcommands.list.date.usage')
|
48
|
+
long_desc I18n.t('subcommands.list.date.long_desc',
|
49
|
+
date_option_description: date_option_description,
|
50
|
+
mnemonic_option_description: mnemonic_option_description)
|
51
|
+
def date(date_or_mnemonic)
|
52
|
+
time = if time_mnemonic?(date_or_mnemonic)
|
53
|
+
time_from_mnemonic(command_option: date_or_mnemonic)
|
71
54
|
else
|
72
|
-
Time.parse(
|
55
|
+
Time.parse(date_or_mnemonic)
|
73
56
|
end
|
74
57
|
times = sorted_dsu_times_for(times: [time, time.yesterday])
|
75
58
|
view_list_for(times: times, options: options)
|
@@ -77,67 +60,13 @@ module Dsu
|
|
77
60
|
Views::Shared::Error.new(messages: e.message).render
|
78
61
|
end
|
79
62
|
|
80
|
-
desc 'dates
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
$ dsu dates|dd OPTIONS -- will display the DSU entries for the OPTIONS provided.
|
86
|
-
|
87
|
-
SYNOPSIS
|
88
|
-
|
89
|
-
$ dsu dates|dd OPTIONS
|
90
|
-
|
91
|
-
OPTIONS
|
92
|
-
|
93
|
-
-a|--include-all true|false: If true, all DSU dates within the specified range will be displayed. If false, DSU dates between the first and last DSU dates that have NO entries will NOT be displayed.. The default is taken from the dsu configuration setting :include_all, see `dsu config info`.
|
94
|
-
|
95
|
-
-f|--from DATE|MNEMONIC: The DATE or MNEUMONIC that represents the start of the range of DSU dates to display. If a relative mneumonic is used (+/-n, e.g +1, -1, etc.), the date calculated will be relative to the current date (e.g. `<MNEUMONIC>.to_i.days.from_now(Time.now)`).
|
96
|
-
|
97
|
-
-t|--to DATE|MNEMONIC: The DATE or MNEUMONIC that represents the end of the range of DSU dates to display. If a relative mneumonic is used (+/-n, e.g +1, -1, etc.), the date calculated will be relative to the date that resulting from the `--from` option date calculation.
|
98
|
-
|
99
|
-
#{date_option_description}
|
100
|
-
|
101
|
-
#{mneumonic_option_description}
|
102
|
-
|
103
|
-
EXAMPLES
|
104
|
-
|
105
|
-
NOTE: All examples are subject to the `--include-all` option.
|
106
|
-
|
107
|
-
The below will display the DSU entries for the range of dates from 1/1 to 1/4:
|
108
|
-
|
109
|
-
$ dsu list dates --from 1/1 --to +3
|
110
|
-
|
111
|
-
This will display the DSU entries for the range of dates from 1/2 to 1/5:
|
112
|
-
|
113
|
-
$ dsu list dates --from 1/5 --to -3
|
114
|
-
|
115
|
-
This (assuming "today" is 1/10) will display the DSU entries for the last week 1/10 to 1/3:
|
116
|
-
|
117
|
-
$ dsu list dates --from today --to -7
|
118
|
-
|
119
|
-
This (assuming "today" is 5/23) will display the DSU entries for the last week 5/16 to 5/22.
|
120
|
-
This example simply illustrates the fact that you can use relative mneumonics for
|
121
|
-
both `--from` and `--to` options; this doesn't mean you should do so...
|
122
|
-
|
123
|
-
While you can use relative mneumonics for both `--from` and `--to` options,
|
124
|
-
there is always a more intuitive way. The below example basically lists one week
|
125
|
-
of DSU entries back 1 week from yesterday's date:
|
126
|
-
|
127
|
-
$ dsu list dates --from -7 --to +6
|
128
|
-
|
129
|
-
The above can be accomplished MUCH easier by simply using the `yesterday` mneumonic...
|
130
|
-
|
131
|
-
This (assuming "today" is 5/23) will display the DSU entries back 1 week from yesterday's date 5/16 to 5/22:
|
132
|
-
|
133
|
-
$ dsu list dates --from yesterday --to -6
|
134
|
-
LONG_DESC
|
135
|
-
# -f, --from FROM [DATE|MNEMONIC] (e.g. -f, --from 1/1[/yyy]|n|t|y|today|tomorrow|yesterday)
|
63
|
+
desc I18n.t('subcommands.list.dates.desc'), I18n.t('subcommands.list.dates.usage')
|
64
|
+
long_desc I18n.t('subcommands.list.dates.long_desc',
|
65
|
+
date_option_description: date_option_description,
|
66
|
+
mnemonic_option_description: mnemonic_option_description)
|
136
67
|
option :from, type: :string, required: true, aliases: '-f', banner: 'DATE|MNEMONIC'
|
137
|
-
# -t, --to TO [DATE|MNEMONIC] (e.g. -t, --to 1/1[/yyy]|n|t|y|today|tomorrow|yesterday)
|
138
68
|
option :to, type: :string, required: true, aliases: '-t', banner: 'DATE|MNEMONIC'
|
139
|
-
|
140
|
-
option :include_all, type: :boolean, aliases: '-a', desc: 'Include dates that have no DSU entries'
|
69
|
+
option :include_all, default: false, type: :boolean, aliases: '-a', desc: I18n.t('options.include_all')
|
141
70
|
def dates
|
142
71
|
options = configuration.to_h.merge(self.options).with_indifferent_access
|
143
72
|
times, errors = Support::CommandOptions::DsuTimes.dsu_times_for(from_option: options[:from], to_option: options[:to]) # rubocop:disable Layout/LineLength
|
@@ -149,9 +78,10 @@ module Dsu
|
|
149
78
|
# NOTE: special sort here, unlike the other commands where rules for
|
150
79
|
# displaying DSU entries are applied; this is more of a list command.
|
151
80
|
times = times_sort(times: times, entries_display_order: options[:entries_display_order])
|
152
|
-
view_entry_groups(times: times, options: options) do |
|
153
|
-
|
154
|
-
|
81
|
+
view_entry_groups(times: times, options: options) do |_total_entry_groups, _total_entry_groups_not_shown|
|
82
|
+
if Services::EntryGroup::CounterService.new(times: times).call.zero?
|
83
|
+
Views::EntryGroup::Shared::NoEntriesToDisplay.new(times: times, options: options).render
|
84
|
+
end
|
155
85
|
end
|
156
86
|
rescue ArgumentError => e
|
157
87
|
Views::Shared::Error.new(messages: e.message).render
|
@@ -11,142 +11,108 @@ require_relative 'base_subcommand'
|
|
11
11
|
module Dsu
|
12
12
|
module Subcommands
|
13
13
|
class Theme < BaseSubcommand
|
14
|
-
map %w[c] => :create if Dsu.env.
|
15
|
-
map %w[d] => :delete if Dsu.env.
|
14
|
+
map %w[c] => :create if Dsu.env.local?
|
15
|
+
map %w[d] => :delete if Dsu.env.local?
|
16
16
|
map %w[l] => :list
|
17
17
|
map %w[s] => :show
|
18
18
|
map %w[u] => :use
|
19
19
|
|
20
|
-
if Dsu.env.
|
21
|
-
desc 'create
|
22
|
-
|
23
|
-
long_desc <<-LONG_DESC
|
24
|
-
Create a dsu color theme named THEME_NAME in the #{Support::Fileable.themes_folder} folder.
|
25
|
-
|
26
|
-
SYNOPSIS
|
27
|
-
|
28
|
-
`dsu create THEME_NAME [-d|--description DESCRIPTION]`
|
29
|
-
|
30
|
-
OPTIONS:
|
31
|
-
|
32
|
-
-d|--description DESCRIPTION: Creates the dsu color theme with having DESCRIPTION as the color theme description.
|
33
|
-
|
34
|
-
DESCRIPTION:
|
35
|
-
|
36
|
-
Must be be between 2 and 256 characters (inclusive) in length.
|
37
|
-
LONG_DESC
|
20
|
+
if Dsu.env.local?
|
21
|
+
desc I18n.t('subcommands.theme.create.desc'), I18n.t('subcommands.theme.create.usage')
|
22
|
+
long_desc I18n.t('subcommands.theme.create.long_desc', themes_folder: Support::Fileable.themes_folder)
|
38
23
|
option :description, type: :string, aliases: '-d', banner: 'DESCRIPTION'
|
39
24
|
option :prompts, type: :hash, default: {}, hide: true, aliases: '-p'
|
40
25
|
def create(theme_name)
|
41
26
|
if Models::ColorTheme.exist?(theme_name: theme_name)
|
42
|
-
|
27
|
+
message = I18n.t('subcommands.theme.create.errors.already_exists', theme_name: theme_name)
|
28
|
+
Views::Shared::Error.new(messages: message).render
|
43
29
|
return false
|
44
30
|
end
|
45
|
-
|
31
|
+
prompt_string = I18n.t('subcommands.theme.create.prompts.create_theme', theme_name: theme_name)
|
32
|
+
prompt = color_theme.prompt_with_options(prompt: prompt_string, options: %w[y N])
|
46
33
|
if yes?(prompt, options: options)
|
47
34
|
theme_hash = Models::ColorTheme::DEFAULT_THEME.dup
|
48
|
-
theme_hash[:description] = options[:description] ||
|
35
|
+
theme_hash[:description] = options[:description] || I18n.t('subcommands.theme.generic.color_theme',
|
36
|
+
theme_name: theme_name.capitalize)
|
49
37
|
Models::ColorTheme.new(theme_name: theme_name, theme_hash: theme_hash).save!
|
50
|
-
|
38
|
+
message = I18n.t('subcommands.theme.create.messages.created', theme_name: theme_name)
|
39
|
+
Views::Shared::Info.new(messages: "\n#{message}").render
|
51
40
|
true
|
52
41
|
else
|
53
|
-
|
42
|
+
message = I18n.t('subcommands.theme.create.messages.canceled')
|
43
|
+
Views::Shared::Info.new(messages: "\n#{message}").render
|
54
44
|
false
|
55
45
|
end
|
56
46
|
end
|
57
47
|
|
58
|
-
desc 'delete
|
59
|
-
|
60
|
-
long_desc <<-LONG_DESC
|
61
|
-
NAME
|
62
|
-
|
63
|
-
`dsu delete [THEME_NAME]` -- will delete the dsu color theme named THEME_NAME located in the #{Support::Fileable.themes_folder} folder.
|
64
|
-
LONG_DESC
|
48
|
+
desc I18n.t('subcommands.theme.delete.desc'), I18n.t('subcommands.theme.delete.usage')
|
49
|
+
long_desc I18n.t('subcommands.theme.delete.long_desc', themes_folder: Support::Fileable.themes_folder)
|
65
50
|
option :prompts, type: :hash, default: {}, hide: true, aliases: '-p'
|
66
|
-
def delete(theme_name)
|
51
|
+
def delete(theme_name) # rubocop:disable Metrics/MethodLength
|
67
52
|
display_dsu_header
|
68
53
|
|
69
54
|
if theme_name == Models::ColorTheme::DEFAULT_THEME_NAME
|
70
|
-
|
71
|
-
Views::Shared::Error.new(messages:
|
55
|
+
message = I18n.t('subcommands.theme.delete.errors.cannot_delete', theme_name: theme_name)
|
56
|
+
Views::Shared::Error.new(messages: message).render
|
72
57
|
return
|
73
58
|
end
|
74
59
|
|
75
60
|
unless Models::ColorTheme.exist?(theme_name: theme_name)
|
76
|
-
|
61
|
+
message = I18n.t('subcommands.theme.generic.errors.does_not_exist', theme_name: theme_name)
|
62
|
+
Views::Shared::Error.new(messages: message).render
|
77
63
|
return
|
78
64
|
end
|
79
65
|
|
80
|
-
|
81
|
-
|
82
|
-
if yes?(prompt, options: options)
|
66
|
+
prompt_string = I18n.t('subcommands.theme.delete.prompts.delete_theme', theme_name: theme_name)
|
67
|
+
prompt = color_theme.prompt_with_options(prompt: prompt_string, options: %w[y N])
|
68
|
+
message = if yes?(prompt, options: options)
|
83
69
|
Models::ColorTheme.delete!(theme_name: theme_name)
|
84
|
-
|
70
|
+
change_theme
|
71
|
+
I18n.t('subcommands.theme.delete.messages.deleted', theme_name: theme_name)
|
85
72
|
else
|
86
|
-
|
73
|
+
I18n.t('subcommands.theme.delete.messages.canceled')
|
87
74
|
end
|
75
|
+
Views::Shared::Info.new(messages: "\n#{message}").render
|
88
76
|
end
|
89
77
|
end
|
90
78
|
|
91
|
-
desc 'list',
|
92
|
-
|
93
|
-
long_desc <<-LONG_DESC
|
94
|
-
NAME
|
95
|
-
|
96
|
-
`dsu list` -- lists the available dsu color themes located in the #{Support::Fileable.themes_folder} folder.
|
97
|
-
LONG_DESC
|
79
|
+
desc I18n.t('subcommands.theme.list.desc'), I18n.t('subcommands.theme.list.usage')
|
80
|
+
long_desc I18n.t('subcommands.theme.list.long_desc', themes_folder: Support::Fileable.themes_folder)
|
98
81
|
def list
|
99
82
|
Views::ColorTheme::Index.new.render
|
100
83
|
end
|
101
84
|
|
102
|
-
desc 'use
|
103
|
-
|
104
|
-
long_desc <<-LONG_DESC
|
105
|
-
NAME
|
106
|
-
|
107
|
-
`dsu theme use [THEME_NAME]` -- sets the dsu color theme to THEME_NAME.
|
108
|
-
|
109
|
-
SYNOPSIS
|
110
|
-
|
111
|
-
If THEME_NAME is not provided, the default theme will be used.
|
112
|
-
If THEME_NAME does not exist, you will be given the option to create a new theme.
|
113
|
-
|
114
|
-
LONG_DESC
|
85
|
+
desc I18n.t('subcommands.theme.use.desc'), I18n.t('subcommands.theme.use.usage')
|
86
|
+
long_desc I18n.t('subcommands.theme.use.long_desc')
|
115
87
|
option :prompts, type: :hash, default: {}, hide: true, aliases: '-p'
|
116
88
|
def use(theme_name = Models::ColorTheme::DEFAULT_THEME_NAME)
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
end
|
89
|
+
display_dsu_header
|
90
|
+
|
91
|
+
return if Dsu.env.local? && !Models::ColorTheme.exist?(theme_name: theme_name) && !create(theme_name)
|
121
92
|
|
122
93
|
unless Models::ColorTheme.exist?(theme_name: theme_name)
|
123
|
-
|
124
|
-
Views::Shared::Error.new(messages:
|
94
|
+
message = I18n.t('subcommands.theme.generic.errors.does_not_exist', theme_name: theme_name)
|
95
|
+
Views::Shared::Error.new(messages: message).render
|
125
96
|
return
|
126
97
|
end
|
127
98
|
|
128
|
-
|
129
|
-
configuration.save!
|
99
|
+
change_theme theme_name: theme_name
|
130
100
|
# We need to display the header after the theme is updated so that it is displayed in the
|
131
101
|
# correct theme color.
|
132
|
-
|
133
|
-
Views::Shared::Info.new(messages:
|
102
|
+
message = I18n.t('subcommands.theme.use.messages.using_color_theme', theme_name: theme_name)
|
103
|
+
Views::Shared::Info.new(messages: message).render
|
134
104
|
end
|
135
105
|
|
136
|
-
desc 'show
|
137
|
-
|
138
|
-
long_desc <<-LONG_DESC
|
139
|
-
NAME
|
140
|
-
|
141
|
-
`dsu show THEME_NAME` -- displays the dsu color theme for THEME_NAME.
|
142
|
-
LONG_DESC
|
106
|
+
desc I18n.t('subcommands.theme.show.desc'), I18n.t('subcommands.theme.show.usage')
|
107
|
+
long_desc I18n.t('subcommands.theme.show.long_desc')
|
143
108
|
def show(theme_name = configuration.theme_name)
|
144
109
|
if Dsu::Models::ColorTheme.exist?(theme_name: theme_name)
|
145
110
|
Views::ColorTheme::Show.new(theme_name: theme_name).render
|
146
111
|
return
|
147
112
|
end
|
148
113
|
|
149
|
-
|
114
|
+
message = I18n.t('subcommands.theme.generic.errors.does_not_exist', theme_name: theme_name)
|
115
|
+
Views::Shared::Error.new(messages: message).render
|
150
116
|
end
|
151
117
|
|
152
118
|
private
|
@@ -154,6 +120,11 @@ module Dsu
|
|
154
120
|
def display_dsu_header
|
155
121
|
self.class.display_dsu_header
|
156
122
|
end
|
123
|
+
|
124
|
+
def change_theme(theme_name: Models::ColorTheme::DEFAULT_THEME_NAME)
|
125
|
+
configuration.theme_name = theme_name
|
126
|
+
configuration.save!
|
127
|
+
end
|
157
128
|
end
|
158
129
|
end
|
159
130
|
end
|
data/lib/dsu/support/ask.rb
CHANGED
@@ -23,7 +23,7 @@ module Dsu
|
|
23
23
|
def auto_prompt(prompt, options)
|
24
24
|
prompt = Utils.strip_escapes(prompt)
|
25
25
|
@auto_prompt ||= begin
|
26
|
-
value = options.dig('prompts', prompt)
|
26
|
+
value = options.dig('prompts', prompt) || options.dig('prompts', 'any')
|
27
27
|
value = (value == 'true' unless value.nil?)
|
28
28
|
value
|
29
29
|
end
|
@@ -12,11 +12,18 @@ module Dsu
|
|
12
12
|
end
|
13
13
|
|
14
14
|
module ClassMethods
|
15
|
+
# Handles general help colorization.
|
15
16
|
def help(shell, subcommand = false) # rubocop:disable Style/OptionalBooleanParameter
|
16
17
|
help_text = Services::StdoutRedirectorService.call { super }
|
17
18
|
puts apply_theme(help_text, theme_color: color_theme.help)
|
18
19
|
end
|
19
20
|
|
21
|
+
# Handles sub-command help colorization.
|
22
|
+
def command_help(shell, subcommand = false) # rubocop:disable Style/OptionalBooleanParameter
|
23
|
+
help_text = Services::StdoutRedirectorService.call { super }
|
24
|
+
puts apply_theme(help_text, theme_color: color_theme.help)
|
25
|
+
end
|
26
|
+
|
20
27
|
def color_theme
|
21
28
|
@color_theme ||= Models::ColorTheme.current_or_default
|
22
29
|
end
|
@@ -35,11 +35,13 @@ module Dsu
|
|
35
35
|
def suspend_header?(args, _options)
|
36
36
|
return false unless args.count > 1
|
37
37
|
|
38
|
+
# TODO: I18n?
|
38
39
|
true if args[0] == 'theme' && %w[use delete].include?(args[1])
|
39
40
|
end
|
40
41
|
|
41
42
|
def display_dsu_footer
|
42
43
|
puts apply_theme('_' * 35, theme_color: color_theme.dsu_footer)
|
44
|
+
# TODO: I18n.
|
43
45
|
footer = apply_theme("Theme: #{color_theme.theme_name}", theme_color: color_theme.dsu_footer)
|
44
46
|
puts footer
|
45
47
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'time'
|
4
|
-
require_relative '
|
4
|
+
require_relative 'time_mnemonic'
|
5
5
|
|
6
6
|
module Dsu
|
7
7
|
module Support
|
@@ -11,14 +11,14 @@ module Dsu
|
|
11
11
|
|
12
12
|
# Returns an array of Time objects. The first element is the "from" time.
|
13
13
|
# The second element is the "to" time. Both arguments are expected to be
|
14
|
-
# command options that are time strings, time or relative time
|
14
|
+
# command options that are time strings, time or relative time mnemonics.
|
15
15
|
def dsu_times_for(from_option:, to_option:)
|
16
16
|
from_time = dsu_from_time_for(from_option: from_option)
|
17
17
|
to_time = dsu_to_time_for(to_option: to_option, from_time: from_time)
|
18
18
|
|
19
19
|
errors = []
|
20
|
-
errors <<
|
21
|
-
errors <<
|
20
|
+
errors << I18n.t('errors.from_option_invalid', from_option: from_option) if from_time.nil?
|
21
|
+
errors << I18n.t('errors.to_option_invalid', to_option: to_option) if to_time.nil?
|
22
22
|
return [[], errors] if errors.any?
|
23
23
|
|
24
24
|
min_time, max_time = [from_time, to_time].sort
|
@@ -28,17 +28,17 @@ module Dsu
|
|
28
28
|
def dsu_from_time_for(from_option:)
|
29
29
|
return if from_option.nil?
|
30
30
|
|
31
|
-
from_time = if
|
32
|
-
|
31
|
+
from_time = if TimeMnemonic.time_mnemonic?(from_option)
|
32
|
+
TimeMnemonic.time_from_mnemonic(command_option: from_option)
|
33
33
|
end
|
34
34
|
from_time || Time.time_from_date_string(command_option: from_option)
|
35
35
|
end
|
36
36
|
|
37
37
|
def dsu_to_time_for(to_option:, from_time:)
|
38
|
-
to_time = if
|
39
|
-
|
40
|
-
elsif
|
41
|
-
|
38
|
+
to_time = if TimeMnemonic.relative_time_mnemonic?(to_option)
|
39
|
+
TimeMnemonic.time_from_mnemonic(command_option: to_option, relative_time: from_time)
|
40
|
+
elsif TimeMnemonic.time_mnemonic?(to_option)
|
41
|
+
TimeMnemonic.time_from_mnemonic(command_option: to_option)
|
42
42
|
end
|
43
43
|
to_time || Time.time_from_date_string(command_option: to_option)
|
44
44
|
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'time_mnemonics'
|
4
|
+
|
5
|
+
module Dsu
|
6
|
+
module Support
|
7
|
+
module CommandOptions
|
8
|
+
# The purpose of this module is to take a command option that is a string and return a Time object.
|
9
|
+
# The command option is expected to be a time mneumoic.
|
10
|
+
module TimeMnemonic
|
11
|
+
include TimeMnemonics
|
12
|
+
|
13
|
+
module_function
|
14
|
+
|
15
|
+
def time_from_mnemonic(command_option:, relative_time: nil)
|
16
|
+
time_from_mnemonic!(command_option: command_option, relative_time: relative_time)
|
17
|
+
rescue ArgumentError
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
# command_option: is expected to me a time mnemonic. If relative_time is NOT nil, all
|
22
|
+
# time mnemonics are relative to relative_time. Otherwise, they are relative to Time.now.
|
23
|
+
# relative_time: is a Time object that is required IF command_option is expected to be
|
24
|
+
# a relative time mnemonic. Otherwise, it is optional.
|
25
|
+
def time_from_mnemonic!(command_option:, relative_time: nil)
|
26
|
+
validate_argument!(command_option: command_option, command_option_name: :command_option)
|
27
|
+
unless relative_time.nil? || relative_time.is_a?(::Time)
|
28
|
+
raise ArgumentError, "relative_time is not a Time object: \"#{relative_time}\""
|
29
|
+
end
|
30
|
+
|
31
|
+
relative_time ||= ::Time.now
|
32
|
+
|
33
|
+
time_for_mnemonic(mnemonic: command_option, relative_time: relative_time)
|
34
|
+
end
|
35
|
+
|
36
|
+
# This method returns true if mnemonic is a valid mnemonic OR
|
37
|
+
# a relative time mnemonic.
|
38
|
+
def time_mnemonic?(mnemonic)
|
39
|
+
mnemonic?(mnemonic) || relative_time_mnemonic?(mnemonic)
|
40
|
+
end
|
41
|
+
|
42
|
+
# This method returns true if mnemonic is a valid relative
|
43
|
+
# time mnemonic.
|
44
|
+
def relative_time_mnemonic?(mnemonic)
|
45
|
+
return false unless mnemonic.is_a?(String)
|
46
|
+
|
47
|
+
mnemonic.match?(RELATIVE_REGEX)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Add private_class_methods here.
|
51
|
+
|
52
|
+
# Returns a Time object from a mnemonic.
|
53
|
+
def time_for_mnemonic(mnemonic:, relative_time:)
|
54
|
+
time = relative_time
|
55
|
+
if today_mnemonic?(mnemonic)
|
56
|
+
time
|
57
|
+
elsif tomorrow_mnemonic?(mnemonic)
|
58
|
+
time.tomorrow
|
59
|
+
elsif yesterday_mnemonic?(mnemonic)
|
60
|
+
time.yesterday
|
61
|
+
elsif relative_time_mnemonic?(mnemonic)
|
62
|
+
relative_time_for(days_from_now: mnemonic, time: time)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def relative_time_for(days_from_now:, time:)
|
67
|
+
days_from_now.to_i.days.from_now(time)
|
68
|
+
end
|
69
|
+
|
70
|
+
# This method returns true if mnemonic is a valid time mnemonic.
|
71
|
+
# This method will return false if mnemonic is an invalid mnemonic
|
72
|
+
# OR if mnemonic is a relative time mnemonic.
|
73
|
+
def mnemonic?(mnemonic)
|
74
|
+
today_mnemonic?(mnemonic) ||
|
75
|
+
tomorrow_mnemonic?(mnemonic) ||
|
76
|
+
yesterday_mnemonic?(mnemonic)
|
77
|
+
end
|
78
|
+
|
79
|
+
def today_mnemonic?(mnemonic)
|
80
|
+
TODAY.include?(mnemonic)
|
81
|
+
end
|
82
|
+
|
83
|
+
def tomorrow_mnemonic?(mnemonic)
|
84
|
+
TOMORROW.include?(mnemonic)
|
85
|
+
end
|
86
|
+
|
87
|
+
def yesterday_mnemonic?(mnemonic)
|
88
|
+
YESERDAY.include?(mnemonic)
|
89
|
+
end
|
90
|
+
|
91
|
+
def validate_argument!(command_option:, command_option_name:)
|
92
|
+
raise ArgumentError, "#{command_option_name} cannot be nil." if command_option.nil?
|
93
|
+
raise ArgumentError, "#{command_option_name} cannot be blank." if command_option.blank?
|
94
|
+
unless command_option.is_a?(String)
|
95
|
+
raise ArgumentError, "#{command_option_name} must be a String: \"#{command_option}\""
|
96
|
+
end
|
97
|
+
unless time_mnemonic?(command_option)
|
98
|
+
raise ArgumentError, "#{command_option_name} is an invalid mnemonic: \"#{command_option}\"."
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private_class_method :time_for_mnemonic, :relative_time_for,
|
103
|
+
:mnemonic?, :today_mnemonic?, :tomorrow_mnemonic?,
|
104
|
+
:yesterday_mnemonic?, :validate_argument!
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|