dsu 0.1.0.alpha.3 → 0.1.0.alpha.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +1 -1
- data/README.md +43 -32
- data/lib/dsu/models/entry.rb +6 -1
- data/lib/dsu/models/entry_group.rb +90 -7
- data/lib/dsu/services/configuration_loader_service.rb +3 -3
- data/lib/dsu/services/entry_group_editor_service.rb +148 -0
- data/lib/dsu/services/entry_group_writer_service.rb +1 -0
- data/lib/dsu/services/temp_file_reader_service.rb +8 -8
- data/lib/dsu/services/temp_file_writer_service.rb +6 -6
- data/lib/dsu/subcommands/edit.rb +8 -79
- data/lib/dsu/support/descriptable.rb +43 -0
- data/lib/dsu/validators/entries_validator.rb +8 -7
- data/lib/dsu/version.rb +1 -1
- data/lib/dsu/views/entry_group/edit.rb +5 -3
- data/lib/dsu/views/entry_group/show.rb +3 -7
- metadata +16 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8563782a0b4d22e374313aa3373b38e62dec995a6f6d996eaa5fa9c58b0d1cb
|
4
|
+
data.tar.gz: 65ebebe762dac44300a6d163c03275eaffd66018a83f9836b3f12cb6333569ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a412bf735ce124b6df3bb419a1ed925b6b9aaf6cc7e8fdb13773fd883886119d92c03cb4bc68633d57bcfd293c274db16d5504200790f9be65d5d3d3f3e5e21e
|
7
|
+
data.tar.gz: bf7ac4a28753385155d6e0cd7f1694723deaa3ad0d0e41205f63446c78a2a8b0b09d42f4e5557d3c3aef4befa8a6d46e568d308a1d9fb6c9a0f4110d301c025d
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## [0.1.0.alpha.5] - 2023-05-12
|
2
|
+
* Changes
|
3
|
+
- `dsu edit SUBCOMMAND` will now allow editing of an entry group for a date that does not yet exist. This will allow you to add entries in the editor using `+|a|add DESCRIPTION`. Be sure to follow the instructions in the editor when editing entry group entries.
|
4
|
+
- `dsu edit SUBCOMMAND` will gracefully display an error if the entry sha (Entry#uuid) or entry discription (Entry#description) are not unique. In this case, the entry will not be added to the entry group.
|
5
|
+
NOTE: Not all edge cases are being handled currently by `dsu edit SUBCOMMAND`.
|
6
|
+
- `dsu add OPTION` will raise an error if the entry discription (Entry#description) are not unique. This will be handled gracefully in a future release.
|
7
|
+
## [0.1.0.alpha.4] - 2023-05-09
|
8
|
+
* Changes
|
9
|
+
- Gemfile gemspec description changes.
|
1
10
|
## [0.1.0.alpha.3] - 2023-05-09
|
2
11
|
* Changes
|
3
12
|
- Entry groups are now editable using the `dsu edit SUBCOMMAND` command. See the README.md or `dsu help edit` for more information.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
|
12
12
|
**NOTE:** This gem is in development (alpha version). Please see the [WIP Notes](#wip-notes) section for current `dsu` features.
|
13
13
|
|
14
|
-
##
|
14
|
+
## Help
|
15
15
|
|
16
16
|
After installation (`gem install dsu`), the first thing you may want to do is run the `dsu` help:
|
17
17
|
### Displaying Help
|
@@ -19,7 +19,7 @@ After installation (`gem install dsu`), the first thing you may want to do is ru
|
|
19
19
|
```shell
|
20
20
|
#=>
|
21
21
|
Commands:
|
22
|
-
dsu add, -a [OPTIONS] DESCRIPTION # Adds a DSU entry
|
22
|
+
dsu add, -a [OPTIONS] DESCRIPTION # Adds a DSU entry...
|
23
23
|
dsu config, -c SUBCOMMAND # Manage configuration...
|
24
24
|
dsu edit, -e SUBCOMMAND # Edit DSU entries...
|
25
25
|
dsu help [COMMAND] # Describe available...
|
@@ -32,32 +32,33 @@ Options:
|
|
32
32
|
|
33
33
|
The next thing you may want to do is `add` some DSU activities (entries) for a particular day:
|
34
34
|
|
35
|
-
|
35
|
+
## Adding DSU Entries
|
36
36
|
`dsu add [OPTIONS] DESCRIPTION`
|
37
37
|
|
38
|
-
Adding DSU entry using this command will _add_ the DSU entry for the given day (or date, `-d`), and also _display_ the given day's (or date's, `-d`) DSU entries, as well as the DSU entries for the previous day relative to the given day or date (`-d`).
|
38
|
+
Adding DSU entry using this command will _add_ the DSU entry for the given day (or date, `-d`), and also _display_ the given day's (or date's, `-d`) DSU entries, as well as the DSU entries for the previous day relative to the given day or date (`-d`). *NOTE: You cannot add duplicate entry group entries; that is, the entry DESCRIPTION needs to be unique within an entry group.*
|
39
39
|
|
40
|
-
|
41
|
-
If you need to add a DSU entry to the current day (today), you can use the `-
|
40
|
+
### Today
|
41
|
+
If you need to add a DSU entry to the current day (today), you can use the `-n`|`--today` option. Today (`-n`) is the default; therefore, the `-n` flag is optional when adding DSU entries for the current day:
|
42
42
|
|
43
|
-
`$ dsu add
|
43
|
+
`$ dsu add -n|-today "Pair with John on ticket IN-12345"`
|
44
44
|
|
45
|
-
|
46
|
-
If for some reason you need to add a DSU entry for
|
45
|
+
### Yesterday
|
46
|
+
If for some reason you need to add a DSU entry for yesterday, you can use the `-y`| `--yesterday` option:
|
47
47
|
|
48
|
-
`$ dsu add -
|
48
|
+
`$ dsu add -y|--yesterday "Pick up ticket IN-12345"`
|
49
49
|
|
50
|
-
|
51
|
-
If you need to add a DSU entry for
|
50
|
+
### Tomorrow
|
51
|
+
If you need to add a DSU entry for tomorrow, you can use the `-t`|`--tomorrow` option:
|
52
52
|
|
53
|
-
`$ dsu add -
|
53
|
+
`$ dsu add -t|--tomorrow "Pick up ticket IN-12345"`
|
54
54
|
|
55
|
-
|
56
|
-
If you need to add a DSU entry for a date other than yesterday, today or tomorrow, you can use the `-d, [--date=DATE]` option, where DATE is any date string that can be parsed using `Time.parse`. For example: `require 'time'; Time.parse("2023-01-01")`:
|
55
|
+
### Miscellaneous Date
|
57
56
|
|
58
57
|
`$ dsu add -d "2022-12-31" "Attend company New Years Coffee Meet & Greet"`
|
59
58
|
|
60
|
-
|
59
|
+
See the [Dates](#dates) section for more information on acceptable DATE formats used by `dsu`.
|
60
|
+
|
61
|
+
## Displaying DSU Entries
|
61
62
|
You can display DSU entries for a particular day or date (`date`) using any of the following commands. When displaying DSU entries for a particular day or date (`date`), `dsu` will display the given day or date's (`date`) DSU entries, as well as the DSU entries for the _previous_ day, relative to the given day or date. If the date or day you are trying to view falls on a weekend or Monday, `dsu` will display back to, and including the weekend and previous Friday inclusive; this is so that you can share what you did over the weekend (if anything) and the previous Friday at your DSU:
|
62
63
|
|
63
64
|
- `$ dsu list today|n`
|
@@ -65,7 +66,7 @@ You can display DSU entries for a particular day or date (`date`) using any of t
|
|
65
66
|
- `$ dsu list yesterday|y`
|
66
67
|
- `$ dsu list date|d DATE`
|
67
68
|
|
68
|
-
|
69
|
+
### Examples
|
69
70
|
The following displays the entries for "Today", where `Time.now == '2023-05-06 08:54:57.6861 -0400'`
|
70
71
|
|
71
72
|
`$ dsu list today`
|
@@ -82,7 +83,7 @@ Friday, (Yesterday) 2023-05-05
|
|
82
83
|
|
83
84
|
`$ dsu list date "2023-05-06"`
|
84
85
|
|
85
|
-
|
86
|
+
See the [Dates](#dates) section for more information on acceptable DATE formats used by `dsu`.
|
86
87
|
|
87
88
|
```shell
|
88
89
|
#=>
|
@@ -94,9 +95,9 @@ Friday, (Yesterday) 2023-05-05
|
|
94
95
|
1. edc25a9a Pick up ticket IN-12345
|
95
96
|
2. f7d3018c Attend new hire meet & greet
|
96
97
|
```
|
97
|
-
|
98
|
+
## Editing DSU Entries
|
98
99
|
|
99
|
-
You can edit DSU entry groups by date. `dsu` will allow you to edit a DSU entry group using the `dsu edit SUBCOMMAND` date (today|tomorrow|yesterday|date DATE) you specify. `dsu edit` will open your DSU entry group entries in your editor, where you'll be able to perform editing functions against one or all of the entries.
|
100
|
+
You can edit DSU entry groups by date. `dsu` will allow you to edit a DSU entry group using the `dsu edit SUBCOMMAND` date (today|tomorrow|yesterday|date DATE) you specify. `dsu edit` will open your DSU entry group entries in your editor, where you'll be able to perform editing functions against one or all of the entries. If no entries exist in the entry group, you can add entries using any of the the *add* (`+|a|add`) editor commands, followed by the entry description. *NOTE: you cannot add duplicate entries; that is, the entry SHA and DESCRIPTION need to be unique within an entry group. Non-unique entries will not be added to the entry group.*
|
100
101
|
|
101
102
|
Note: See the "[Customizing the `dsu` Configuration File](#customizing-the-dsu-configuration-file)"" section to configure `dsu` to use the editor of your choice.
|
102
103
|
|
@@ -105,7 +106,7 @@ Note: See the "[Customizing the `dsu` Configuration File](#customizing-the-dsu-c
|
|
105
106
|
- `$ dsu edit yesterday|y`
|
106
107
|
- `$ dsu edit date|d DATE`
|
107
108
|
|
108
|
-
|
109
|
+
### Examples
|
109
110
|
|
110
111
|
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:
|
111
112
|
|
@@ -133,7 +134,7 @@ The following will edit your DSU entry group entries for "Today", where `Time.no
|
|
133
134
|
# *** When you are done, save and close your editor ***
|
134
135
|
```
|
135
136
|
|
136
|
-
|
137
|
+
#### Edit an Entry
|
137
138
|
|
138
139
|
Simply change the entry descripton text.
|
139
140
|
|
@@ -143,7 +144,7 @@ from: 3849f0c0 Interative planning meeting 11:00AM.
|
|
143
144
|
to: 3849f0c0 Interative planning meeting 12:00AM.
|
144
145
|
```
|
145
146
|
|
146
|
-
|
147
|
+
#### Add an Entry
|
147
148
|
|
148
149
|
Replace the entry `sha` one of the add commands: `[+|a|add]`.
|
149
150
|
|
@@ -152,7 +153,7 @@ For example...
|
|
152
153
|
+ Add me to this entry group.
|
153
154
|
```
|
154
155
|
|
155
|
-
|
156
|
+
#### Delete an Entry
|
156
157
|
|
157
158
|
Simply delete the entry or replace the entry `sha` one of the delete commands: `[-|d|delete]`.
|
158
159
|
|
@@ -167,7 +168,7 @@ from: 3849f0c0 Interative planning meeting 11:00AM.
|
|
167
168
|
to: - Interative planning meeting 11:00AM.
|
168
169
|
```
|
169
170
|
|
170
|
-
|
171
|
+
#### Reorder Entries
|
171
172
|
|
172
173
|
Simply reorder the entries in the editor.
|
173
174
|
|
@@ -183,11 +184,11 @@ from: 3849f0c0 Interative planning meeting 11:00AM.
|
|
183
184
|
3849f0c0 Interative planning meeting 11:00AM.
|
184
185
|
```
|
185
186
|
|
186
|
-
|
187
|
+
## Customizing the `dsu` Configuration File
|
187
188
|
|
188
189
|
It is **not** recommended that you create and customize a `dsu` configuration file while this gem is in alpha release. This is because changes to what configuration options are available may take place while in alpha that could break `dsu`. If you *do* want to create and customize the `dsu` configuration file reglardless, you may do the following.
|
189
190
|
|
190
|
-
|
191
|
+
### Initializing/Customizing the `dsu` Configuration File
|
191
192
|
|
192
193
|
```shell
|
193
194
|
# Creates a dsu configuration file in your home folder.
|
@@ -207,25 +208,26 @@ Where `<whoami>` would be your username (`$ whoami` on nix systems)
|
|
207
208
|
|
208
209
|
Once the configuration file is created, you can locate where the `dsu` configuration file is located by running `$ dsu config info` and taking note of the confiruration file path. You may then edit this file using your favorite editor.
|
209
210
|
|
210
|
-
|
211
|
-
|
211
|
+
#### Configuration File Options
|
212
|
+
|
213
|
+
##### editor
|
212
214
|
This is the default editor to use when editing entry groups if the EDITOR environment variable on your system is not set.
|
213
215
|
|
214
216
|
Default: `nano` (you'll need to change the default editor on Windows systems)
|
215
217
|
|
216
|
-
|
218
|
+
##### entries_display_order
|
217
219
|
Valid values are 'asc' and 'desc', and will sort listed DSU entries in ascending or descending order respectfully, by day.
|
218
220
|
|
219
221
|
Default: `'desc'`
|
220
222
|
|
221
|
-
|
223
|
+
##### entries_file_name
|
222
224
|
The entries file name format. It is recommended that you do not change this. The file name must include `%Y`, `%m` and `%d` `Time` formatting specifiers to make sure the file name is unique and able to be located by `dsu` functions. For example, the default file name is `%Y-%m-%d.json`; however, something like `%m-%d-%Y.json` or `entry-group-%m-%d-%Y.json` would work as well.
|
223
225
|
|
224
226
|
ATTENTION: Please keep in mind that if you change this value `dsu` will not recognize entry files using a different format. You would (at this time), have to manually rename any existing entry file names to the new format.
|
225
227
|
|
226
228
|
Default: `'%Y-%m-%d.json'`
|
227
229
|
|
228
|
-
|
230
|
+
##### entries_folder
|
229
231
|
This is the folder where `dsu` stores entry files. You may change this to anything you want. `dsu` will create this folder for you, as long as your system's write permissions allow this.
|
230
232
|
|
231
233
|
ATTENTION: Please keep in mind that if you change this value `dsu` will not be able to find entry files in any previous folder. You would (at this time), have to manually mode any existing entry files to this new folder.
|
@@ -234,9 +236,18 @@ Default: `'/Users/<whoami>/dsu/entries'` on nix systems.
|
|
234
236
|
|
235
237
|
Where `<whoami>` would be your username (`$ whoami` on nix systems)
|
236
238
|
|
239
|
+
## Dates
|
240
|
+
|
241
|
+
These notes apply to anywhere DATE is used...
|
242
|
+
|
243
|
+
DATE may be any date string that can be parsed using `Time.parse`. Consequently, you may use also use '/' as date separators, as well as omit the year if the date you want to display is the current year (e.g. <month>/<day>, or 1/31). For example: `require 'time'; Time.parse('2023-01-02'); Time.parse('1/2') # etc.`
|
244
|
+
|
237
245
|
## WIP Notes
|
238
246
|
This gem is in development (alpha release).
|
239
247
|
|
248
|
+
- Not all edge cases are being handled currently by `dsu edit SUBCOMMAND`.
|
249
|
+
- `dsu add OPTION` will raise an error if the entry discription (Entry#description) are not unique. This will be handled gracefully in a future release.
|
250
|
+
|
240
251
|
## Installation
|
241
252
|
|
242
253
|
$ gem install dsu
|
data/lib/dsu/models/entry.rb
CHANGED
@@ -2,12 +2,17 @@
|
|
2
2
|
|
3
3
|
require 'deco_lite'
|
4
4
|
require 'securerandom'
|
5
|
+
require_relative '../support/descriptable'
|
5
6
|
|
6
7
|
module Dsu
|
7
8
|
module Models
|
8
9
|
class Entry < DecoLite::Model
|
10
|
+
include Support::Descriptable
|
11
|
+
|
12
|
+
ENTRY_UUID_REGEX = /\A[0-9a-f]{8}\z/i
|
13
|
+
|
9
14
|
validates :uuid, presence: true, format: {
|
10
|
-
with:
|
15
|
+
with: ENTRY_UUID_REGEX,
|
11
16
|
message: 'is the wrong format. ' \
|
12
17
|
'0-9, a-f, and 8 characters were expected.' \
|
13
18
|
}
|
@@ -1,17 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'deco_lite'
|
4
|
-
require_relative '../
|
4
|
+
require_relative '../services/entry_group_editor_service'
|
5
5
|
require_relative '../services/entry_group_deleter_service'
|
6
6
|
require_relative '../services/entry_group_reader_service'
|
7
7
|
require_relative '../services/entry_group_writer_service'
|
8
|
+
require_relative '../support/entry_group_loadable'
|
9
|
+
require_relative '../support/time_formatable'
|
8
10
|
require_relative '../validators/entries_validator'
|
9
11
|
require_relative '../validators/time_validator'
|
12
|
+
require_relative 'entry'
|
10
13
|
|
11
14
|
module Dsu
|
12
15
|
module Models
|
13
16
|
class EntryGroup < DecoLite::Model
|
14
17
|
extend Support::EntryGroupLoadable
|
18
|
+
include Support::TimeFormatable
|
15
19
|
|
16
20
|
validates_with Validators::EntriesValidator, fields: [:entries]
|
17
21
|
validates_with Validators::TimeValidator, fields: [:time]
|
@@ -36,6 +40,16 @@ module Dsu
|
|
36
40
|
Services::EntryGroupDeleterService.new(time: time, options: options).call
|
37
41
|
end
|
38
42
|
|
43
|
+
def edit(time:, options: {})
|
44
|
+
# NOTE: Uncomment this line to prohibit edits on
|
45
|
+
# Entry Groups that do not exist (i.e. have no entries).
|
46
|
+
# return new(time: time) unless exists?(time: time)
|
47
|
+
|
48
|
+
load(time: time).tap do |entry_group|
|
49
|
+
entry_group.edit(options: options)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
39
53
|
def exists?(time:)
|
40
54
|
Dsu::Services::EntryGroupReaderService.entry_group_file_exists?(time: time)
|
41
55
|
end
|
@@ -53,15 +67,18 @@ module Dsu
|
|
53
67
|
entry_group_hash = entry_group_hash_for(time: time)
|
54
68
|
hydrate_entry_group_hash(entry_group_hash: entry_group_hash, time: time)
|
55
69
|
end
|
70
|
+
|
71
|
+
def unique?(entry:)
|
72
|
+
|
73
|
+
end
|
56
74
|
end
|
57
75
|
|
58
76
|
def required_fields
|
59
77
|
%i[time entries]
|
60
78
|
end
|
61
79
|
|
62
|
-
def
|
63
|
-
|
64
|
-
Services::EntryGroupWriterService.new(entry_group: self).call
|
80
|
+
def edit(options: {})
|
81
|
+
Services::EntryGroupEditorService.new(entry_group: self, options: options).call
|
65
82
|
self
|
66
83
|
end
|
67
84
|
|
@@ -71,6 +88,15 @@ module Dsu
|
|
71
88
|
self
|
72
89
|
end
|
73
90
|
|
91
|
+
def entries?
|
92
|
+
entries.any?
|
93
|
+
end
|
94
|
+
|
95
|
+
def save!
|
96
|
+
validate!
|
97
|
+
Services::EntryGroupWriterService.new(entry_group: self).call
|
98
|
+
end
|
99
|
+
|
74
100
|
def to_h
|
75
101
|
super.tap do |hash|
|
76
102
|
hash[:entries] = hash[:entries].dup
|
@@ -80,10 +106,67 @@ module Dsu
|
|
80
106
|
end
|
81
107
|
end
|
82
108
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
109
|
+
def check_unique(sha_or_editor_command:, description:)
|
110
|
+
raise ArgumentError, 'sha_or_editor_command is nil' if sha_or_editor_command.nil?
|
111
|
+
raise ArgumentError, 'description is nil' if description.nil?
|
112
|
+
raise ArgumentError, 'sha_or_editor_command is the wrong object type' unless sha_or_editor_command.is_a?(String)
|
113
|
+
raise ArgumentError, 'description is the wrong object type' unless description.is_a?(String)
|
114
|
+
|
115
|
+
if entries.blank?
|
116
|
+
entry_unique_hash = entry_unique_hash_for(uuid_unique: true, description_unique: true)
|
117
|
+
return entry_unique_struct_from(entry_unique_hash: entry_unique_hash)
|
86
118
|
end
|
119
|
+
|
120
|
+
entry_hash = entries.each_with_object({}) do |entry_group_entry, hash|
|
121
|
+
hash[entry_group_entry.uuid] = entry_group_entry.description
|
122
|
+
end
|
123
|
+
|
124
|
+
# It is possible that sha_or_editor_command may have an editor command (e.g. +|a|add). If this
|
125
|
+
# is the case, just treat it as unique because when the entry is added, it will get a unique uuid.
|
126
|
+
uuid_unique = !sha_or_editor_command.match?(Entry::ENTRY_UUID_REGEX) || !entry_hash.key?(sha_or_editor_command)
|
127
|
+
entry_unique_hash = entry_unique_hash_for(
|
128
|
+
uuid: sha_or_editor_command,
|
129
|
+
uuid_unique: uuid_unique,
|
130
|
+
description: description,
|
131
|
+
description_unique: !entry_hash.value?(description)
|
132
|
+
)
|
133
|
+
entry_unique_struct_from(entry_unique_hash: entry_unique_hash)
|
134
|
+
end
|
135
|
+
|
136
|
+
def entry_unique_hash_for(uuid_unique:, description_unique:, uuid: nil, description: nil)
|
137
|
+
{
|
138
|
+
uuid: uuid,
|
139
|
+
uuid_unique: uuid_unique,
|
140
|
+
description: description,
|
141
|
+
description_unique: description_unique,
|
142
|
+
formatted_time: Support::TimeFormatable.formatted_time(time: time)
|
143
|
+
}
|
144
|
+
end
|
145
|
+
|
146
|
+
def entry_unique_struct_from(entry_unique_hash:)
|
147
|
+
Struct.new(*entry_unique_hash.keys, keyword_init: true) do
|
148
|
+
def unique?
|
149
|
+
uuid_unique? && description_unique?
|
150
|
+
end
|
151
|
+
|
152
|
+
def uuid_unique?
|
153
|
+
uuid_unique
|
154
|
+
end
|
155
|
+
|
156
|
+
def description_unique?
|
157
|
+
description_unique
|
158
|
+
end
|
159
|
+
|
160
|
+
def messages
|
161
|
+
return [] if unique?
|
162
|
+
|
163
|
+
short_description = Models::Entry.short_description(string: description)
|
164
|
+
|
165
|
+
messages = []
|
166
|
+
messages << "#uuid is not unique: \"#{uuid} #{short_description}\"" unless uuid_unique?
|
167
|
+
messages << "#description is not unique: \"#{uuid} #{short_description}\""
|
168
|
+
end
|
169
|
+
end.new(**entry_unique_hash)
|
87
170
|
end
|
88
171
|
end
|
89
172
|
end
|
@@ -9,8 +9,6 @@ module Dsu
|
|
9
9
|
class ConfigurationLoaderService
|
10
10
|
include Dsu::Support::Configuration
|
11
11
|
|
12
|
-
attr_reader :default_options
|
13
|
-
|
14
12
|
def initialize(default_options: nil)
|
15
13
|
unless default_options.nil? ||
|
16
14
|
default_options.is_a?(Hash) ||
|
@@ -18,7 +16,7 @@ module Dsu
|
|
18
16
|
raise ArgumentError, 'default_options must be a Hash or ActiveSupport::HashWithIndifferentAccess'
|
19
17
|
end
|
20
18
|
|
21
|
-
@default_options
|
19
|
+
@default_options = default_options || {}
|
22
20
|
@default_options = @default_options.with_indifferent_access if @default_options.is_a?(Hash)
|
23
21
|
end
|
24
22
|
|
@@ -28,6 +26,8 @@ module Dsu
|
|
28
26
|
|
29
27
|
private
|
30
28
|
|
29
|
+
attr_reader :default_options
|
30
|
+
|
31
31
|
def config_options
|
32
32
|
return Support::Configuration::DEFAULT_DSU_OPTIONS unless config_file?
|
33
33
|
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../models/entry'
|
4
|
+
require_relative '../support/colorable'
|
5
|
+
require_relative '../support/say'
|
6
|
+
require_relative '../support/time_formatable'
|
7
|
+
require_relative 'configuration_loader_service'
|
8
|
+
|
9
|
+
module Dsu
|
10
|
+
module Services
|
11
|
+
class EntryGroupEditorService
|
12
|
+
include Support::Colorable
|
13
|
+
include Support::Say
|
14
|
+
include Support::TimeFormatable
|
15
|
+
|
16
|
+
def initialize(entry_group:, options: {})
|
17
|
+
raise ArgumentError, 'entry_group is nil' if entry_group.nil?
|
18
|
+
raise ArgumentError, 'entry_group is the wrong object type' unless entry_group.is_a?(Models::EntryGroup)
|
19
|
+
raise ArgumentError, 'options is the wrong object type' unless options.is_a?(Hash) || options.nil?
|
20
|
+
|
21
|
+
@entry_group = entry_group
|
22
|
+
@options = options || {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def call
|
26
|
+
edit_view = render_edit_view
|
27
|
+
edit!(edit_view: edit_view)
|
28
|
+
# NOTE: Return the original entry group object as any permanent changes
|
29
|
+
# will have been applied to it.
|
30
|
+
entry_group
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_reader :entry_group, :options
|
36
|
+
|
37
|
+
# Renders the edit view to a string so we can write it to a temporary file
|
38
|
+
# and edit it. The edits will be used to update the entry group.
|
39
|
+
def render_edit_view
|
40
|
+
say "Editing entry group #{formatted_time(time: entry_group.time)}...", HIGHLIGHT
|
41
|
+
capture_stdxxx { Views::EntryGroup::Edit.new(entry_group: entry_group).render }
|
42
|
+
end
|
43
|
+
|
44
|
+
# Writes the temporary file contents to disk and opens it in the editor.
|
45
|
+
def edit!(edit_view:)
|
46
|
+
Services::TempFileWriterService.new(tmp_file_content: edit_view).call do |tmp_file_path|
|
47
|
+
unless Kernel.system("${EDITOR:-#{configuration[:editor]}} #{tmp_file_path}")
|
48
|
+
say "Failed to open temporary file in editor '#{configuration[:editor]}';" \
|
49
|
+
"the system error returned was: '#{$CHILD_STATUS}'.", ERROR
|
50
|
+
say 'Either set the EDITOR environment variable ' \
|
51
|
+
'or set the dsu editor configuration option (`$ dsu config init`).', ERROR
|
52
|
+
say 'Run `$ dsu help config` for more information.', ERROR
|
53
|
+
|
54
|
+
system('dsu help config')
|
55
|
+
|
56
|
+
return # rubocop:disable Lint/NonLocalExitFromIterator: This is not an iterator.
|
57
|
+
end
|
58
|
+
|
59
|
+
update_entry_group!(tmp_file_path: tmp_file_path)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# TODO: Clean this up
|
64
|
+
def update_entry_group!(tmp_file_path:)
|
65
|
+
errors = []
|
66
|
+
entry_group.entries = entries = []
|
67
|
+
Services::TempFileReaderService.new(tmp_file_path: tmp_file_path).call do |tmp_file_line|
|
68
|
+
next if comment_or_empty?(tmp_file_line: tmp_file_line)
|
69
|
+
|
70
|
+
entry_info = editor_entry_info_from(tmp_file_line: tmp_file_line)
|
71
|
+
next if entry_info.empty?
|
72
|
+
next if delete_entry_cmd?(sha: entry_info[:sha])
|
73
|
+
next unless add_entry_cmd?(sha: entry_info[:sha]) || sha?(sha: entry_info[:sha])
|
74
|
+
|
75
|
+
entry_info[:sha_or_editor_command] = entry_info[:sha]
|
76
|
+
entry_info[:sha] = nil if add_entry_cmd?(sha: entry_info[:sha])
|
77
|
+
|
78
|
+
entry = Models::Entry.new(uuid: entry_info[:sha], description: entry_info[:description])
|
79
|
+
entry_group.check_unique(sha_or_editor_command: entry_info[:sha_or_editor_command],
|
80
|
+
description: entry_info[:description]).tap do |status|
|
81
|
+
entries << entry and next if status.unique?
|
82
|
+
|
83
|
+
errors << status.messages
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Display any errors encountered.
|
88
|
+
if errors.any?
|
89
|
+
say 'Error: one or more entry values were not unique within the entry group entries:', ERROR
|
90
|
+
errors.flatten.each { |message| say "Error: #{message}", ERROR }
|
91
|
+
end
|
92
|
+
|
93
|
+
# Save or delete any entries.
|
94
|
+
entry_group.entries = entries
|
95
|
+
entry_group.delete and return unless entry_group.entries?
|
96
|
+
|
97
|
+
entry_group.save!
|
98
|
+
end
|
99
|
+
|
100
|
+
def sha?(sha:)
|
101
|
+
sha.match?(Models::Entry::ENTRY_UUID_REGEX)
|
102
|
+
end
|
103
|
+
|
104
|
+
def delete_entry_cmd?(sha:)
|
105
|
+
%w[- d delete].include?(sha)
|
106
|
+
end
|
107
|
+
|
108
|
+
def add_entry_cmd?(sha:)
|
109
|
+
%w[+ a add].include?(sha)
|
110
|
+
end
|
111
|
+
|
112
|
+
def comment_or_empty?(tmp_file_line:)
|
113
|
+
['#', nil].include? tmp_file_line[0]
|
114
|
+
end
|
115
|
+
|
116
|
+
def editor_entry_info_from(tmp_file_line:)
|
117
|
+
match_data = tmp_file_line.match(/(\S+)\s(.+)/)
|
118
|
+
{
|
119
|
+
sha: match_data[1]&.strip,
|
120
|
+
description: match_data[2]&.strip
|
121
|
+
}
|
122
|
+
rescue StandardError
|
123
|
+
{}
|
124
|
+
end
|
125
|
+
|
126
|
+
# TODO: Add this to a module.
|
127
|
+
# https://stackoverflow.com/questions/4459330/how-do-i-temporarily-redirect-stderr-in-ruby/4459463#4459463
|
128
|
+
def capture_stdxxx
|
129
|
+
# The output stream must be an IO-like object. In this case we capture it in
|
130
|
+
# an in-memory IO object so we can return the string value. You can assign any
|
131
|
+
# IO object here.
|
132
|
+
string_io = StringIO.new
|
133
|
+
prev_stdout, $stdout = $stdout, string_io # rubocop:disable Style/ParallelAssignment
|
134
|
+
prev_stderr, $stderr = $stderr, string_io # rubocop:disable Style/ParallelAssignment
|
135
|
+
yield
|
136
|
+
string_io.string
|
137
|
+
ensure
|
138
|
+
# Restore the previous value of stderr and stdout (typically equal to STDERR).
|
139
|
+
$stdout = prev_stdout
|
140
|
+
$stderr = prev_stderr
|
141
|
+
end
|
142
|
+
|
143
|
+
def configuration
|
144
|
+
@configuration ||= ConfigurationLoaderService.new.call
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -3,29 +3,29 @@
|
|
3
3
|
module Dsu
|
4
4
|
module Services
|
5
5
|
class TempFileReaderService
|
6
|
-
def initialize(
|
7
|
-
raise ArgumentError, '
|
8
|
-
raise ArgumentError, '
|
9
|
-
raise ArgumentError, '
|
10
|
-
raise ArgumentError, '
|
6
|
+
def initialize(tmp_file_path:, options: {})
|
7
|
+
raise ArgumentError, 'tmp_file_path is nil' if tmp_file_path.nil?
|
8
|
+
raise ArgumentError, 'tmp_file_path is the wrong object type' unless tmp_file_path.is_a?(String)
|
9
|
+
raise ArgumentError, 'tmp_file_path is empty' if tmp_file_path.empty?
|
10
|
+
raise ArgumentError, 'tmp_file_path does not exist' unless File.exist?(tmp_file_path)
|
11
11
|
raise ArgumentError, 'options is nil' if options.nil?
|
12
12
|
raise ArgumentError, 'options is the wrong object type' unless options.is_a?(Hash)
|
13
13
|
|
14
|
-
@
|
14
|
+
@tmp_file_path = tmp_file_path
|
15
15
|
@options = options || {}
|
16
16
|
end
|
17
17
|
|
18
18
|
def call
|
19
19
|
raise ArgumentError, 'no block given' unless block_given?
|
20
20
|
|
21
|
-
File.foreach(
|
21
|
+
File.foreach(tmp_file_path) do |line|
|
22
22
|
yield line.strip
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
private
|
27
27
|
|
28
|
-
attr_reader :
|
28
|
+
attr_reader :tmp_file_path, :options
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -5,13 +5,13 @@ require 'tempfile'
|
|
5
5
|
module Dsu
|
6
6
|
module Services
|
7
7
|
class TempFileWriterService
|
8
|
-
def initialize(
|
9
|
-
raise ArgumentError, '
|
10
|
-
raise ArgumentError, '
|
8
|
+
def initialize(tmp_file_content:, options: {})
|
9
|
+
raise ArgumentError, 'tmp_file_content is nil' if tmp_file_content.nil?
|
10
|
+
raise ArgumentError, 'tmp_file_content is the wrong object type' unless tmp_file_content.is_a?(String)
|
11
11
|
raise ArgumentError, 'options is nil' if options.nil?
|
12
12
|
raise ArgumentError, 'options is the wrong object type' unless options.is_a?(Hash)
|
13
13
|
|
14
|
-
@
|
14
|
+
@tmp_file_content = tmp_file_content
|
15
15
|
@options = options || {}
|
16
16
|
end
|
17
17
|
|
@@ -19,7 +19,7 @@ module Dsu
|
|
19
19
|
raise ArgumentError, 'no block given' unless block_given?
|
20
20
|
|
21
21
|
Tempfile.new('dsu').tap do |file|
|
22
|
-
file.write("#{
|
22
|
+
file.write("#{tmp_file_content}\n")
|
23
23
|
file.close
|
24
24
|
yield file.path
|
25
25
|
end.unlink
|
@@ -27,7 +27,7 @@ module Dsu
|
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
-
attr_reader :
|
30
|
+
attr_reader :tmp_file_content, :options
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
data/lib/dsu/subcommands/edit.rb
CHANGED
@@ -1,19 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'English'
|
4
3
|
require_relative '../base_cli'
|
5
4
|
require_relative '../models/entry_group'
|
6
|
-
require_relative '../services/temp_file_reader_service'
|
7
|
-
require_relative '../services/temp_file_writer_service'
|
8
|
-
require_relative '../support/time_formatable'
|
9
|
-
require_relative '../views/entry_group/edit'
|
10
5
|
require_relative '../views/entry_group/show'
|
11
6
|
|
12
7
|
module Dsu
|
13
8
|
module Subcommands
|
14
9
|
class Edit < Dsu::BaseCLI
|
15
|
-
include Support::TimeFormatable
|
16
|
-
|
17
10
|
map %w[d] => :date
|
18
11
|
map %w[n] => :today
|
19
12
|
map %w[t] => :tomorrow
|
@@ -25,7 +18,8 @@ module Dsu
|
|
25
18
|
Edits the DSU entries for today.
|
26
19
|
LONG_DESC
|
27
20
|
def today
|
28
|
-
|
21
|
+
entry_group = Models::EntryGroup.edit(time: Time.now)
|
22
|
+
Views::EntryGroup::Show.new(entry_group: entry_group).render
|
29
23
|
end
|
30
24
|
|
31
25
|
desc 'tomorrow, t',
|
@@ -34,7 +28,8 @@ module Dsu
|
|
34
28
|
Edits the DSU entries for tomorrow.
|
35
29
|
LONG_DESC
|
36
30
|
def tomorrow
|
37
|
-
|
31
|
+
entry_group = Models::EntryGroup.edit(time: Time.now.tomorrow)
|
32
|
+
Views::EntryGroup::Show.new(entry_group: entry_group).render
|
38
33
|
end
|
39
34
|
|
40
35
|
desc 'yesterday, y',
|
@@ -43,7 +38,8 @@ module Dsu
|
|
43
38
|
Edits the DSU entries for yesterday.
|
44
39
|
LONG_DESC
|
45
40
|
def yesterday
|
46
|
-
|
41
|
+
entry_group = Models::EntryGroup.edit(time: Time.now.yesterday)
|
42
|
+
Views::EntryGroup::Show.new(entry_group: entry_group).render
|
47
43
|
end
|
48
44
|
|
49
45
|
desc 'date, d DATE',
|
@@ -54,79 +50,12 @@ module Dsu
|
|
54
50
|
\x5 #{date_option_description}
|
55
51
|
LONG_DESC
|
56
52
|
def date(date)
|
57
|
-
|
53
|
+
entry_group = Models::EntryGroup.edit(time: Time.parse(date))
|
54
|
+
Views::EntryGroup::Show.new(entry_group: entry_group).render
|
58
55
|
rescue ArgumentError => e
|
59
56
|
say "Error: #{e.message}", ERROR
|
60
57
|
exit 1
|
61
58
|
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
def edit_entry_group(time:)
|
66
|
-
formatted_time = formatted_time(time: time)
|
67
|
-
unless Models::EntryGroup.exists?(time: time)
|
68
|
-
say "No DSU entries exist for #{formatted_time}"
|
69
|
-
exit 1
|
70
|
-
end
|
71
|
-
|
72
|
-
say "Editing DSU entries for #{formatted_time}..."
|
73
|
-
entry_group = Models::EntryGroup.load(time: time)
|
74
|
-
|
75
|
-
# This renders the view to a string...
|
76
|
-
output = capture_stdxxx do
|
77
|
-
Views::EntryGroup::Edit.new(entry_group: entry_group).render
|
78
|
-
end
|
79
|
-
# ...which is then written to a temp file.
|
80
|
-
Services::TempFileWriterService.new(temp_file_content: output).call do |temp_file_path|
|
81
|
-
unless system("${EDITOR:-#{configuration[:editor]}} #{temp_file_path}")
|
82
|
-
say "Failed to open temporary file in editor '#{configuration[:editor]}';" \
|
83
|
-
"the system error returned was: '#{$CHILD_STATUS}'.", ERROR
|
84
|
-
say 'Either set the EDITOR environment variable ' \
|
85
|
-
'or set the dsu editor configuration option (`$ dsu config init`).', ERROR
|
86
|
-
say 'Run `$ dsu help config` for more information.', ERROR
|
87
|
-
system('dsu help config')
|
88
|
-
exit 1
|
89
|
-
end
|
90
|
-
entries = []
|
91
|
-
Services::TempFileReaderService.new(temp_file_path: temp_file_path).call do |temp_file_line|
|
92
|
-
# Skip comments and blank lines.
|
93
|
-
next if ['#', nil].include? temp_file_line[0]
|
94
|
-
|
95
|
-
match_data = temp_file_line.match(/(\S+)\s(.+)/)
|
96
|
-
# TODO: Error handling if match_data is nil.
|
97
|
-
entry_sha = match_data[1]
|
98
|
-
entry_description = match_data[2]
|
99
|
-
|
100
|
-
next if %w[- d delete].include?(entry_sha) # delete the entry
|
101
|
-
|
102
|
-
entry_sha = nil if %w[+ a add].include?(entry_sha) # add the new entry
|
103
|
-
entries << Models::Entry.new(uuid: entry_sha, description: entry_description)
|
104
|
-
end
|
105
|
-
|
106
|
-
entry_group.entries = entries
|
107
|
-
|
108
|
-
return entry_group.delete if entries.empty?
|
109
|
-
|
110
|
-
entry_group.save!
|
111
|
-
end
|
112
|
-
entry_group
|
113
|
-
end
|
114
|
-
|
115
|
-
# https://stackoverflow.com/questions/4459330/how-do-i-temporarily-redirect-stderr-in-ruby/4459463#4459463
|
116
|
-
def capture_stdxxx
|
117
|
-
# The output stream must be an IO-like object. In this case we capture it in
|
118
|
-
# an in-memory IO object so we can return the string value. You can assign any
|
119
|
-
# IO object here.
|
120
|
-
string_io = StringIO.new
|
121
|
-
prev_stdout, $stdout = $stdout, string_io # rubocop:disable Style/ParallelAssignment
|
122
|
-
prev_stderr, $stderr = $stderr, string_io # rubocop:disable Style/ParallelAssignment
|
123
|
-
yield
|
124
|
-
string_io.string
|
125
|
-
ensure
|
126
|
-
# Restore the previous value of stderr and stdout (typically equal to STDERR).
|
127
|
-
$stdout = prev_stdout
|
128
|
-
$stderr = prev_stderr
|
129
|
-
end
|
130
59
|
end
|
131
60
|
end
|
132
61
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dsu
|
4
|
+
module Support
|
5
|
+
module Descriptable
|
6
|
+
class << self
|
7
|
+
def included(mod)
|
8
|
+
mod.extend(ClassMethods)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def short_description
|
13
|
+
return '' if description.blank?
|
14
|
+
|
15
|
+
self.class.short_description(string: description)
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def short_description(string:, count: 25, elipsis: '...')
|
20
|
+
return elipsis unless string.is_a?(String)
|
21
|
+
|
22
|
+
elipsis_length = elipsis.length
|
23
|
+
count = elipsis_length if count.nil? || count < elipsis_length
|
24
|
+
|
25
|
+
return string if string.length <= count
|
26
|
+
|
27
|
+
tokens = string.split
|
28
|
+
string = ''
|
29
|
+
|
30
|
+
return "#{tokens.first[0..(count - elipsis_length)]}#{elipsis}" if tokens.count == 1
|
31
|
+
|
32
|
+
tokens.each do |token|
|
33
|
+
break if string.length + token.length + elipsis_length > count
|
34
|
+
|
35
|
+
string = "#{string} #{token}"
|
36
|
+
end
|
37
|
+
|
38
|
+
"#{string.strip}#{elipsis}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -24,7 +24,8 @@ module Dsu
|
|
24
24
|
end
|
25
25
|
|
26
26
|
validate_entry_types field, entries, record
|
27
|
-
|
27
|
+
validate_unique_entry_attr :uuid, field, entries, record
|
28
|
+
validate_unique_entry_attr :description, field, entries, record
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
@@ -42,17 +43,17 @@ module Dsu
|
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
45
|
-
def
|
46
|
+
def validate_unique_entry_attr(attr, field, entries, record)
|
46
47
|
return unless entries.is_a? Array
|
47
48
|
|
48
49
|
entry_objects = entries.select { |entry| entry.is_a?(Dsu::Models::Entry) }
|
49
50
|
|
50
|
-
|
51
|
-
return if
|
51
|
+
attrs = entry_objects.map(&attr)
|
52
|
+
return if attrs.uniq.length == attrs.length
|
52
53
|
|
53
|
-
|
54
|
-
if
|
55
|
-
record.errors.add(field, "contains duplicate
|
54
|
+
non_unique_attrs = attrs.select { |attr| attrs.count(attr) > 1 }.uniq # rubocop:disable Lint/ShadowingOuterLocalVariable
|
55
|
+
if non_unique_attrs.any?
|
56
|
+
record.errors.add(field, "contains duplicate ##{attr}s: #{non_unique_attrs.join(', ')}.",
|
56
57
|
type: Dsu::Support::FieldErrors::FIELD_DUPLICATE_ERROR)
|
57
58
|
end
|
58
59
|
end
|
data/lib/dsu/version.rb
CHANGED
@@ -42,13 +42,15 @@ module Dsu
|
|
42
42
|
|
43
43
|
def render_entry_group!
|
44
44
|
say "# Editing DSU Entries for #{formatted_time(time: entry_group.time)}"
|
45
|
-
|
46
|
-
|
45
|
+
# TODO: Display entry group entries from the previous DSU date so they can be
|
46
|
+
# easily copied over; or, add them to the current entry group entries below as
|
47
|
+
# a "# [+|a|add] <entry group from previous DSU entry description>" (e.g. commented
|
48
|
+
# out) by default?
|
47
49
|
say ''
|
48
50
|
say '# [SHA/COMMAND] [DESCRIPTION]'
|
49
51
|
|
50
52
|
entry_group.entries.each do |entry|
|
51
|
-
say "#{entry.uuid} #{entry.description}"
|
53
|
+
say "#{entry.uuid} #{entry.description.strip}"
|
52
54
|
end
|
53
55
|
|
54
56
|
say ''
|
@@ -26,13 +26,7 @@ module Dsu
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def call
|
29
|
-
# Just in case the entry group is invalid, we'll
|
30
|
-
# validate it before displaying it.
|
31
|
-
entry_group.validate!
|
32
29
|
render_entry_group!
|
33
|
-
rescue ActiveModel::ValidationError
|
34
|
-
puts "Error(s) encountered: #{entry_group.errors.full_messages}"
|
35
|
-
raise
|
36
30
|
end
|
37
31
|
alias render call
|
38
32
|
|
@@ -47,7 +41,9 @@ module Dsu
|
|
47
41
|
entry_group.entries.each_with_index do |entry, index|
|
48
42
|
prefix = "#{format('%03s', index + 1)}. #{entry.uuid}"
|
49
43
|
description = colorize_string(string: entry.description, mode: :bold)
|
50
|
-
|
44
|
+
entry_info = "#{prefix} #{description}"
|
45
|
+
entry_info = "#{entry_info} (validation failed)" unless entry.valid?
|
46
|
+
say entry_info
|
51
47
|
end
|
52
48
|
end
|
53
49
|
end
|
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: 0.1.0.alpha.
|
4
|
+
version: 0.1.0.alpha.5
|
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-05-
|
11
|
+
date: 2023-05-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -112,12 +112,18 @@ dependencies:
|
|
112
112
|
- - "~>"
|
113
113
|
- !ruby/object:Gem::Version
|
114
114
|
version: '1.0'
|
115
|
-
description:
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
115
|
+
description: " dsu is little gem that helps manage your Agile DSU (Daily Stand
|
116
|
+
Up) participation. How? by providing a simple command line interface (CLI) which
|
117
|
+
allows you to create, read, update, and delete (CRUD) noteworthy activities that
|
118
|
+
you performed during your day. During your DSU, you can then easily recall and share
|
119
|
+
these these activities with your team. Activities are grouped by day and can be
|
120
|
+
viewed in simple text format from the command line. When displaying DSU entries
|
121
|
+
for a particular day or date (date), dsu will display the given day or date's (date)
|
122
|
+
DSU entries, as well as the DSU entries for the previous day, relative to the given
|
123
|
+
day or date. If the date or day you are trying to view falls on a weekend or Monday,
|
124
|
+
dsu will display back to, and including the weekend and previous Friday inclusive;
|
125
|
+
this is so that you can share what you did over the weekend (if anything) and the
|
126
|
+
previous Friday at your DSU.\n"
|
121
127
|
email:
|
122
128
|
- public.gma@gmail.com
|
123
129
|
executables:
|
@@ -147,6 +153,7 @@ files:
|
|
147
153
|
- lib/dsu/models/entry_group.rb
|
148
154
|
- lib/dsu/services/configuration_loader_service.rb
|
149
155
|
- lib/dsu/services/entry_group_deleter_service.rb
|
156
|
+
- lib/dsu/services/entry_group_editor_service.rb
|
150
157
|
- lib/dsu/services/entry_group_hydrator_service.rb
|
151
158
|
- lib/dsu/services/entry_group_reader_service.rb
|
152
159
|
- lib/dsu/services/entry_group_writer_service.rb
|
@@ -162,6 +169,7 @@ files:
|
|
162
169
|
- lib/dsu/support/commander/command_help.rb
|
163
170
|
- lib/dsu/support/commander/subcommand.rb
|
164
171
|
- lib/dsu/support/configuration.rb
|
172
|
+
- lib/dsu/support/descriptable.rb
|
165
173
|
- lib/dsu/support/entry_group_fileable.rb
|
166
174
|
- lib/dsu/support/entry_group_loadable.rb
|
167
175
|
- lib/dsu/support/entry_group_viewable.rb
|