piece_of_wax 1.0.0.rc1 → 1.0.0.rc6
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/bin/piece_of_wax +2 -1
- data/lib/piece_of_wax.rb +89 -16
- data/lib/piece_of_wax/cli_options.rb +31 -0
- data/lib/piece_of_wax/date_time_decorator/error_message_display.rb +28 -0
- data/lib/piece_of_wax/date_time_decorator/read_display.rb +23 -0
- data/lib/piece_of_wax/date_time_helper.rb +33 -0
- data/lib/piece_of_wax/file_io.rb +24 -0
- data/lib/piece_of_wax/logfile.rb +36 -20
- data/lib/piece_of_wax/output_line/activity.rb +24 -0
- data/lib/piece_of_wax/output_line/date.rb +21 -0
- metadata +27 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e3d7bf2ae9792450cc94d927669b1d48e8c4abdde8285c7580532065372780c
|
4
|
+
data.tar.gz: a2728bf010e7a3be407291ed6bd037a1c45fee19f2813e2f3d103ceae87f6649
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0165421b35cf5701533a15aba5d62f324ad575686588b6858336fcc9e21171b98103019191ba67bf6c512ffa8fc39604a3bbac496f3d810ae455772faeca82a6
|
7
|
+
data.tar.gz: 64cf7f4ddb03e81c714892e0381bbc948883185bbf0124e36a7fcdfec8ee34b90a3f0168aa2bddf69a5dea35b0b9614cceb442bc6ea34a280bdba4d7e92a6e7b
|
data/bin/piece_of_wax
CHANGED
data/lib/piece_of_wax.rb
CHANGED
@@ -1,38 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "json"
|
2
4
|
require "piece_of_wax/cli_options"
|
3
|
-
require "piece_of_wax/
|
5
|
+
require "piece_of_wax/date_time_helper"
|
4
6
|
require "piece_of_wax/date_time_decorator/error_message_display"
|
5
7
|
require "piece_of_wax/logfile"
|
6
8
|
require "thor"
|
7
9
|
|
8
10
|
module PieceOfWax
|
11
|
+
#
|
12
|
+
# Implements command line interface. Each public method corresponds to a `piece_of_wax`
|
13
|
+
# subcommand.
|
14
|
+
#
|
9
15
|
class CLI < Thor
|
10
|
-
desc 'activity "_activity_"', "log activity
|
11
|
-
option :time, aliases: :t, desc:
|
12
|
-
def activity(str)
|
13
|
-
|
14
|
-
time =
|
15
|
-
|
16
|
-
|
16
|
+
desc 'activity "_activity_"', "log activity"
|
17
|
+
option :time, aliases: :t, desc: "time when activity was started"
|
18
|
+
def activity(*str)
|
19
|
+
capture_options(options)
|
20
|
+
time = DateTimeHelper.safe_parse(CLIOptions.instance[:time]) || DateTimeHelper.current_time
|
21
|
+
description = str.join(" ")
|
22
|
+
Logfile.new(DateTimeHelper.current_date).add_activity(time, description)
|
23
|
+
$stdout.puts "wrote #{description} to file"
|
17
24
|
end
|
18
25
|
|
19
|
-
desc
|
20
|
-
option :
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
+
desc 'edit "_activity_"', "edit activity"
|
27
|
+
option :n, default: "1", desc: "the activity to edit, 1 being the most recently-logged"
|
28
|
+
def edit(*str)
|
29
|
+
capture_options(options)
|
30
|
+
description = str.join(" ")
|
31
|
+
index = (0 - CLIOptions.instance[:n].to_i)
|
32
|
+
logfile = Logfile.new(DateTimeHelper.current_date)
|
33
|
+
if logfile.contents[index]
|
34
|
+
logfile.edit_activity(index, description)
|
35
|
+
$stdout.puts "wrote #{description} to file"
|
36
|
+
else
|
37
|
+
warn 'activity referenced by "n" option does not exist'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "read [date]", "print activities on given [date] (today by default)"
|
42
|
+
option :military, aliases: :m, desc: "render time in military (24-hour) format"
|
43
|
+
option(
|
44
|
+
:'quitting-time',
|
45
|
+
default: "17:45:00 -0500",
|
46
|
+
aliases: :q,
|
47
|
+
desc: "last activity period is capped off at this time"
|
48
|
+
)
|
49
|
+
def read(date_str = "")
|
50
|
+
capture_options(options)
|
51
|
+
date = get_date(date_str)
|
52
|
+
logfile = Logfile.new(date) if date
|
53
|
+
if logfile&.any_contents?
|
26
54
|
$stdout.puts logfile
|
27
55
|
else
|
28
|
-
|
56
|
+
error_message(date_str, date)
|
29
57
|
end
|
30
58
|
end
|
31
59
|
|
32
60
|
private
|
33
61
|
|
62
|
+
def capture_options(options)
|
63
|
+
CLIOptions.instance.set(options)
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_date(date_str)
|
67
|
+
if date_str == "previous"
|
68
|
+
previous_logfile_date
|
69
|
+
else
|
70
|
+
DateTimeHelper.safe_parse(date_str) || DateTimeHelper.current_date
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def error_message(date_str, date)
|
75
|
+
if date_str == "previous" && date.nil?
|
76
|
+
warn(
|
77
|
+
"Sorry, I couldn't find any logs prior to "\
|
78
|
+
"#{DateTimeDecorator::ErrorMessageDisplay.new(DateTimeHelper.current_date)}."
|
79
|
+
)
|
80
|
+
else
|
81
|
+
warn "Sorry, I couldn't find any logs for #{DateTimeDecorator::ErrorMessageDisplay.new(date)}."
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
34
85
|
def exit_on_failure?
|
35
86
|
true
|
36
87
|
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# @return [Logfile] most recent logfile (excluding current date)
|
91
|
+
#
|
92
|
+
# rubocop:disable Metrics/MethodLength
|
93
|
+
def previous_logfile_date
|
94
|
+
# rubocop:enable Metrics/MethodLength
|
95
|
+
logfile_dates =
|
96
|
+
Dir.entries(".").map do |filename|
|
97
|
+
date = filename.gsub(".txt", "")
|
98
|
+
DateTimeHelper.safe_parse(date)
|
99
|
+
end.compact
|
100
|
+
most_recent_date, second_most_recent_date =
|
101
|
+
logfile_dates.sort.reverse.first(2)
|
102
|
+
# if most recent logfile is from today, return the
|
103
|
+
# second most recent
|
104
|
+
if most_recent_date&.to_date == Date.today
|
105
|
+
second_most_recent_date
|
106
|
+
else
|
107
|
+
most_recent_date
|
108
|
+
end
|
109
|
+
end
|
37
110
|
end
|
38
111
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
require "singleton"
|
5
|
+
|
6
|
+
module PieceOfWax
|
7
|
+
#
|
8
|
+
# Singleton class that stores options/flags passed from the command line. Purpose
|
9
|
+
# of the class is to make these options globally available.
|
10
|
+
#
|
11
|
+
class CLIOptions
|
12
|
+
include Singleton
|
13
|
+
extend Forwardable
|
14
|
+
|
15
|
+
def [](key)
|
16
|
+
options[key]
|
17
|
+
end
|
18
|
+
|
19
|
+
def set(opts)
|
20
|
+
raise "CLIOptions is an immutable singleton; #set can only be called once per program execution" if options.any?
|
21
|
+
|
22
|
+
@options = opts
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def options
|
28
|
+
@options || {}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "piece_of_wax/date_time"
|
4
|
+
|
5
|
+
module PieceOfWax
|
6
|
+
module DateTimeDecorator
|
7
|
+
#
|
8
|
+
# Decorator class designed to wrap DateTime instances. Implements form of to_s used
|
9
|
+
# to render error messages.
|
10
|
+
#
|
11
|
+
class ErrorMessageDisplay
|
12
|
+
def initialize(date_time)
|
13
|
+
@date_time = date_time
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
case @date_time.to_date
|
18
|
+
when DateTimeHelper.current_date
|
19
|
+
"today"
|
20
|
+
when DateTimeHelper.current_date.prev_day
|
21
|
+
"yesterday"
|
22
|
+
else
|
23
|
+
@date_time.strftime("%Y-%-m-%-d")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PieceOfWax
|
4
|
+
module DateTimeDecorator
|
5
|
+
#
|
6
|
+
# Decorator class designed to wrap DateTime instances. Implements form of to_s used
|
7
|
+
# to render times in output of `read` subcommand.
|
8
|
+
#
|
9
|
+
class ReadDisplay
|
10
|
+
def initialize(date_time)
|
11
|
+
@date_time = date_time
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
if CLIOptions.instance[:military]
|
16
|
+
@date_time.strftime("%H:%M")
|
17
|
+
else
|
18
|
+
@date_time.strftime("%I:%M %p")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "piece_of_wax/cli_options"
|
4
|
+
require "time"
|
5
|
+
|
6
|
+
module PieceOfWax
|
7
|
+
#
|
8
|
+
# Implements helper methods related to Date/Time
|
9
|
+
#
|
10
|
+
module DateTimeHelper
|
11
|
+
def self.safe_parse(arg)
|
12
|
+
# NOTE: calling to_s so method is safe for non-string args
|
13
|
+
str = arg.to_s
|
14
|
+
begin
|
15
|
+
Time.parse(str)
|
16
|
+
rescue ArgumentError
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.current_date
|
22
|
+
# NOTE: Possible that current_date returns two different values over course of
|
23
|
+
# same piece_of_wax invocation (if run at midnight.) I consider this
|
24
|
+
# to be a major edge case with minimal consequences, so I'm not
|
25
|
+
# going to the trouble of memoizing at this point. - Ben S.
|
26
|
+
Time.now.to_date
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.current_time
|
30
|
+
Time.now
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PieceOfWax
|
4
|
+
#
|
5
|
+
# A FileIO instance represents a file. Abstracts reading from and writing to the file system.
|
6
|
+
#
|
7
|
+
class FileIO
|
8
|
+
def initialize(filename)
|
9
|
+
@filename = filename
|
10
|
+
end
|
11
|
+
|
12
|
+
def read
|
13
|
+
File.read(@filename)
|
14
|
+
rescue Errno::ENOENT
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def overwrite_with(str)
|
19
|
+
File.open(@filename, "w") do |f|
|
20
|
+
f.write(str)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/piece_of_wax/logfile.rb
CHANGED
@@ -1,32 +1,44 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
require "json"
|
5
|
+
require "piece_of_wax/file_io"
|
6
|
+
require "piece_of_wax/output_line/activity"
|
7
|
+
require "piece_of_wax/output_line/date"
|
6
8
|
|
7
9
|
module PieceOfWax
|
10
|
+
#
|
11
|
+
# A Logfile instance represents a specific type of file used by piece_of_wax to
|
12
|
+
# store logged time (a "time log.") A time log stores information for a single day,
|
13
|
+
# which is why a date must be passed to the Logfile constructor.
|
14
|
+
#
|
8
15
|
class Logfile
|
9
16
|
def initialize(date)
|
10
|
-
filename = "%s.txt"
|
17
|
+
filename = format("%s.txt", date.strftime("%y%m%d"))
|
11
18
|
@file_io = FileIO.new(filename)
|
12
19
|
end
|
13
20
|
|
14
21
|
def contents
|
15
|
-
return unless raw_content = @file_io.read
|
22
|
+
return [] unless (raw_content = @file_io.read)
|
23
|
+
|
16
24
|
JSON.parse(raw_content)
|
17
25
|
end
|
18
26
|
|
27
|
+
def any_contents?
|
28
|
+
contents.any?
|
29
|
+
end
|
30
|
+
|
19
31
|
def add_activity(time, description)
|
20
|
-
data =
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@file_io.overwrite_with(
|
32
|
+
data = { datetime: time, description: description }
|
33
|
+
index = proper_index(time)
|
34
|
+
json_str = contents.insert(index, data).to_json
|
35
|
+
@file_io.overwrite_with(json_str)
|
36
|
+
end
|
37
|
+
|
38
|
+
def edit_activity(index, description)
|
39
|
+
updated_contents = contents.tap { |c| c[index]["description"] = description }
|
40
|
+
json_str = updated_contents.to_json
|
41
|
+
@file_io.overwrite_with(json_str)
|
30
42
|
end
|
31
43
|
|
32
44
|
def to_s
|
@@ -36,7 +48,7 @@ module PieceOfWax
|
|
36
48
|
<% contents.each_cons(2).map do |line1, line2| %>
|
37
49
|
<%= OutputLine::Activity.new(line1['datetime'], line2['datetime'], line1['description']) %>
|
38
50
|
<% end.join("\n") %>
|
39
|
-
<%= OutputLine::Activity.new(last_entry['datetime'],
|
51
|
+
<%= OutputLine::Activity.new(last_entry['datetime'], quitting_time, last_entry['description']) %>
|
40
52
|
ERB
|
41
53
|
# Unsure why ERB is inserting the double linebreaks after each
|
42
54
|
# iteration of `contents.each_cons(2)`. For now, subbing single linebreak
|
@@ -48,9 +60,9 @@ module PieceOfWax
|
|
48
60
|
|
49
61
|
def proper_index(time)
|
50
62
|
contents.each_with_index do |line, i|
|
51
|
-
return i if Time.parse(line[
|
63
|
+
return i if Time.parse(line["datetime"]) > time
|
52
64
|
end
|
53
|
-
|
65
|
+
contents.length
|
54
66
|
end
|
55
67
|
|
56
68
|
def first_entry
|
@@ -60,5 +72,9 @@ module PieceOfWax
|
|
60
72
|
def last_entry
|
61
73
|
contents.last
|
62
74
|
end
|
75
|
+
|
76
|
+
def quitting_time
|
77
|
+
CLIOptions.instance[:'quitting-time']
|
78
|
+
end
|
63
79
|
end
|
64
80
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "piece_of_wax/date_time_helper"
|
4
|
+
require "piece_of_wax/date_time_decorator/read_display"
|
5
|
+
|
6
|
+
module PieceOfWax
|
7
|
+
module OutputLine
|
8
|
+
#
|
9
|
+
# An Activity instance represents a single logged activity, rendered as a line of
|
10
|
+
# `read` subcommand output.
|
11
|
+
#
|
12
|
+
class Activity
|
13
|
+
def initialize(start_time_str, end_time_str, description)
|
14
|
+
@start_time = DateTimeDecorator::ReadDisplay.new(DateTimeHelper.safe_parse(start_time_str))
|
15
|
+
@end_time = DateTimeDecorator::ReadDisplay.new(DateTimeHelper.safe_parse(end_time_str))
|
16
|
+
@description = description
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"#{@start_time}-#{@end_time} - #{@description}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "piece_of_wax/date_time_helper"
|
4
|
+
|
5
|
+
module PieceOfWax
|
6
|
+
module OutputLine
|
7
|
+
#
|
8
|
+
# A Date instance represents the date of a time log (see Logfile,) rendered as a line of
|
9
|
+
# `read` subcommand output.
|
10
|
+
#
|
11
|
+
class Date
|
12
|
+
def initialize(datetime_str)
|
13
|
+
@date = DateTimeHelper.safe_parse(datetime_str)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
@date.strftime("%-m/%-d/%y")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: piece_of_wax
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.rc6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Stegeman
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: overcommit
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.55.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.55.0
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: pry
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,28 +100,28 @@ dependencies:
|
|
86
100
|
requirements:
|
87
101
|
- - "~>"
|
88
102
|
- !ruby/object:Gem::Version
|
89
|
-
version: 3.7
|
103
|
+
version: '3.7'
|
90
104
|
type: :development
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
108
|
- - "~>"
|
95
109
|
- !ruby/object:Gem::Version
|
96
|
-
version: 3.7
|
110
|
+
version: '3.7'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
112
|
+
name: rubocop
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
115
|
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version: 0.
|
117
|
+
version: 0.88.0
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.
|
124
|
+
version: 0.88.0
|
111
125
|
description: ''
|
112
126
|
email: bstegeman17@gmail.com
|
113
127
|
executables:
|
@@ -117,7 +131,14 @@ extra_rdoc_files: []
|
|
117
131
|
files:
|
118
132
|
- bin/piece_of_wax
|
119
133
|
- lib/piece_of_wax.rb
|
134
|
+
- lib/piece_of_wax/cli_options.rb
|
135
|
+
- lib/piece_of_wax/date_time_decorator/error_message_display.rb
|
136
|
+
- lib/piece_of_wax/date_time_decorator/read_display.rb
|
137
|
+
- lib/piece_of_wax/date_time_helper.rb
|
138
|
+
- lib/piece_of_wax/file_io.rb
|
120
139
|
- lib/piece_of_wax/logfile.rb
|
140
|
+
- lib/piece_of_wax/output_line/activity.rb
|
141
|
+
- lib/piece_of_wax/output_line/date.rb
|
121
142
|
homepage:
|
122
143
|
licenses:
|
123
144
|
- MIT
|