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.
- 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
         
     |