timet 1.4.1 → 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 +4 -4
- data/CHANGELOG.md +44 -0
- data/README.md +51 -40
- data/lib/timet/application.rb +28 -41
- data/lib/timet/application_helper.rb +76 -0
- data/lib/timet/table.rb +24 -44
- data/lib/timet/tag_distribution.rb +53 -14
- data/lib/timet/time_report.rb +57 -17
- data/lib/timet/time_statistics.rb +82 -0
- data/lib/timet/version.rb +2 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7754392fd614ebc62c53293166db637a9593f8497b4cc22ea3ea602bc51546f7
|
4
|
+
data.tar.gz: e4f699cf2725be5cf6849a5946323270d078ab1d6fa13892877f17ce161b1d1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a8be74697ff40c179a0546662fc7b067d0ceddf4da159ea3107c87fef68b3f6cb7a7c3e61ff9c9115bcc799d5d5278fe209629a892077783aa56c77c772c81f
|
7
|
+
data.tar.gz: bd9131bccca060ea7d8a7710d9a96b6c784cfeca7312a9146f8fa5c31d8bd0e40b3a58e82ec670328baf5e92d0d2f8b3fa8e80a47a25a0f771c2cb1a6c5e667b
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,49 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [1.4.2] - 2024-11-01
|
4
|
+
|
5
|
+
**Improvements:**
|
6
|
+
|
7
|
+
- Refactored the `table` method in `lib/timet/table.rb` to simplify its return value and remove unnecessary complexity.
|
8
|
+
- Updated the `process_time_entries` and `process_time_block_item` methods to streamline the processing of time entries and time block items.
|
9
|
+
- Integrated the `TimeStatistics` class into the `TagDistribution` module to calculate and display detailed statistics for each tag.
|
10
|
+
- Modified the `tag_distribution` method to use the `TimeStatistics` class for generating tag distribution information.
|
11
|
+
- Updated the `display` method in `lib/timet/time_report.rb` to use the refactored methods and integrate the new tag distribution logic.
|
12
|
+
- Added the `descriptive_statistics` gem to the Gemfile to support statistical calculations.
|
13
|
+
- Created a new `TimeStatistics` class in `lib/timet/time_statistics.rb` to analyze and summarize time duration data associated with various tags.
|
14
|
+
- Implemented methods in `TimeStatistics` to calculate total duration by tag, sorted duration by tag, average duration by tag, standard deviation by tag, and additional descriptive statistics by tag.
|
15
|
+
- Updated Gemfile.lock to reflect the new dependency.
|
16
|
+
- Update README.md
|
17
|
+
|
18
|
+
**Tasks:**
|
19
|
+
|
20
|
+
- Refactor time tracking report methods and integrate `TimeStatistics`.
|
21
|
+
- Add `descriptive_statistics` gem and create `TimeStatistics` class.
|
22
|
+
- Fix typo in `README.md`.
|
23
|
+
|
24
|
+
**Bug fixes:**
|
25
|
+
|
26
|
+
- Fixed a typo in `README.md`.
|
27
|
+
|
28
|
+
## [1.4.1] - 2024-10-31
|
29
|
+
|
30
|
+
**Improvements:**
|
31
|
+
|
32
|
+
- Refactor `resume` method to accept an optional `id` parameter for resuming a specific tracking item.
|
33
|
+
- Renamed `last_item_status` method to `item_status` in the `Database` class for better clarity and flexibility.
|
34
|
+
- Updated `Application` class methods (`start`, `stop`, `resume`, `cancel`) to use the new `item_status` method.
|
35
|
+
- Introduced `determine_status` method within the `Database` class to encapsulate status determination logic.
|
36
|
+
- Updated documentation and test cases to reflect the changes and ensure consistent status handling.
|
37
|
+
- Bumped version to reflect the changes.
|
38
|
+
- Updated README.md to include new features and improvements.
|
39
|
+
|
40
|
+
**Tasks:**
|
41
|
+
|
42
|
+
- Refactor `resume` method.
|
43
|
+
- Bump version.
|
44
|
+
- Update README.md.
|
45
|
+
- Refactor `Database` class for improved status determination and encapsulation.
|
46
|
+
|
3
47
|
## [1.4.0] - 2024-10-29
|
4
48
|
|
5
49
|
**Improvements:**
|
data/README.md
CHANGED
@@ -7,23 +7,24 @@
|
|
7
7
|
|
8
8
|

|
9
9
|
|
10
|
-
Timet
|
10
|
+
[Timet](https://rubygems.org/gems/timet) is a command-line tool designed to track your activities by recording the time spent on each task. This allows you to monitor your work hours and productivity directly from your terminal without needing a graphical interface. Essentially, it's a way to log your time spent on different projects or tasks using simple text commands.
|
11
11
|
|
12
12
|
🔑 **Key Features:**
|
13
13
|
|
14
|
-
- **Local Data Storage:** Timet
|
14
|
+
- **Local Data Storage:** Timet uses SQLite to store your time tracking data locally, ensuring privacy and security.
|
15
15
|
- **Lightweight and Fast:** Its efficient design and local data storage make Timet a speedy and responsive tool.
|
16
16
|
- **Structured Data:** SQLite ensures your data is organized and easily accessible.
|
17
17
|
- **Scalability:** Timet can handle growing time tracking needs.
|
18
18
|
- **Data Integrity:** SQLite maintains the accuracy and consistency of your data.
|
19
19
|
- **Querying and Reporting:** Generate detailed reports for specific periods.
|
20
20
|
- **CSV Export:** Easily export your time tracking data to CSV format for further analysis or sharing.
|
21
|
-
- **Pomodoro Integration:** The pomodoro option in the start command enhances time tracking by integrating the Pomodoro Technique.
|
22
|
-
- **Block Time Plot:** Visualizes the distribution of tracked time across a specified range of dates
|
21
|
+
- **Pomodoro Integration:** The `pomodoro` option in the `start` command enhances time tracking by integrating the Pomodoro Technique.
|
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
|
+
- **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.
|
24
26
|
|
25
|
-
|
26
|
-
Examples:
|
27
|
+
**Examples:**
|
27
28
|
|
28
29
|

|
29
30
|
|
@@ -32,10 +33,9 @@ Examples:
|
|
32
33
|
- Ruby version: >= 3.0.0
|
33
34
|
- sqlite3: > 1.7
|
34
35
|
|
35
|
-
|
36
|
+
For older versions of Ruby and Sqlite:
|
36
37
|
|
37
38
|
- [Ruby >= 2.7](https://github.com/frankvielma/timet/tree/ruby-2.7.0)
|
38
|
-
|
39
39
|
- [Ruby >= 2.4](https://github.com/frankvielma/timet/tree/ruby-2.4.0)
|
40
40
|
|
41
41
|
## 💾 Installation
|
@@ -54,7 +54,8 @@ gem install timet
|
|
54
54
|
- `tt`: An alias for the `timet` command, providing a shorter alternative.
|
55
55
|
|
56
56
|
---
|
57
|
-
|
57
|
+
|
58
|
+
- **`timet start [tag] --notes="" --pomodoro=[minutes]`:** Starts tracking time for a task labeled with the provided [tag], notes, and "pomodoro time" in minutes (optional). Example:
|
58
59
|
|
59
60
|
```bash
|
60
61
|
timet start task1 --notes="Meeting with client" --pomodoro=25
|
@@ -81,15 +82,15 @@ gem install timet
|
|
81
82
|
|
82
83
|
The `pomodoro` option in the `start` command enhances time tracking by integrating the Pomodoro Technique. Users can specify a Pomodoro session length in minutes, like `pomodoro=25`, to start a 25-minute work interval. The app automatically tracks time and notifies users when the interval ends, helping maintain focus.
|
83
84
|
|
84
|
-
**Benefits
|
85
|
+
**Benefits:**
|
85
86
|
|
86
|
-
|
87
|
-
|
88
|
-
|
87
|
+
- **Flexibility:** Supports various productivity strategies.
|
88
|
+
- **Focus:** Encourages disciplined work practices.
|
89
|
+
- **Productivity:** Helps achieve higher productivity and better time management.
|
89
90
|
|
90
91
|
---
|
91
92
|
|
92
|
-
-
|
93
|
+
- **`timet stop`:** Stops tracking the current task, records the elapsed time, and displays the total time spent on all tasks.
|
93
94
|
|
94
95
|
```bash
|
95
96
|
timet stop
|
@@ -105,8 +106,14 @@ gem install timet
|
|
105
106
|
| Total: | 01:00:00 | |
|
106
107
|
+-------+------------+--------+----------+----------+----------+--------------------------+
|
107
108
|
```
|
109
|
+
|
108
110
|
---
|
109
|
-
|
111
|
+
|
112
|
+
- **`timet resume [id]`:** This command allows users to quickly resume tracking a task that was previously in progress. If an ID is provided, it resumes the tracking session for the specified task. If no ID is provided, it resumes the last completed task.
|
113
|
+
|
114
|
+
```bash
|
115
|
+
timet resume 1
|
116
|
+
```
|
110
117
|
|
111
118
|
```
|
112
119
|
Tracked time report [today]:
|
@@ -119,10 +126,12 @@ gem install timet
|
|
119
126
|
| Total: | 01:00:00 | |
|
120
127
|
+-------+------------+--------+----------+----------+----------+--------------------------+
|
121
128
|
```
|
129
|
+
|
122
130
|
---
|
123
|
-
- **timet edit**: It allows users to update a task's notes, tag, start, or end fields. Users can either interactively select the field and provide a new value or specify them directly in the command.
|
124
131
|
|
125
|
-
-
|
132
|
+
- **`timet edit`:** Allows users to update a task's notes, tag, start, or end fields. Users can either interactively select the field and provide a new value or specify them directly in the command.
|
133
|
+
|
134
|
+
**Interactive Mode:**
|
126
135
|
|
127
136
|
```bash
|
128
137
|
timet edit 1
|
@@ -145,7 +154,7 @@ gem install timet
|
|
145
154
|
End
|
146
155
|
```
|
147
156
|
|
148
|
-
|
157
|
+
**Direct Specification Mode:**
|
149
158
|
|
150
159
|
```bash
|
151
160
|
timet e 1 notes "New Meeting Notes"
|
@@ -163,24 +172,24 @@ gem install timet
|
|
163
172
|
+-------+------------+--------+----------+----------+----------+--------------------------+
|
164
173
|
```
|
165
174
|
|
166
|
-
## 📋
|
175
|
+
## 📋 Command Reference
|
167
176
|
|
168
|
-
| Command
|
169
|
-
|
|
170
|
-
| `timet start [tag] --notes=''
|
171
|
-
| `timet stop`
|
172
|
-
| `timet summary today (t)`
|
173
|
-
| `timet summary yesterday (y)`
|
174
|
-
| `timet summary week (w)`
|
175
|
-
| `timet summary month (m)`
|
176
|
-
| `timet su t --csv=[filename]`
|
177
|
-
| `timet
|
178
|
-
| `timet delete [id]`
|
179
|
-
| `timet cancel`
|
180
|
-
| `timet edit [id]`
|
181
|
-
| `timet su [date]`
|
182
|
-
| `timet su [start_date]..[end_date]`
|
183
|
-
| `timet resume [id]`
|
177
|
+
| Command | Description | Example Usage |
|
178
|
+
| -------------------------------------------- | --------------------------------------------------------------------------- | --------------------------------- |
|
179
|
+
| `timet start [tag] --notes='' --pomodoro=[time]` | Start tracking time for a task labeled [tag] and notes (optional). | `timet start Task "My notes" 25` |
|
180
|
+
| `timet stop` | Stop tracking time. | `timet stop` |
|
181
|
+
| `timet summary today (t)` | Display a report of tracked time for today. | `timet su t` or `timet su` |
|
182
|
+
| `timet summary yesterday (y)` | Display a report of tracked time for yesterday. | `timet su y` |
|
183
|
+
| `timet summary week (w)` | Display a report of tracked time for the week. | `timet su w` |
|
184
|
+
| `timet summary month (m)` | Display a report of tracked time for the month. | `timet su m` |
|
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` |
|
187
|
+
| `timet delete [id]` | Delete a task by its ID. | `timet d [id]` |
|
188
|
+
| `timet cancel` | Cancel active time tracking. | `timet c` |
|
189
|
+
| `timet edit [id]` | Update a task's notes, tag, start, or end fields. | `timet e [id]` |
|
190
|
+
| `timet su [date]` | Display a report of tracked time for a specific date. | `timet su 2024-01-03` |
|
191
|
+
| `timet su [start_date]..[end_date]` | Display a report of tracked time for a date range. | `timet su 2024-01-02..2024-01-03` |
|
192
|
+
| `timet resume (r) [id]` | Resume tracking a task by ID or the last completed task. | `timet resume [id]` |
|
184
193
|
|
185
194
|
### Date Range in Summary
|
186
195
|
|
@@ -188,20 +197,21 @@ The `timet summary` command now supports specifying a date range for generating
|
|
188
197
|
|
189
198
|
#### Examples:
|
190
199
|
|
191
|
-
- **Single Date
|
200
|
+
- **Single Date:** Display a report for a specific date.
|
192
201
|
|
193
202
|
```sh
|
194
203
|
timet su 2024-01-03
|
195
204
|
```
|
196
205
|
|
197
|
-
- **Date Range
|
206
|
+
- **Date Range:** Display a report for a date range.
|
207
|
+
|
198
208
|
```sh
|
199
209
|
timet su 2024-01-02..2024-01-03
|
200
210
|
```
|
201
211
|
|
202
212
|
## Data
|
203
213
|
|
204
|
-
Timet's data is stored in
|
214
|
+
Timet's data is stored in `~/.timet.db`.
|
205
215
|
|
206
216
|
## Development
|
207
217
|
|
@@ -211,13 +221,14 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
211
221
|
|
212
222
|
## Contributing
|
213
223
|
|
214
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/frankvielma/timet. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/frankvielma/timet/blob/master/CODE_OF_CONDUCT.md).
|
224
|
+
Bug reports and pull requests are welcome on GitHub at [https://github.com/frankvielma/timet](https://github.com/frankvielma/timet). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/frankvielma/timet/blob/master/CODE_OF_CONDUCT.md).
|
215
225
|
|
216
226
|
## Buy Me A Coffee! ☕
|
217
227
|
|
218
228
|
Many people have contacted me asking how to contribute. Any contribution, from a virtual coffee to a kind word, is greatly appreciated and helps me continue my work. Please only donate if you're able, as there are no refunds. Your support is entirely voluntary, and I thank you for your consideration.
|
219
229
|
|
220
230
|
**Bitcoin Address:**
|
231
|
+
|
221
232
|
```sh
|
222
233
|
bc1qkg9me2jsuhpzu2hp9kkpxagwtf9ewnyfl4kszl
|
223
234
|
```
|
@@ -232,4 +243,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
232
243
|
|
233
244
|
## Code of Conduct
|
234
245
|
|
235
|
-
Everyone interacting in the Timet project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/frankvielma/timet/blob/master/CODE_OF_CONDUCT.md).
|
246
|
+
Everyone interacting in the Timet project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [code of conduct](https://github.com/frankvielma/timet/blob/master/CODE_OF_CONDUCT.md).
|
data/lib/timet/application.rb
CHANGED
@@ -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
|
-
'
|
40
|
-
|
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', '
|
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]', '
|
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
|
-
'
|
136
|
-
|
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
|
141
|
-
#
|
142
|
-
# @param tag [String, nil] The tag to
|
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
|
145
|
-
# exporting
|
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
|
-
|
163
|
-
report = TimeReport.new(@db,
|
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
|
-
'
|
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]', '
|
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)', '
|
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
|
data/lib/timet/table.rb
CHANGED
@@ -9,12 +9,12 @@ module Timet
|
|
9
9
|
# @example
|
10
10
|
# table
|
11
11
|
#
|
12
|
-
# @return [
|
12
|
+
# @return [String] The time block string.
|
13
13
|
#
|
14
14
|
# @note
|
15
15
|
# - The method relies on the `header`, `process_time_entries`, `separator`, and `total` methods.
|
16
16
|
# - The `header` method is responsible for printing the table header.
|
17
|
-
# - The `process_time_entries` method processes the time entries and returns the time block
|
17
|
+
# - The `process_time_entries` method processes the time entries and returns the time block.
|
18
18
|
# - The `separator` method returns a string representing the separator line.
|
19
19
|
# - The `total` method prints the total duration.
|
20
20
|
#
|
@@ -24,10 +24,10 @@ module Timet
|
|
24
24
|
# @see #total
|
25
25
|
def table
|
26
26
|
header
|
27
|
-
time_block
|
27
|
+
time_block = process_time_entries
|
28
28
|
puts separator
|
29
29
|
total
|
30
|
-
|
30
|
+
time_block
|
31
31
|
end
|
32
32
|
|
33
33
|
# Formats the header of the time tracking report table.
|
@@ -62,73 +62,53 @@ module Timet
|
|
62
62
|
'+-------+------------+--------+----------+----------+----------+--------------------+'
|
63
63
|
end
|
64
64
|
|
65
|
-
# Processes
|
65
|
+
# Processes time entries and generates a time block structure.
|
66
66
|
#
|
67
|
-
# @return [
|
68
|
-
#
|
69
|
-
# @example
|
70
|
-
# items = [
|
71
|
-
# [start_time1, end_time1, tag1],
|
72
|
-
# [start_time2, end_time2, tag2]
|
73
|
-
# ]
|
74
|
-
# process_time_entries
|
75
|
-
# #=> [{ '2024-10-21' => { 8 => [duration1, tag1], 9 => [duration2, tag2] } },
|
76
|
-
# { tag1 => total_duration1, tag2 => total_duration2 }]
|
67
|
+
# @return [Hash] A nested hash representing the time block structure.
|
77
68
|
#
|
78
69
|
# @note
|
79
|
-
# - The method
|
80
|
-
# -
|
81
|
-
# -
|
82
|
-
# - The `
|
70
|
+
# - The method iterates over each item in the `items` array.
|
71
|
+
# - For each item, it calls `display_time_entry` to display the time entry.
|
72
|
+
# - It then processes the time block item using `process_time_block_item`.
|
73
|
+
# - The `TimeHelper.extract_date` method is used to extract the date from the items.
|
83
74
|
#
|
84
|
-
# @see #items
|
85
75
|
# @see #display_time_entry
|
86
76
|
# @see #process_time_block_item
|
77
|
+
# @see TimeHelper#extract_date
|
87
78
|
def process_time_entries
|
88
|
-
duration_by_tag = Hash.new(0)
|
89
79
|
time_block = Hash.new { |hash, key| hash[key] = {} }
|
90
80
|
|
91
81
|
items.each_with_index do |item, idx|
|
92
82
|
display_time_entry(item, TimeHelper.extract_date(items, idx))
|
93
|
-
time_block
|
83
|
+
time_block = process_time_block_item(item, time_block)
|
94
84
|
end
|
95
|
-
|
85
|
+
|
86
|
+
time_block
|
96
87
|
end
|
97
88
|
|
98
|
-
# Processes a time block item and updates the time block
|
89
|
+
# Processes a single time block item and updates the time block structure.
|
99
90
|
#
|
100
|
-
# @param item [Array]
|
101
|
-
# @param time_block [Hash]
|
102
|
-
# slots and their corresponding values.
|
103
|
-
# @param duration_by_tag [Hash] A hash containing the total duration by tag.
|
91
|
+
# @param item [Array] An array containing the item details, including start time, end time, and tag.
|
92
|
+
# @param time_block [Hash] The current time block structure.
|
104
93
|
#
|
105
|
-
# @return [
|
106
|
-
# by tag hash.
|
107
|
-
#
|
108
|
-
# @example
|
109
|
-
# item = [nil, Time.new(2024, 10, 21, 8, 0, 0), Time.new(2024, 10, 21, 9, 0, 0), 'work']
|
110
|
-
# time_block = {}
|
111
|
-
# duration_by_tag = {}
|
112
|
-
# process_time_block_item(item, time_block, duration_by_tag)
|
113
|
-
# #=> [{ '2024-10-21' => { 8 => [3600, 'work'] } }, { 'work' => 3600 }]
|
94
|
+
# @return [Hash] The updated time block structure.
|
114
95
|
#
|
115
96
|
# @note
|
116
|
-
# - The method
|
117
|
-
# -
|
118
|
-
# -
|
97
|
+
# - The method extracts the start time, end time, and tag from the item.
|
98
|
+
# - It calculates the number of seconds per hour block using `TimeHelper.count_seconds_per_hour_block`.
|
99
|
+
# - It converts the start time to a date using `TimeHelper.timestamp_to_date`.
|
100
|
+
# - It updates the time block structure by adding the new block hour to the existing structure.
|
119
101
|
#
|
120
102
|
# @see TimeHelper#count_seconds_per_hour_block
|
121
103
|
# @see TimeHelper#timestamp_to_date
|
122
|
-
# @see TimeHelper#calculate_duration
|
123
104
|
# @see #add_hashes
|
124
|
-
def process_time_block_item(item, time_block
|
105
|
+
def process_time_block_item(item, time_block)
|
125
106
|
_, start_time, end_time, tag = item
|
126
107
|
|
127
108
|
block_hour = TimeHelper.count_seconds_per_hour_block(start_time, end_time, tag)
|
128
109
|
date_line = TimeHelper.timestamp_to_date(start_time)
|
129
110
|
time_block[date_line] = add_hashes(time_block[date_line], block_hour)
|
130
|
-
|
131
|
-
[time_block, duration_by_tag]
|
111
|
+
time_block
|
132
112
|
end
|
133
113
|
|
134
114
|
# Displays a single time entry in the report.
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'time_statistics'
|
3
4
|
module Timet
|
4
5
|
# The TagDistribution module provides functionality to format and display the distribution of tags based on their
|
5
6
|
# durations. This is particularly useful for visualizing how time is distributed across different tags in a project
|
@@ -12,20 +13,23 @@ module Timet
|
|
12
13
|
# Formats and displays the tag distribution.
|
13
14
|
#
|
14
15
|
# @param duration_by_tag [Hash<String, Integer>] A hash where keys are tags and values are durations in seconds.
|
16
|
+
# @param colors [Hash<String, String>] A hash where keys are tags and values are color codes for display.
|
15
17
|
# @return [void] This method outputs the formatted tag distribution to the console.
|
16
18
|
#
|
17
19
|
# @example
|
18
20
|
# duration_by_tag = { "timet" => 3600, "nextjs" => 1800 }
|
19
|
-
#
|
21
|
+
# colors = { "timet" => "\e[31m", "nextjs" => "\e[32m" }
|
22
|
+
# Formatter.format_tag_distribution(duration_by_tag, colors)
|
20
23
|
# # Output:
|
21
|
-
# # timet: 66.67% ====================
|
22
|
-
# # nextjs: 33.33% ==========
|
23
|
-
def tag_distribution(
|
24
|
-
|
24
|
+
# # \e[31m timet: 66.67% ==================== \e[0m
|
25
|
+
# # \e[32m nextjs: 33.33% ========== \e[0m
|
26
|
+
def tag_distribution(colors)
|
27
|
+
time_stats = TimeStatistics.new(@items)
|
28
|
+
total = time_stats.total_duration
|
29
|
+
|
25
30
|
return unless total.positive?
|
26
31
|
|
27
|
-
|
28
|
-
process_and_print_tags(sorted_duration_by_tag, total, colors)
|
32
|
+
process_and_print_tags(time_stats, total, colors)
|
29
33
|
end
|
30
34
|
|
31
35
|
# Processes and prints the tag distribution information.
|
@@ -34,15 +38,50 @@ module Timet
|
|
34
38
|
# tag and its corresponding duration, sorted by duration in descending order.
|
35
39
|
# @param total [Numeric] The total duration of all tags combined.
|
36
40
|
# @return [void] This method outputs the tag distribution information to the standard output.
|
37
|
-
def process_and_print_tags(
|
38
|
-
sorted_duration_by_tag.each do |tag, duration|
|
39
|
-
|
40
|
-
horizontal_bar = (BLOCK_CHAR * bar_length).to_s.color(colors[tag] + 1)
|
41
|
-
tag = tag[0..TAG_SIZE - 1] if tag.size >= TAG_SIZE
|
42
|
-
puts "#{tag.rjust(TAG_SIZE)}: #{value.to_s.rjust(5)}% #{horizontal_bar}"
|
41
|
+
def process_and_print_tags(time_stats, total, colors)
|
42
|
+
time_stats.sorted_duration_by_tag.each do |tag, duration|
|
43
|
+
print_tag_info(tag, duration, total, time_stats, colors)
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
47
|
+
# Prints the detailed information for a specific tag.
|
48
|
+
#
|
49
|
+
# @param tag [String] The tag for which to print the information.
|
50
|
+
# @param duration [Numeric] The duration associated with the tag.
|
51
|
+
# @param total [Numeric] The total duration of all tags combined.
|
52
|
+
# @param time_stats [Object] An object containing time statistics for the tags.
|
53
|
+
# @param colors [Hash] A hash mapping tags to color indices for display.
|
54
|
+
# @return [void] This method outputs the tag information to the standard output.
|
55
|
+
def print_tag_info(tag, duration, total, time_stats, colors)
|
56
|
+
value, bar_length = calculate_value_and_bar_length(duration, total)
|
57
|
+
horizontal_bar = generate_horizontal_bar(bar_length, colors[tag])
|
58
|
+
formatted_tag = tag[0...TAG_SIZE].rjust(TAG_SIZE)
|
59
|
+
stats = generate_stats(tag, time_stats)
|
60
|
+
|
61
|
+
puts "#{formatted_tag}: #{value.to_s.rjust(5)}% #{horizontal_bar} [#{stats}]"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Generates a horizontal bar for display based on the bar length and color index.
|
65
|
+
#
|
66
|
+
# @param bar_length [Numeric] The length of the bar to generate.
|
67
|
+
# @param color_index [Numeric] The color index to use for the bar.
|
68
|
+
# @return [String] The generated horizontal bar string.
|
69
|
+
def generate_horizontal_bar(bar_length, color_index)
|
70
|
+
(BLOCK_CHAR * bar_length).to_s.color(color_index + 1)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Generates the statistics string for a given tag.
|
74
|
+
#
|
75
|
+
# @param tag [String] The tag for which to generate the statistics.
|
76
|
+
# @param time_stats [Object] An object containing time statistics for the tags.
|
77
|
+
# @return [String] The generated statistics string.
|
78
|
+
def generate_stats(tag, time_stats)
|
79
|
+
total_hours = (time_stats.total_duration_by_tag[tag] / 3600.0).round(1)
|
80
|
+
avg_minutes = (time_stats.average_by_tag[tag] / 60.0).round(1)
|
81
|
+
sd_minutes = (time_stats.standard_deviation_by_tag[tag] / 60).round(1)
|
82
|
+
"T: #{total_hours}h, AVG: #{avg_minutes}min SD: #{sd_minutes}min".gray
|
83
|
+
end
|
84
|
+
|
46
85
|
# Calculates the percentage value and bar length for a given duration and total duration.
|
47
86
|
#
|
48
87
|
# @param duration [Numeric] The duration for the current tag.
|
@@ -53,7 +92,7 @@ module Timet
|
|
53
92
|
# calculate_value_and_bar_length(50, 100, 2) #=> [50.0, 25]
|
54
93
|
def calculate_value_and_bar_length(duration, total)
|
55
94
|
value = duration.to_f / total
|
56
|
-
percentage_value = (duration.to_f / total * 100).round(
|
95
|
+
percentage_value = (duration.to_f / total * 100).round(1)
|
57
96
|
bar_length = (value * MAX_BAR_LENGTH).round
|
58
97
|
[percentage_value, bar_length]
|
59
98
|
end
|
data/lib/timet/time_report.rb
CHANGED
@@ -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 :
|
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
|
33
|
-
#
|
34
|
-
#
|
35
|
-
# @
|
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,
|
47
|
+
# TimeReport.new(db, filter: 'today', tag: 'work', csv: 'report.csv', ics: 'icalendar.ics')
|
48
|
+
def initialize(db, options = {})
|
43
49
|
@db = db
|
44
|
-
@
|
45
|
-
@
|
46
|
-
@
|
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.
|
@@ -54,15 +61,22 @@ module Timet
|
|
54
61
|
# time_report.display
|
55
62
|
#
|
56
63
|
# @note The method formats and prints the table header, rows, and total duration.
|
64
|
+
#
|
65
|
+
# @param items [Array<Hash>] The list of time entries to be displayed.
|
66
|
+
# @param options [Hash] Additional options for customizing the display (e.g., color scheme).
|
67
|
+
#
|
68
|
+
# @see #table
|
69
|
+
# @see #print_time_block_chart
|
70
|
+
# @see #tag_distribution
|
57
71
|
def display
|
58
|
-
return puts 'No tracked time found for the specified filter.' if items.empty?
|
72
|
+
return puts 'No tracked time found for the specified filter.' if @items.empty?
|
59
73
|
|
60
|
-
time_block
|
74
|
+
time_block = table
|
61
75
|
|
62
|
-
colors =
|
76
|
+
colors = @items.map { |x| x[3] }.uniq.each_with_index.to_h
|
63
77
|
print_time_block_chart(time_block, colors)
|
64
78
|
|
65
|
-
tag_distribution(
|
79
|
+
tag_distribution(colors)
|
66
80
|
end
|
67
81
|
|
68
82
|
# Displays a single row of the report.
|
@@ -87,16 +101,42 @@ module Timet
|
|
87
101
|
# @return [void] This method does not return a value; it performs side effects such as writing the CSV file.
|
88
102
|
#
|
89
103
|
# @example Export the report to a CSV file
|
90
|
-
# time_report.
|
104
|
+
# time_report.export_csv
|
91
105
|
#
|
92
106
|
# @note The method writes the items to a CSV file and prints a confirmation message.
|
93
|
-
def
|
94
|
-
file_name = "#{
|
107
|
+
def export_csv
|
108
|
+
file_name = "#{csv_filename}.csv"
|
95
109
|
write_csv(file_name)
|
96
110
|
|
97
111
|
puts "The #{file_name} has been exported."
|
98
112
|
end
|
99
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
|
+
|
100
140
|
private
|
101
141
|
|
102
142
|
# Writes the items to a CSV file.
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'descriptive_statistics'
|
4
|
+
require_relative 'time_helper'
|
5
|
+
|
6
|
+
module Timet
|
7
|
+
# @!attribute [r] duration_by_tag
|
8
|
+
# @return [Hash] A hash where keys are tags and values are arrays of durations (in seconds) associated
|
9
|
+
# with each tag.
|
10
|
+
# @!attribute [r] total_duration
|
11
|
+
# @return [Integer] The total duration (in seconds) of all time intervals across all tags.
|
12
|
+
class TimeStatistics
|
13
|
+
attr_reader :duration_by_tag, :total_duration
|
14
|
+
|
15
|
+
# Initializes a new instance of TimeStatistics.
|
16
|
+
#
|
17
|
+
# @param data [Array<Array>] An array of arrays where each sub-array contains:
|
18
|
+
# - [0] An identifier (not used in calculations)
|
19
|
+
# - [1] The start time (in seconds since the epoch)
|
20
|
+
# - [2] The end time (in seconds since the epoch), or nil if the interval is ongoing
|
21
|
+
# - [3] The tag associated with the time interval
|
22
|
+
# @return [TimeStatistics] A new instance of TimeStatistics.
|
23
|
+
def initialize(data)
|
24
|
+
@data = data
|
25
|
+
@duration_by_tag = Hash.new { |hash, key| hash[key] = [] }
|
26
|
+
@total_duration = 0
|
27
|
+
calculate_durations_by_tag
|
28
|
+
end
|
29
|
+
|
30
|
+
# Calculates the duration for each tag and updates the @duration_by_tag and @total_duration attributes.
|
31
|
+
#
|
32
|
+
# @return [void]
|
33
|
+
def calculate_durations_by_tag
|
34
|
+
@data.each do |row|
|
35
|
+
start_time = row[1]
|
36
|
+
end_time = row[2] || Time.now.to_i
|
37
|
+
tag = row[3]
|
38
|
+
|
39
|
+
duration = end_time - start_time
|
40
|
+
@duration_by_tag[tag] << duration
|
41
|
+
@total_duration += duration
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns a hash where keys are tags and values are the total duration (in seconds) for each tag.
|
46
|
+
#
|
47
|
+
# @return [Hash<String, Integer>] A hash mapping tags to their total durations.
|
48
|
+
def total_duration_by_tag
|
49
|
+
@duration_by_tag.transform_values(&:sum)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns an array of arrays where each sub-array contains a tag and its total duration, sorted by duration in
|
53
|
+
# descending order.
|
54
|
+
#
|
55
|
+
# @return [Array<Array>] An array of [tag, total_duration] pairs sorted by total_duration in descending order.
|
56
|
+
def sorted_duration_by_tag
|
57
|
+
@duration_by_tag.map { |tag, durations| [tag, durations.sum] }.sort_by { |_, sum| -sum }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns a hash where keys are tags and values are the average duration (in seconds) for each tag.
|
61
|
+
#
|
62
|
+
# @return [Hash<String, Float>] A hash mapping tags to their average durations.
|
63
|
+
def average_by_tag
|
64
|
+
@duration_by_tag.transform_values { |durations| durations.sum.to_f / durations.size }
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns a hash where keys are tags and values are the standard deviation of durations for each tag.
|
68
|
+
#
|
69
|
+
# @return [Hash<String, Float>] A hash mapping tags to their standard deviations.
|
70
|
+
def standard_deviation_by_tag
|
71
|
+
@duration_by_tag.transform_values(&:standard_deviation)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns a hash where keys are tags and values are additional descriptive statistics for the durations of each tag.
|
75
|
+
#
|
76
|
+
# @return [Hash<String, Hash>] A hash mapping tags to a hash of descriptive statistics
|
77
|
+
# (e.g., min, max, median, etc.).
|
78
|
+
def additional_stats_by_tag
|
79
|
+
@duration_by_tag.transform_values(&:descriptive_statistics)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/timet/version.rb
CHANGED
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.
|
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
|
+
date: 2024-11-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -88,6 +88,7 @@ files:
|
|
88
88
|
- lib/timet/time_helper.rb
|
89
89
|
- lib/timet/time_report.rb
|
90
90
|
- lib/timet/time_report_helper.rb
|
91
|
+
- lib/timet/time_statistics.rb
|
91
92
|
- lib/timet/validation_edit_helper.rb
|
92
93
|
- lib/timet/version.rb
|
93
94
|
- sig/timet.rbs
|