dsu 2.2.1 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 331d6a98a37267f72d525f38e9010da69de44144ce12fb8610a21db86e738dd0
4
- data.tar.gz: e380e7a42eebb5535db7419170cab3f16354187a1a30556f3cc0ec4eccdbdcd0
3
+ metadata.gz: dac644f91b9d952fc3ef289c0ed147f428fcb485418af0e93a64c1478670bf15
4
+ data.tar.gz: c605401ea6b2917af9a6c96617fcc4c2b7b57963282654e0e189ec57e3f5dc05
5
5
  SHA512:
6
- metadata.gz: 378484c87521d25af3885615c60cb1f8c520c1e80d8dbbaa4a6838a80e4001382516bf83731e0ca186530482154a92041e316cb453d530dc209f91155e5254ea
7
- data.tar.gz: c0a98718ea256ef9e37e0b6b1056eb29dfd33d3bb0ede8e75e418c12bf2393b94d6fd7bdc482a160a03433873c8fbd078a5105c1e866d005e720d6f5ef9f189f
6
+ metadata.gz: dbbb3642b22b661b68c14dab8236b553cd5dc4a4c9be80fb6fdce07dc344276a235f68b8593cab8279a09ecf68827c0c1c86283276f89440c5dc9f166c95a57c
7
+ data.tar.gz: a0727206ac2d647abafb20975eb88b396e1ff5abe37e98ae5f4502a99dbe43f19767d51a5611155bb1848dace96c17ba5d235ff0a1ca9ded099f9f44634d8a89
data/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ## [2.3.0] 2023-12-25
2
+
3
+ Enhancements
4
+
5
+ - Added `dsu export` command to export all DSU entries or DSU entries between two given dates. Entries are written to a comma-delimited csv file located in your OS temp folder. For more information see `dsu help export` or the README.md file.
6
+
7
+ Changes
8
+
9
+ - Updated README.md to reflect new `dsu export` command.
10
+ - Fix misspelling of "cancelable" to "cancellable" in the codebase.
11
+ - Update ruby gems.
12
+
13
+ ## [2.2.2] 2023-12-23
14
+
15
+ Changes
16
+
17
+ - README.md updates.
18
+
19
+ Bug fix
20
+
21
+ - Fix `dsu config` shortcut command mapping bug that caused `dsu c` to display `dsu delete` command help instead of `dsu config` command help.
22
+
1
23
  ## [2.2.1] 2023-12-23
2
24
 
3
25
  Changes
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dsu (2.2.1)
4
+ dsu (2.3.0)
5
5
  activemodel (>= 7.0.8, < 8.0)
6
6
  activesupport (>= 7.0.8, < 8.0)
7
7
  colorize (>= 0.8.1, < 1.0)
@@ -98,7 +98,7 @@ GEM
98
98
  rubocop (~> 1.41)
99
99
  rubocop-factory_bot (2.24.0)
100
100
  rubocop (~> 1.33)
101
- rubocop-performance (1.20.0)
101
+ rubocop-performance (1.20.1)
102
102
  rubocop (>= 1.48.1, < 2.0)
103
103
  rubocop-ast (>= 1.30.0, < 2.0)
104
104
  rubocop-rspec (2.25.0)
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # `dsu`- Streamline Your Daily Stand-Up Meeting Participation!
2
2
 
3
3
  [![Ruby](https://github.com/gangelo/dsu/actions/workflows/ruby.yml/badge.svg)](https://github.com/gangelo/dsu/actions/workflows/ruby.yml)
4
- [![GitHub version](http://badge.fury.io/gh/gangelo%2Fdsu.svg)](https://badge.fury.io/gh/gangelo%2Fdsu)
5
- [![Gem Version](https://badge.fury.io/rb/dsu.svg)](https://badge.fury.io/rb/dsu)
4
+ [![GitHub version](http://badge.fury.io/gh/gangelo%2Fdsu.svg?refresh=2)](https://badge.fury.io/gh/gangelo%2Fdsu)
5
+ [![Gem Version](https://badge.fury.io/rb/dsu.svg?refresh=2)](https://badge.fury.io/rb/dsu)
6
6
  [![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/dsu/)
7
7
  [![Report Issues](https://img.shields.io/badge/report-issues-red.svg)](https://github.com/gangelo/dsu/issues)
8
8
  [![License](http://img.shields.io/badge/license-MIT-yellowgreen.svg)](#license)
@@ -42,6 +42,7 @@ Commands:
42
42
  dsu config|c SUBCOMMAND # Manage configuration...
43
43
  dsu delete|d SUBCOMMAND # Delete DSU entries...
44
44
  dsu edit|e SUBCOMMAND # Edit DSU entries...
45
+ dsu export|x SUBCOMMAND # Export DSU entries...
45
46
  dsu help [COMMAND] # Describe available...
46
47
  dsu info|i # Displays information...
47
48
  dsu list|l SUBCOMMAND # Displays DSU entries...
@@ -58,8 +59,9 @@ The folowing section outlines how to use the `dsu` gem.
58
59
  ## Adding DSU Entries
59
60
  The next thing you may want to do is `add` some DSU activities (entries) for a particular day:
60
61
 
61
- `dsu add [OPTIONS] DESCRIPTION`
62
- `dsu a [OPTIONS] DESCRIPTION`
62
+ `$ dsu add [OPTIONS] DESCRIPTION`
63
+
64
+ `$ dsu a [OPTIONS] DESCRIPTION`
63
65
 
64
66
  Adding DSU entry using this command will _add_ the DSU entry for the given day or date, and then _display_ the DSU entries for that day or date.
65
67
 
@@ -69,18 +71,21 @@ Adding DSU entry using this command will _add_ the DSU entry for the given day o
69
71
  If you need to add a DSU entry for the current day (today), you can use the `-n`|`--today` option. Today (`-n`) is the default; therefore, the `-n` flag is optional if you want to add a DSU entry for the _current day_ (today). For example, the below commands will both accomplish the same thing:
70
72
 
71
73
  `$ dsu add [-n|--today] "Pair with John on ticket IN-12345"`
74
+
72
75
  `$ dsu a "Pair with John on ticket IN-12345"`
73
76
 
74
77
  ### Yesterday
75
78
  If for some reason you need to add a DSU entry for yesterday, you can use the `-y`| `--yesterday` option. Both of the below commands accomplish the same thing:
76
79
 
77
80
  `$ dsu add --yesterday "Pick up ticket IN-12345"`
81
+
78
82
  `$ dsu a -y "Pick up ticket IN-12345"`
79
83
 
80
84
  ### Tomorrow
81
85
  If you need to add a DSU entry for tomorrow, you can use the `-t`|`--tomorrow` option:
82
86
 
83
87
  `$ dsu add --tomorrow "Pick up ticket IN-12345"`
88
+
84
89
  `$ dsu a -t "Pick up ticket IN-12345"`
85
90
 
86
91
  ### Miscellaneous Date
@@ -91,6 +96,7 @@ Both of the below examples will accomplish the same thing, assuming the current
91
96
  **NOTE:** When **including year**, dates must be entered in `YYYY/MM/DD` format.
92
97
 
93
98
  `$ dsu add --date 2023/12/31 "Attend New Years Coffee Meet & Greet"`
99
+
94
100
  `$ dsu a -d 12/31 "Attend New Years Coffee Meet & Greet"`
95
101
 
96
102
  See the [Dates](#dates) section for more information on acceptable DATE formats used by `dsu`.
@@ -100,13 +106,13 @@ You can display DSU entries for a particular day or date using any of the follow
100
106
 
101
107
  - `$ dsu list today`
102
108
  - `$ dsu l n` # Equivalent to the above, only using shortcuts
103
- - `$ dsu list tomorrow|t`
109
+ - `$ dsu list tomorrow`
104
110
  - `$ dsu l t` # Equivalent to the above, only using shortcuts
105
- - `$ dsu list yesterday|y`
111
+ - `$ dsu list yesterday`
106
112
  - `$ dsu l y` # Equivalent to the above, only using shortcuts
107
- - `$ dsu list date|d DATE|MNEMONIC`
113
+ - `$ dsu list date DATE|MNEMONIC`
108
114
  - `$ dsu l d DATE|MNEMONIC` # Equivalent to the above, only using shortcuts
109
- - `$ dsu list dates|dd OPTIONS`
115
+ - `$ dsu list dates OPTIONS`
110
116
  - `$ dsu l dd OPTIONS` # Equivalent to the above, only using shortcuts
111
117
 
112
118
  See the [Dates](#dates) section for more information on acceptable DATE formats used by `dsu`.
@@ -118,6 +124,7 @@ See the [Mnemonics](#mnemonics) section for more information on acceptable MNEMO
118
124
  The following displays the entries for "Today", where `Time.now == '2023-05-06 08:54:57.6861 -0400'`
119
125
 
120
126
  `$ dsu list today`
127
+
121
128
  `$ dsu l t`
122
129
  ```shell
123
130
  #=>
@@ -130,7 +137,9 @@ Friday, (Yesterday) 2023-05-05
130
137
  ```
131
138
 
132
139
  `$ dsu list date 5/7/2023`
140
+
133
141
  `$ dsu list d 2023/7/5`
142
+
134
143
  `$ dsu l d 7/5` # When omitting YYYY, MM/DD is assumed
135
144
 
136
145
  ```shell
@@ -151,22 +160,27 @@ For more information, see the [Mnemonics](#mnemonics) section for more informati
151
160
 
152
161
  ##### Display the DSU entries for the last 3 days
153
162
  `$ dsu list dates --from yesterday --to -2`
163
+
154
164
  `$ dsu l dd -f y -t -2`
155
165
 
156
166
  ##### Display the DSU entries for 1/1 to 1/4 for the current year
157
167
  `$ dsu list dates --from 1/1 --to +3`
168
+
158
169
  `$ dsu l dd -f 1/1 -t +3`
159
170
 
160
171
  ##### Display the DSU entries for 1/2 to 1/5
161
172
  `$ dsu list dates --from 1/5 --to -3`
173
+
162
174
  `$ dsu l dd -f 1/5 -t -3`
163
175
 
164
176
  ##### Display the DSU entries for the last week
165
177
  `$ dsu list dates --from today --to -6`
178
+
166
179
  `$ dsu l dd -f n -t -6`
167
180
 
168
181
  ##### Display the DSU entries back 1 week from yesterday's date
169
182
  `$ dsu list dates --from -7 --to +6`
183
+
170
184
  `$ dsu l dd -f -7 -t +6`
171
185
 
172
186
  **NOTE:** **The above example is silly,** but it illustrates the fact that you can use relative mnemonics for both `--from` and `--to` options. While you *can* use relative mnemonics for both the `--from` and `--to` options, there is usually a more intuitive way.
@@ -176,6 +190,7 @@ For example:
176
190
  This can be accomplished MUCH easier by using the `yesterday` mnemonic. This will display the DSU entries back 1 week from yesterday's date.
177
191
 
178
192
  `$ dsu list dates --from yesterday --to -6`
193
+
179
194
  `$ dsu l dd -f y -t -6`
180
195
 
181
196
  ## Browsing DSU Entries
@@ -214,6 +229,7 @@ If no entries exist for the DSU date, the editor will open and allow you to add
214
229
  The following will edit your DSU entry group entries for "Today", where `Time.now == '2023-05-09 12:13:45.8273 -0400'`. Simply follow the directions in the editor file, then save and close your editor to apply the changes:
215
230
 
216
231
  `$ dsu edit today`
232
+
217
233
  `$ dsu e n`
218
234
 
219
235
  ```shell
@@ -257,20 +273,22 @@ from: Interative planning meeting 11:00AM.
257
273
 
258
274
  #### Add an Entry
259
275
 
260
- Simply type a new entry on a separate line. *Note: any entry that starts with a `#` in the first character position will be ignored.*
276
+ Simply type a new entry on a separate line.
261
277
 
262
278
  For example...
263
279
  ```
264
280
  Add me to this entry group.
265
281
  ```
266
282
 
283
+ **NOTE:** Any entry that starts with a `#` in the first character position will be ignored.*
284
+
267
285
  #### Delete an Entry
268
286
 
269
287
  Simply delete the entry.
270
288
 
271
289
  For example...
272
290
  ```
273
- # Delete this this entry from the editor file
291
+ # Delete this entry from the editor file
274
292
  from: Interative planning meeting 11:00AM.
275
293
  to: <deleted>
276
294
  ```
@@ -315,6 +333,7 @@ See the [Mnemonics](#mnemonics) section for more information on acceptable MNEMO
315
333
  The following example deletes the entry group and *all* entries for today's date.
316
334
 
317
335
  `$ dsu delete today`
336
+
318
337
  `$ dsu d n`
319
338
  ```shell
320
339
  #=>
@@ -324,6 +343,7 @@ Deleted 1 entry group(s).
324
343
  The following example deletes the entry group and *all* entries for yesterday's date.
325
344
 
326
345
  `$ dsu delete yesterday`
346
+
327
347
  `$ dsu d y`
328
348
  ```shell
329
349
  #=>
@@ -333,6 +353,7 @@ Deleted 1 entry group(s).
333
353
  The following example deletes the entry group and *all* entries for tomorrow's date.
334
354
 
335
355
  `$ dsu delete tomorrow`
356
+
336
357
  `$ dsu d t`
337
358
  ```shell
338
359
  #=>
@@ -343,6 +364,7 @@ Deleted 1 entry group(s).
343
364
  The following deletes the entry group and all entries for 12/17 of the current year.
344
365
 
345
366
  `$ dsu delete date 12/17`
367
+
346
368
  `$ dsu d d 12/17`
347
369
  ```shell
348
370
  #=>
@@ -353,12 +375,44 @@ Deleted 1 entry group(s)
353
375
  The following deletes the entry group and all entries for the past week, starting from today (12/17/2023).
354
376
 
355
377
  `$ dsu delete dates --from today --to -6`
378
+
356
379
  `$ dsu d dd -f n -t -6`
357
380
  ```shell
358
381
  #=>
359
382
  Are you sure you want to delete all the entries for 2023-12-11 thru 2023-12-17 (7 entry groups)? [y/N]> y
360
383
  Deleted 7 entry group(s).
361
384
  ```
385
+
386
+ ## Exporting DSU Entries
387
+
388
+ Some ingenious soul may want to write a utility at some point, so `dsu` provides the means to export its data into a `csv` file for convenience. Of course, if you feel so inclined, you may also use the `dsu` entry group `json` files directly. The `dsu` entry group `json` files can be located by running the `dsu info` command, and locating the "Entries folder" value.
389
+
390
+ If you want to use a `csv` file, you can export `dsu` entries to a `csv` file by using any of the following commands:
391
+
392
+ - `$ dsu export all`
393
+ - `$ dsu x a` # Equivalent to the above, only using shortcuts
394
+ - `$ dsu export dates OPTIONS`
395
+ - `$ dsu x dd OPTIONS` # Equivalent to the above, only using shortcuts
396
+
397
+ **NOTE:** Each `export` command will prompt you to confirm the export. If confirmed, `dsu` will write a `csv` file to your operating systems temp folder, in the following format: `"dsu-<timestamp>-<from date>-thru-<to date>.csv"`:
398
+
399
+ Where:
400
+ - <timestamp> = '%Y%m%d%H%M%S'
401
+ - <from date> = the date of the earliest entry group exported (if `export all`) or the earliest date of the entry group dates to be exported (if `export dates`).
402
+ - <to date> = the date of the most resent entry group exported (if `export all`) or the most recent date of the entry group dates to be exported (if `export dates`).
403
+ -
404
+ ### For example
405
+
406
+ The following command, when run on December 25, 2023, at 20:15:46...
407
+
408
+ `$ dsu export dates -f 1/1/1999 -t 12/23/2023`
409
+
410
+ ...will export `dsu` entries for all Entry Groups that fall between the dates of January 1st, 1999 through December 23rd 2023 in the time zone it was executed, and write them to the following file:
411
+
412
+ `/var/folders/yv/5n77gtzn7z33ytwgr9mlbbrhf5rws6/T/dsu-20231225201546-1999-01-01-thru-2023-12-23.csv`
413
+
414
+ For more information, see `dsu` help (`$ dsu export` or `dsu help export`) for more information.
415
+
362
416
  ## Customizing the `dsu` Configuration File
363
417
  To customize the `dsu` configuration file, you may follow the instructions outlined here. It is only recommended that you customize the `dsu` configuration file *only* if you are working with an official release (`n.n.n.n`).
364
418
 
data/lib/dsu/cli.rb CHANGED
@@ -7,6 +7,7 @@ require_relative 'subcommands/browse'
7
7
  require_relative 'subcommands/config'
8
8
  require_relative 'subcommands/delete'
9
9
  require_relative 'subcommands/edit'
10
+ require_relative 'subcommands/export'
10
11
  require_relative 'subcommands/list'
11
12
  require_relative 'subcommands/theme'
12
13
 
@@ -18,6 +19,7 @@ module Dsu
18
19
  map I18n.t('commands.config.key_mappings') => :config
19
20
  map I18n.t('commands.delete.key_mappings') => :delete
20
21
  map I18n.t('commands.edit.key_mappings') => :edit
22
+ map I18n.t('commands.export.key_mappings') => :export
21
23
  map I18n.t('commands.help.key_mappings') => :help
22
24
  map I18n.t('commands.info.key_mappings') => :info
23
25
  map I18n.t('commands.list.key_mappings') => :list
@@ -60,6 +62,9 @@ module Dsu
60
62
  desc I18n.t('commands.edit.desc'), I18n.t('commands.edit.usage')
61
63
  subcommand :edit, Subcommands::Edit
62
64
 
65
+ desc I18n.t('commands.export.desc'), I18n.t('commands.export.usage')
66
+ subcommand :export, Subcommands::Export
67
+
63
68
  desc I18n.t('commands.theme.desc'), I18n.t('commands.theme.usage')
64
69
  subcommand :theme, Subcommands::Theme
65
70
 
@@ -120,9 +120,7 @@ module Dsu
120
120
  next unless entry_file_name.match?(ENTRIES_FILE_NAME_REGEX)
121
121
 
122
122
  entry_date = File.basename(entry_file_name, '.*')
123
- file_path = entries_path_for(time: Time.parse(entry_date))
124
- entry_group_hash = read!(file_path: file_path)
125
- Services::EntryGroup::HydratorService.new(entry_group_hash: entry_group_hash).call
123
+ find time: Time.parse(entry_date)
126
124
  end
127
125
  end
128
126
 
@@ -167,6 +165,12 @@ module Dsu
167
165
  end
168
166
  end
169
167
 
168
+ def entry_groups(between:)
169
+ entry_group_times(between: between).filter_map do |time|
170
+ Models::EntryGroup.find(time: Time.parse(time))
171
+ end
172
+ end
173
+
170
174
  def find(time:)
171
175
  file_path = entries_path_for(time: time)
172
176
  entry_group_hash = read!(file_path: file_path)
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'delegate'
4
+ require_relative '../models/color_theme'
5
+ require_relative '../support/color_themable'
6
+
7
+ module Dsu
8
+ module Presenters
9
+ class BasePresenterEx
10
+ include Support::ColorThemable
11
+
12
+ def initialize(options: {})
13
+ @options = options || {}
14
+ @color_theme = Models::ColorTheme.find(theme_name: theme_name)
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :color_theme, :options
20
+
21
+ def theme_name
22
+ @theme_name ||= options.fetch(:theme_name, Models::Configuration.new.theme_name)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/entry_group'
4
+ require_relative '../../services/entry_group/exporter_service'
5
+ require_relative '../../support/ask'
6
+ require_relative '../base_presenter_ex'
7
+ require_relative 'messages'
8
+ require_relative 'service_callable'
9
+
10
+ module Dsu
11
+ module Presenters
12
+ module Export
13
+ class AllPresenter < BasePresenterEx
14
+ include Messages
15
+ include ServiceCallable
16
+ include Support::Ask
17
+
18
+ def render(response:)
19
+ return display_cancelled_message unless response
20
+
21
+ export_file_path = exporter_service_call
22
+
23
+ display_exported_message
24
+ display_exported_to_message(file_path: export_file_path)
25
+ end
26
+
27
+ def display_export_prompt
28
+ yes?(prompt_with_options(prompt: export_prompt, options: export_prompt_options))
29
+ end
30
+
31
+ private
32
+
33
+ def entry_groups
34
+ @entry_groups ||= Models::EntryGroup.all
35
+ end
36
+
37
+ def export_prompt
38
+ I18n.t('subcommands.export.prompts.export_all_confirm', count: entry_groups.count)
39
+ end
40
+
41
+ def export_prompt_options
42
+ I18n.t('subcommands.export.prompts.options')
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/entry_group'
4
+ require_relative '../../support/ask'
5
+ require_relative '../base_presenter_ex'
6
+ require_relative 'messages'
7
+ require_relative 'service_callable'
8
+
9
+ module Dsu
10
+ module Presenters
11
+ module Export
12
+ class DatesPresenter < BasePresenterEx
13
+ include Messages
14
+ include ServiceCallable
15
+ include Support::Ask
16
+
17
+ def initialize(from:, to:, options: {})
18
+ super(options: options)
19
+
20
+ @from = from
21
+ @to = to
22
+ end
23
+
24
+ def render(response:)
25
+ return display_cancelled_message unless response
26
+
27
+ export_file_path = exporter_service_call
28
+
29
+ display_exported_message
30
+ display_exported_to_message(file_path: export_file_path)
31
+ end
32
+
33
+ def display_export_prompt
34
+ yes?(prompt_with_options(prompt: export_prompt, options: export_prompt_options))
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :from, :to, :options
40
+
41
+ def entry_groups
42
+ Models::EntryGroup.entry_groups(between: [from, to])
43
+ end
44
+
45
+ def export_prompt
46
+ I18n.t('subcommands.export.prompts.export_dates_confirm',
47
+ from: from.to_date, to: to.to_date, count: entry_groups.count)
48
+ end
49
+
50
+ def export_prompt_options
51
+ I18n.t('subcommands.export.prompts.options')
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/entry_group'
4
+ require_relative '../base_presenter_ex'
5
+
6
+ module Dsu
7
+ module Presenters
8
+ module Export
9
+ module Messages
10
+ def display_export_prompt
11
+ raise NotImplementedError
12
+ end
13
+
14
+ private
15
+
16
+ def display_cancelled_message
17
+ puts apply_theme(I18n.t('subcommands.export.messages.cancelled'), theme_color: color_theme.info)
18
+ end
19
+
20
+ def display_exported_message
21
+ puts apply_theme(I18n.t('subcommands.export.messages.exported'), theme_color: color_theme.success)
22
+ end
23
+
24
+ def display_exported_to_message(file_path:)
25
+ puts apply_theme(I18n.t('subcommands.export.messages.exported_to', file_path: file_path),
26
+ theme_color: color_theme.success)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../services/entry_group/exporter_service'
4
+
5
+ module Dsu
6
+ module Presenters
7
+ module Export
8
+ module ServiceCallable
9
+ private
10
+
11
+ def exporter_service_call
12
+ @exporter_service_call ||= begin
13
+ exporter_service = Services::EntryGroup::ExporterService.new(entry_groups: entry_groups, options: options)
14
+ exporter_service.call
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+ require_relative '../../models/entry_group'
5
+ require_relative '../../support/fileable'
6
+
7
+ module Dsu
8
+ module Services
9
+ module EntryGroup
10
+ class ExporterService
11
+ include Support::Fileable
12
+
13
+ def initialize(entry_groups:, options: {})
14
+ raise ArgumentError, 'Argument entry_groups is nil' if entry_groups.nil?
15
+
16
+ @entry_groups = entry_groups
17
+ @options = options
18
+ end
19
+
20
+ def call
21
+ CSV.open(export_file_name, 'w') do |csv|
22
+ csv << %i[version entry_group entry_no total_entries entry_group_entry]
23
+
24
+ entry_groups.each do |entry_group|
25
+ next unless entry_group.exist?
26
+
27
+ entry_group.entries.each_with_index do |entry, index|
28
+ csv << [
29
+ entry_group.version,
30
+ entry_group.time.to_date,
31
+ index + 1,
32
+ entry_group.entries.count,
33
+ entry.description
34
+ ]
35
+ end
36
+ end
37
+ end
38
+
39
+ export_file_name
40
+ end
41
+
42
+ def export_file_name
43
+ @export_file_name ||= begin
44
+ file_name = "dsu-#{export_timestamp}-#{times.min.to_date}-thru-#{times.max.to_date}.csv"
45
+ File.join(temp_folder, file_name)
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ attr_reader :entry_groups, :options
52
+
53
+ def times
54
+ @times ||= entry_groups.map(&:time)
55
+ end
56
+
57
+ def export_timestamp
58
+ Time.now.in_time_zone.strftime('%Y%m%d%H%M%S')
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -91,7 +91,7 @@ module Dsu
91
91
  message = I18n.t('subcommands.delete.messages.deleted', count: deleted_count)
92
92
  Views::Shared::Success.new(messages: message).render
93
93
  else
94
- message = I18n.t('subcommands.delete.messages.canceled')
94
+ message = I18n.t('subcommands.delete.messages.cancelled')
95
95
  Views::Shared::Info.new(messages: message).render
96
96
  end
97
97
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../support/command_options/dsu_times'
4
+ require_relative '../support/command_options/time_mnemonic'
5
+ require_relative '../support/time_formatable'
6
+ require_relative '../views/export'
7
+ require_relative '../views/shared/error'
8
+ require_relative 'base_subcommand'
9
+
10
+ module Dsu
11
+ module Subcommands
12
+ class Export < BaseSubcommand
13
+ include Support::CommandOptions::TimeMnemonic
14
+ include Support::TimeFormatable
15
+
16
+ # TODO: I18n.
17
+ map %w[a] => :all
18
+ map %w[dd] => :dates
19
+
20
+ desc I18n.t('subcommands.export.all.desc'), I18n.t('subcommands.export.all.usage')
21
+ long_desc I18n.t('subcommands.export.all.long_desc')
22
+ option :prompts, type: :hash, default: {}, hide: true, aliases: '-p'
23
+ def all
24
+ Views::Export.new(presenter: all_presenter(options: options)).render
25
+ end
26
+
27
+ desc I18n.t('subcommands.export.dates.desc'), I18n.t('subcommands.export.dates.usage')
28
+ long_desc I18n.t('subcommands.export.dates.long_desc',
29
+ date_option_description: date_option_description,
30
+ mnemonic_option_description: mnemonic_option_description)
31
+ option :from, type: :string, required: true, aliases: '-f', banner: 'DATE|MNEMONIC'
32
+ option :to, type: :string, required: true, aliases: '-t', banner: 'DATE|MNEMONIC'
33
+ option :prompts, type: :hash, default: {}, hide: true, aliases: '-p'
34
+ def dates
35
+ options = configuration.to_h.merge(self.options).with_indifferent_access
36
+ times, errors = Support::CommandOptions::DsuTimes.dsu_times_for(from_option: options[:from], to_option: options[:to]) # rubocop:disable Layout/LineLength
37
+ if errors.any?
38
+ Views::Shared::Error.new(messages: errors).render
39
+ return
40
+ end
41
+
42
+ times = times_sort(times: times, entries_display_order: options[:entries_display_order])
43
+ Views::Export.new(presenter: dates_presenter_for(from: times.min, to: times.max, options: options)).render
44
+ rescue ArgumentError => e
45
+ Views::Shared::Error.new(messages: e.message).render
46
+ end
47
+
48
+ private
49
+
50
+ def all_presenter(options:)
51
+ Presenters::Export::AllPresenter.new(options: options)
52
+ end
53
+
54
+ def dates_presenter_for(from:, to:, options:)
55
+ Presenters::Export::DatesPresenter.new(from: from, to: to, options: options)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -40,7 +40,7 @@ module Dsu
40
40
  Views::Shared::Info.new(messages: "\n#{message}").render
41
41
  true
42
42
  else
43
- message = I18n.t('subcommands.theme.create.messages.canceled')
43
+ message = I18n.t('subcommands.theme.create.messages.cancelled')
44
44
  Views::Shared::Info.new(messages: "\n#{message}").render
45
45
  false
46
46
  end
@@ -71,7 +71,7 @@ module Dsu
71
71
  change_theme
72
72
  I18n.t('subcommands.theme.delete.messages.deleted', theme_name: theme_name)
73
73
  else
74
- I18n.t('subcommands.theme.delete.messages.canceled')
74
+ I18n.t('subcommands.theme.delete.messages.cancelled')
75
75
  end
76
76
  Views::Shared::Info.new(messages: "\n#{message}").render
77
77
  end
@@ -6,10 +6,12 @@ module Dsu
6
6
  module Support
7
7
  module ColorThemable
8
8
  def prompt_with_options(prompt:, options:)
9
+ # HACK: This module needs to be refactored to be more generic.
10
+ target_color_theme = defined?(color_theme) ? color_theme : self
9
11
  options = "[#{options.join('/')}]"
10
- "#{apply_theme(prompt, theme_color: self.prompt)} " \
11
- "#{apply_theme(options, theme_color: prompt_options)}" \
12
- "#{apply_theme('>', theme_color: self.prompt)}"
12
+ "#{apply_theme(prompt, theme_color: target_color_theme.prompt)} " \
13
+ "#{apply_theme(options, theme_color: target_color_theme.prompt_options)}" \
14
+ "#{apply_theme('>', theme_color: target_color_theme.prompt)}"
13
15
  end
14
16
 
15
17
  module_function
data/lib/dsu/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Dsu
4
4
  VERSION_REGEX = /\A\d+\.\d+\.\d+(\.(alpha|rc)\.\d+)?\z/
5
- VERSION = '2.2.1'
5
+ VERSION = '2.3.0'
6
6
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../models/color_theme'
4
+ require_relative '../models/configuration'
5
+ require_relative '../support/color_themable'
6
+
7
+ module Dsu
8
+ module Views
9
+ class Export
10
+ include Support::ColorThemable
11
+
12
+ def initialize(presenter:)
13
+ @presenter = presenter
14
+ end
15
+
16
+ def render
17
+ response = presenter.display_export_prompt
18
+ presenter.render response: response
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :presenter
24
+ end
25
+ end
26
+ end
@@ -58,13 +58,17 @@ en:
58
58
  desc: config|c SUBCOMMAND
59
59
  usage: Manage configuration file for this gem
60
60
  delete:
61
- key_mappings: c
61
+ key_mappings: d
62
62
  desc: delete|d SUBCOMMAND
63
63
  usage: Delete DSU entries for the given SUBCOMMAND
64
64
  edit:
65
65
  desc: edit|e SUBCOMMAND
66
66
  usage: Edit DSU entries for the given SUBCOMMAND
67
67
  key_mappings: e
68
+ export:
69
+ key_mappings: x
70
+ desc: export|x SUBCOMMAND
71
+ usage: Export DSU entries for the given SUBCOMMAND
68
72
  info:
69
73
  key_mappings: i
70
74
  desc: info|i
@@ -118,9 +118,9 @@ en:
118
118
  long_desc: |
119
119
  Deletes the DSU entries for the given OPTIONS.
120
120
 
121
- $ dsu dates OPTIONS
121
+ $ dsu delete dates OPTIONS
122
122
 
123
- $ dsu dd OPTIONS
123
+ $ dsu d dd OPTIONS
124
124
 
125
125
  OPTIONS:
126
126
 
@@ -191,7 +191,7 @@ en:
191
191
  $ dsu delete y
192
192
  messages:
193
193
  deleted: Deleted %{count} entry group(s).
194
- canceled: Canceled.
194
+ cancelled: Cancelled.
195
195
  prompts:
196
196
  are_you_sure: Are you sure you want to delete all the entries for %{dates} (%{count} entry groups)?
197
197
  edit:
@@ -217,6 +217,76 @@ en:
217
217
  usage: Edits the DSU entries for yesterday
218
218
  long_desc: |
219
219
  Edits the DSU entries for yesterday.
220
+ export:
221
+ dates:
222
+ desc: dates|dd OPTIONS
223
+ usage: Exports the DSU entries for the OPTIONS provided
224
+ long_desc: |
225
+ Exports the DSU entries for the given OPTIONS.
226
+
227
+ $ dsu export dates OPTIONS
228
+
229
+ $ dsu x dd OPTIONS
230
+
231
+ OPTIONS:
232
+
233
+ -f|--from DATE|MNEMONIC: The DATE or MNEMONIC that represents the start of the range of DSU dates to export. If a relative mnemonic is used (+/-n, e.g +1, -1, etc.), the date calculated will be relative to the current date (e.g. `<MNEMONIC>.to_i.days.from_now(Time.now)`).
234
+
235
+ -t|--to DATE|MNEMONIC: The DATE or MNEMONIC that represents the end of the range of DSU dates to export. If a relative mnemonic 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.
236
+
237
+ %{date_option_description}
238
+
239
+ %{mnemonic_option_description}
240
+
241
+ EXAMPLES:
242
+
243
+ NOTE: All examples can substitute their respective short form options (e.g. `-f`, `-t`, etc. for `--from`, `--to`, etc.).
244
+
245
+ The below will export the DSU entries for the range of dates from 1/1 to 1/4 for the current year:
246
+
247
+ $ dsu export dates --from 1/1 --to +3
248
+
249
+ This will export the DSU entries for the range of dates from 1/2 to 1/5 for the year 2022:
250
+
251
+ $ dsu x dd --from 1/5/2022 --to -3
252
+
253
+ This (assuming "today" is 1/10) will export the DSU entries for the last week 1/10 to 1/3 of the current year:
254
+
255
+ $ dsu export dates --from today --to -7
256
+
257
+ This (assuming "today" is 5/23) will export the DSU entries for the last week 5/16 to 5/22.
258
+ This example simply illustrates the fact that you can use relative mnemonics for
259
+ both `--from` and `--to` options; this doesn't mean you should do so...
260
+
261
+ While you can use relative mnemonics for both `--from` and `--to` options,
262
+ there is always a more intuitive way. The below example basically exports one week of DSU entries back 1 week from yesterday's date:
263
+
264
+ $ dsu export dates --from -7 --to +6
265
+
266
+ The above can be accomplished MUCH easier by simply using the `yesterday` mnemonic...
267
+
268
+ This (assuming "today" is 5/23) will delete the DSU entries back 1 week from yesterday's date 5/16 to 5/22:
269
+
270
+ $ dsu x dd --from yesterday --to -6
271
+ all:
272
+ desc: all|a
273
+ usage: Exports all DSU entries
274
+ long_desc: |
275
+ Exports all DSU entries.
276
+
277
+ $ dsu export all
278
+
279
+ $ dsu x a
280
+ messages:
281
+ exported: Export successful.
282
+ exported_to: Entry groups exported to %{file_path}.
283
+ cancelled: Cancelled.
284
+ prompts:
285
+ export_all_confirm: Export all the entries (%{count} entry groups)?
286
+ export_dates_confirm: Export all the entries for %{from} thru %{to} (%{count} entry groups)?
287
+ options:
288
+ - y
289
+ - N
220
290
  list:
221
291
  date:
222
292
  desc: date|d DATE|MNEMONIC
@@ -233,9 +303,9 @@ en:
233
303
  long_desc: |
234
304
  Displays the DSU entries for the given OPTIONS.
235
305
 
236
- $ dsu dates OPTIONS
306
+ $ dsu list dates OPTIONS
237
307
 
238
- $ dsu dd OPTIONS
308
+ $ dsu l dd OPTIONS
239
309
 
240
310
  OPTIONS:
241
311
 
@@ -331,7 +401,7 @@ en:
331
401
  already_exists: Color theme "%{theme_name}" already exists.
332
402
  messages:
333
403
  created: Created color theme "%{theme_name}".
334
- canceled: Canceled.
404
+ cancelled: Cancelled.
335
405
  delete:
336
406
  desc: delete THEME_NAME
337
407
  usage: Deletes the existing dsu color theme THEME_NAME
@@ -344,7 +414,7 @@ en:
344
414
  errors:
345
415
  cannot_delete: Color theme "%{theme_name}" cannot be deleted.
346
416
  messages:
347
- canceled: Canceled.
417
+ cancelled: Cancelled.
348
418
  deleted: Deleted color theme "%{theme_name}".
349
419
  list:
350
420
  desc: list
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dsu
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gene M. Angelo, Jr.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-24 00:00:00.000000000 Z
11
+ date: 2023-12-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -179,11 +179,16 @@ files:
179
179
  - lib/dsu/models/entry_group.rb
180
180
  - lib/dsu/models/migration_version.rb
181
181
  - lib/dsu/presenters/base_presenter.rb
182
+ - lib/dsu/presenters/base_presenter_ex.rb
182
183
  - lib/dsu/presenters/color_theme_presenter.rb
183
184
  - lib/dsu/presenters/color_theme_show_presenter.rb
184
185
  - lib/dsu/presenters/configuration_presenter.rb
185
186
  - lib/dsu/presenters/entry_group_presenter.rb
186
187
  - lib/dsu/presenters/entry_presenter.rb
188
+ - lib/dsu/presenters/export/all_presenter.rb
189
+ - lib/dsu/presenters/export/dates_presenter.rb
190
+ - lib/dsu/presenters/export/messages.rb
191
+ - lib/dsu/presenters/export/service_callable.rb
187
192
  - lib/dsu/services/color_theme/hydrator_service.rb
188
193
  - lib/dsu/services/configuration/hydrator_service.rb
189
194
  - lib/dsu/services/entry/hydrator_service.rb
@@ -191,6 +196,7 @@ files:
191
196
  - lib/dsu/services/entry_group/counter_service.rb
192
197
  - lib/dsu/services/entry_group/deleter_service.rb
193
198
  - lib/dsu/services/entry_group/editor_service.rb
199
+ - lib/dsu/services/entry_group/exporter_service.rb
194
200
  - lib/dsu/services/entry_group/hydrator_service.rb
195
201
  - lib/dsu/services/migration_version/hydrator_service.rb
196
202
  - lib/dsu/services/stderr_redirector_service.rb
@@ -202,6 +208,7 @@ files:
202
208
  - lib/dsu/subcommands/config.rb
203
209
  - lib/dsu/subcommands/delete.rb
204
210
  - lib/dsu/subcommands/edit.rb
211
+ - lib/dsu/subcommands/export.rb
205
212
  - lib/dsu/subcommands/list.rb
206
213
  - lib/dsu/subcommands/theme.rb
207
214
  - lib/dsu/support/ask.rb
@@ -237,6 +244,7 @@ files:
237
244
  - lib/dsu/views/entry_group/shared/no_entries_to_display_for_week_of.rb
238
245
  - lib/dsu/views/entry_group/shared/no_entries_to_display_for_year_of.rb
239
246
  - lib/dsu/views/entry_group/show.rb
247
+ - lib/dsu/views/export.rb
240
248
  - lib/dsu/views/shared/error.rb
241
249
  - lib/dsu/views/shared/info.rb
242
250
  - lib/dsu/views/shared/message.rb