dsu 0.1.0.alpha.5 → 1.0.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: d8563782a0b4d22e374313aa3373b38e62dec995a6f6d996eaa5fa9c58b0d1cb
4
- data.tar.gz: 65ebebe762dac44300a6d163c03275eaffd66018a83f9836b3f12cb6333569ad
3
+ metadata.gz: fa1b6f69c4de21d556a38cd96f29ba9ad8b7b4b2a9f5d34cda7fccb61f15d63f
4
+ data.tar.gz: 7376022ead177228164448d6fa4b8ee554a35611d45450955c586ed1bf84462a
5
5
  SHA512:
6
- metadata.gz: a412bf735ce124b6df3bb419a1ed925b6b9aaf6cc7e8fdb13773fd883886119d92c03cb4bc68633d57bcfd293c274db16d5504200790f9be65d5d3d3f3e5e21e
7
- data.tar.gz: bf7ac4a28753385155d6e0cd7f1694723deaa3ad0d0e41205f63446c78a2a8b0b09d42f4e5557d3c3aef4befa8a6d46e568d308a1d9fb6c9a0f4110d301c025d
6
+ metadata.gz: 7128d03202e5f9536e6fda51c2dab009dd0ed32f56f00e17b6d1c96cb5420daa8dd0ab71c69d25f811ee41acf14cda05d133211f3b9480b70907736201d7162b
7
+ data.tar.gz: bc276d357add40377ec88b79b8379fad502cea936440c31a81e7e0ed18c1ad766244f0a09b9eb33a1536a0d60d2c7140b429d5643aa6a3d51b2f362cdec60673
data/.rubocop.yml CHANGED
@@ -10,7 +10,7 @@ AllCops:
10
10
  - '.idea/**/*'
11
11
  - 'init/*'
12
12
  - 'Rakefile'
13
- # - '*.gemspec'
13
+ - '*.gemspec'
14
14
  # - 'spec/**/*'
15
15
  - 'vendor/**/*'
16
16
  - 'scratch*.rb'
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
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.
1
12
  ## [0.1.0.alpha.5] - 2023-05-12
2
13
  * Changes
3
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.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dsu (0.1.0.alpha.5)
4
+ dsu (1.0.0)
5
5
  activesupport (~> 7.0, >= 7.0.4)
6
6
  colorize (~> 0.8.1)
7
7
  deco_lite (~> 1.3)
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:
@@ -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. 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.*
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
- # [SHA/COMMAND] [DESCRIPTION]
121
- 3849f0c0 Interative planning meeting 11:00AM.
122
- 586478f5 Pair with Chad on ticket 31211.
123
- 9e5f82c8 Investigate spike ticket 31255.
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
- # ADD a DSU entry: use one of the following commands: [+|a|add] followed by the description.
128
- # EDIT a DSU entry: change the description.
129
- # DELETE a DSU entry: delete the entry or replace the sha with one of the following commands: [-|d|delete].
130
- # NOTE: deleting all the entries will delete the entry group file;
131
- # this is preferable if this is what you want to do :)
132
- # REORDER a DSU entry: reorder the DSU entries in order preference.
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: 3849f0c0 Interative planning meeting 11:00AM.
144
- to: 3849f0c0 Interative planning meeting 12:00AM.
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
- Replace the entry `sha` one of the add commands: `[+|a|add]`.
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
- + Add me to this entry group.
150
+ Add me to this entry group.
154
151
  ```
155
152
 
156
153
  #### Delete an Entry
157
154
 
158
- Simply delete the entry or replace the entry `sha` one of the delete commands: `[-|d|delete]`.
155
+ Simply delete the entry.
159
156
 
160
157
  For example...
161
158
  ```
162
159
  # Delete this this entry from the editor file
163
- 3849f0c0 Interative planning meeting 11:00AM.
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: 3849f0c0 Interative planning meeting 11:00AM.
178
- 586478f5 Pair with Chad on ticket 31211.
179
- 9e5f82c8 Investigate spike ticket 31255.
180
- 59b25ca7 Review Kelsey's PR ticket 30721.
181
- to: 59b25ca7 Review Kelsey's PR ticket 30721.
182
- 9e5f82c8 Investigate spike ticket 31255.
183
- 586478f5 Pair with Chad on ticket 31211.
184
- 3849f0c0 Interative planning meeting 11:00AM.
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,12 +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
- - 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
-
251
238
  ## Installation
252
239
 
253
240
  $ gem install dsu
data/lib/dsu/base_cli.rb CHANGED
@@ -15,9 +15,6 @@ require_relative 'version'
15
15
  require_relative 'views/entry_group/show'
16
16
 
17
17
  module Dsu
18
- #
19
- # The `dsu` command.
20
- #
21
18
  class BaseCLI < ::Thor
22
19
  include Support::Colorable
23
20
  include Support::EntryGroupViewable
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 #{date_option_description}
33
+ \x5
34
+ #{date_option_description}
34
35
 
35
- \x5 -n: Adds a DSU entry having DESCRIPTION to today's date (`Time.now`).
36
+ \x5
37
+ -n: Adds a DSU entry having DESCRIPTION to today's date (`Time.now`).
36
38
 
37
- \x5 -t: Adds a DSU entry having DESCRIPTION to tomorrow's date (`Time.new.tomorrow`).
39
+ \x5
40
+ -t: Adds a DSU entry having DESCRIPTION to tomorrow's date (`Time.new.tomorrow`).
38
41
 
39
- \x5 -y: Adds a DSU entry having DESCRIPTION to yesterday's date (`Time.new.yesterday`).
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
- times = if options[:date].present?
49
- time = Time.parse(options[:date])
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
- [time.tomorrow, time.tomorrow.yesterday]
59
+ Time.now.tomorrow
55
60
  elsif options[:yesterday].present?
56
- [time.yesterday, time.yesterday.yesterday]
61
+ Time.now.yesterday
57
62
  elsif options[:today].present?
58
- [time, time.yesterday]
63
+ Time.now
59
64
  end
60
65
  end
61
66
  entry = Models::Entry.new(description: description)
62
- # NOTE: We need to add the Entry to the date that is the furthest in the future
63
- # (time.max) because this is the DSU entry that the user specified.
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 Dsu::Support::EntryGroupLoadable
13
- include Dsu::Support::FolderLocations
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?(Dsu::Models::Entry)
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 = Dsu::Models::EntryGroup.load(time: time)
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.uuid
34
- rescue ActiveModel::ValidationError
35
- puts "Error(s) encountered: #{entry.errors.full_messages}"
36
- raise
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
- Dsu::Services::EntryGroupWriterService.new(entry_group: entry_group).call
57
+ Services::EntryGroupWriterService.new(entry_group: entry_group).call
58
58
  end
59
59
  end
60
60
  end
@@ -1,44 +1,56 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'deco_lite'
3
+ require 'active_model'
4
4
  require 'securerandom'
5
5
  require_relative '../support/descriptable'
6
+ require_relative '../validators/description_validator'
6
7
 
7
8
  module Dsu
8
9
  module Models
9
- class Entry < DecoLite::Model
10
+ # This class represents something someone might want to share at their
11
+ # daily standup (DSU).
12
+ class Entry
13
+ include ActiveModel::Model
10
14
  include Support::Descriptable
11
15
 
12
- ENTRY_UUID_REGEX = /\A[0-9a-f]{8}\z/i
16
+ validates_with Validators::DescriptionValidator
13
17
 
14
- validates :uuid, presence: true, format: {
15
- with: ENTRY_UUID_REGEX,
16
- message: 'is the wrong format. ' \
17
- '0-9, a-f, and 8 characters were expected.' \
18
- }
19
- validates :description, presence: true, length: { minimum: 2, maximum: 256 }
18
+ attr_reader :description
20
19
 
21
- def initialize(description:, uuid: nil)
22
- raise ArgumentError, 'description is nil' if description.nil?
20
+ def initialize(description:)
23
21
  raise ArgumentError, 'description is the wrong object type' unless description.is_a?(String)
24
- raise ArgumentError, 'uuid is the wrong object type' unless uuid.is_a?(String) || uuid.nil?
25
22
 
26
- uuid ||= SecureRandom.uuid[0..7]
23
+ self.description = description
24
+ end
25
+
26
+ class << self
27
+ def clean_description(description)
28
+ return if description.nil?
29
+
30
+ description.strip.gsub(/\s+/, ' ')
31
+ end
32
+ end
27
33
 
28
- super(hash: {
29
- uuid: uuid,
30
- description: description
31
- })
34
+ def description=(description)
35
+ @description = self.class.clean_description description
32
36
  end
33
37
 
34
- def required_fields
35
- %i[uuid description]
38
+ def to_h
39
+ { description: description }
36
40
  end
37
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.
38
45
  def ==(other)
39
46
  return false unless other.is_a?(Entry)
40
47
 
41
- uuid == other.uuid && description == other.description
48
+ description == other.description
49
+ end
50
+ alias eql? ==
51
+
52
+ def hash
53
+ description.hash
42
54
  end
43
55
  end
44
56
  end