timet 1.5.2 → 1.5.4

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.
data/lib/timet/table.rb CHANGED
@@ -1,9 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # require_relative 'color_codes'
4
+ require 'timet/time_report_helper'
3
5
  module Timet
4
- # This module is responsible for formatting the output of the `timet` application.
6
+ # This class is responsible for formatting the output of the `timet` application.
5
7
  # It provides methods for formatting the table header, separators, and rows.
6
- module Table
8
+ class Table
9
+ include TimeReportHelper
10
+
11
+ attr_reader :filter, :items
12
+
13
+ def initialize(filter, items, db)
14
+ @filter = filter
15
+ @items = items
16
+ @db = db
17
+ end
18
+
7
19
  # Generates and displays a table summarizing time entries, including headers, time blocks, and total durations.
8
20
  #
9
21
  # @example
@@ -64,22 +76,26 @@ module Timet
64
76
 
65
77
  # Processes time entries and generates a time block structure.
66
78
  #
67
- # @return [Hash] A nested hash representing the time block structure.
79
+ # This method iterates over each item in the `items` array, displays the time entry (if enabled),
80
+ # and processes the time block item to build a nested hash representing the time block structure.
81
+ #
82
+ # @param display [Boolean] Whether to display the time entry during processing. Defaults to `true`.
83
+ # @return [Hash] A nested hash representing the time block structure, where keys are dates and values
84
+ # are processed time block items.
68
85
  #
69
86
  # @note
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`.
87
+ # - The method uses `display_time_entry` to display the time entry if `display` is `true`.
88
+ # - It processes each time block item using `process_time_block_item`.
73
89
  # - The `TimeHelper.extract_date` method is used to extract the date from the items.
74
90
  #
75
91
  # @see #display_time_entry
76
92
  # @see #process_time_block_item
77
93
  # @see TimeHelper#extract_date
78
- def process_time_entries
94
+ def process_time_entries(display: true)
79
95
  time_block = Hash.new { |hash, key| hash[key] = {} }
80
96
 
81
- items.each_with_index do |item, idx|
82
- display_time_entry(item, TimeHelper.extract_date(items, idx))
97
+ @items.each_with_index do |item, idx|
98
+ display_time_entry(item, TimeHelper.extract_date(@items, idx)) if display
83
99
  time_block = process_time_block_item(item, time_block)
84
100
  end
85
101
 
@@ -41,6 +41,17 @@ module Timet
41
41
  def process_and_print_tags(time_stats, total, colors)
42
42
  print_summary(time_stats, total)
43
43
  print_tags_info(time_stats, total, colors)
44
+ print_footer
45
+ end
46
+
47
+ # Prints the footer information.
48
+ #
49
+ # @return [void] This method outputs the footer information to the standard output.
50
+ def print_footer
51
+ puts '-' * 45
52
+ puts 'T:'.rjust(4).red + 'The total duration'.gray
53
+ puts 'AVG:'.rjust(4).red + 'The average duration'.gray
54
+ puts 'SD:'.rjust(4).red + 'The standard deviation of the durations'.gray
44
55
  end
45
56
 
46
57
  # Prints the summary information including total duration, average duration, and standard deviation.
@@ -104,7 +115,7 @@ module Timet
104
115
  # calculate_value_and_bar_length(50, 100, 2) #=> [50.0, 25]
105
116
  def calculate_value_and_bar_length(duration, total)
106
117
  value = duration.to_f / total
107
- percentage_value = (duration.to_f / total * 100).round(1)
118
+ percentage_value = (value * 100).round(1)
108
119
  bar_length = (value * MAX_BAR_LENGTH).round
109
120
  [percentage_value, bar_length]
110
121
  end
@@ -1,9 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Timet
4
- # This module is responsible for formatting the output of the `timet` application.
5
- # It provides methods for formatting the table header, separators, and rows.
6
- module TimeBlockChart
4
+ #
5
+ # The TimeBlockChart class is responsible for generating and printing a visual representation
6
+ # of time blocks for a given set of data. It uses character mapping to represent different
7
+ # time ranges and provides methods to print the chart with headers, footers, and colored blocks.
8
+ #
9
+ # Example usage:
10
+ # time_block = {
11
+ # "2023-10-01" => { "08" => [3600, "work"], "09" => [1800, "break"] },
12
+ # "2023-10-02" => { "10" => [4500, "work"] }
13
+ # }
14
+ # colors = { "work" => 31, "break" => 32 }
15
+ # chart = TimeBlockChart.new(table)
16
+ # chart.print_time_block_chart(table, colors)
17
+ #
18
+ # @attr_reader [Integer] start_hour The starting hour of the time block
19
+ # @attr_reader [Integer] end_hour The ending hour of the time block
20
+ class TimeBlockChart
21
+ # Character mapping for different time ranges
7
22
  CHAR_MAPPING = {
8
23
  0..120 => '_',
9
24
  121..450 => '▁',
@@ -16,87 +31,115 @@ module Timet
16
31
  3151..3600 => '█'
17
32
  }.freeze
18
33
 
34
+ # Separator character for the chart
19
35
  SEPARATOR_CHAR = '░'
20
36
 
21
- # Prints a time block chart based on the provided time block and colors.
37
+ # Initializes a new TimeBlockChart instance.
22
38
  #
23
- # @param time_block [Hash] A hash where the keys are time blocks and the values are hashes of time slots and their
24
- # corresponding values.
25
- # Example: { "block1" => { 10 => "value1", 11 => "value2" }, "block2" => { 12 => "value3" } }
26
- # @param colors [Hash] A hash where the keys are time slots and the values are the colors to be used
27
- # for those slots.
28
- # Example: { 10 => "red", 11 => "blue", 12 => "green" }
39
+ # This method sets up the time block chart by processing the time entries from the provided table
40
+ # and determining the start and end hours for the chart based on the time block data.
29
41
  #
30
- # @return [void] This method does not return a value; it prints the chart directly to the output.
42
+ # @param table [Table] The table instance containing the time entries to be processed.
43
+ # @return [void] This method does not return a value; it initializes the instance variables.
31
44
  #
32
- # @example
33
- # time_block = { "block1" => { 10 => "value1", 11 => "value2" }, "block2" => { 12 => "value3" } }
34
- # colors = { 10 => "red", 11 => "blue", 12 => "green" }
35
- # print_time_block_chart(time_block, colors)
45
+ # @note
46
+ # - The `@time_block` instance variable is populated by processing the time entries from the table.
47
+ # - The `@start_hour` and `@end_hour` instance variables are calculated based on the earliest and latest
48
+ # hours present in the time block data.
36
49
  #
37
- # @note This method relies on two helper methods: `print_header` and `print_blocks`.
38
- # Ensure these methods are defined and available in the scope where `print_time_block_chart` is called.
39
- #
40
- # @see #print_header
41
- # @see #print_blocks
42
- def print_time_block_chart(time_block, colors)
43
- start_hour = time_block.values.map(&:keys).flatten.uniq.min.to_i
44
- print_header(start_hour)
45
- print_blocks(time_block, colors, start_hour)
50
+ # @see Table#process_time_entries
51
+ def initialize(table)
52
+ @time_block = table.process_time_entries(display: false)
53
+ @start_hour = @time_block.values.map(&:keys).flatten.uniq.min.to_i
54
+ @end_hour = @time_block.values.map(&:keys).flatten.uniq.max.to_i
46
55
  end
47
56
 
48
- # Prints the header of the time block chart.
57
+ # Prints the time block chart.
49
58
  #
50
- # The header includes a visual representation of the time slots from the given start time to 23.
51
- # Each time slot is formatted as a two-digit number and aligned to the right within a fixed width.
59
+ # This method formats and prints the time block chart, including the header and the time blocks
60
+ # for each entry. The chart is color-coded based on the provided color mapping for different tags.
52
61
  #
53
- # @param start_hour [Integer] The starting time for the chart. This should be an integer between 0 and 23.
62
+ # @param table [Hash] The time block data to be displayed in the chart.
63
+ # @param colors [Hash] A mapping of tags to colors, used to color-code the time blocks.
64
+ # @return [void] This method does not return a value; it performs side effects such as printing the chart.
54
65
  #
55
- # @return [void] This method does not return a value; it prints the header directly to the output.
66
+ # @example Print a time block chart
67
+ # chart = TimeBlockChart.new(table)
68
+ # chart.print_time_block_chart(table, colors)
56
69
  #
57
- # @example
58
- # print_header(10)
59
- # # Output:
60
- # #
61
- # # ⏳ ↦ [ 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
70
+ # @note
71
+ # - The method first prints the header of the chart, which includes the time range.
72
+ # - It then prints the time blocks, using the provided color mapping to visually distinguish
73
+ # between different tags.
74
+ #
75
+ # @see #print_header
76
+ # @see #print_blocks
77
+ def print_time_block_chart(table, colors)
78
+ print_header
79
+ print_blocks(table, colors)
80
+ end
81
+
82
+ private
83
+
84
+ # Prints the header of the chart
62
85
  #
63
- # @note The method assumes that the start_hour is within the valid range of 0 to 23.
64
- # If the start_hour is outside this range, the output may not be as expected.
65
- def print_header(start_hour)
86
+ # @return [void]
87
+ def print_header
66
88
  puts
67
89
  print ' ' * 19
68
- (start_hour..23).each { |hour| print format('%02d', hour).rjust(4) }
90
+ (@start_hour..@end_hour + 1).each { |hour| print format('%02d', hour).rjust(4) }
69
91
  puts
70
- puts '┌╴W ╴╴╴╴╴╴⏰╴╴╴╴╴╴┼'.gray + "#{'╴' * (24 - start_hour) * 4}╴╴╴┼".gray
92
+ puts '┌╴W ╴╴╴╴╴╴⏰╴╴╴╴╴╴┼'.gray + "#{'╴' * (@end_hour - @start_hour + 1) * 4}╴╴╴┼".gray
71
93
  end
72
94
 
73
- # Prints the time blocks for each date in the given time block data structure.
95
+ # Prints the time blocks for each date in the time block data.
74
96
  #
75
- # @param time_block [Hash] A hash where keys are date strings and values are time block data.
76
- # @param colors [Hash] A hash containing color codes for formatting.
77
- # @param start_hour [Integer] The starting hour for the time blocks.
78
- # @return [void]
79
- def print_blocks(time_block, colors, start_hour)
80
- return unless time_block
97
+ # This method iterates over the time block data, formats and prints the date information,
98
+ # prints the time blocks for each date using the provided color mapping, and calculates
99
+ # and prints the total hours for each day. It also prints a footer at the end.
100
+ #
101
+ # @param table [Hash] The time block data containing the time entries for each date.
102
+ # @param colors [Hash] A mapping of tags to colors, used to color-code the time blocks.
103
+ # @return [void] This method does not return a value; it performs side effects such as printing
104
+ # the time blocks and related information.
105
+ #
106
+ # @example Print time blocks
107
+ # chart = TimeBlockChart.new(table)
108
+ # chart.print_blocks(table, colors)
109
+ #
110
+ # @note
111
+ # - The method skips processing if the `table` parameter is `nil`.
112
+ # - For each date in the time block data, it formats and prints the date and day of the week.
113
+ # - It prints the time blocks using the provided color mapping to visually distinguish
114
+ # between different tags.
115
+ # - It calculates and prints the total hours for each day.
116
+ # - A footer is printed at the end to provide a visual separation.
117
+ #
118
+ # @see #format_and_print_date_info
119
+ # @see #print_time_blocks
120
+ # @see #calculate_and_print_hours
121
+ # @see #print_footer
122
+ def print_blocks(table, colors)
123
+ return unless table
81
124
 
82
125
  weeks = []
83
- time_block.each_key do |date_string|
126
+ @time_block.each_key do |date_string|
84
127
  date = Date.parse(date_string)
85
- day = date.strftime('%a')[0..1]
128
+ day = date.strftime('%a')[0..2]
86
129
 
87
- format_and_print_date_info(date_string, day, weeks, start_hour)
130
+ format_and_print_date_info(date_string, day, weeks)
88
131
 
89
- time_block_initial = time_block[date_string]
90
- print_time_blocks(start_hour, time_block_initial, colors)
132
+ time_block_initial = @time_block[date_string]
133
+ print_time_blocks(time_block_initial, colors)
91
134
 
92
135
  calculate_and_print_hours(time_block_initial)
93
136
  end
94
- print_footer(start_hour)
137
+ print_footer
95
138
  end
96
139
 
97
- # Calculates the total hours from the given time block data and prints it.
140
+ # Calculates and prints the total hours for a day
98
141
  #
99
- # @param time_block_initial [Hash] A hash containing time block data for a specific date.
142
+ # @param [Hash] time_block_initial The initial time block data for a day
100
143
  # @return [void]
101
144
  def calculate_and_print_hours(time_block_initial)
102
145
  total_seconds = time_block_initial.values.map { |item| item[0] }.sum
@@ -105,104 +148,88 @@ module Timet
105
148
  puts
106
149
  end
107
150
 
108
- # Formats and prints the date information including the week and day.
151
+ # Formats and prints the date information
109
152
  #
110
- # @param date_string [String] The date string in a parsable format.
111
- # @param day [String] The abbreviated day of the week (e.g., "Mo" for Monday).
112
- # @param weeks [Array<Integer>] An array storing the week numbers.
113
- # @param start_hour [Integer] The starting hour for the time blocks.
153
+ # @param [String] date_string The date string
154
+ # @param [String] day The day of the week
155
+ # @param [Array] weeks The list of weeks
114
156
  # @return [void]
115
- def format_and_print_date_info(date_string, day, weeks, start_hour)
157
+ def format_and_print_date_info(date_string, day, weeks)
116
158
  weekend = date_string
117
159
  day = day.red if %w[Sa Su].include?(day)
118
160
  weekend = weekend.red if %w[Sa Su].include?(day)
119
161
 
120
- week = format_and_print_week(date_string, weeks, start_hour)
162
+ week = format_and_print_week(date_string, weeks)
121
163
 
122
- print '┆'.gray + "#{week} #{weekend} #{day} " + '┆- '.gray
164
+ print '┆'.gray + "#{week} #{weekend} #{day}" + '┆- '.gray
123
165
  end
124
166
 
125
- # Formats and prints the week information including the separator if necessary.
167
+ # Formats and prints the week information
126
168
  #
127
- # @param date_string [String] The date string in a parsable format.
128
- # @param weeks [Array<Integer>] An array storing the week numbers.
129
- # @param start_hour [Integer] The starting hour for the time blocks.
130
- # @return [String] The formatted week string.
131
- def format_and_print_week(date_string, weeks, start_hour)
169
+ # @param [String] date_string The date string
170
+ # @param [Array] weeks The list of weeks
171
+ # @return [String] The formatted week string
172
+ def format_and_print_week(date_string, weeks)
132
173
  week, current_index = determine_week(date_string, weeks)
133
- print_separator(start_hour, week, current_index)
174
+ print_separator(week, current_index)
134
175
  week
135
176
  end
136
177
 
137
- # Determines the week string based on the date and the previous week.
178
+ # Determines the week for a given date
138
179
  #
139
- # @param date_string [String] The date string in a parsable format.
140
- # @param weeks [Array<Integer>] An array storing the week numbers.
141
- # @return [Array<String, Integer>] An array containing the formatted week string and the current index.
180
+ # @param [String] date_string The date string
181
+ # @param [Array] weeks The list of weeks
182
+ # @return [Array] The week string and current index
142
183
  def determine_week(date_string, weeks)
143
184
  weeks << Date.parse(date_string).cweek
144
185
  current_index = weeks.size - 1
145
186
  current_week = weeks[current_index]
146
- week = current_week == weeks[current_index - 1] && current_index.positive? ? ' ' : current_week.to_s.underline
187
+ week = if current_week == weeks[current_index - 1] && current_index.positive?
188
+ ' '
189
+ else
190
+ format('%02d', current_week).to_s.underline
191
+ end
147
192
  [week, current_index]
148
193
  end
149
194
 
150
- # Prints the separator line if the week string is not empty and the current index is positive.
195
+ # Prints the separator line
151
196
  #
152
- # @param start_hour [Integer] The starting hour for the time blocks.
153
- # @param week [String] The formatted week string.
154
- # @param current_index [Integer] The current index in the weeks array.
197
+ # @param [String] week The week string
198
+ # @param [Integer] current_index The current index
155
199
  # @return [void]
156
- def print_separator(start_hour, week, current_index)
200
+ def print_separator(week, current_index)
157
201
  return unless week != ' ' && current_index.positive?
158
202
 
159
203
  sep = SEPARATOR_CHAR
160
- puts "┆#{sep * 17}┼#{sep * (24 - start_hour) * 4}#{sep * 3}┼#{sep * 4}".gray
204
+ puts "┆#{sep * 17}┼#{sep * (@end_hour - @start_hour + 1) * 4}#{sep * 3}┼#{sep * 4}".gray
161
205
  end
162
206
 
163
- # Prints the footer of the report.
207
+ # Prints the footer of the chart
164
208
  #
165
- # @param start_hour [Integer] The start time used to calculate the footer length.
166
- # @return [void] This method does not return a value; it prints directly to the standard output.
167
- def print_footer(start_hour)
209
+ # @return [void]
210
+ def print_footer
168
211
  timet = "\e]8;;https://github.com/frankvielma/timet/\aTimet\e]8;;\a".green
169
- puts '└╴╴╴╴╴╴╴'.gray + timet + "╴╴╴╴╴┴#{'╴' * (24 - start_hour) * 4}╴╴╴┴".gray
212
+ puts '└╴╴╴╴╴╴╴'.gray + timet + "╴╴╴╴╴┴#{'╴' * (@end_hour - @start_hour + 1) * 4}╴╴╴┴".gray
170
213
  puts
171
214
  end
172
215
 
173
- # Prints time blocks for each hour from the start time to 23.
216
+ # Prints the time blocks for a given day
174
217
  #
175
- # @param start_time [Integer] The starting hour for printing time blocks.
176
- # @param time_block_initial [Hash] A hash containing time block data, where keys are formatted hours and values
177
- # are arrays containing block data.
178
- # @param colors [Hash] A hash mapping tags to color codes.
218
+ # @param [Hash] time_block_initial The initial time block data for a day
219
+ # @param [Hash] colors The color mapping for different tags
179
220
  # @return [void]
180
- #
181
- # @example
182
- # time_block_initial = {
183
- # '01' => ['block_char_data', 'tag']
184
- # }
185
- # colors = { 'tag' => 1 }
186
- # print_time_blocks(1, time_block_initial, colors) # Prints time blocks for hours 1 to 23
187
- def print_time_blocks(start_time, time_block_initial, colors)
188
- (start_time..23).each do |hour|
221
+ def print_time_blocks(time_block_initial, colors)
222
+ (@start_hour..@end_hour).each do |hour|
189
223
  tag, block_char = get_formatted_block_char(hour, time_block_initial)
190
224
  print_colored_block(block_char, tag, colors)
191
225
  end
192
226
  end
193
227
 
194
- # Returns the formatted block character and its associated tag for a given hour.
195
- #
196
- # @param hour [Integer] The hour for which to retrieve the block character.
197
- # @param time_block_initial [Hash] A hash containing time block data, where keys are formatted hours and values
198
- # are arrays containing block data.
199
- # @return [Array<(String, String)>] An array containing the tag and the block character.
228
+ # Gets the formatted block character for a given hour
200
229
  #
201
- # @example
202
- # time_block_initial = {
203
- # '01' => ['block_char_data', 'tag']
204
- # }
205
- # get_formatted_block_char(1, time_block_initial) #=> ['tag', 'block_char']
230
+ # @param [Integer] hour The hour
231
+ # @param [Hash] time_block_initial The initial time block data for a day
232
+ # @return [Array] The tag and block character
206
233
  def get_formatted_block_char(hour, time_block_initial)
207
234
  formatted_hour = format('%02d', hour)
208
235
  hour_data = time_block_initial[formatted_hour]
@@ -210,15 +237,12 @@ module Timet
210
237
  [tag, get_block_char(hour_data&.first)]
211
238
  end
212
239
 
213
- # Prints a colored block character based on the provided tag and block character.
240
+ # Prints the colored block character
214
241
  #
215
- # @param block_char [String] The block character to be printed.
216
- # @param tag [String] The tag associated with the block character, used to determine the color.
217
- # @param colors [Hash] A hash mapping tags to color codes.
218
- #
219
- # @example
220
- # colors = { 'tag' => 1 }
221
- # print_colored_block('X', 'tag', colors) # Prints a colored block character 'XX'
242
+ # @param [String] block_char The block character
243
+ # @param [String] tag The tag
244
+ # @param [Hash] colors The color mapping for different tags
245
+ # @return [void]
222
246
  def print_colored_block(block_char, tag, colors)
223
247
  color_code = colors[tag]
224
248
  block = block_char * 2
@@ -226,10 +250,10 @@ module Timet
226
250
  print colored_block.rjust(4)
227
251
  end
228
252
 
229
- # Determines the block character based on the value.
253
+ # Gets the block character for a given value
230
254
  #
231
- # @param value [Integer] The value to determine the block character for.
232
- # @return [String] The block character corresponding to the value.
255
+ # @param [Integer, nil] value The value
256
+ # @return [String] The block character
233
257
  def get_block_char(value)
234
258
  return ' ' unless value
235
259
 
@@ -14,8 +14,6 @@ module Timet
14
14
  # a formatted table with the relevant information.
15
15
  class TimeReport
16
16
  include TimeReportHelper
17
- include Table
18
- include TimeBlockChart
19
17
  include TagDistribution
20
18
 
21
19
  # Provides access to the database instance.
@@ -33,37 +31,55 @@ module Timet
33
31
  # Initializes a new instance of the TimeReport class.
34
32
  #
35
33
  # @param db [Database] The database instance to use for fetching data.
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.
42
- #
43
- # @return [void] This method does not return a value; it performs side effects such as initializing the
44
- # instance variables.
34
+ # @param options [Hash] A hash containing optional parameters for configuring the report.
35
+ # @option options [String, nil] :filter The filter to apply when fetching items. Possible values include:
36
+ # - 'today': Filters items for the current day.
37
+ # - 'yesterday': Filters items for the previous day.
38
+ # - 'week': Filters items for the current week.
39
+ # - 'month': Filters items for the current month.
40
+ # - A date range in the format 'YYYY-MM-DD..YYYY-MM-DD': Filters items within the specified date range.
41
+ # @option options [String, nil] :tag The tag to filter the items by. Only items with this tag will be included.
42
+ # @option options [String, nil] :csv The filename to use when exporting the report to CSV. If provided, the report
43
+ # will be exported to the specified file.
44
+ # @option options [String, nil] :ics The filename to use when exporting the report to iCalendar format. If provided,
45
+ # the report will be exported to the specified file.
46
+ #
47
+ # @return [void] This method does not return a value; it initializes the instance variables and prepares the report.
45
48
  #
46
49
  # @example Initialize a new TimeReport instance with a filter and tag
47
50
  # TimeReport.new(db, filter: 'today', tag: 'work', csv: 'report.csv', ics: 'icalendar.ics')
51
+ #
52
+ # @example Initialize a new TimeReport instance with a date range filter
53
+ # TimeReport.new(db, filter: '2023-10-01..2023-10-31', tag: 'project')
54
+ #
55
+ # @note
56
+ # - If no filter is provided, all items from the database will be fetched.
57
+ # - The `@table` instance variable is initialized with the filtered items and filter configuration.
48
58
  def initialize(db, options = {})
49
59
  @db = db
50
60
  @csv_filename = options[:csv]
51
61
  @ics_filename = options[:ics]
52
62
  @filter = formatted_filter(options[:filter])
53
63
  @items = options[:filter] ? filter_items(@filter, options[:tag]) : @db.all_items
64
+ @table = Table.new(@filter, @items, @db)
54
65
  end
55
66
 
56
67
  # Displays the report of tracked time entries.
57
68
  #
69
+ # This method formats and prints the report, including the table header, rows, total duration,
70
+ # a time block chart, and tag distribution. If no tracked time entries are found for the specified filter,
71
+ # it displays a message indicating no data is available.
72
+ #
58
73
  # @return [void] This method does not return a value; it performs side effects such as printing the report.
59
74
  #
60
75
  # @example Display the report
61
76
  # time_report.display
62
77
  #
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).
78
+ # @note
79
+ # - The method checks if there are any tracked time entries. If not, it prints a message and exits.
80
+ # - It uses the `@table` instance to format and display the table.
81
+ # - A time block chart is generated and printed using the `TimeBlockChart` class.
82
+ # - The tag distribution is calculated and displayed based on the unique colors assigned to tags.
67
83
  #
68
84
  # @see #table
69
85
  # @see #print_time_block_chart
@@ -71,29 +87,38 @@ module Timet
71
87
  def display
72
88
  return puts 'No tracked time found for the specified filter.' if @items.empty?
73
89
 
74
- time_block = table
75
-
90
+ @table.table
76
91
  colors = @items.map { |x| x[3] }.uniq.each_with_index.to_h
77
- print_time_block_chart(time_block, colors)
78
-
92
+ chart = TimeBlockChart.new(@table)
93
+ chart.print_time_block_chart(@table, colors)
79
94
  tag_distribution(colors)
80
95
  end
81
96
 
82
97
  # Displays a single row of the report.
83
98
  #
84
- # @param item [Array] The item to display.
99
+ # This method formats and prints a single row of the report, including the table header, the specified row,
100
+ # a separator, and the total duration. It is used to display individual time entries in a structured format.
101
+ #
102
+ # @param item [Array] The item (time entry) to display. The item is expected to contain the necessary data
103
+ # for the row, such as the time, description, and duration.
85
104
  #
86
105
  # @return [void] This method does not return a value; it performs side effects such as printing the row.
87
106
  #
88
107
  # @example Display a single row
89
108
  # time_report.show_row(item)
90
109
  #
91
- # @note The method formats and prints the table header, row, and total duration.
110
+ # @note
111
+ # - The method uses the `@table` instance to format and display the table header and row.
112
+ # - A separator is printed after the row to visually distinguish it from other rows.
113
+ # - The total duration is displayed at the end of the row.
114
+ #
115
+ # @see #table
116
+ # @see #display_time_entry
92
117
  def show_row(item)
93
- header
94
- display_time_entry(item)
95
- puts separator
96
- total
118
+ @table.header
119
+ @table.display_time_entry(item)
120
+ puts @table.separator
121
+ @table.total
97
122
  end
98
123
 
99
124
  private
@@ -34,8 +34,6 @@ module Timet
34
34
  # - :avg [Numeric] The average duration.
35
35
  # - :sd [Numeric] The standard deviation of the durations.
36
36
  def totals
37
- @duration_by_tag.values.flatten
38
-
39
37
  durations = @duration_by_tag.values.flatten
40
38
  { total: @total_duration, avg: durations.mean, sd: durations.standard_deviation }
41
39
  end
@@ -51,7 +51,8 @@ module Timet
51
51
  # @note The method formats the date value and checks if it is valid.
52
52
  # @note If the date value is valid, it updates the time field with the new value.
53
53
  # @note If the date value is invalid, it prints an error message.
54
- def process_and_update_time_field(item, field, date_value, id)
54
+ def process_and_update_time_field(*args)
55
+ item, field, date_value, id = args
55
56
  formatted_date = TimeHelper.format_time_string(date_value)
56
57
 
57
58
  return print_error(date_value) unless formatted_date
@@ -82,17 +83,17 @@ module Timet
82
83
  #
83
84
  # @param item [Array] The tracking item to be updated.
84
85
  # @param field [String] The time field to be updated.
85
- # @param formatted_value [String] The formatted date value.
86
+ # @param new_time [String] The new time value.
86
87
  #
87
88
  # @return [Time] The updated time value.
88
89
  #
89
90
  # @example Update the 'start' field of a tracking item with a formatted date value
90
- # update_time_field(item, 'start', '2023-10-01 12:00:00')
91
- def update_time_field(item, field, formatted_value)
91
+ # update_time_field(item, 'start', '11:10:00')
92
+ def update_time_field(item, field, new_time)
92
93
  field_index = Timet::Application::FIELD_INDEX[field]
93
94
  timestamp = item[field_index]
94
95
  current_time = Time.at(timestamp || TimeHelper.current_timestamp).to_s.split
95
- current_time[1] = formatted_value
96
+ current_time[1] = new_time
96
97
  DateTime.strptime(current_time.join(' '), '%Y-%m-%d %H:%M:%S %z').to_time
97
98
  end
98
99
 
@@ -107,7 +108,8 @@ module Timet
107
108
  #
108
109
  # @example Validate a new 'start' time value
109
110
  # valid_time_value?(item, 'start', 1633072800, 1)
110
- def valid_time_value?(item, field, new_value_epoch, id)
111
+ def valid_time_value?(*args)
112
+ item, field, new_value_epoch, id = args
111
113
  item_start = fetch_item_start(item)
112
114
  item_end = fetch_item_end(item)
113
115
  item_before_end = fetch_item_before_end(id, item_start)