timet 1.4.2 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c57d8e7c61f25526dda2e7a5d1208814cadbc93192b7c60c342399c83f0b545
4
- data.tar.gz: 625f4ba71e547e2ebb483d93f1de3812a8b075cacc7afaff7c80554267e5bcc1
3
+ metadata.gz: 7754392fd614ebc62c53293166db637a9593f8497b4cc22ea3ea602bc51546f7
4
+ data.tar.gz: e4f699cf2725be5cf6849a5946323270d078ab1d6fa13892877f17ce161b1d1b
5
5
  SHA512:
6
- metadata.gz: 99b2d1783c14024620865d826d11e16c42146ce220a50ae066cf762231129c42d683d88e4bb50086a5743cc923cdacd1d88f6fd4a4af4f5b5934017bfbb7b476
7
- data.tar.gz: 7d3cb54c375f6fe2b86f0ffedb290d31c5d2348ec877a0848fc9c20d47c90422db6573a5ab0265ef4c0d8f6f89465dda7916f2f6dae59c2296511761b2f63705
6
+ metadata.gz: 2a8be74697ff40c179a0546662fc7b067d0ceddf4da159ea3107c87fef68b3f6cb7a7c3e61ff9c9115bcc799d5d5278fe209629a892077783aa56c77c772c81f
7
+ data.tar.gz: bd9131bccca060ea7d8a7710d9a96b6c784cfeca7312a9146f8fa5c31d8bd0e40b3a58e82ec670328baf5e92d0d2f8b3fa8e80a47a25a0f771c2cb1a6c5e667b
data/README.md CHANGED
@@ -22,6 +22,7 @@
22
22
  - **Block Time Plot:** Visualizes the distribution of tracked time across a specified range of dates. Each column represents the amount of time tracked during a specific hour, with a header showing the hours and a row for each date displaying the time blocks for each hour.
23
23
  - **Tag Distribution Plot:** Illustrates the proportion of total tracked time allocated to each tag, showing the relative contribution of each tag to the overall time tracked.
24
24
  - **Detailed Statistics:** Displays detailed statistics for each tag, including total duration, average duration, and standard deviation.
25
+ - **iCalendar Export:** Easily export your time tracking data to iCalendar format for integration with calendar applications.
25
26
 
26
27
  **Examples:**
27
28
 
@@ -181,7 +182,8 @@ gem install timet
181
182
  | `timet summary yesterday (y)` | Display a report of tracked time for yesterday. | `timet su y` |
182
183
  | `timet summary week (w)` | Display a report of tracked time for the week. | `timet su w` |
183
184
  | `timet summary month (m)` | Display a report of tracked time for the month. | `timet su m` |
184
- | `timet su t --csv=[filename]` | Display a report of tracked time for today and export it to `filename.csv`. | `timet su t --csv=file.csv` |
185
+ | `timet su t --csv=[filename]` | Display a report of tracked time for today and export to CSV file | `timet su t --csv=file.csv` |
186
+ | `timet su w --ics=[filename]` | Display a report of tracked time for week and export to iCalendar file | `timet su w --ics=file.csv` |
185
187
  | `timet delete [id]` | Delete a task by its ID. | `timet d [id]` |
186
188
  | `timet cancel` | Cancel active time tracking. | `timet c` |
187
189
  | `timet edit [id]` | Update a task's notes, tag, start, or end fields. | `timet e [id]` |
@@ -36,8 +36,9 @@ module Timet
36
36
  VALID_STATUSES_FOR_INSERTION = %i[no_items complete].freeze
37
37
 
38
38
  desc "start [tag] --notes='' --pomodoro=[min]",
39
- 'Starts tracking time for a task labeled with the provided [tag], notes and "pomodoro time" in minutes
40
- (optional).'
39
+ 'Start time tracking for a task labeled with the provided [tag], notes and "pomodoro time"
40
+ in minutes (optional).
41
+ tt start project1 "Starting project1" --pomodoro=25'
41
42
  option :notes, type: :string, desc: 'Add a note'
42
43
  option :pomodoro, type: :numeric, desc: 'Pomodoro time in minutes'
43
44
  # Starts a new tracking session with the given tag and optional notes.
@@ -76,7 +77,7 @@ module Timet
76
77
  summary
77
78
  end
78
79
 
79
- desc 'stop', 'stop time tracking'
80
+ desc 'stop', 'Stop time tracking'
80
81
  # Stops the current tracking session if there is one in progress.
81
82
  #
82
83
  # @return [void] This method does not return a value; it performs side effects such as updating the tracking item
@@ -99,7 +100,7 @@ module Timet
99
100
  summary unless display
100
101
  end
101
102
 
102
- desc 'resume (r) [id]', 'resume last task'
103
+ desc 'resume (r) [id]', 'Resume last task (id is an optional parameter) => tt resume'
103
104
  # Resumes the last tracking session if it was completed.
104
105
  #
105
106
  # @return [void] This method does not return a value; it performs side effects such as resuming a tracking session
@@ -131,48 +132,34 @@ module Timet
131
132
  end
132
133
  end
133
134
 
134
- desc 'summary (su) [time_scope] [tag] --csv=csv_filename',
135
- '[time_scope] => [today (t), yesterday (y), week (w), month (m), [start_date]..[end_date]] [tag]'
136
- option :csv, type: :string, desc: 'Export to CSV file'
135
+ desc 'summary (su) [time_scope] [tag] --csv=csv_filename --ics=ics_filename',
136
+ 'Display a summary of tracked time and export to CSV.
137
+ [time_scope] => [today (t), yesterday (y), week (w), month (m). => tt su yesterday
138
+ [start_date]..[end_date]] => tt su 2024-10-03..2024-10-20
139
+ [tag] => tt su Task1
140
+ --csv=csv_filename => tt su month --csv=myfile
141
+ --ics=ics_filename => tt su week --csv=mycalendar'
142
+ option :csv, type: :string, desc: 'Export to CSV'
143
+ option :ics, type: :string, desc: 'Export to iCalendar'
137
144
  # Generates a summary of tracking items based on the provided time_scope and tag, and optionally exports the summary
138
- # to a CSV file.
145
+ # to a CSV file and/or an iCalendar file.
139
146
  #
140
- # @param time_scope [String, nil] The time_scope to apply when generating the summary. Possible values include
141
- # 'today', 'yesterday', 'week', 'month', or a date range in the format '[start_date]..[end_date]'.
142
- # @param tag [String, nil] The tag to time_scope the tracking items by.
147
+ # @param time_scope [String, nil] The filter to apply when fetching items. Possible values include 'today',
148
+ # 'yesterday', 'week', 'month', or a date range in the format 'YYYY-MM-DD..YYYY-MM-DD'.
149
+ # @param tag [String, nil] The tag to filter the items by.
143
150
  #
144
- # @return [void] This method does not return a value; it performs side effects such as displaying the summary and
145
- # exporting to CSV if specified.
146
- #
147
- # @example Generate a summary for today
148
- # summary('today')
149
- #
150
- # @example Generate a summary for a specific tag
151
- # summary(nil, 'work')
152
- #
153
- # @example Generate a summary for a date range and export to CSV
154
- # summary('2023-01-01..2023-01-31', nil, csv: 'summary.csv')
155
- #
156
- # @note The method initializes a `TimeReport` object with the database, time_scope, tag, and optional CSV filename.
157
- # @note The method calls `display` on the `TimeReport` object to show the summary.
158
- # @note If a CSV filename is provided and there are items to export, the method calls `export_sheet` to export the
159
- # summary to a CSV file.
160
- # @note If no items are found to export, it prints a message indicating that no items were found.
151
+ # @return [void] This method does not return a value; it performs side effects such as displaying
152
+ # and exporting the report.
161
153
  def summary(time_scope = nil, tag = nil)
162
- csv_filename = options[:csv]&.split('.')&.first
163
- report = TimeReport.new(@db, time_scope, tag, csv_filename)
164
-
165
- report.display
166
- items = report.items
167
- if csv_filename && items.any?
168
- report.export_sheet
169
- elsif items.empty?
170
- puts 'No items found to export'
171
- end
154
+ options = build_options(time_scope, tag)
155
+ report = TimeReport.new(@db, options)
156
+ display_and_export_report(report, options)
172
157
  end
173
158
 
174
159
  desc 'edit (e) [id] [field] [value]',
175
- 'edit a task, [field] (notes, tag, start or end) and [value] are optional parameters'
160
+ 'Edit task, [field] (notes, tag, start or end) and [value] are optional parameters.
161
+ Update notes => tt edit 12 notes "Update note"
162
+ Update start time => tt edit 12 start 12:33'
176
163
  # Edits a specific tracking item by its ID, allowing the user to modify fields such as notes, tag, start time, or
177
164
  # end time.
178
165
  #
@@ -211,7 +198,7 @@ module Timet
211
198
  display_item(updated_item || item)
212
199
  end
213
200
 
214
- desc 'delete (d) [id]', 'delete a task'
201
+ desc 'delete (d) [id]', 'Delete task => tt d 23'
215
202
  # Deletes a specific tracking item by its ID after confirming with the user.
216
203
  #
217
204
  # @param id [Integer] The ID of the tracking item to be deleted.
@@ -238,7 +225,7 @@ module Timet
238
225
  delete_item_and_print_message(id, "Deleted #{id}")
239
226
  end
240
227
 
241
- desc 'cancel (c)', 'cancel active time tracking'
228
+ desc 'cancel (c)', 'Cancel active time tracking => tt c'
242
229
  # Cancels the active time tracking session by deleting the last tracking item.
243
230
  #
244
231
  # @return [void] This method does not return a value; it performs side effects such as deleting the active tracking
@@ -184,5 +184,81 @@ module Timet
184
184
  tag, notes = item.values_at(Application::FIELD_INDEX['tag'], Application::FIELD_INDEX['notes'])
185
185
  start(tag, notes)
186
186
  end
187
+
188
+ # Builds a hash of options to be used when initializing a TimeReport instance.
189
+ #
190
+ # @param time_scope [String, nil] The filter to apply when fetching items. Possible values include 'today',
191
+ # 'yesterday', 'week', 'month', or a date range in the format 'YYYY-MM-DD..YYYY-MM-DD'.
192
+ # @param tag [String, nil] The tag to filter the items by.
193
+ #
194
+ # @return [Hash] A hash containing the filter, tag, CSV filename, and iCalendar filename.
195
+ #
196
+ # @example Build options with a filter and tag
197
+ # build_options('today', 'work') # => { filter: 'today', tag: 'work', csv: nil, ics: nil }
198
+ def build_options(time_scope, tag)
199
+ csv_filename = options[:csv]&.split('.')&.first
200
+ ics_filename = options[:ics]&.split('.')&.first
201
+ {
202
+ filter: time_scope,
203
+ tag: tag,
204
+ csv: csv_filename,
205
+ ics: ics_filename
206
+ }
207
+ end
208
+
209
+ # @note This class is responsible for exporting reports to CSV and iCalendar formats.
210
+ class ReportExporter
211
+ # Exports the report to a CSV file if the `csv` option is provided.
212
+ #
213
+ # @param report [TimeReport] The report object to export.
214
+ # @param options [Hash] The options hash containing export settings.
215
+ # @option options [String] :csv The filename to use when exporting the report to CSV.
216
+ # @return [void]
217
+ def self.export_csv_report(report, options)
218
+ report.export_csv if options[:csv]
219
+ end
220
+
221
+ # Exports the report to an iCalendar file if the `ics` option is provided.
222
+ #
223
+ # @param report [TimeReport] The report object to export.
224
+ # @param options [Hash] The options hash containing export settings.
225
+ # @option options [String] :ics The filename to use when exporting the report to iCalendar.
226
+ # @return [void]
227
+ def self.export_icalendar_report(report, options)
228
+ report.export_icalendar if options[:ics]
229
+ end
230
+ end
231
+
232
+ # Displays the report and exports it to a CSV file and/or an iCalendar file if specified.
233
+ #
234
+ # @param report [TimeReport] The TimeReport instance to display and export.
235
+ # @param options [Hash] A hash containing the options for exporting the report.
236
+ # @option options [String, nil] :csv The filename to use when exporting the report to CSV.
237
+ # @option options [String, nil] :ics The filename to use when exporting the report to iCalendar.
238
+ #
239
+ # @return [void] This method does not return a value; it performs side effects such as displaying
240
+ # and exporting the report.
241
+ #
242
+ # @example Display and export the report to CSV and iCalendar
243
+ # display_and_export_report(report, { csv: 'report.csv', ics: 'icalendar.ics' })
244
+ def display_and_export_report(report, options)
245
+ report.display
246
+ export_report(report, options)
247
+ end
248
+
249
+ # Exports the given report in CSV and iCalendar formats if there are items, otherwise prints a message.
250
+ #
251
+ # @param report [Report] The report to be exported.
252
+ # @param options [Hash] The options to pass to the exporter.
253
+ # @return [void]
254
+ def export_report(report, options)
255
+ items = report.items
256
+ if items.any?
257
+ ReportExporter.export_csv_report(report, options)
258
+ ReportExporter.export_icalendar_report(report, options)
259
+ else
260
+ puts 'No items found to export'
261
+ end
262
+ end
187
263
  end
188
264
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'date'
4
4
  require 'csv'
5
+ require 'icalendar'
5
6
  require_relative 'time_report_helper'
6
7
  require_relative 'table'
7
8
  require_relative 'time_block_chart'
@@ -24,26 +25,32 @@ module Timet
24
25
  attr_reader :items
25
26
 
26
27
  # Provides access to the CSV filename.
27
- attr_reader :filename
28
+ attr_reader :csv_filename
29
+
30
+ # Provides access to the ICS filename.
31
+ attr_reader :ics_filename
28
32
 
29
33
  # Initializes a new instance of the TimeReport class.
30
34
  #
31
35
  # @param db [Database] The database instance to use for fetching data.
32
- # @param filter [String, nil] The filter to apply when fetching items. Possible values include 'today',
33
- # 'yesterday', 'week', 'month', or a date range in the format 'YYYY-MM-DD..YYYY-MM-DD'.
34
- # @param tag [String, nil] The tag to filter the items by.
35
- # @param csv [String, nil] The filename to use when exporting the report to CSV.
36
+ # @param options [Hash] A hash containing optional parameters.
37
+ # @option options [String, nil] :filter The filter to apply when fetching items. Possible values include 'today',
38
+ # 'yesterday', 'week', 'month', or a date range in the format 'YYYY-MM-DD..YYYY-MM-DD'.
39
+ # @option options [String, nil] :tag The tag to filter the items by.
40
+ # @option options [String, nil] :csv The filename to use when exporting the report to CSV.
41
+ # @option options [String, nil] :ics The filename to use when exporting the report to iCalendar.
36
42
  #
37
43
  # @return [void] This method does not return a value; it performs side effects such as initializing the
38
44
  # instance variables.
39
45
  #
40
46
  # @example Initialize a new TimeReport instance with a filter and tag
41
- # TimeReport.new(db, 'today', 'work', 'report.csv')
42
- def initialize(db, filter = nil, tag = nil, csv = nil)
47
+ # TimeReport.new(db, filter: 'today', tag: 'work', csv: 'report.csv', ics: 'icalendar.ics')
48
+ def initialize(db, options = {})
43
49
  @db = db
44
- @filename = csv
45
- @filter = formatted_filter(filter)
46
- @items = filter ? filter_items(@filter, tag) : @db.all_items
50
+ @csv_filename = options[:csv]
51
+ @ics_filename = options[:ics]
52
+ @filter = formatted_filter(options[:filter])
53
+ @items = options[:filter] ? filter_items(@filter, options[:tag]) : @db.all_items
47
54
  end
48
55
 
49
56
  # Displays the report of tracked time entries.
@@ -94,16 +101,42 @@ module Timet
94
101
  # @return [void] This method does not return a value; it performs side effects such as writing the CSV file.
95
102
  #
96
103
  # @example Export the report to a CSV file
97
- # time_report.export_sheet
104
+ # time_report.export_csv
98
105
  #
99
106
  # @note The method writes the items to a CSV file and prints a confirmation message.
100
- def export_sheet
101
- file_name = "#{filename}.csv"
107
+ def export_csv
108
+ file_name = "#{csv_filename}.csv"
102
109
  write_csv(file_name)
103
110
 
104
111
  puts "The #{file_name} has been exported."
105
112
  end
106
113
 
114
+ def export_icalendar
115
+ file_name = "#{ics_filename}.ics"
116
+
117
+ cal = Icalendar::Calendar.new
118
+ items.each do |item|
119
+ dtstart = Time.at(item[1]).to_datetime
120
+ end_time = item[2] || TimeHelper.current_timestamp
121
+ dtend = Time.at(end_time).to_datetime
122
+
123
+ tag = item[3]
124
+ notes = item[4]
125
+ cal.event do |e|
126
+ e.dtstart = dtstart
127
+ e.dtend = dtend
128
+ e.summary = tag
129
+ e.description = notes
130
+ e.ip_class = 'PRIVATE'
131
+ end
132
+ end
133
+ cal.publish
134
+
135
+ File.write(file_name, cal.to_ical)
136
+
137
+ puts "The #{file_name} has been generated."
138
+ end
139
+
107
140
  private
108
141
 
109
142
  # Writes the items to a CSV file.
data/lib/timet/version.rb CHANGED
@@ -6,6 +6,6 @@ module Timet
6
6
  # @return [String] The version number in the format 'major.minor.patch'.
7
7
  #
8
8
  # @example Get the version of the Timet application
9
- # Timet::VERSION # => '1.4.2'
10
- VERSION = '1.4.2'
9
+ # Timet::VERSION # => '1.4.3'
10
+ VERSION = '1.4.3'
11
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timet
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.2
4
+ version: 1.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Frank Vielma
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-01 00:00:00.000000000 Z
11
+ date: 2024-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor