dsu 0.1.0.alpha.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +17 -0
- data/Gemfile.lock +1 -1
- data/README.md +29 -39
- data/lib/dsu/base_cli.rb +0 -3
- data/lib/dsu/cli.rb +42 -49
- data/lib/dsu/command_services/add_entry_service.rb +21 -21
- data/lib/dsu/models/entry.rb +37 -20
- data/lib/dsu/models/entry_group.rb +66 -38
- data/lib/dsu/services/configuration_loader_service.rb +4 -3
- data/lib/dsu/services/entry_group_editor_service.rb +99 -0
- data/lib/dsu/services/entry_group_writer_service.rb +1 -0
- data/lib/dsu/services/stdout_redirector_service.rb +27 -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/colorable.rb +1 -0
- data/lib/dsu/support/descriptable.rb +43 -0
- data/lib/dsu/support/entry_group_loadable.rb +10 -12
- data/lib/dsu/validators/description_validator.rb +38 -0
- data/lib/dsu/validators/entries_validator.rb +43 -31
- data/lib/dsu/validators/time_validator.rb +11 -20
- data/lib/dsu/version.rb +1 -1
- data/lib/dsu/views/edited_entries/shared/errors.rb +39 -0
- data/lib/dsu/views/entry_group/edit.rb +30 -33
- data/lib/dsu/views/entry_group/show.rb +12 -10
- data/lib/dsu/views/shared/messages.rb +56 -0
- data/lib/dsu.rb +4 -0
- metadata +10 -8
- data/lib/dsu/support/commander/command.rb +0 -130
- data/lib/dsu/support/commander/command_help.rb +0 -62
- data/lib/dsu/support/commander/subcommand.rb +0 -45
- data/lib/dsu/support/interactive/cli.rb +0 -161
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa1b6f69c4de21d556a38cd96f29ba9ad8b7b4b2a9f5d34cda7fccb61f15d63f
|
4
|
+
data.tar.gz: 7376022ead177228164448d6fa4b8ee554a35611d45450955c586ed1bf84462a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7128d03202e5f9536e6fda51c2dab009dd0ed32f56f00e17b6d1c96cb5420daa8dd0ab71c69d25f811ee41acf14cda05d133211f3b9480b70907736201d7162b
|
7
|
+
data.tar.gz: bc276d357add40377ec88b79b8379fad502cea936440c31a81e7e0ed18c1ad766244f0a09b9eb33a1536a0d60d2c7140b429d5643aa6a3d51b2f362cdec60673
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
## [1.0.0] - 2023-05-18
|
2
|
+
* First official release.
|
3
|
+
* NOTE: If you have been using the alpha version of `dsu`, you will need to delete the `entries` folder (e.g. `/Users/<whoami>/dsu/entries` on a nix os) as the old entries .json files are incompatible with this official release.
|
4
|
+
* Changes from the alpha version
|
5
|
+
- When editing an entry group, editor commands are no longer necessary. Simply add, remove or change entries as needed. See the README.md for more information.
|
6
|
+
- When editing an entry group and saving the results, take note of the folowing behavior:
|
7
|
+
- Entering duplicate entries are not allowed, only one entry with a given description is allowed per entry group.
|
8
|
+
- Entering entries whose descriptions are < 2 or > 256 characters will fail validation and will not be saved.
|
9
|
+
- When editing and encountering any of the aforementioned, the errors will be displayed to the console after the editor file is saved.
|
10
|
+
- Sha's are no longer being used, as I've not found a good use (currently) to use them. I may add them back in the future if I find a good use for them (tracking entries across entry groups, etc.).
|
11
|
+
- When adding an entry (`dsu add OPTION`), it used to be that after the entry was added, the entry group for the date being edited would be displayed, as well as "yesterday's" date. This is no longer the case; now, only the entry group for the date being edited is displayed.
|
12
|
+
## [0.1.0.alpha.5] - 2023-05-12
|
13
|
+
* Changes
|
14
|
+
- `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.
|
15
|
+
- `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.
|
16
|
+
NOTE: Not all edge cases are being handled currently by `dsu edit SUBCOMMAND`.
|
17
|
+
- `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.
|
1
18
|
## [0.1.0.alpha.4] - 2023-05-09
|
2
19
|
* Changes
|
3
20
|
- Gemfile gemspec description changes.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -9,8 +9,6 @@
|
|
9
9
|
## About
|
10
10
|
`dsu` is little gem that helps manage your Agile DSU (Daily Stand Up) participation. How? by providing a simple command line interface (CLI) which allows you to create, read, update, and delete (CRUD) noteworthy activities that you performed during your day. During your DSU, you can then easily recall and share these these activities with your team. Activities are grouped by day and can be viewed in simple text format from the command line. When viewing a particular day, `dsu` will automatically display the previous day's activities as well. This is useful for remembering what you did yesterday, so you can share your "Today" and "Yesterday" activities with your team during your DSU. If the 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, so that you can share what you did over the weekend (if anything) and the previous Friday.
|
11
11
|
|
12
|
-
**NOTE:** This gem is in development (alpha version). Please see the [WIP Notes](#wip-notes) section for current `dsu` features.
|
13
|
-
|
14
12
|
## Help
|
15
13
|
|
16
14
|
After installation (`gem install dsu`), the first thing you may want to do is run the `dsu` help:
|
@@ -19,7 +17,7 @@ After installation (`gem install dsu`), the first thing you may want to do is ru
|
|
19
17
|
```shell
|
20
18
|
#=>
|
21
19
|
Commands:
|
22
|
-
dsu add, -a [OPTIONS] DESCRIPTION # Adds a DSU entry
|
20
|
+
dsu add, -a [OPTIONS] DESCRIPTION # Adds a DSU entry...
|
23
21
|
dsu config, -c SUBCOMMAND # Manage configuration...
|
24
22
|
dsu edit, -e SUBCOMMAND # Edit DSU entries...
|
25
23
|
dsu help [COMMAND] # Describe available...
|
@@ -35,7 +33,7 @@ The next thing you may want to do is `add` some DSU activities (entries) for a p
|
|
35
33
|
## Adding DSU Entries
|
36
34
|
`dsu add [OPTIONS] DESCRIPTION`
|
37
35
|
|
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`).
|
36
|
+
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
37
|
|
40
38
|
### Today
|
41
39
|
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:
|
@@ -97,7 +95,7 @@ Friday, (Yesterday) 2023-05-05
|
|
97
95
|
```
|
98
96
|
## Editing DSU Entries
|
99
97
|
|
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.
|
98
|
+
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 the the date, the editor will allow you to add entries for that date. *NOTE: duplicate entries are not allowed; that is, the entry DESCRIPTION need to be unique within an entry group. Non-unique entries will not be added to the entry group. The same holds true for entries whose DESCRIPTION that do not pass validation (between 2 and 256 characters (inclusive) in length).*
|
101
99
|
|
102
100
|
Note: See the "[Customizing the `dsu` Configuration File](#customizing-the-dsu-configuration-file)"" section to configure `dsu` to use the editor of your choice.
|
103
101
|
|
@@ -116,20 +114,19 @@ The following will edit your DSU entry group entries for "Today", where `Time.no
|
|
116
114
|
```shell
|
117
115
|
#=> In your editor, you will see...
|
118
116
|
# Editing DSU Entries for Tuesday, (Today) 2023-05-09 EDT
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
59b25ca7 Review Kelsey's PR ticket 30721.
|
117
|
+
# [ENTRY DESCRIPTION]
|
118
|
+
Interative planning meeting 11:00AM.
|
119
|
+
Pair with Chad on ticket 31211.
|
120
|
+
Investigate spike ticket 31255.
|
121
|
+
Review Kelsey's PR ticket 30721.
|
125
122
|
|
126
123
|
# INSTRUCTIONS:
|
127
|
-
#
|
128
|
-
#
|
129
|
-
# DELETE a DSU entry: delete the
|
130
|
-
#
|
131
|
-
#
|
132
|
-
# REORDER a DSU entry: reorder the
|
124
|
+
# ADD a DSU entry: type an ENTRY DESCRIPTION on a new line.
|
125
|
+
# EDIT a DSU entry: change the existing ENTRY DESCRIPTION.
|
126
|
+
# DELETE a DSU entry: delete the ENTRY DESCRIPTION.
|
127
|
+
# NOTE: deleting all of the ENTRY DESCRIPTIONs will delete the entry group file;
|
128
|
+
# this is preferable if this is what you want to do :)
|
129
|
+
# REORDER a DSU entry: reorder the ENTRY DESCRIPTIONs in order preference.
|
133
130
|
#
|
134
131
|
# *** When you are done, save and close your editor ***
|
135
132
|
```
|
@@ -140,32 +137,28 @@ Simply change the entry descripton text.
|
|
140
137
|
|
141
138
|
For example...
|
142
139
|
```
|
143
|
-
from:
|
144
|
-
to:
|
140
|
+
from: Interative planning meeting 11:00AM.
|
141
|
+
to: Interative planning meeting 12:00AM.
|
145
142
|
```
|
146
143
|
|
147
144
|
#### Add an Entry
|
148
145
|
|
149
|
-
|
146
|
+
Simply type a new entry on a separate line. *Note: any entry that starts with a `#` in the first character position will be ignored.*
|
150
147
|
|
151
148
|
For example...
|
152
149
|
```
|
153
|
-
|
150
|
+
Add me to this entry group.
|
154
151
|
```
|
155
152
|
|
156
153
|
#### Delete an Entry
|
157
154
|
|
158
|
-
Simply delete the entry
|
155
|
+
Simply delete the entry.
|
159
156
|
|
160
157
|
For example...
|
161
158
|
```
|
162
159
|
# Delete this this entry from the editor file
|
163
|
-
|
164
|
-
|
165
|
-
or
|
166
|
-
```
|
167
|
-
from: 3849f0c0 Interative planning meeting 11:00AM.
|
168
|
-
to: - Interative planning meeting 11:00AM.
|
160
|
+
from: Interative planning meeting 11:00AM.
|
161
|
+
to: <deleted>
|
169
162
|
```
|
170
163
|
|
171
164
|
#### Reorder Entries
|
@@ -174,14 +167,14 @@ Simply reorder the entries in the editor.
|
|
174
167
|
|
175
168
|
For example...
|
176
169
|
```
|
177
|
-
from:
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
to:
|
182
|
-
|
183
|
-
|
184
|
-
|
170
|
+
from: Interative planning meeting 11:00AM.
|
171
|
+
Pair with Chad on ticket 31211.
|
172
|
+
Investigate spike ticket 31255.
|
173
|
+
Review Kelsey's PR ticket 30721.
|
174
|
+
to: Review Kelsey's PR ticket 30721.
|
175
|
+
Investigate spike ticket 31255.
|
176
|
+
Pair with Chad on ticket 31211.
|
177
|
+
Interative planning meeting 11:00AM.
|
185
178
|
```
|
186
179
|
|
187
180
|
## Customizing the `dsu` Configuration File
|
@@ -242,9 +235,6 @@ These notes apply to anywhere DATE is used...
|
|
242
235
|
|
243
236
|
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
|
246
|
-
This gem is in development (alpha release).
|
247
|
-
|
248
238
|
## Installation
|
249
239
|
|
250
240
|
$ gem install dsu
|
data/lib/dsu/base_cli.rb
CHANGED
data/lib/dsu/cli.rb
CHANGED
@@ -30,14 +30,21 @@ module Dsu
|
|
30
30
|
\x5
|
31
31
|
-d DATE: Adds a DSU entry having DESCRIPTION to the DATE.
|
32
32
|
|
33
|
-
\x5
|
33
|
+
\x5
|
34
|
+
#{date_option_description}
|
34
35
|
|
35
|
-
\x5
|
36
|
+
\x5
|
37
|
+
-n: Adds a DSU entry having DESCRIPTION to today's date (`Time.now`).
|
36
38
|
|
37
|
-
\x5
|
39
|
+
\x5
|
40
|
+
-t: Adds a DSU entry having DESCRIPTION to tomorrow's date (`Time.new.tomorrow`).
|
38
41
|
|
39
|
-
\x5
|
42
|
+
\x5
|
43
|
+
-y: Adds a DSU entry having DESCRIPTION to yesterday's date (`Time.new.yesterday`).
|
40
44
|
|
45
|
+
DESCRIPTION:
|
46
|
+
\x5
|
47
|
+
Must be be between 2 and 256 characters (inclusive) in length.
|
41
48
|
LONG_DESC
|
42
49
|
option :date, type: :string, aliases: '-d'
|
43
50
|
option :tomorrow, type: :boolean, aliases: '-t'
|
@@ -45,52 +52,50 @@ module Dsu
|
|
45
52
|
option :today, type: :boolean, aliases: '-n', default: true
|
46
53
|
|
47
54
|
def add(description)
|
48
|
-
|
49
|
-
|
50
|
-
[time, time.yesterday]
|
55
|
+
time = if options[:date].present?
|
56
|
+
Time.parse(options[:date])
|
51
57
|
else
|
52
|
-
time = Time.now
|
53
58
|
if options[:tomorrow].present?
|
54
|
-
|
59
|
+
Time.now.tomorrow
|
55
60
|
elsif options[:yesterday].present?
|
56
|
-
|
61
|
+
Time.now.yesterday
|
57
62
|
elsif options[:today].present?
|
58
|
-
|
63
|
+
Time.now
|
59
64
|
end
|
60
65
|
end
|
61
66
|
entry = Models::Entry.new(description: description)
|
62
|
-
|
63
|
-
|
64
|
-
CommandServices::AddEntryService.new(entry: entry, time: times.max).call
|
65
|
-
sorted_dsu_times_for(times: times).each do |t|
|
66
|
-
view_entry_group(time: t)
|
67
|
-
puts
|
68
|
-
end
|
67
|
+
CommandServices::AddEntryService.new(entry: entry, time: time).call
|
68
|
+
view_entry_group(time: time)
|
69
69
|
end
|
70
70
|
|
71
|
+
# def add(description)
|
72
|
+
# times = if options[:date].present?
|
73
|
+
# time = Time.parse(options[:date])
|
74
|
+
# [time, time.yesterday]
|
75
|
+
# else
|
76
|
+
# time = Time.now
|
77
|
+
# if options[:tomorrow].present?
|
78
|
+
# [time.tomorrow, time.tomorrow.yesterday]
|
79
|
+
# elsif options[:yesterday].present?
|
80
|
+
# [time.yesterday, time.yesterday.yesterday]
|
81
|
+
# elsif options[:today].present?
|
82
|
+
# [time, time.yesterday]
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
# entry = Models::Entry.new(description: description)
|
86
|
+
# # NOTE: We need to add the Entry to the date that is the furthest in the future
|
87
|
+
# # (time.max) because this is the DSU entry that the user specified.
|
88
|
+
# CommandServices::AddEntryService.new(entry: entry, time: times.max).call
|
89
|
+
# sorted_dsu_times_for(times: times).each do |t|
|
90
|
+
# view_entry_group(time: t)
|
91
|
+
# puts
|
92
|
+
# end
|
93
|
+
# end
|
94
|
+
|
71
95
|
desc 'list, -l SUBCOMMAND',
|
72
96
|
'Displays DSU entries for the given SUBCOMMAND'
|
73
97
|
subcommand :list, Subcommands::List
|
74
98
|
|
75
|
-
# TODO: Implement this.
|
76
|
-
# desc 'interactive', 'Opens a DSU interactive session'
|
77
|
-
# long_desc ''
|
78
|
-
# option :next_day, type: :boolean, aliases: '-n'
|
79
|
-
# option :previous_day, type: :boolean, aliases: '-p'
|
80
|
-
# option :today, type: :boolean, aliases: '-t'
|
81
|
-
|
82
|
-
# # https://stackoverflow.com/questions/4604905/interactive-prompt-with-thor
|
83
|
-
# def interactive
|
84
|
-
# exit_commands = %w[x q exit quit]
|
85
|
-
# display_interactive_help
|
86
|
-
# loop do
|
87
|
-
# command = ask('dsu > ')
|
88
|
-
# display_interactive_help if command == 'h'
|
89
|
-
# break if exit_commands.include? command
|
90
|
-
# end
|
91
|
-
# say 'Done.'
|
92
|
-
# end
|
93
|
-
|
94
99
|
desc 'config, -c SUBCOMMAND',
|
95
100
|
'Manage configuration file for this gem'
|
96
101
|
subcommand :config, Subcommands::Config
|
@@ -104,17 +109,5 @@ module Dsu
|
|
104
109
|
def version
|
105
110
|
say VERSION
|
106
111
|
end
|
107
|
-
|
108
|
-
private
|
109
|
-
|
110
|
-
def display_interactive_help
|
111
|
-
say 'Interactive Mode Commands:'
|
112
|
-
say '---'
|
113
|
-
say '[h]: show this help screen'
|
114
|
-
say '[t]: next day'
|
115
|
-
say '[y]: previous day'
|
116
|
-
say '[n]: today'
|
117
|
-
say '[x|q|exit|quit]: Exit interactive mode'
|
118
|
-
end
|
119
112
|
end
|
120
113
|
end
|
@@ -1,60 +1,60 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../services/entry_group_writer_service'
|
4
3
|
require_relative '../models/entry'
|
4
|
+
require_relative '../services/entry_group_writer_service'
|
5
|
+
require_relative '../support/colorable'
|
6
|
+
require_relative '../support/descriptable'
|
5
7
|
require_relative '../support/entry_group_loadable'
|
6
8
|
require_relative '../support/folder_locations'
|
9
|
+
require_relative '../support/say'
|
10
|
+
require_relative '../views/shared/messages'
|
7
11
|
|
8
12
|
module Dsu
|
9
13
|
module CommandServices
|
10
|
-
# This class adds (does NOT update) an entry to an entry group
|
14
|
+
# This class adds (does NOT update) an entry to an entry group by
|
15
|
+
# writing it to the appropriate entry group json file.
|
11
16
|
class AddEntryService
|
12
|
-
include
|
13
|
-
include
|
17
|
+
include Support::Colorable
|
18
|
+
include Support::Descriptable
|
19
|
+
include Support::EntryGroupLoadable
|
20
|
+
include Support::FolderLocations
|
21
|
+
include Support::Say
|
14
22
|
|
15
23
|
attr_reader :entry, :entry_group, :time
|
16
24
|
|
25
|
+
delegate :description, to: :entry
|
26
|
+
|
17
27
|
# :entry is an Entry object
|
18
28
|
# :time is a Time object; the time of the entry group.
|
19
29
|
def initialize(entry:, time:)
|
20
30
|
raise ArgumentError, 'entry is nil' if entry.nil?
|
21
|
-
raise ArgumentError, 'entry is the wrong object type' unless entry.is_a?(
|
31
|
+
raise ArgumentError, 'entry is the wrong object type' unless entry.is_a?(Models::Entry)
|
22
32
|
raise ArgumentError, 'time is nil' if time.nil?
|
23
33
|
raise ArgumentError, 'time is the wrong object type' unless time.is_a?(Time)
|
24
34
|
|
25
35
|
@entry = entry
|
26
36
|
@time = time
|
27
|
-
@entry_group =
|
37
|
+
@entry_group = Models::EntryGroup.load(time: time)
|
28
38
|
end
|
29
39
|
|
30
40
|
def call
|
31
41
|
entry.validate!
|
32
42
|
save_entry_group!
|
33
|
-
entry
|
34
|
-
rescue ActiveModel::ValidationError
|
35
|
-
|
36
|
-
|
43
|
+
entry
|
44
|
+
rescue ActiveModel::ValidationError => e
|
45
|
+
header = 'An error was encountered; the entry could not be added added:'
|
46
|
+
Views::Shared::Messages.new(messages: e.message, message_type: :error, options: { header: header }).render
|
37
47
|
end
|
38
48
|
|
39
49
|
private
|
40
50
|
|
41
51
|
attr_writer :entry, :entry_group, :time
|
42
52
|
|
43
|
-
def entry_exists?
|
44
|
-
@entry_exists ||= entry_group.entries.include? entry.uuid
|
45
|
-
end
|
46
|
-
|
47
|
-
def entry_group_hash
|
48
|
-
@entry_group_hash ||= entry_group_hash_for time: time
|
49
|
-
end
|
50
|
-
|
51
53
|
def save_entry_group!
|
52
|
-
raise "Entry #{entry.uuid} already exists in entry group #{time}" if entry_exists?
|
53
|
-
|
54
54
|
entry_group.entries << entry
|
55
55
|
entry_group.validate!
|
56
56
|
|
57
|
-
|
57
|
+
Services::EntryGroupWriterService.new(entry_group: entry_group).call
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
data/lib/dsu/models/entry.rb
CHANGED
@@ -1,39 +1,56 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'active_model'
|
4
4
|
require 'securerandom'
|
5
|
+
require_relative '../support/descriptable'
|
6
|
+
require_relative '../validators/description_validator'
|
5
7
|
|
6
8
|
module Dsu
|
7
9
|
module Models
|
8
|
-
class
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
# This class represents something someone might want to share at their
|
11
|
+
# daily standup (DSU).
|
12
|
+
class Entry
|
13
|
+
include ActiveModel::Model
|
14
|
+
include Support::Descriptable
|
15
|
+
|
16
|
+
validates_with Validators::DescriptionValidator
|
17
|
+
|
18
|
+
attr_reader :description
|
19
|
+
|
20
|
+
def initialize(description:)
|
18
21
|
raise ArgumentError, 'description is the wrong object type' unless description.is_a?(String)
|
19
|
-
raise ArgumentError, 'uuid is the wrong object type' unless uuid.is_a?(String) || uuid.nil?
|
20
22
|
|
21
|
-
|
23
|
+
self.description = description
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def clean_description(description)
|
28
|
+
return if description.nil?
|
22
29
|
|
23
|
-
|
24
|
-
|
25
|
-
description: description
|
26
|
-
})
|
30
|
+
description.strip.gsub(/\s+/, ' ')
|
31
|
+
end
|
27
32
|
end
|
28
33
|
|
29
|
-
def
|
30
|
-
|
34
|
+
def description=(description)
|
35
|
+
@description = self.class.clean_description description
|
31
36
|
end
|
32
37
|
|
38
|
+
def to_h
|
39
|
+
{ description: description }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Override == and hash so that we can compare Entry objects based
|
43
|
+
# on description alone. This is useful for comparing entries in
|
44
|
+
# an array, for example.
|
33
45
|
def ==(other)
|
34
46
|
return false unless other.is_a?(Entry)
|
35
47
|
|
36
|
-
|
48
|
+
description == other.description
|
49
|
+
end
|
50
|
+
alias eql? ==
|
51
|
+
|
52
|
+
def hash
|
53
|
+
description.hash
|
37
54
|
end
|
38
55
|
end
|
39
56
|
end
|
@@ -1,41 +1,53 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
require_relative '../
|
3
|
+
require 'active_model'
|
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
|
-
class
|
16
|
+
# This class represents a group of entries for a given day. IOW,
|
17
|
+
# things someone might want to share at their daily standup (DSU).
|
18
|
+
class EntryGroup
|
19
|
+
include ActiveModel::Model
|
14
20
|
extend Support::EntryGroupLoadable
|
21
|
+
include Support::TimeFormatable
|
15
22
|
|
16
|
-
|
17
|
-
|
23
|
+
attr_accessor :time
|
24
|
+
attr_reader :entries
|
25
|
+
|
26
|
+
validates_with Validators::EntriesValidator
|
27
|
+
validates_with Validators::TimeValidator
|
18
28
|
|
19
29
|
def initialize(time: nil, entries: [])
|
20
30
|
raise ArgumentError, 'time is the wrong object type' unless time.is_a?(Time) || time.nil?
|
21
|
-
raise ArgumentError, 'entries is the wrong object type' unless entries.is_a?(Array) || entries.nil?
|
22
|
-
|
23
|
-
time ||= Time.now
|
24
|
-
time = time.localtime if time.utc?
|
25
31
|
|
26
|
-
|
27
|
-
|
28
|
-
super(hash: {
|
29
|
-
time: time,
|
30
|
-
entries: entries
|
31
|
-
})
|
32
|
+
@time = ensure_local_time(time)
|
33
|
+
self.entries = entries || []
|
32
34
|
end
|
33
35
|
|
34
36
|
class << self
|
35
|
-
def delete(time:, options: {})
|
37
|
+
def delete!(time:, options: {})
|
36
38
|
Services::EntryGroupDeleterService.new(time: time, options: options).call
|
37
39
|
end
|
38
40
|
|
41
|
+
def edit(time:, options: {})
|
42
|
+
# NOTE: Uncomment this line to prohibit edits on
|
43
|
+
# Entry Groups that do not exist (i.e. have no entries).
|
44
|
+
# return new(time: time) unless exists?(time: time)
|
45
|
+
|
46
|
+
load(time: time).tap do |entry_group|
|
47
|
+
Services::EntryGroupEditorService.new(entry_group: entry_group, options: options).call
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
39
51
|
def exists?(time:)
|
40
52
|
Dsu::Services::EntryGroupReaderService.entry_group_file_exists?(time: time)
|
41
53
|
end
|
@@ -43,47 +55,63 @@ module Dsu
|
|
43
55
|
# Loads the EntryGroup from the file system and returns an
|
44
56
|
# instantiated EntryGroup object.
|
45
57
|
def load(time: nil)
|
46
|
-
|
58
|
+
load_entry_group_file_for(time: time)
|
47
59
|
end
|
48
60
|
|
49
61
|
# This function returns a hash whose :time and :entries
|
50
62
|
# key values are hydrated with instantiated Time and Entry
|
51
63
|
# objects.
|
52
|
-
def
|
53
|
-
|
54
|
-
hydrate_entry_group_hash(entry_group_hash: entry_group_hash, time: time)
|
64
|
+
def load_entry_group_for(time:)
|
65
|
+
load_entry_group_file_for(time: time)
|
55
66
|
end
|
56
67
|
end
|
57
68
|
|
58
|
-
def
|
59
|
-
|
69
|
+
def valid_unique_entries
|
70
|
+
entries&.select(&:valid?)&.uniq(&:description)
|
60
71
|
end
|
61
72
|
|
62
|
-
def
|
63
|
-
|
64
|
-
|
65
|
-
|
73
|
+
def clone
|
74
|
+
clone = super
|
75
|
+
|
76
|
+
clone.entries = clone.entries.map(&:clone)
|
77
|
+
clone
|
78
|
+
end
|
79
|
+
|
80
|
+
def entries=(entries)
|
81
|
+
entries ||= []
|
82
|
+
|
83
|
+
raise ArgumentError, 'entries is the wrong object type' unless entries.is_a?(Array)
|
84
|
+
raise ArgumentError, 'entries contains the wrong object type' unless entries.all?(Entry)
|
85
|
+
|
86
|
+
@entries = entries.map(&:clone)
|
66
87
|
end
|
67
88
|
|
68
89
|
# Deletes the entry group file from the file system.
|
69
|
-
def delete
|
70
|
-
self.class.delete(time: time)
|
90
|
+
def delete!
|
91
|
+
self.class.delete!(time: time)
|
92
|
+
self.entries = []
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
def save!
|
97
|
+
delete! and return if entries.empty?
|
98
|
+
|
99
|
+
validate!
|
100
|
+
Services::EntryGroupWriterService.new(entry_group: self).call
|
71
101
|
self
|
72
102
|
end
|
73
103
|
|
74
104
|
def to_h
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
80
|
-
end
|
105
|
+
{
|
106
|
+
time: time.dup,
|
107
|
+
entries: entries.map(&:to_h)
|
108
|
+
}
|
81
109
|
end
|
82
110
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
111
|
+
private
|
112
|
+
|
113
|
+
def ensure_local_time(time)
|
114
|
+
time.nil? ? Time.now : time.dup.localtime
|
87
115
|
end
|
88
116
|
end
|
89
117
|
end
|