aoc_cli 0.2.2 → 1.0.0
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/.rspec +1 -0
- data/.rubocop.yml +88 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +187 -0
- data/README.md +88 -282
- data/Rakefile +9 -2
- data/Steepfile +13 -0
- data/aoc_cli.gemspec +36 -26
- data/db/migrate/1_create_events.rb +14 -0
- data/db/migrate/2_create_puzzles.rb +21 -0
- data/db/migrate/3_create_stats.rb +19 -0
- data/db/migrate/4_create_attempts.rb +19 -0
- data/db/migrate/5_create_locations.rb +17 -0
- data/db/migrate/6_create_puzzle_dir_sync_logs.rb +18 -0
- data/exe/aoc +5 -0
- data/lib/aoc_cli/components/attempts_table.erb +5 -0
- data/lib/aoc_cli/components/attempts_table.rb +58 -0
- data/lib/aoc_cli/components/docs_component.erb +19 -0
- data/lib/aoc_cli/components/docs_component.rb +41 -0
- data/lib/aoc_cli/components/errors_component.erb +8 -0
- data/lib/aoc_cli/components/errors_component.rb +36 -0
- data/lib/aoc_cli/components/progress_table.erb +1 -0
- data/lib/aoc_cli/components/progress_table.rb +43 -0
- data/lib/aoc_cli/components/puzzle_sync_component.erb +2 -0
- data/lib/aoc_cli/components/puzzle_sync_component.rb +26 -0
- data/lib/aoc_cli/configurators/session_configurator.rb +7 -0
- data/lib/aoc_cli/controllers/application_controller.rb +27 -0
- data/lib/aoc_cli/controllers/concerns/error_concern.rb +17 -0
- data/lib/aoc_cli/controllers/concerns/location_concern.rb +79 -0
- data/lib/aoc_cli/controllers/default_controller.rb +9 -0
- data/lib/aoc_cli/controllers/event_controller.rb +35 -0
- data/lib/aoc_cli/controllers/help/event_controller.rb +11 -0
- data/lib/aoc_cli/controllers/help/puzzle_controller.rb +13 -0
- data/lib/aoc_cli/controllers/puzzle_controller.rb +39 -0
- data/lib/aoc_cli/core/attempt_parser.rb +69 -0
- data/lib/aoc_cli/core/processor.rb +32 -0
- data/lib/aoc_cli/core/repository.rb +74 -0
- data/lib/aoc_cli/core/request.rb +37 -0
- data/lib/aoc_cli/core/resource.rb +39 -0
- data/lib/aoc_cli/core/stats_parser.rb +43 -0
- data/lib/aoc_cli/helpers/table_generator.rb +64 -0
- data/lib/aoc_cli/helpers/view_helper.rb +35 -0
- data/lib/aoc_cli/models/attempt.rb +67 -0
- data/lib/aoc_cli/models/event.rb +9 -0
- data/lib/aoc_cli/models/location.rb +24 -0
- data/lib/aoc_cli/models/puzzle.rb +28 -0
- data/lib/aoc_cli/models/puzzle_dir_sync_log.rb +14 -0
- data/lib/aoc_cli/models/stats.rb +43 -0
- data/lib/aoc_cli/presenters/attempt_presenter.rb +29 -0
- data/lib/aoc_cli/presenters/puzzle_presenter.rb +29 -0
- data/lib/aoc_cli/presenters/stats_presenter.rb +32 -0
- data/lib/aoc_cli/processors/event_initialiser.rb +64 -0
- data/lib/aoc_cli/processors/puzzle_dir_synchroniser.rb +80 -0
- data/lib/aoc_cli/processors/puzzle_initialiser.rb +91 -0
- data/lib/aoc_cli/processors/puzzle_refresher.rb +27 -0
- data/lib/aoc_cli/processors/resource_attacher.rb +22 -0
- data/lib/aoc_cli/processors/solution_poster.rb +72 -0
- data/lib/aoc_cli/processors/stats_initialiser.rb +36 -0
- data/lib/aoc_cli/processors/stats_refresher.rb +23 -0
- data/lib/aoc_cli/validators/collection_type_validator.rb +57 -0
- data/lib/aoc_cli/validators/event_year_validator.rb +42 -0
- data/lib/aoc_cli/validators/included_validator.rb +21 -0
- data/lib/aoc_cli/validators/integer_validator.rb +32 -0
- data/lib/aoc_cli/validators/path_validator.rb +39 -0
- data/lib/aoc_cli/validators/type_validator.rb +54 -0
- data/lib/aoc_cli/version.rb +1 -1
- data/lib/aoc_cli/views/event/attach.erb +3 -0
- data/lib/aoc_cli/views/event/init.erb +3 -0
- data/lib/aoc_cli/views/help/event/attach.erb +32 -0
- data/lib/aoc_cli/views/help/event/init.erb +38 -0
- data/lib/aoc_cli/views/help/event/progress.erb +12 -0
- data/lib/aoc_cli/views/help/puzzle/attempts.erb +12 -0
- data/lib/aoc_cli/views/help/puzzle/init.erb +31 -0
- data/lib/aoc_cli/views/help/puzzle/solve.erb +33 -0
- data/lib/aoc_cli/views/help/puzzle/sync.erb +32 -0
- data/lib/aoc_cli/views/puzzle/init.erb +3 -0
- data/lib/aoc_cli/views/puzzle/solve.erb +10 -0
- data/lib/aoc_cli.rb +32 -16
- data/rbs_collection.lock.yaml +168 -0
- data/rbs_collection.yaml +28 -0
- data/sig/aoc_cli/components/attempts_table.rbs +29 -0
- data/sig/aoc_cli/components/docs_component.rbs +15 -0
- data/sig/aoc_cli/components/errors_component.rbs +19 -0
- data/sig/aoc_cli/components/progress_table.rbs +28 -0
- data/sig/aoc_cli/components/puzzle_sync_component.rbs +19 -0
- data/sig/aoc_cli/configurators/session_configurator.rbs +7 -0
- data/sig/aoc_cli/controllers/application_controller.rbs +12 -0
- data/sig/aoc_cli/controllers/concerns/error_concern.rbs +9 -0
- data/sig/aoc_cli/controllers/concerns/location_concern.rbs +35 -0
- data/sig/aoc_cli/controllers/default_controller.rbs +7 -0
- data/sig/aoc_cli/controllers/event_controller.rbs +18 -0
- data/sig/aoc_cli/controllers/help/event_controller.rbs +11 -0
- data/sig/aoc_cli/controllers/help/puzzle_controller.rbs +13 -0
- data/sig/aoc_cli/controllers/puzzle_controller.rbs +15 -0
- data/sig/aoc_cli/core/attempt_parser.rbs +41 -0
- data/sig/aoc_cli/core/processor.rbs +25 -0
- data/sig/aoc_cli/core/repository.rbs +25 -0
- data/sig/aoc_cli/core/request.rbs +29 -0
- data/sig/aoc_cli/core/resource.rbs +25 -0
- data/sig/aoc_cli/core/stats_parser.rbs +23 -0
- data/sig/aoc_cli/helpers/table_generator.rbs +36 -0
- data/sig/aoc_cli/helpers/view_helper.rbs +15 -0
- data/sig/aoc_cli/models/attempt.rbs +35 -0
- data/sig/aoc_cli/models/event.rbs +17 -0
- data/sig/aoc_cli/models/location.rbs +19 -0
- data/sig/aoc_cli/models/puzzle.rbs +28 -0
- data/sig/aoc_cli/models/puzzle_dir_sync_log.rbs +11 -0
- data/sig/aoc_cli/models/stats.rbs +53 -0
- data/sig/aoc_cli/presenters/attempt_presenter.rbs +13 -0
- data/sig/aoc_cli/presenters/puzzle_presenter.rbs +19 -0
- data/sig/aoc_cli/presenters/stats_presenter.rbs +19 -0
- data/sig/aoc_cli/processors/event_initialiser.rbs +26 -0
- data/sig/aoc_cli/processors/puzzle_dir_synchroniser.rbs +40 -0
- data/sig/aoc_cli/processors/puzzle_initialiser.rbs +37 -0
- data/sig/aoc_cli/processors/puzzle_refresher.rbs +21 -0
- data/sig/aoc_cli/processors/resource_attacher.rbs +16 -0
- data/sig/aoc_cli/processors/solution_poster.rbs +34 -0
- data/sig/aoc_cli/processors/stats_initialiser.rbs +15 -0
- data/sig/aoc_cli/processors/stats_refresher.rbs +19 -0
- data/sig/aoc_cli/validators/collection_type_validator.rbs +24 -0
- data/sig/aoc_cli/validators/event_year_validator.rbs +19 -0
- data/sig/aoc_cli/validators/included_validator.rbs +11 -0
- data/sig/aoc_cli/validators/integer_validator.rbs +15 -0
- data/sig/aoc_cli/validators/path_validator.rbs +17 -0
- data/sig/aoc_cli/validators/type_validator.rbs +22 -0
- data/sig/aoc_cli.rbs +6 -0
- data/sig/http.rbs +3 -0
- data/sig/kangaru.rbs +5 -0
- data/sig/nokogiri.rbs +3 -0
- data/sig/reverse_markdown.rbs +3 -0
- metadata +142 -34
- data/.gitignore +0 -5
- data/bin/aoc +0 -4
- data/bin/console +0 -15
- data/bin/setup +0 -7
- data/lib/aoc_cli/commands.rb +0 -232
- data/lib/aoc_cli/database.rb +0 -224
- data/lib/aoc_cli/day.rb +0 -124
- data/lib/aoc_cli/db/reddit.db +0 -0
- data/lib/aoc_cli/errors.rb +0 -275
- data/lib/aoc_cli/files.rb +0 -163
- data/lib/aoc_cli/help.rb +0 -77
- data/lib/aoc_cli/interface.rb +0 -81
- data/lib/aoc_cli/paths.rb +0 -101
- data/lib/aoc_cli/solve.rb +0 -104
- data/lib/aoc_cli/tables.rb +0 -138
- data/lib/aoc_cli/tools.rb +0 -120
- data/lib/aoc_cli/year.rb +0 -116
- data/sample/aoc.rc +0 -21
data/lib/aoc_cli/files.rb
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
module AocCli
|
|
2
|
-
module Files
|
|
3
|
-
module Config
|
|
4
|
-
class Tools
|
|
5
|
-
def self.is_set?(key:nil, val:nil)
|
|
6
|
-
read.split("\n").grep(/(?<!\/\/)#{key}=>#{val}/).any?
|
|
7
|
-
end
|
|
8
|
-
def self.get_all(key:)
|
|
9
|
-
read.scan(/(?:(?<=(?<!\/\/)#{key}=>)).*$/)
|
|
10
|
-
end
|
|
11
|
-
def self.get_line(key:)
|
|
12
|
-
get_all(key:key)&.first
|
|
13
|
-
#read.scan(/(?:(?<=(?<!\/\/)#{key}=>)).*$/)&.first
|
|
14
|
-
end
|
|
15
|
-
def self.get_bool(key:)
|
|
16
|
-
get_line(key:key) == "true" ? true : false
|
|
17
|
-
end
|
|
18
|
-
def self.mod_line(key:, val:)
|
|
19
|
-
is_set?(key:key) ?
|
|
20
|
-
write(f:read.gsub(/(?<=^#{key}=>).*$/, val.to_s)) :
|
|
21
|
-
write(f:"#{key}=>#{val}\n", m:"a")
|
|
22
|
-
end
|
|
23
|
-
def self.set_line(key:, val:)
|
|
24
|
-
write(f:"#{key}=>#{val}\n", m:"a")
|
|
25
|
-
end
|
|
26
|
-
private
|
|
27
|
-
def self.read
|
|
28
|
-
Paths::Config.create
|
|
29
|
-
File.read(Paths::Config.path)
|
|
30
|
-
end
|
|
31
|
-
def self.write(f:, m:"w")
|
|
32
|
-
Paths::Config.create
|
|
33
|
-
File.write(Paths::Config.path, f, mode:m)
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
class Prefs < Tools
|
|
37
|
-
def self.default_alias
|
|
38
|
-
is_set?(key:"default") ? get_line(key:"default") :
|
|
39
|
-
is_set?(key:"cookie=>main") ? "main" :
|
|
40
|
-
list_aliases.first || "main"
|
|
41
|
-
end
|
|
42
|
-
def self.list_aliases
|
|
43
|
-
get_all(key:"cookie")&.map{|a| a.gsub(/=>.*/, "")}
|
|
44
|
-
end
|
|
45
|
-
def self.bool(key:)
|
|
46
|
-
is_set?(key:key) ?
|
|
47
|
-
get_bool(key:key) : defaults[key.to_sym]
|
|
48
|
-
end
|
|
49
|
-
def self.string(key:)
|
|
50
|
-
is_set?(key:key) ?
|
|
51
|
-
get_line(key:key) : defaults[key.to_sym]
|
|
52
|
-
end
|
|
53
|
-
private
|
|
54
|
-
def self.defaults
|
|
55
|
-
{ calendar_file:true,
|
|
56
|
-
day_dir_prefix:"",
|
|
57
|
-
ignore_md_files:true,
|
|
58
|
-
ignore_meta_files:true,
|
|
59
|
-
init_git:false,
|
|
60
|
-
lb_in_calendar:true,
|
|
61
|
-
reddit_in_browser:false,
|
|
62
|
-
unicode_tables:true
|
|
63
|
-
}
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
class Cookie < Tools
|
|
67
|
-
def self.store(user:, key:)
|
|
68
|
-
set_line(key:"cookie=>#{Validate.set_user(user)}",
|
|
69
|
-
val:Validate.set_key(key))
|
|
70
|
-
end
|
|
71
|
-
def self.key(user:)
|
|
72
|
-
Validate.key(get_line(key:"cookie=>#{Validate
|
|
73
|
-
.user(user)}"))
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
class Example
|
|
77
|
-
def self.write
|
|
78
|
-
File.write(Validate.no_config, file)
|
|
79
|
-
end
|
|
80
|
-
def self.file
|
|
81
|
-
<<~file
|
|
82
|
-
//aoc-cli example config
|
|
83
|
-
//See the github repo for more information on configuring aoc-cli
|
|
84
|
-
//https://github.com/apexatoll/aoc-cli
|
|
85
|
-
|
|
86
|
-
[General]
|
|
87
|
-
//Print table in unicode rather than ascii
|
|
88
|
-
unicode_tables=>true
|
|
89
|
-
//Open Reddit in browser rather than use a Reddit CLI
|
|
90
|
-
reddit_in_browser=>false
|
|
91
|
-
|
|
92
|
-
[Initialise Year]
|
|
93
|
-
//Create a calendar file
|
|
94
|
-
calendar_file=>true
|
|
95
|
-
//Initialise git repo on year initialisation
|
|
96
|
-
init_git=>false
|
|
97
|
-
//Add calendar and puzzle files to gitignore
|
|
98
|
-
ignore_md_files=>true
|
|
99
|
-
//Add .meta files to gitignore
|
|
100
|
-
ignore_meta_files=>true
|
|
101
|
-
//Include leaderboard stats in calendar file
|
|
102
|
-
lb_in_calendar=>true
|
|
103
|
-
file
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
class Metafile
|
|
108
|
-
def self.get(field)
|
|
109
|
-
read.scan(/(?<=#{field}=>).*$/)&.first&.chomp
|
|
110
|
-
end
|
|
111
|
-
def self.type
|
|
112
|
-
get("dir").to_sym
|
|
113
|
-
end
|
|
114
|
-
def self.part(d:)
|
|
115
|
-
Database::Calendar::Part.new(d:d).get
|
|
116
|
-
end
|
|
117
|
-
private
|
|
118
|
-
def self.read(dir:".")
|
|
119
|
-
File.read("#{Validate.init(dir)}/.meta")
|
|
120
|
-
end
|
|
121
|
-
def self.year(u:, y:)
|
|
122
|
-
<<~meta
|
|
123
|
-
dir=>ROOT
|
|
124
|
-
user=>#{u}
|
|
125
|
-
year=>#{y}
|
|
126
|
-
meta
|
|
127
|
-
end
|
|
128
|
-
def self.day(u:, y:, d:)
|
|
129
|
-
<<~meta
|
|
130
|
-
dir=>DAY
|
|
131
|
-
user=>#{u}
|
|
132
|
-
year=>#{y}
|
|
133
|
-
day=>#{d}
|
|
134
|
-
part=>#{part(d:d)}
|
|
135
|
-
meta
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
class Calendar
|
|
139
|
-
attr_reader :cal, :stats, :year
|
|
140
|
-
def initialize(y:Metafile.get(:year), cal:, stats:)
|
|
141
|
-
@year, @cal, @stats = Validate.year(y), cal, stats
|
|
142
|
-
end
|
|
143
|
-
def include_leaderboard?
|
|
144
|
-
Prefs.bool(key:"lb_in_calendar")
|
|
145
|
-
end
|
|
146
|
-
def title
|
|
147
|
-
"Year #{year}: #{stats.total_stars}/50 *"
|
|
148
|
-
end
|
|
149
|
-
def underline
|
|
150
|
-
"-" * (cal.data[0].to_s.length + 2)
|
|
151
|
-
end
|
|
152
|
-
def make
|
|
153
|
-
<<~file
|
|
154
|
-
#{title}
|
|
155
|
-
#{underline}
|
|
156
|
-
#{cal.data.join("\n")}\n
|
|
157
|
-
#{stats.data.join("\n") if stats.total_stars > 0 &&
|
|
158
|
-
include_leaderboard?}
|
|
159
|
-
file
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
end
|
data/lib/aoc_cli/help.rb
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
def title(title)
|
|
2
|
-
"#{title.bold}"
|
|
3
|
-
end
|
|
4
|
-
def flag(short, full)
|
|
5
|
-
str = " #{short.yellow.bold} [#{full.blue.italic}]"
|
|
6
|
-
full.length > 6 ?
|
|
7
|
-
str += "\t" :
|
|
8
|
-
str += "\t\t"
|
|
9
|
-
str
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
help = <<~help
|
|
13
|
-
Advent of Code - cli, version #{AocCli::VERSION}
|
|
14
|
-
#{"C. Welham Feb 2021".italic}
|
|
15
|
-
|
|
16
|
-
#{title("Usage")}
|
|
17
|
-
#{" aoc".bold + " -flag".italic.yellow + " value".bold.blue}
|
|
18
|
-
|
|
19
|
-
#{title("General")}
|
|
20
|
-
#{flag("-v","--version")}Print version
|
|
21
|
-
#{flag("-h","--help")}Print this screen
|
|
22
|
-
|
|
23
|
-
#{title("Setup")}
|
|
24
|
-
- Store session cookie keys to access AoC
|
|
25
|
-
|
|
26
|
-
#{flag("-k","--key")}Store a session cookie to use the cli.
|
|
27
|
-
#{flag("-u","--user")}Set alias for key (default: "main")
|
|
28
|
-
#{flag("-U","--default")}Get/set default alias
|
|
29
|
-
|
|
30
|
-
#{title("Year Directory")}
|
|
31
|
-
- Initialise a year directory to use aoc-cli.
|
|
32
|
-
- If no alias is passed, the default key is used
|
|
33
|
-
|
|
34
|
-
#{flag("-y","--init-year")}Initialise directory and fetch calendar
|
|
35
|
-
#{flag("-u","--user")}Specify alias for initialisation
|
|
36
|
-
#{flag("-d","--init-day")}Create day subdirectory, fetch puzzle and input
|
|
37
|
-
#{flag("-r", "--refresh")}Refresh calendar
|
|
38
|
-
|
|
39
|
-
#{title("Day Subdirectory")}
|
|
40
|
-
- These commands can be run from the day subdirectory
|
|
41
|
-
|
|
42
|
-
#{flag("-s","--solve")}Attempt puzzle
|
|
43
|
-
#{flag("-p","--part")}Specify part (attempts)
|
|
44
|
-
#{flag("-r","--refresh")}Refresh puzzle
|
|
45
|
-
|
|
46
|
-
#{title("Reddit")}
|
|
47
|
-
- Defaults to a Reddit CLI if one is installed
|
|
48
|
-
|
|
49
|
-
#{flag("-R","--reddit")}Open Reddit solution megathread
|
|
50
|
-
#{flag("-B","--browser")}Open Reddit thread in browser
|
|
51
|
-
|
|
52
|
-
#{title("Manual Usage")}
|
|
53
|
-
- AocCli uses metadata so that these flags do not need to be entered.
|
|
54
|
-
- Command flags can be entered manually, but this is not recommended
|
|
55
|
-
|
|
56
|
-
#{flag("-u","--user")}Specify user
|
|
57
|
-
#{flag("-Y","--year")}Specify year
|
|
58
|
-
#{flag("-D","--day")}Specify day
|
|
59
|
-
#{flag("-p","--part")}Specify part
|
|
60
|
-
|
|
61
|
-
#{title("Configuration")}
|
|
62
|
-
- Pass with a value to update setting
|
|
63
|
-
- Pass without an argument to display current setting.
|
|
64
|
-
|
|
65
|
-
#{flag("-U","--default")}Default key alias to use
|
|
66
|
-
#{flag("-G","--gen-config")}Creates an example config file
|
|
67
|
-
|
|
68
|
-
#{title("Tables")}
|
|
69
|
-
- Print stats in a terminal-friendly table
|
|
70
|
-
|
|
71
|
-
#{flag("-a","--attempts")}Prints previous attempts for puzzle (part needed)
|
|
72
|
-
#{flag("-c","--simple-cal")}Prints your progress
|
|
73
|
-
#{flag("-C","--fancy-cal")}Prints your calendar file
|
|
74
|
-
#{flag("-S","--stats")}Prints your stats (time taken, number of attempts)
|
|
75
|
-
|
|
76
|
-
help
|
|
77
|
-
system("echo '#{help}' | less -r")
|
data/lib/aoc_cli/interface.rb
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
module AocCli
|
|
2
|
-
module Interface
|
|
3
|
-
class Query
|
|
4
|
-
def initialize
|
|
5
|
-
ARGV.size > 0 ?
|
|
6
|
-
run(args:Args.new.parse) : Help.print
|
|
7
|
-
rescue StandardError => e
|
|
8
|
-
abort e.message
|
|
9
|
-
end
|
|
10
|
-
def run(args:)
|
|
11
|
-
cmd = Commands.const_get(Validate.cmd(args.cmd))
|
|
12
|
-
.new(args.args).exec
|
|
13
|
-
cmd.respond if cmd.class
|
|
14
|
-
.instance_methods.include?(:respond)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
class Help
|
|
18
|
-
def self.print
|
|
19
|
-
require_relative "help.rb"
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
class Args
|
|
23
|
-
attr_reader :cmd, :args
|
|
24
|
-
def initialize
|
|
25
|
-
@args = {}
|
|
26
|
-
end
|
|
27
|
-
def parse
|
|
28
|
-
while ARGV.size > 0
|
|
29
|
-
case ARGV.shift
|
|
30
|
-
when "-a", "--attempts"
|
|
31
|
-
@cmd = :AttemptsTable
|
|
32
|
-
when "-B", "--browser"
|
|
33
|
-
@cmd = :OpenReddit
|
|
34
|
-
args[:browser] = true
|
|
35
|
-
when "-c", "--simple-cal"
|
|
36
|
-
@cmd = :CalendarTable
|
|
37
|
-
when "-C", "--fancy-cal"
|
|
38
|
-
@cmd = :PrintCal
|
|
39
|
-
when "-d", "--init-day"
|
|
40
|
-
@cmd = :DayInit
|
|
41
|
-
args[:day] = Validate.day(ARGV.shift.to_i)
|
|
42
|
-
when "-D", "--day"
|
|
43
|
-
args[:day] = ARGV.shift.to_i
|
|
44
|
-
when "-G", "--gen-config"
|
|
45
|
-
@cmd = :GenerateConfig
|
|
46
|
-
when "-h", "--help"
|
|
47
|
-
exit Help.print
|
|
48
|
-
when "-k", "--key"
|
|
49
|
-
@cmd = :KeyStore
|
|
50
|
-
args[:key] = Validate.set_key(ARGV.shift)
|
|
51
|
-
when "-p", "--part"
|
|
52
|
-
args[:part] = ARGV.shift.to_i
|
|
53
|
-
when "-r", "--refresh"
|
|
54
|
-
@cmd = :Refresh
|
|
55
|
-
when "-R", "--reddit"
|
|
56
|
-
@cmd = :OpenReddit
|
|
57
|
-
when "-s", "--solve"
|
|
58
|
-
@cmd = :DaySolve
|
|
59
|
-
args[:ans] = ARGV.shift
|
|
60
|
-
when "-S", "--stats"
|
|
61
|
-
@cmd = :StatsTable
|
|
62
|
-
when "-u", "--user"
|
|
63
|
-
args[:user] = ARGV.shift
|
|
64
|
-
when "-U", "--default"
|
|
65
|
-
@cmd = :DefaultAlias
|
|
66
|
-
args[:user] = ARGV.shift
|
|
67
|
-
when "-v", "--version"
|
|
68
|
-
abort "aoc-cli(#{VERSION})"
|
|
69
|
-
when "-y", "--init-year"
|
|
70
|
-
@cmd = :YearInit
|
|
71
|
-
args[:year] = Validate.year(ARGV.shift.to_i)
|
|
72
|
-
when "-Y", "--year"
|
|
73
|
-
args[:year] = ARGV.shift.to_i
|
|
74
|
-
else raise Errors::FlagInv
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
self
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
data/lib/aoc_cli/paths.rb
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
module AocCli
|
|
2
|
-
module Paths
|
|
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)
|
|
10
|
-
end
|
|
11
|
-
def in_year?
|
|
12
|
-
File.exist?("./.meta") ?
|
|
13
|
-
Metafile.type == :ROOT : true
|
|
14
|
-
end
|
|
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
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
class Day
|
|
30
|
-
attr_reader :user, :year, :day
|
|
31
|
-
def initialize(u:Metafile.get(:user),
|
|
32
|
-
y:Metafile.get(:year), d:)
|
|
33
|
-
@user = Validate.user(u)
|
|
34
|
-
@year = Validate.year(y)
|
|
35
|
-
@day = Validate.day(d)
|
|
36
|
-
end
|
|
37
|
-
def create_cache
|
|
38
|
-
FileUtils.mkdir_p(cache_dir) unless Dir.exist?(cache_dir)
|
|
39
|
-
end
|
|
40
|
-
def prefix
|
|
41
|
-
Prefs.string(key:"day_dir_prefix")
|
|
42
|
-
end
|
|
43
|
-
def filename(f:)
|
|
44
|
-
case f.to_sym
|
|
45
|
-
when :Input then "input"
|
|
46
|
-
when :Puzzle then "#{day}.md"
|
|
47
|
-
when :meta then ".meta"
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
def in_day?
|
|
51
|
-
Metafile.type == :DAY
|
|
52
|
-
end
|
|
53
|
-
def day_dir
|
|
54
|
-
day.to_i < 10 ?
|
|
55
|
-
"#{prefix}0#{day}" :
|
|
56
|
-
"#{prefix}#{day}"
|
|
57
|
-
end
|
|
58
|
-
def local_dir
|
|
59
|
-
in_day? ? "." : "#{day_dir}"
|
|
60
|
-
end
|
|
61
|
-
def cache_dir
|
|
62
|
-
"#{Dir.home}/.cache/aoc-cli/"\
|
|
63
|
-
"#{user}/#{year}/#{day_dir}"
|
|
64
|
-
end
|
|
65
|
-
def local(f:)
|
|
66
|
-
"#{local_dir}/#{filename(f:f)}"
|
|
67
|
-
end
|
|
68
|
-
def cache_path(f:)
|
|
69
|
-
"#{cache_dir}/#{filename(f:f)}"
|
|
70
|
-
end
|
|
71
|
-
def cache_and_local(f:)
|
|
72
|
-
[cache_path(f:f), local(f:f)]
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
class Config
|
|
76
|
-
def self.create
|
|
77
|
-
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
|
78
|
-
File.write(path, "", mode:"a") unless File.exist?(path)
|
|
79
|
-
end
|
|
80
|
-
def self.dir
|
|
81
|
-
"#{Dir.home}/.config/aoc-cli"
|
|
82
|
-
end
|
|
83
|
-
def self.path
|
|
84
|
-
"#{dir}/aoc.rc"
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
class Database < Config
|
|
88
|
-
def self.dir
|
|
89
|
-
"#{super}/db"
|
|
90
|
-
end
|
|
91
|
-
def self.cfg(name)
|
|
92
|
-
FileUtils.mkdir_p(dir) unless Dir
|
|
93
|
-
.exist?(dir)
|
|
94
|
-
"#{dir}/#{name}.db"
|
|
95
|
-
end
|
|
96
|
-
def self.root(name)
|
|
97
|
-
"#{__dir__}/db/#{name}.db"
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
end
|
data/lib/aoc_cli/solve.rb
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
module AocCli
|
|
2
|
-
module Solve
|
|
3
|
-
CORRECT = "That's the right answer"
|
|
4
|
-
INCORRECT = "That's not the right answer"
|
|
5
|
-
WAIT = "You gave an answer too recently"
|
|
6
|
-
class Attempt
|
|
7
|
-
attr_reader :user, :year, :day, :part, :answer
|
|
8
|
-
def initialize(u:Metafile.get(:user),
|
|
9
|
-
y:Metafile.get(:year),
|
|
10
|
-
d:Metafile.get(:day),
|
|
11
|
-
p:Metafile.get(:part), a:)
|
|
12
|
-
@user = Validate.user(u)
|
|
13
|
-
@year = Validate.year(y)
|
|
14
|
-
@day = Validate.day(d)
|
|
15
|
-
@part = Validate.part(p)
|
|
16
|
-
@answer = Validate.ans(attempt:self, ans:a)
|
|
17
|
-
end
|
|
18
|
-
def exists?
|
|
19
|
-
Database::Attempt.new(attempt:self)
|
|
20
|
-
end
|
|
21
|
-
def raw
|
|
22
|
-
@raw ||= Tools::Post.new(u:user, y:year, d:day,
|
|
23
|
-
data:{level:part, answer:answer}).plain
|
|
24
|
-
end
|
|
25
|
-
def check
|
|
26
|
-
case raw
|
|
27
|
-
when /#{CORRECT}/ then :Correct
|
|
28
|
-
when /#{INCORRECT}/ then :Incorrect
|
|
29
|
-
when /#{WAIT}/ then :Wait
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
def respond
|
|
33
|
-
Respond.const_get(check)
|
|
34
|
-
.new(attempt:self)
|
|
35
|
-
.respond
|
|
36
|
-
.react
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
module Respond
|
|
40
|
-
class Response
|
|
41
|
-
attr_reader :attempt
|
|
42
|
-
def initialize(attempt:)
|
|
43
|
-
@attempt = attempt
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
class Correct < Response
|
|
47
|
-
def react
|
|
48
|
-
Database.correct(attempt:attempt)
|
|
49
|
-
Year.refresh
|
|
50
|
-
Day.refresh(files:[:Puzzle])
|
|
51
|
-
end
|
|
52
|
-
def respond
|
|
53
|
-
puts <<~response
|
|
54
|
-
#{"Correct!".bold.green} #{
|
|
55
|
-
case attempt.part
|
|
56
|
-
when "1" then "Downloading part two..."
|
|
57
|
-
when "2" then "This day is now complete!".green
|
|
58
|
-
end }
|
|
59
|
-
response
|
|
60
|
-
self
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
class Incorrect < Response
|
|
64
|
-
def react
|
|
65
|
-
Database::Attempt
|
|
66
|
-
.new(attempt:attempt)
|
|
67
|
-
.incorrect(high:high, low:low)
|
|
68
|
-
end
|
|
69
|
-
def respond
|
|
70
|
-
puts <<~response
|
|
71
|
-
#{"Incorrect".red.bold}: You guessed - #{attempt
|
|
72
|
-
.answer.to_s.red} #{
|
|
73
|
-
high ? "(too high)" :
|
|
74
|
-
low ? "(too low)" : ""}
|
|
75
|
-
#{"Please wait".yellow} #{wait_time} before answering again
|
|
76
|
-
response
|
|
77
|
-
self
|
|
78
|
-
end
|
|
79
|
-
def high
|
|
80
|
-
/too high/.match?(attempt.raw)
|
|
81
|
-
end
|
|
82
|
-
def low
|
|
83
|
-
/too low/.match?(attempt.raw)
|
|
84
|
-
end
|
|
85
|
-
def wait_time
|
|
86
|
-
attempt.raw.scan(/(?:(one minute|\d+ minutes))/)
|
|
87
|
-
.first.first.to_s
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
class Wait < Response
|
|
91
|
-
def respond
|
|
92
|
-
puts <<~response
|
|
93
|
-
#{"Please wait".yellow.bold}: #{time.to_s}
|
|
94
|
-
response
|
|
95
|
-
self
|
|
96
|
-
end
|
|
97
|
-
def time
|
|
98
|
-
attempt.raw.scan(/(?:\d+m\s)?\d+s/).first.to_s
|
|
99
|
-
end
|
|
100
|
-
def react; end
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
end
|
data/lib/aoc_cli/tables.rb
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
module AocCli
|
|
2
|
-
module Tables
|
|
3
|
-
class Table
|
|
4
|
-
require 'terminal-table'
|
|
5
|
-
attr_reader :user, :year, :table, :cols, :where
|
|
6
|
-
def initialize(u:Metafile.get(:user), y:Metafile.get(:year))
|
|
7
|
-
@user = Validate.user(u)
|
|
8
|
-
@year = Validate.year(y)
|
|
9
|
-
end
|
|
10
|
-
def border
|
|
11
|
-
Prefs.bool(key:"unicode_tables") ? :unicode : :ascii
|
|
12
|
-
end
|
|
13
|
-
def data
|
|
14
|
-
Database::Query
|
|
15
|
-
.new(path:Paths::Database.cfg(user))
|
|
16
|
-
.select(t:table, cols:cols, where:where)
|
|
17
|
-
end
|
|
18
|
-
def print
|
|
19
|
-
puts rows.count > 0 ? make : nil_message
|
|
20
|
-
end
|
|
21
|
-
def make
|
|
22
|
-
tab = Terminal::Table.new(
|
|
23
|
-
:headings => headings,
|
|
24
|
-
:rows => rows,
|
|
25
|
-
:title => title)
|
|
26
|
-
tab.style = {
|
|
27
|
-
:border => border,
|
|
28
|
-
:alignment => :center}
|
|
29
|
-
tab
|
|
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
|
|
45
|
-
def title
|
|
46
|
-
"#{year} - Day #{day}:#{part}".bold
|
|
47
|
-
end
|
|
48
|
-
def headings
|
|
49
|
-
["Answer", "Time", "Hint"]
|
|
50
|
-
end
|
|
51
|
-
def rows
|
|
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")
|
|
61
|
-
.strftime("%H:%M - %d/%m/%y")
|
|
62
|
-
end
|
|
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!"
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
module Stats
|
|
72
|
-
class Year < Table
|
|
73
|
-
def initialize(u:Metafile.get(:user),
|
|
74
|
-
y:Metafile.get(:year))
|
|
75
|
-
super(u:u, y:y)
|
|
76
|
-
@table = :stats
|
|
77
|
-
@cols = "day, part, attempts, elapsed"
|
|
78
|
-
@where = {year:"'#{year}'", correct:"'1'"}
|
|
79
|
-
end
|
|
80
|
-
def title
|
|
81
|
-
"Year #{year}"
|
|
82
|
-
end
|
|
83
|
-
def headings
|
|
84
|
-
["Day", "Part", "Attempts", "Time (h:m:s)"]
|
|
85
|
-
end
|
|
86
|
-
def rows
|
|
87
|
-
@rows ||= data.map{|d| [d[0], d[1], d[2], d[3]]}
|
|
88
|
-
end
|
|
89
|
-
def nil_message
|
|
90
|
-
"You have not completed any puzzles yet"
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
class Day < Year
|
|
94
|
-
attr_reader :day
|
|
95
|
-
def initialize(u:Metafile.get(:user),
|
|
96
|
-
y:Metafile.get(:year),
|
|
97
|
-
d:Metafile.get(:day))
|
|
98
|
-
super(u:u, y:y)
|
|
99
|
-
@day = Validate.day(d)
|
|
100
|
-
@cols = "part, attempts, elapsed"
|
|
101
|
-
@where = { year:"'#{year}'",
|
|
102
|
-
day:"'#{day}'",
|
|
103
|
-
correct:"'1'" }
|
|
104
|
-
end
|
|
105
|
-
def title
|
|
106
|
-
"Year #{year}: Day #{day}"
|
|
107
|
-
end
|
|
108
|
-
def headings
|
|
109
|
-
["Part", "Attempts", "Time (h:m:s)"]
|
|
110
|
-
end
|
|
111
|
-
def rows
|
|
112
|
-
@rows ||= data.map{|d| [d[0], d[1], d[2]]}
|
|
113
|
-
end
|
|
114
|
-
end
|
|
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
|
-
end
|
|
138
|
-
end
|