Class: PunchCard
- Inherits:
-
Object
- Object
- PunchCard
- Defined in:
- lib/punchcard.rb
Constant Summary collapse
- SETTINGS_DIR =
ENV['PUNCHCARD_DIR'] || File.('~/.punchcard')
- HOURLY_RATE_PATTERN =
/^\s*(\d+)([^\d]+)*\s*/i.freeze
- TIME_POINT_PATTERN =
/^((\d+|.+?\s[\+\-]\d{4}?\s*)(\-)*(\d+|\s.+\d?)*)$/.freeze
- META_KEY_PATTERN =
/^([a-zA-Z0-9]+)\:\s*(.*)$/.freeze
- VERSION =
'1.3.3'
Instance Attribute Summary collapse
-
#title ⇒ Object
Returns the value of attribute title.
Class Method Summary collapse
- .decimal_digits(digit) ⇒ Object
- .format_time(datetime) ⇒ Object
- .humanize_duration(duration) ⇒ Object
Instance Method Summary collapse
- #csv(start_at: nil, end_at: nil) ⇒ Object
- #details ⇒ Object
-
#initialize(project_name) ⇒ PunchCard
constructor
A new instance of PunchCard.
- #project ⇒ Object
- #project=(project_name) ⇒ Object
- #remove ⇒ Object
- #rename(new_project_name) ⇒ Object
- #set(key, value) ⇒ Object
- #start ⇒ Object
- #status ⇒ Object
- #stop ⇒ Object
- #title_and_project ⇒ Object
- #title_or_project ⇒ Object
- #toggle ⇒ Object
- #total(start_at: nil, end_at: nil) ⇒ Object
Constructor Details
#initialize(project_name) ⇒ PunchCard
Returns a new instance of PunchCard.
20 21 22 23 24 25 26 27 28 29 |
# File 'lib/punchcard.rb', line 20 def initialize(project_name) @wilcard_for_filename = '' @meta_data = {} find_or_make_settings_dir return unless project_name self.project = project_name find_or_make_file read_project_data end |
Instance Attribute Details
#title ⇒ Object
Returns the value of attribute title.
18 19 20 |
# File 'lib/punchcard.rb', line 18 def title @title end |
Class Method Details
.decimal_digits(digit) ⇒ Object
214 215 216 217 218 219 220 |
# File 'lib/punchcard.rb', line 214 def self.decimal_digits(digit) if digit.to_i < 10 "0#{digit}" else digit.to_s end end |
.format_time(datetime) ⇒ Object
201 202 203 |
# File 'lib/punchcard.rb', line 201 def self.format_time(datetime) datetime.strftime('%F %T') end |
.humanize_duration(duration) ⇒ Object
205 206 207 208 209 210 211 212 |
# File 'lib/punchcard.rb', line 205 def self.humanize_duration(duration) return nil unless duration hours = duration / (60 * 60) minutes = (duration / 60) % 60 seconds = duration % 60 "#{decimal_digits(hours)}:#{decimal_digits(minutes)}:#{decimal_digits(seconds)}" end |
Instance Method Details
#csv(start_at: nil, end_at: nil) ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/punchcard.rb', line 106 def csv(start_at: nil, end_at: nil) project_exists_or_stop! find_or_make_file durations = [] last_activity = nil project_data_without_comments.map do |line| points = line_to_time_points(line) next unless points start_time = points[0] end_time = points[1] || next if time_range_is_excluded_by_filter?( start_at: start_at, end_at: end_at, start_time: start_time, end_time: end_time ) last_activity = points[1] || points[0] durations.push end_time - start_time end total_duration = self.class.humanize_duration( durations.reduce(&:+) || 0 ) '"' + [ title_and_project, running_status, last_activity ? self.class.format_time(Time.at(last_activity).to_datetime) : '', total_duration, hourly_rate ? hourly_rate[:hourlyRate].to_s + " #{hourly_rate[:currency]}" : '', hourly_rate ? (hourly_rate[:hourlyRate] * total / 3600.0).round(2).to_s + " #{hourly_rate[:currency]}" : '' ].join('","') + '"' end |
#details ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/punchcard.rb', line 85 def details project_exists_or_stop! find_or_make_file output = [] data = project_data data[0] = "#{data[0]} (#{running_status})" data.map do |line| points = line_to_time_points(line) unless points output << line + "\n" next end starttime = points[0] endtime = points[1] || output << duration(starttime, endtime) + "\t" + self.class.format_time(Time.at(starttime)) + ' - ' + self.class.format_time(Time.at(endtime)) end output << "========\n#{humanized_total}\t(total)" output.join("\n") end |
#project ⇒ Object
166 167 168 |
# File 'lib/punchcard.rb', line 166 def project @project.strip end |
#project=(project_name) ⇒ Object
157 158 159 160 161 162 163 164 |
# File 'lib/punchcard.rb', line 157 def project=(project_name) @project = project_name if @project.end_with?('*') @wilcard_for_filename = '*' @project = @project.chomp('*') end @project.strip end |
#remove ⇒ Object
141 142 143 144 145 146 |
# File 'lib/punchcard.rb', line 141 def remove if File.exist?(project_file) File.delete(project_file) "Deleted #{project_file}" end end |
#rename(new_project_name) ⇒ Object
148 149 150 151 152 153 154 155 |
# File 'lib/punchcard.rb', line 148 def rename(new_project_name) old_filename = project_filename data = project_data data[0] = new_project_name write_string_to_project_file! data.join("\n") self.project = new_project_name File.rename(old_filename, project_filename) && "#{old_filename} -> #{project_filename}" end |
#set(key, value) ⇒ Object
170 171 172 173 174 175 176 177 178 |
# File 'lib/punchcard.rb', line 170 def set(key, value) unless key =~ /^[a-zA-Z0-9]+$/ raise PunchCardError, "Key '#{key}' can only be alphanumeric" end @meta_data[key.to_sym] = value write_to_project_file! @meta_data end |
#start ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/punchcard.rb', line 31 def start output = [] if start_time && !end_time output << "'#{title_or_project}' already started (#{humanized_total} total)" output << duration(start_time, ).to_s else output << "'#{title_or_project}' started (#{humanized_total} total)" self.start_time = end output.join("\n") end |
#status ⇒ Object
76 77 78 79 80 81 82 83 |
# File 'lib/punchcard.rb', line 76 def status project_exists_or_stop! find_or_make_file output = [] output << (title_or_project + " (#{running_status})\n") output << humanized_total output.join("\n") end |
#stop ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/punchcard.rb', line 43 def stop output = [] if end_time output << "'#{title_or_project}' already stopped (#{humanized_total} total)" elsif start_time output << "'#{title_or_project}' stopped (#{humanized_total} total)" self.end_time = else output << 'Nothing to stop' end output.join("\n") end |
#title_and_project ⇒ Object
68 69 70 71 72 73 74 |
# File 'lib/punchcard.rb', line 68 def title_and_project if title != project "#{title} [#{project}]" else project end end |
#title_or_project ⇒ Object
64 65 66 |
# File 'lib/punchcard.rb', line 64 def title_or_project title || project end |
#toggle ⇒ Object
56 57 58 59 60 61 62 |
# File 'lib/punchcard.rb', line 56 def toggle if active? stop else start end end |
#total(start_at: nil, end_at: nil) ⇒ Object
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/punchcard.rb', line 180 def total(start_at: nil, end_at: nil) total = 0 project_data_without_comments.map do |line| points = line_to_time_points(line) next unless points start_time = points[0] end_time = points[1] || next if time_range_is_excluded_by_filter?( start_at: start_at, end_at: end_at, start_time: start_time, end_time: end_time ) total += end_time - start_time end total end |