aoc_cli 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/CHANGELOG.md +18 -2
- data/Gemfile +0 -8
- data/README.md +138 -53
- data/aoc_cli.gemspec +1 -1
- data/bin/setup +1 -2
- data/lib/aoc_cli.rb +1 -1
- data/lib/aoc_cli/commands.rb +86 -69
- data/lib/aoc_cli/database.rb +75 -14
- data/lib/aoc_cli/day.rb +58 -87
- data/lib/aoc_cli/errors.rb +18 -3
- data/lib/aoc_cli/files.rb +125 -56
- data/lib/aoc_cli/help.rb +30 -9
- data/lib/aoc_cli/interface.rb +45 -28
- data/lib/aoc_cli/paths.rb +33 -30
- data/lib/aoc_cli/solve.rb +27 -35
- data/lib/aoc_cli/tables.rb +79 -79
- data/lib/aoc_cli/tools.rb +30 -6
- data/lib/aoc_cli/version.rb +1 -3
- data/lib/aoc_cli/year.rb +49 -32
- data/sample/aoc.rc +21 -0
- metadata +4 -4
- data/pkg/aoc_cli-0.1.2.gem +0 -0
data/lib/aoc_cli/help.rb
CHANGED
@@ -8,8 +8,9 @@ def flag(short, full)
|
|
8
8
|
str += "\t\t"
|
9
9
|
str
|
10
10
|
end
|
11
|
-
|
12
|
-
|
11
|
+
|
12
|
+
help = <<~help
|
13
|
+
Advent of Code - cli, version #{AocCli::VERSION}
|
13
14
|
#{"C. Welham Feb 2021".italic}
|
14
15
|
|
15
16
|
#{title("Usage")}
|
@@ -17,12 +18,16 @@ Advent of Code - cli, version 0.1.0
|
|
17
18
|
|
18
19
|
#{title("Setup")}
|
19
20
|
- Store session cookie keys to access AoC
|
20
|
-
|
21
|
-
#{flag("-
|
21
|
+
|
22
|
+
#{flag("-k","--key")}Store a session cookie to use the cli.
|
23
|
+
#{flag("-u","--user")}Set alias for key (default: "main")
|
24
|
+
#{flag("-U","--default")}Get/set default alias
|
25
|
+
#{flag("-h","--help")}Print this screen
|
22
26
|
|
23
27
|
#{title("Year Directory")}
|
24
28
|
- Initialise a year directory to use aoc-cli.
|
25
29
|
- If no alias is passed, the default key is used
|
30
|
+
|
26
31
|
#{flag("-y","--init-year")}Initialise directory and fetch calendar
|
27
32
|
#{flag("-u","--user")}Specify alias for initialisation
|
28
33
|
#{flag("-d","--init-day")}Create day subdirectory, fetch puzzle and input
|
@@ -30,16 +35,21 @@ Advent of Code - cli, version 0.1.0
|
|
30
35
|
|
31
36
|
#{title("Day Subdirectory")}
|
32
37
|
- These commands can be run from the day subdirectory
|
38
|
+
|
33
39
|
#{flag("-s","--solve")}Attempt puzzle
|
34
|
-
#{flag("-r","--refresh")}Refresh puzzle
|
35
|
-
#{flag("-a","--attempts")}Prints previous attempt table
|
36
40
|
#{flag("-p","--part")}Specify part (attempts)
|
41
|
+
#{flag("-r","--refresh")}Refresh puzzle
|
42
|
+
|
43
|
+
#{title("Reddit")}
|
44
|
+
- Defaults to a Reddit CLI if one is installed
|
45
|
+
|
37
46
|
#{flag("-R","--reddit")}Open Reddit solution megathread
|
38
|
-
#{flag("-
|
47
|
+
#{flag("-B","--browser")}Open Reddit thread in browser
|
39
48
|
|
40
49
|
#{title("Manual Usage")}
|
41
50
|
- AocCli uses metadata so that these flags do not need to be entered.
|
42
51
|
- Command flags can be entered manually, but this is not recommended
|
52
|
+
|
43
53
|
#{flag("-u","--user")}Specify user
|
44
54
|
#{flag("-Y","--year")}Specify year
|
45
55
|
#{flag("-D","--day")}Specify day
|
@@ -48,6 +58,17 @@ Advent of Code - cli, version 0.1.0
|
|
48
58
|
#{title("Configuration")}
|
49
59
|
- Pass with a value to update setting
|
50
60
|
- Pass without an argument to display current setting.
|
51
|
-
|
52
|
-
#{flag("-U","--default")}Default key alias to use
|
61
|
+
|
62
|
+
#{flag("-U","--default")}Default key alias to use
|
63
|
+
#{flag("-G","--gen-config")}Creates an example config file
|
64
|
+
|
65
|
+
#{title("Tables")}
|
66
|
+
- Print stats in a terminal-friendly table
|
67
|
+
|
68
|
+
#{flag("-a","--attempts")}Prints previous attempts for puzzle (part needed)
|
69
|
+
#{flag("-c","--simple-cal")}Prints your progress
|
70
|
+
#{flag("-C","--fancy-cal")}Prints your calendar file
|
71
|
+
#{flag("-S","--stats")}Prints your stats (time taken, number of attempts)
|
72
|
+
|
53
73
|
help
|
74
|
+
system("echo '#{help}' | less -r")
|
data/lib/aoc_cli/interface.rb
CHANGED
@@ -3,17 +3,16 @@ module AocCli
|
|
3
3
|
class Query
|
4
4
|
def initialize
|
5
5
|
ARGV.size > 0 ?
|
6
|
-
run(opts:Opts.new.parse_args) :
|
7
|
-
puts(Help.print)
|
6
|
+
run(opts:Opts.new.parse_args) : Help.print
|
8
7
|
rescue StandardError => e
|
9
8
|
abort e.message
|
10
9
|
end
|
11
10
|
def run(opts:)
|
12
|
-
cmd =
|
13
|
-
.const_get("AocCli::Commands::#{opts.cmd}")
|
11
|
+
cmd = Commands.const_get(Validate.cmd(opts.cmd))
|
14
12
|
.new(opts.args)
|
15
13
|
.exec
|
16
|
-
cmd.respond if cmd.class
|
14
|
+
cmd.respond if cmd.class
|
15
|
+
.instance_methods.include?(:respond)
|
17
16
|
end
|
18
17
|
end
|
19
18
|
class Help
|
@@ -31,60 +30,65 @@ module AocCli
|
|
31
30
|
case ARGV.shift
|
32
31
|
when "-a", "--attempts"
|
33
32
|
@cmd = :AttemptsTable
|
34
|
-
when "-
|
33
|
+
when "-B", "--browser"
|
34
|
+
@cmd = :OpenReddit
|
35
35
|
args[:browser] = true
|
36
|
+
when "-c", "--simple-cal"
|
37
|
+
@cmd = :CalendarTable
|
38
|
+
when "-C", "--fancy-cal"
|
39
|
+
@cmd = :PrintCal
|
36
40
|
when "-d", "--init-day"
|
37
41
|
@cmd = :DayInit
|
38
42
|
args[:day] = Validate.day(ARGV.shift.to_i)
|
43
|
+
when "-D", "--day"
|
44
|
+
args[:day] = ARGV.shift.to_i
|
45
|
+
when "-G", "--gen-config"
|
46
|
+
@cmd = :GenerateConfig
|
39
47
|
when "-h", "--help"
|
40
48
|
exit Help.print
|
41
49
|
when "-k", "--key"
|
42
50
|
@cmd = :KeyStore
|
43
51
|
args[:key] = Validate.set_key(ARGV.shift)
|
44
52
|
when "-p", "--part"
|
45
|
-
args[:part] =
|
53
|
+
args[:part] = ARGV.shift.to_i
|
46
54
|
when "-r", "--refresh"
|
47
55
|
@cmd = :Refresh
|
56
|
+
when "-R", "--reddit"
|
57
|
+
@cmd = :OpenReddit
|
48
58
|
when "-s", "--solve"
|
49
59
|
@cmd = :DaySolve
|
50
60
|
args[:ans] = Validate.ans(ARGV.shift)
|
61
|
+
when "-S", "--stats"
|
62
|
+
@cmd = :StatsTable
|
51
63
|
when "-u", "--user"
|
52
64
|
args[:user] = ARGV.shift
|
65
|
+
when "-U", "--default"
|
66
|
+
@cmd = :DefaultAlias
|
67
|
+
args[:user] = ARGV.shift
|
53
68
|
when "-y", "--init-year"
|
54
69
|
@cmd = :YearInit
|
55
70
|
args[:year] = Validate.year(ARGV.shift.to_i)
|
56
|
-
when "-B", "--browser"
|
57
|
-
@cmd = :DefaultReddit
|
58
|
-
args[:value] = ARGV.shift
|
59
|
-
when "-D", "--day"
|
60
|
-
args[:day] = Validate.day(ARGV.shift.to_i)
|
61
|
-
when "-R", "--reddit"
|
62
|
-
@cmd = :OpenReddit
|
63
|
-
when "-S", "--stats"
|
64
|
-
@cmd = :StatsTable
|
65
|
-
when "-U", "--default-user"
|
66
|
-
@cmd = :DefaultUser
|
67
|
-
args[:user] = ARGV.shift
|
68
71
|
when "-Y", "--year"
|
69
|
-
args[:year] =
|
72
|
+
args[:year] = ARGV.shift.to_i
|
70
73
|
else raise E::FlagInv
|
71
74
|
end
|
72
75
|
end
|
73
|
-
raise E::NoCmd if cmd.nil?
|
74
76
|
self
|
75
77
|
end
|
76
78
|
end
|
77
79
|
class Validate
|
80
|
+
def self.cmd(cmd)
|
81
|
+
raise E::CmdNil if cmd.nil?
|
82
|
+
cmd
|
83
|
+
end
|
78
84
|
def self.user(user)
|
79
85
|
raise E::UserNil if user.nil?
|
80
|
-
raise E::UserInv.new(user) unless
|
81
|
-
.new.is_set?(key:"cookie=>#{user}")
|
86
|
+
raise E::UserInv.new(user) unless user_in_config?(user)
|
82
87
|
user
|
83
88
|
end
|
84
89
|
def self.set_user(user)
|
85
90
|
raise E::UserNil if user.nil?
|
86
|
-
raise E::UserDup if
|
87
|
-
.is_set?(key:"cookie=>#{user}")
|
91
|
+
raise E::UserDup.new(user) if user_in_config?(user)
|
88
92
|
user
|
89
93
|
end
|
90
94
|
def self.year(year)
|
@@ -107,12 +111,14 @@ module AocCli
|
|
107
111
|
end
|
108
112
|
def self.set_key(key)
|
109
113
|
raise E::KeyNil if key.nil?
|
110
|
-
raise E::KeyDup if Files::Config
|
111
|
-
.
|
114
|
+
raise E::KeyDup.new(key) if Files::Config::Tools
|
115
|
+
.is_set?(val:"#{key}(\b|$)")
|
116
|
+
raise E::KeyInv unless valid_key?(key)
|
112
117
|
key
|
113
118
|
end
|
114
|
-
def self.
|
119
|
+
def self.key(key)
|
115
120
|
raise E::KeyNil if key.nil?
|
121
|
+
raise E::KeyInv unless valid_key?(key)
|
116
122
|
key
|
117
123
|
end
|
118
124
|
def self.ans(ans)
|
@@ -132,6 +138,17 @@ module AocCli
|
|
132
138
|
Metafile.get(:year) != year.to_s
|
133
139
|
dir
|
134
140
|
end
|
141
|
+
def self.no_config
|
142
|
+
raise E::ConfigExist if File.exist?(Paths::Config.path)
|
143
|
+
Paths::Config.path
|
144
|
+
end
|
145
|
+
private
|
146
|
+
def self.valid_key?(key)
|
147
|
+
/session=(?:[a-f0-9]){96}/.match?(key)
|
148
|
+
end
|
149
|
+
def self.user_in_config?(user)
|
150
|
+
Files::Config::Tools.is_set?(key:"cookie=>#{user}")
|
151
|
+
end
|
135
152
|
end
|
136
153
|
end
|
137
154
|
end
|
data/lib/aoc_cli/paths.rb
CHANGED
@@ -1,16 +1,29 @@
|
|
1
1
|
module AocCli
|
2
2
|
module Paths
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
require 'fileutils'
|
4
|
+
class Year
|
5
|
+
attr_reader :user, :year
|
6
|
+
def initialize(u:Metafile.get(:user),
|
7
|
+
y:Metafile.get(:year))
|
8
|
+
@user = Validate.user(u)
|
9
|
+
@year = Validate.year(y)
|
8
10
|
end
|
9
|
-
def
|
10
|
-
|
11
|
+
def in_year?
|
12
|
+
File.exist?("./.meta") ?
|
13
|
+
Metafile.type == :ROOT : true
|
11
14
|
end
|
12
|
-
def
|
13
|
-
"
|
15
|
+
def year_dir
|
16
|
+
in_year? ? "." : ".."
|
17
|
+
end
|
18
|
+
def local(f:)
|
19
|
+
"#{Validate.not_init(dir:year_dir,
|
20
|
+
year:year)}/#{filename(f:f)}"
|
21
|
+
end
|
22
|
+
def filename(f:)
|
23
|
+
case f.to_sym
|
24
|
+
when :Stars then "#{year}.md"
|
25
|
+
when :meta then ".meta"
|
26
|
+
end
|
14
27
|
end
|
15
28
|
end
|
16
29
|
class Day
|
@@ -21,6 +34,9 @@ module AocCli
|
|
21
34
|
@year = Validate.year(y)
|
22
35
|
@day = Validate.day(d)
|
23
36
|
end
|
37
|
+
def create_cache
|
38
|
+
FileUtils.mkdir_p(cache_dir) unless Dir.exist?(cache_dir)
|
39
|
+
end
|
24
40
|
def filename(f:)
|
25
41
|
case f.to_sym
|
26
42
|
when :Input then "input"
|
@@ -51,29 +67,16 @@ module AocCli
|
|
51
67
|
[cache_path(f:f), local(f:f)]
|
52
68
|
end
|
53
69
|
end
|
54
|
-
class
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
@user = Validate.user(u)
|
59
|
-
@year = Validate.year(y)
|
60
|
-
end
|
61
|
-
def in_year?
|
62
|
-
File.exist?("./.meta") ?
|
63
|
-
Metafile.type == :ROOT : true
|
64
|
-
end
|
65
|
-
def year_dir
|
66
|
-
in_year? ? "." : ".."
|
70
|
+
class Config
|
71
|
+
def self.create
|
72
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
73
|
+
File.write(path, "", mode:"a") unless File.exist?(path)
|
67
74
|
end
|
68
|
-
def
|
69
|
-
"#{
|
70
|
-
year:year)}/#{filename(f:f)}"
|
75
|
+
def self.dir
|
76
|
+
"#{Dir.home}/.config/aoc-cli"
|
71
77
|
end
|
72
|
-
def
|
73
|
-
|
74
|
-
when :Stars then "#{year}.md"
|
75
|
-
when :meta then ".meta"
|
76
|
-
end
|
78
|
+
def self.path
|
79
|
+
"#{dir}/aoc.rc"
|
77
80
|
end
|
78
81
|
end
|
79
82
|
class Database < Config
|
data/lib/aoc_cli/solve.rb
CHANGED
@@ -16,10 +16,8 @@ module AocCli
|
|
16
16
|
@answer = Validate.ans(a)
|
17
17
|
end
|
18
18
|
def raw
|
19
|
-
@raw ||= Tools::Post
|
20
|
-
|
21
|
-
data:{level:part, answer:answer})
|
22
|
-
.plain
|
19
|
+
@raw ||= Tools::Post.new(u:user, y:year, d:day,
|
20
|
+
data:{level:part, answer:answer}).plain
|
23
21
|
end
|
24
22
|
def check
|
25
23
|
case raw
|
@@ -29,8 +27,7 @@ module AocCli
|
|
29
27
|
end
|
30
28
|
end
|
31
29
|
def respond
|
32
|
-
|
33
|
-
.const_get("AocCli::Solve::Respond::#{check}")
|
30
|
+
Respond.const_get(check)
|
34
31
|
.new(attempt:self)
|
35
32
|
.respond
|
36
33
|
.react
|
@@ -45,44 +42,35 @@ module AocCli
|
|
45
42
|
end
|
46
43
|
class Correct < Response
|
47
44
|
def react
|
48
|
-
|
49
|
-
.new(attempt:attempt)
|
50
|
-
.correct
|
51
|
-
Database::Stats::Complete
|
52
|
-
.new(n:log.count_attempts)
|
53
|
-
.update
|
45
|
+
Database.correct(attempt:attempt)
|
54
46
|
Year.refresh
|
55
|
-
Day.refresh
|
56
|
-
Database::Stats::Init.new.init
|
47
|
+
Day.refresh(files:[:Puzzle])
|
57
48
|
end
|
58
49
|
def respond
|
59
|
-
response
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
50
|
+
puts <<~response
|
51
|
+
#{"Correct!".bold.green} #{
|
52
|
+
case attempt.part
|
53
|
+
when "1" then "Downloading part two..."
|
54
|
+
when "2" then "This day is now complete!".green
|
55
|
+
end }
|
56
|
+
response
|
64
57
|
self
|
65
58
|
end
|
66
|
-
private
|
67
|
-
def next_part
|
68
|
-
"Downloading part two.."
|
69
|
-
end
|
70
|
-
def complete
|
71
|
-
"This day is now complete!".green
|
72
|
-
end
|
73
59
|
end
|
74
60
|
class Incorrect < Response
|
75
61
|
def react
|
76
|
-
Database::
|
62
|
+
Database::Attempt
|
77
63
|
.new(attempt:attempt)
|
78
64
|
.incorrect(high:high, low:low)
|
79
65
|
end
|
80
66
|
def respond
|
81
|
-
response
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
67
|
+
puts <<~response
|
68
|
+
#{"Incorrect".red.bold}: You guessed - #{attempt
|
69
|
+
.answer.to_s.red} #{
|
70
|
+
high ? "(too high)" :
|
71
|
+
low ? "(too low)" : ""}
|
72
|
+
#{"Please wait".yellow} #{wait_time} before answering again
|
73
|
+
response
|
86
74
|
self
|
87
75
|
end
|
88
76
|
def high
|
@@ -91,12 +79,16 @@ module AocCli
|
|
91
79
|
def low
|
92
80
|
/too low/.match?(attempt.raw)
|
93
81
|
end
|
82
|
+
def wait_time
|
83
|
+
attempt.raw.scan(/(?:(one minute|\d+ minutes))/)
|
84
|
+
.first.first.to_s
|
85
|
+
end
|
94
86
|
end
|
95
87
|
class Wait < Response
|
96
88
|
def respond
|
97
|
-
response
|
98
|
-
|
99
|
-
|
89
|
+
puts <<~response
|
90
|
+
#{"Please wait".yellow.bold}: #{time.to_s}
|
91
|
+
response
|
100
92
|
self
|
101
93
|
end
|
102
94
|
def time
|
data/lib/aoc_cli/tables.rb
CHANGED
@@ -1,34 +1,47 @@
|
|
1
1
|
module AocCli
|
2
2
|
module Tables
|
3
|
-
class
|
3
|
+
class Table
|
4
4
|
require 'terminal-table'
|
5
|
-
attr_reader :user, :year, :
|
6
|
-
def initialize(u:Metafile.get(:user),
|
7
|
-
y:Metafile.get(:year),
|
8
|
-
d:Metafile.get(:day),
|
9
|
-
p:Metafile.get(:part))
|
5
|
+
attr_reader :user, :year, :table, :cols, :where
|
6
|
+
def initialize(u:Metafile.get(:user), y:Metafile.get(:year))
|
10
7
|
@user = Validate.user(u)
|
11
8
|
@year = Validate.year(y)
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
end
|
10
|
+
def border
|
11
|
+
Prefs.bool(key:"unicode_tables") ? :unicode : :ascii
|
12
|
+
end
|
13
|
+
def data
|
14
|
+
Database::Query
|
15
15
|
.new(path:Paths::Database.cfg(user))
|
16
|
+
.select(t:table, cols:cols, where:where)
|
16
17
|
end
|
17
|
-
def
|
18
|
-
puts rows.count > 0 ?
|
19
|
-
"You have not attempted this puzzle yet!"
|
18
|
+
def print
|
19
|
+
puts rows.count > 0 ? make : nil_message
|
20
20
|
end
|
21
|
-
|
22
|
-
def table
|
21
|
+
def make
|
23
22
|
tab = Terminal::Table.new(
|
24
23
|
:headings => headings,
|
25
24
|
:rows => rows,
|
26
25
|
:title => title)
|
27
26
|
tab.style = {
|
28
|
-
:border =>
|
27
|
+
:border => border,
|
29
28
|
:alignment => :center}
|
30
29
|
tab
|
31
30
|
end
|
31
|
+
end
|
32
|
+
class Attempts < Table
|
33
|
+
attr_reader :day, :part
|
34
|
+
def initialize(u:Metafile.get(:user),
|
35
|
+
y:Metafile.get(:year),
|
36
|
+
d:Metafile.get(:day),
|
37
|
+
p:Metafile.get(:part))
|
38
|
+
super(u:u, y:y)
|
39
|
+
@day = Validate.day(d)
|
40
|
+
@part = Validate.part(p)
|
41
|
+
@table = :attempts
|
42
|
+
@cols = "time, answer, high, low, correct"
|
43
|
+
@where = {year:year, day:day, part:part}
|
44
|
+
end
|
32
45
|
def title
|
33
46
|
"#{year} - Day #{day}:#{part}".bold
|
34
47
|
end
|
@@ -36,56 +49,33 @@ module AocCli
|
|
36
49
|
["Answer", "Time", "Hint"]
|
37
50
|
end
|
38
51
|
def rows
|
39
|
-
@rows ||=
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
def parse_ans(attempt)
|
49
|
-
attempt[4] == 1 ?
|
50
|
-
attempt[1].to_s.green :
|
51
|
-
attempt[1].to_s.red
|
52
|
-
end
|
53
|
-
def parse_time(attempt)
|
54
|
-
DateTime
|
55
|
-
.strptime(attempt[0], "%Y-%m-%d %H:%M:%S %Z")
|
52
|
+
@rows ||= data.map do |d|
|
53
|
+
[parse_ans(d), parse_time(d), parse_hint(d)]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
def parse_ans(row)
|
57
|
+
row[4] == 1 ? row[1].to_s.green : row[1].to_s.red
|
58
|
+
end
|
59
|
+
def parse_time(row)
|
60
|
+
DateTime.strptime(row[0], "%Y-%m-%d %H:%M:%S %Z")
|
56
61
|
.strftime("%H:%M - %d/%m/%y")
|
57
62
|
end
|
58
|
-
def parse_hint(
|
59
|
-
|
60
|
-
|
63
|
+
def parse_hint(row)
|
64
|
+
row[3] == 1 ? "low" :
|
65
|
+
row[2] == 1 ? "high" : "-"
|
66
|
+
end
|
67
|
+
def nil_message
|
68
|
+
"You have not attempted part #{part} yet!"
|
61
69
|
end
|
62
70
|
end
|
63
71
|
module Stats
|
64
|
-
class Year
|
65
|
-
attr_reader :user, :year, :db
|
72
|
+
class Year < Table
|
66
73
|
def initialize(u:Metafile.get(:user),
|
67
74
|
y:Metafile.get(:year))
|
68
|
-
|
69
|
-
@
|
70
|
-
@
|
71
|
-
|
72
|
-
end
|
73
|
-
def print
|
74
|
-
puts rows.count > 0 ? table :
|
75
|
-
"You have not completed any puzzles yet"
|
76
|
-
end
|
77
|
-
def rows
|
78
|
-
@rows ||= stats.map{|s| [s[0], s[1], s[2], s[3]]}
|
79
|
-
end
|
80
|
-
def table
|
81
|
-
tab = Terminal::Table.new(
|
82
|
-
:headings => headings,
|
83
|
-
:rows => rows,
|
84
|
-
:title => title)
|
85
|
-
tab.style = {
|
86
|
-
:border => :unicode,
|
87
|
-
:alignment => :center}
|
88
|
-
tab
|
75
|
+
super(u:u, y:y)
|
76
|
+
@table = :stats
|
77
|
+
@cols = "day, part, attempts, elapsed"
|
78
|
+
@where = {year:"'#{year}'", correct:"'1'"}
|
89
79
|
end
|
90
80
|
def title
|
91
81
|
"Year #{year}"
|
@@ -93,15 +83,11 @@ module AocCli
|
|
93
83
|
def headings
|
94
84
|
["Day", "Part", "Attempts", "Time (h:m:s)"]
|
95
85
|
end
|
96
|
-
def
|
97
|
-
@
|
98
|
-
t:"stats",
|
99
|
-
cols:"day, part, attempts, elapsed",
|
100
|
-
data:where)
|
86
|
+
def rows
|
87
|
+
@rows ||= data.map{|d| [d[0], d[1], d[2], d[3]]}
|
101
88
|
end
|
102
|
-
def
|
103
|
-
|
104
|
-
correct:"'1'"}
|
89
|
+
def nil_message
|
90
|
+
"You have not completed any puzzles yet"
|
105
91
|
end
|
106
92
|
end
|
107
93
|
class Day < Year
|
@@ -111,9 +97,10 @@ module AocCli
|
|
111
97
|
d:Metafile.get(:day))
|
112
98
|
super(u:u, y:y)
|
113
99
|
@day = Validate.day(d)
|
114
|
-
|
115
|
-
|
116
|
-
|
100
|
+
@cols = "part, attempts, elapsed"
|
101
|
+
@where = { year:"'#{year}'",
|
102
|
+
day:"'#{day}'",
|
103
|
+
correct:"'1'" }
|
117
104
|
end
|
118
105
|
def title
|
119
106
|
"Year #{year}: Day #{day}"
|
@@ -121,18 +108,31 @@ module AocCli
|
|
121
108
|
def headings
|
122
109
|
["Part", "Attempts", "Time (h:m:s)"]
|
123
110
|
end
|
124
|
-
def
|
125
|
-
@
|
126
|
-
t:"stats",
|
127
|
-
cols:"part, attempts, elapsed",
|
128
|
-
data:where)
|
129
|
-
end
|
130
|
-
def where
|
131
|
-
{year:"'#{year}'",
|
132
|
-
day:"'#{day}'",
|
133
|
-
correct:"'1'"}
|
111
|
+
def rows
|
112
|
+
@rows ||= data.map{|d| [d[0], d[1], d[2]]}
|
134
113
|
end
|
135
114
|
end
|
136
115
|
end
|
116
|
+
class Calendar < Table
|
117
|
+
def initialize(u:Metafile.get(:user),
|
118
|
+
y:Metafile.get(:year))
|
119
|
+
super(u:u, y:y)
|
120
|
+
@table = :calendar
|
121
|
+
@cols = "*"
|
122
|
+
@where = {year:year}
|
123
|
+
end
|
124
|
+
def title
|
125
|
+
"#{user}: #{year}"
|
126
|
+
end
|
127
|
+
def headings
|
128
|
+
["Day", "Stars"]
|
129
|
+
end
|
130
|
+
def rows
|
131
|
+
@rows ||= data.map{|d| [d[1], parse_stars(d[2])]}
|
132
|
+
end
|
133
|
+
def parse_stars(day)
|
134
|
+
day.to_i == 0 ? ".." : ("*" * day.to_i).ljust(2, ".")
|
135
|
+
end
|
136
|
+
end
|
137
137
|
end
|
138
138
|
end
|