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/database.rb
DELETED
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
module AocCli
|
|
2
|
-
module Database
|
|
3
|
-
def self.correct(attempt:)
|
|
4
|
-
attempt = Attempt.new(attempt:attempt).correct
|
|
5
|
-
Stats::Complete.new(n:attempt.count_attempts).update
|
|
6
|
-
Calendar::Part.new.increment
|
|
7
|
-
end
|
|
8
|
-
class Query
|
|
9
|
-
require 'sqlite3'
|
|
10
|
-
attr_reader :db
|
|
11
|
-
def initialize(path:)
|
|
12
|
-
@db = SQLite3::Database.open(path)
|
|
13
|
-
end
|
|
14
|
-
def select(t:, cols:"*", where:)
|
|
15
|
-
db.execute(
|
|
16
|
-
"SELECT #{cols} FROM #{t} "\
|
|
17
|
-
"WHERE #{where.map{|k, v| "#{k} = #{v}"}.join(" AND ")}")
|
|
18
|
-
end
|
|
19
|
-
def table(t:, cols:)
|
|
20
|
-
db.execute(
|
|
21
|
-
"CREATE TABLE IF NOT EXISTS "\
|
|
22
|
-
"#{t}(#{cols.map{|c, t| "#{c} #{t}"}.join(", ")})")
|
|
23
|
-
self
|
|
24
|
-
end
|
|
25
|
-
def insert(t:, val:)
|
|
26
|
-
db.execute(
|
|
27
|
-
"INSERT INTO #{t} "\
|
|
28
|
-
"VALUES(#{val.join(", ")})")
|
|
29
|
-
self
|
|
30
|
-
end
|
|
31
|
-
def update(t:, val:, where:)
|
|
32
|
-
db.execute(
|
|
33
|
-
"UPDATE #{t} "\
|
|
34
|
-
"SET #{val.map{|c, v| "#{c} = #{v}"}.join(", ")} "\
|
|
35
|
-
"WHERE #{where.map{|c, v| "#{c} = #{v}"}.join(" AND ")}")
|
|
36
|
-
self
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
class Attempt
|
|
40
|
-
attr_reader :attempt, :db
|
|
41
|
-
def initialize(attempt:)
|
|
42
|
-
@attempt = attempt
|
|
43
|
-
@db = Query.new(path:Paths::Database.cfg(attempt.user))
|
|
44
|
-
.table(t:"attempts", cols:cols)
|
|
45
|
-
end
|
|
46
|
-
def correct
|
|
47
|
-
db.insert(t:"attempts", val:data << 1 << 0 << 0)
|
|
48
|
-
self
|
|
49
|
-
end
|
|
50
|
-
def incorrect(low:, high:)
|
|
51
|
-
db.insert(t:"attempts",
|
|
52
|
-
val:data << 0 << parse_hint(low:low, high:high))
|
|
53
|
-
self
|
|
54
|
-
end
|
|
55
|
-
def duplicate?(ans:)
|
|
56
|
-
db.select(t:"attempts",
|
|
57
|
-
where:where.merge({answer:ans})).count > 0
|
|
58
|
-
end
|
|
59
|
-
def parse_hint(low:, high:)
|
|
60
|
-
[ low ? 1 : 0, high ? 1 : 0 ]
|
|
61
|
-
end
|
|
62
|
-
def data
|
|
63
|
-
[ "'#{Time.now}'",
|
|
64
|
-
"'#{attempt.year}'",
|
|
65
|
-
"'#{attempt.day}'",
|
|
66
|
-
"'#{attempt.part}'",
|
|
67
|
-
"'#{attempt.answer}'" ]
|
|
68
|
-
end
|
|
69
|
-
def cols
|
|
70
|
-
{ time: :TEXT,
|
|
71
|
-
year: :INT,
|
|
72
|
-
day: :INT,
|
|
73
|
-
part: :INT,
|
|
74
|
-
answer: :TEXT,
|
|
75
|
-
correct: :INT,
|
|
76
|
-
low: :INT,
|
|
77
|
-
high: :INT }
|
|
78
|
-
end
|
|
79
|
-
def count_attempts
|
|
80
|
-
db.select(t:"attempts", where:where).count
|
|
81
|
-
end
|
|
82
|
-
def where
|
|
83
|
-
{ year:attempt.year,
|
|
84
|
-
day:attempt.day,
|
|
85
|
-
part:attempt.part }
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
module Stats
|
|
89
|
-
class Init
|
|
90
|
-
attr_reader :user, :year, :day, :part, :now, :db
|
|
91
|
-
def initialize(u:Metafile.get(:user),
|
|
92
|
-
y:Metafile.get(:year),
|
|
93
|
-
d:Metafile.get(:day),
|
|
94
|
-
p:Metafile.get(:part))
|
|
95
|
-
@user = Validate.user(u)
|
|
96
|
-
@year = Validate.year(y)
|
|
97
|
-
@day = Validate.day(d)
|
|
98
|
-
@part = p
|
|
99
|
-
@now = Time.now
|
|
100
|
-
@db = Query.new(path:Paths::Database.cfg(user))
|
|
101
|
-
.table(t:"stats", cols:cols)
|
|
102
|
-
end
|
|
103
|
-
def cols
|
|
104
|
-
{ year: :INT,
|
|
105
|
-
day: :INT,
|
|
106
|
-
part: :INT,
|
|
107
|
-
dl_time: :TEXT,
|
|
108
|
-
end_time: :TEXT,
|
|
109
|
-
elapsed: :TEXT,
|
|
110
|
-
attempts: :INT,
|
|
111
|
-
correct: :INT }
|
|
112
|
-
end
|
|
113
|
-
def init
|
|
114
|
-
db.insert(t:"stats", val:data)
|
|
115
|
-
end
|
|
116
|
-
def data
|
|
117
|
-
[ "'#{year}'",
|
|
118
|
-
"'#{day}'",
|
|
119
|
-
"'#{part}'",
|
|
120
|
-
"'#{now}'",
|
|
121
|
-
"NULL",
|
|
122
|
-
"NULL",
|
|
123
|
-
"'0'",
|
|
124
|
-
"'0'" ]
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
class Complete < Init
|
|
128
|
-
attr_reader :n_attempts
|
|
129
|
-
def initialize(u:Metafile.get(:user),
|
|
130
|
-
y:Metafile.get(:year),
|
|
131
|
-
d:Metafile.get(:day),
|
|
132
|
-
p:Metafile.get(:part),
|
|
133
|
-
n:)
|
|
134
|
-
super(u:u, y:y, d:d, p:p)
|
|
135
|
-
@n_attempts = n
|
|
136
|
-
end
|
|
137
|
-
def update
|
|
138
|
-
db.update(t:"stats", val:val, where:where)
|
|
139
|
-
end
|
|
140
|
-
def val
|
|
141
|
-
{ elapsed: "'#{elapsed}'",
|
|
142
|
-
end_time: "'#{now}'",
|
|
143
|
-
attempts: "'#{n_attempts}'",
|
|
144
|
-
correct: "'1'" }
|
|
145
|
-
end
|
|
146
|
-
def where
|
|
147
|
-
{ year: year,
|
|
148
|
-
day: day,
|
|
149
|
-
part: part }
|
|
150
|
-
end
|
|
151
|
-
def elapsed
|
|
152
|
-
@elapsed ||= hms(now - dl_time)
|
|
153
|
-
end
|
|
154
|
-
def hms(seconds)
|
|
155
|
-
[seconds/3600, seconds/60 % 60, seconds % 60]
|
|
156
|
-
.map{|t| t.to_i.to_s.rjust(2, "0")}.join(":")
|
|
157
|
-
end
|
|
158
|
-
def dl_time
|
|
159
|
-
@dl_time ||= Time.parse(db
|
|
160
|
-
.select(t:"stats", cols:"dl_time", where:where)
|
|
161
|
-
.flatten.first)
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
module Calendar
|
|
166
|
-
class Init
|
|
167
|
-
attr_reader :user, :year, :db, :stars
|
|
168
|
-
def initialize(u:Metafile.get(:user),
|
|
169
|
-
y:Metafile.get(:year),
|
|
170
|
-
stars:)
|
|
171
|
-
@user = Validate.user(u)
|
|
172
|
-
@year = Validate.year(y)
|
|
173
|
-
@stars = stars
|
|
174
|
-
@db = Query
|
|
175
|
-
.new(path:Paths::Database.cfg(user))
|
|
176
|
-
.table(t:"calendar", cols:cols)
|
|
177
|
-
end
|
|
178
|
-
def cols
|
|
179
|
-
{ year: :INT,
|
|
180
|
-
day: :INT,
|
|
181
|
-
stars: :TEXT }
|
|
182
|
-
end
|
|
183
|
-
def n_stars(day)
|
|
184
|
-
stars.keys.include?(day) ? stars[day] : 0
|
|
185
|
-
end
|
|
186
|
-
def day_data(day)
|
|
187
|
-
["'#{year}'", "'#{day}'", "'#{n_stars(day)}'"]
|
|
188
|
-
end
|
|
189
|
-
def table_exist?
|
|
190
|
-
db.select(t:"calendar", where:{year:"'#{year}'"}).count > 0
|
|
191
|
-
end
|
|
192
|
-
def insert
|
|
193
|
-
unless table_exist?
|
|
194
|
-
1.upto(25){|day|
|
|
195
|
-
db.insert(t:"calendar",
|
|
196
|
-
val:day_data(day))}
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
class Part
|
|
201
|
-
attr_reader :user, :year, :day, :db
|
|
202
|
-
def initialize(u:Metafile.get(:user),
|
|
203
|
-
y:Metafile.get(:year),
|
|
204
|
-
d:Metafile.get(:day))
|
|
205
|
-
@user = Validate.user(u)
|
|
206
|
-
@year = Validate.year(y)
|
|
207
|
-
@day = Validate.day(d)
|
|
208
|
-
@db = Query.new(path:Paths::Database.cfg(user))
|
|
209
|
-
end
|
|
210
|
-
def get
|
|
211
|
-
db.select(t:"calendar", cols:"stars", where:where)
|
|
212
|
-
.flatten.first.to_i + 1
|
|
213
|
-
end
|
|
214
|
-
def increment
|
|
215
|
-
db.update(t:"calendar", val:{stars:get}, where:where)
|
|
216
|
-
end
|
|
217
|
-
def where
|
|
218
|
-
{ year:"'#{year}'",
|
|
219
|
-
day:"'#{day}'" }
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
|
-
end
|
|
223
|
-
end
|
|
224
|
-
end
|
data/lib/aoc_cli/day.rb
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
module AocCli
|
|
2
|
-
module Day
|
|
3
|
-
class Init
|
|
4
|
-
attr_reader :user, :year, :day, :paths
|
|
5
|
-
def initialize(u:Metafile.get(:user),
|
|
6
|
-
y:Metafile.get(:year),
|
|
7
|
-
d:Metafile.get(:day))
|
|
8
|
-
@user = Validate.user(u)
|
|
9
|
-
@year = Validate.year(y)
|
|
10
|
-
@day = Validate.day(d)
|
|
11
|
-
@paths = Paths::Day.new(u:user, y:year, d:day)
|
|
12
|
-
end
|
|
13
|
-
def mkdir
|
|
14
|
-
Dir.mkdir(Validate.day_dir(paths.day_dir))
|
|
15
|
-
self
|
|
16
|
-
end
|
|
17
|
-
def meta
|
|
18
|
-
File.write(paths.local(f:"meta"),
|
|
19
|
-
Metafile.day(u:user, y:year, d:day))
|
|
20
|
-
self
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
class Pages < Init
|
|
24
|
-
attr_reader :files, :use_cache
|
|
25
|
-
def initialize(u:Metafile.get(:user),
|
|
26
|
-
y:Metafile.get(:year),
|
|
27
|
-
d:Metafile.get(:day),
|
|
28
|
-
f:[:Input, :Puzzle],
|
|
29
|
-
use_cache:true)
|
|
30
|
-
super(u:u, y:y, d:d)
|
|
31
|
-
@files = f
|
|
32
|
-
@use_cache = use_cache
|
|
33
|
-
end
|
|
34
|
-
def load
|
|
35
|
-
files.each do |file| use_cache && cache[file] ?
|
|
36
|
-
copy(file:file) : download(page:file) end
|
|
37
|
-
end
|
|
38
|
-
def cache
|
|
39
|
-
@cache ||= Cache.new(d:day, f:files).query
|
|
40
|
-
end
|
|
41
|
-
def copy(file:)
|
|
42
|
-
File.write(paths.local(f:file), cache[file])
|
|
43
|
-
end
|
|
44
|
-
def download(page:)
|
|
45
|
-
req = Requests.const_get(page)
|
|
46
|
-
.new(u:user, y:year, d:day)
|
|
47
|
-
.write(to:paths.cache_and_local(f:page))
|
|
48
|
-
req.init_stats if page == :Puzzle
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
class Cache < Pages
|
|
52
|
-
def initialize(u:Metafile.get(:user),
|
|
53
|
-
y:Metafile.get(:year),
|
|
54
|
-
d:Metafile.get(:day),
|
|
55
|
-
f:[:Input, :Puzzle])
|
|
56
|
-
super(u:u, y:y, d:d, f:f)
|
|
57
|
-
paths.create_cache
|
|
58
|
-
end
|
|
59
|
-
def query
|
|
60
|
-
files.map{|file| [file, read(file:file)]}.to_h
|
|
61
|
-
end
|
|
62
|
-
private
|
|
63
|
-
def read(file:)
|
|
64
|
-
File.exist?(paths.cache_path(f:file)) ?
|
|
65
|
-
File.read(paths.cache_path(f:file)) : nil
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
module Requests
|
|
69
|
-
class Request < Init
|
|
70
|
-
attr_reader :data, :part
|
|
71
|
-
def initialize(u:Metafile.get(:user),
|
|
72
|
-
y:Metafile.get(:year),
|
|
73
|
-
d:Metafile.get(:day))
|
|
74
|
-
super(u:u, y:y, d:d)
|
|
75
|
-
@data = parse(raw:fetch)
|
|
76
|
-
@part = Metafile.part(d:day)
|
|
77
|
-
end
|
|
78
|
-
def write(to:)
|
|
79
|
-
to.each{|path| File.write(path, data)}; self
|
|
80
|
-
end
|
|
81
|
-
private
|
|
82
|
-
def fetch
|
|
83
|
-
Tools::Get.new(u:user, y:year, d:day, p:page)
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
class Puzzle < Request
|
|
87
|
-
def page
|
|
88
|
-
:Puzzle
|
|
89
|
-
end
|
|
90
|
-
def parse(raw:fetch)
|
|
91
|
-
raw.chunk(f:"<article", t:"<\/article", f_off:2)
|
|
92
|
-
.md
|
|
93
|
-
.gsub(/(?<=\])\[\]/, "")
|
|
94
|
-
.gsub(/\n.*<!--.*-->.*\n/, "")
|
|
95
|
-
end
|
|
96
|
-
def init_stats
|
|
97
|
-
Database::Stats::Init
|
|
98
|
-
.new(d:day, p:part)
|
|
99
|
-
.init if part < 3 && !stats_exist?
|
|
100
|
-
end
|
|
101
|
-
def stats_exist?
|
|
102
|
-
Database::Query
|
|
103
|
-
.new(path:Paths::Database.cfg(user))
|
|
104
|
-
.select(t:"stats",
|
|
105
|
-
where:{year:year, day:day, part:part})
|
|
106
|
-
.count > 0
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
class Input < Request
|
|
110
|
-
def page
|
|
111
|
-
:Input
|
|
112
|
-
end
|
|
113
|
-
def parse(raw:fetch)
|
|
114
|
-
raw.raw
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
def self.refresh(files:[:Input, :Puzzle])
|
|
119
|
-
puts "- Updating puzzle...".blue
|
|
120
|
-
Init.new.meta
|
|
121
|
-
Pages.new(f:files, use_cache:false).load
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
end
|
data/lib/aoc_cli/db/reddit.db
DELETED
|
Binary file
|
data/lib/aoc_cli/errors.rb
DELETED
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
module AocCli
|
|
2
|
-
module Errors
|
|
3
|
-
ERROR = "Error".bold.red
|
|
4
|
-
class UserNil < StandardError
|
|
5
|
-
def message
|
|
6
|
-
<<~error
|
|
7
|
-
#{ERROR}: No user alias value.
|
|
8
|
-
Specify an alias to use when passing the #{"-u".yellow} or #{"--user".yellow} flag
|
|
9
|
-
error
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
class UserInv < StandardError
|
|
13
|
-
def initialize(user)
|
|
14
|
-
@user = user
|
|
15
|
-
end
|
|
16
|
-
def message
|
|
17
|
-
<<~error
|
|
18
|
-
#{ERROR}: Invalid user: #{@user.to_s.red}
|
|
19
|
-
No key was found under this alias
|
|
20
|
-
error
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
class UserDup < StandardError
|
|
24
|
-
attr_reader :user
|
|
25
|
-
def initialize(user)
|
|
26
|
-
@user = user
|
|
27
|
-
end
|
|
28
|
-
def message
|
|
29
|
-
<<~error
|
|
30
|
-
#{ERROR}: There is already a key set for the user #{user.yellow}
|
|
31
|
-
Either check your config file or set a new username for this key using the #{"-u".yellow} or #{"--user".yellow} flags
|
|
32
|
-
error
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
class YearNil < StandardError
|
|
36
|
-
def message
|
|
37
|
-
<<~error
|
|
38
|
-
#{ERROR}: No year value.
|
|
39
|
-
Set the year using the #{"-y".yellow} or #{"--year".yellow} flags.
|
|
40
|
-
error
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
class YearInv < StandardError
|
|
44
|
-
attr_reader :year
|
|
45
|
-
def initialize(year)
|
|
46
|
-
@year = year
|
|
47
|
-
end
|
|
48
|
-
def message
|
|
49
|
-
<<~error
|
|
50
|
-
#{ERROR}: Invalid year: #{year.to_s.red}
|
|
51
|
-
Advent of Code currently spans 2015 - 2020.
|
|
52
|
-
error
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
class DayNil < StandardError
|
|
56
|
-
def message
|
|
57
|
-
<<~error
|
|
58
|
-
#{ERROR}: No day value.
|
|
59
|
-
Specify the day using the #{"-d".yellow} or #{"--day".yellow} flags.
|
|
60
|
-
error
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
class DayInv < StandardError
|
|
64
|
-
def initialize(day)
|
|
65
|
-
@day = day
|
|
66
|
-
end
|
|
67
|
-
def message
|
|
68
|
-
<<~error
|
|
69
|
-
#{ERROR}: Invalid day: #{@day.to_s.red}
|
|
70
|
-
Valid days are between 1 and 25
|
|
71
|
-
error
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
class DayExist < StandardError
|
|
75
|
-
def initialize(day)
|
|
76
|
-
@day = day.to_s
|
|
77
|
-
end
|
|
78
|
-
def message
|
|
79
|
-
<<~error
|
|
80
|
-
#{ERROR}: Day #{@day.red} is already initialised!
|
|
81
|
-
error
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
class PartNil < StandardError
|
|
85
|
-
def message
|
|
86
|
-
<<~error
|
|
87
|
-
#{ERROR}: No part value.
|
|
88
|
-
Check the .meta file or pass it manually with the #{"-p".yellow} or #{"--part".yellow} flags
|
|
89
|
-
error
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
class PartInv < StandardError
|
|
93
|
-
attr_reader :part
|
|
94
|
-
def initialize(part)
|
|
95
|
-
@part = part
|
|
96
|
-
end
|
|
97
|
-
def message
|
|
98
|
-
<<~error
|
|
99
|
-
#{ERROR}: Invalid part: #{part.red}
|
|
100
|
-
Part refers to the part of the puzzle and can either be 1 or 2.
|
|
101
|
-
error
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
class AnsNil < StandardError
|
|
105
|
-
def message
|
|
106
|
-
<<~error
|
|
107
|
-
#{ERROR}: No answer value.
|
|
108
|
-
error
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
class KeyNil < StandardError
|
|
112
|
-
def message
|
|
113
|
-
<<~error
|
|
114
|
-
#{ERROR}: No session key value.
|
|
115
|
-
Use the #{"-k".yellow} or #{"--key".yellow} flags to store the key
|
|
116
|
-
error
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
class KeyDup < StandardError
|
|
120
|
-
attr_reader :key
|
|
121
|
-
def initialize(key)
|
|
122
|
-
@key = key
|
|
123
|
-
end
|
|
124
|
-
def message
|
|
125
|
-
<<~error
|
|
126
|
-
#{ERROR}: The key #{key.yellow} already exists in your config file
|
|
127
|
-
error
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
class AlrInit < StandardError
|
|
131
|
-
def message
|
|
132
|
-
<<~error
|
|
133
|
-
#{ERROR}: This directory is already initialised.
|
|
134
|
-
error
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
class NotInit < StandardError
|
|
138
|
-
def message
|
|
139
|
-
<<~error
|
|
140
|
-
#{ERROR}: You must initialise the directory first
|
|
141
|
-
error
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
class PuzzComp < StandardError
|
|
145
|
-
def message
|
|
146
|
-
<<~error
|
|
147
|
-
#{ERROR}: This puzzle is already complete!
|
|
148
|
-
error
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
class FlagInv < StandardError
|
|
152
|
-
attr_reader :flag
|
|
153
|
-
def initialize(flag)
|
|
154
|
-
@flag = flag
|
|
155
|
-
end
|
|
156
|
-
def message
|
|
157
|
-
<<~error
|
|
158
|
-
#{ERROR}: Invalid flag: #{flag.red}
|
|
159
|
-
Use the #{"-h".yellow} or #{"--help".yellow} flags for a list of commands
|
|
160
|
-
error
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
class CmdNil < StandardError
|
|
164
|
-
def message
|
|
165
|
-
<<~error
|
|
166
|
-
#{ERROR}: Flags passed but no command specified
|
|
167
|
-
error
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
class KeyInv < StandardError
|
|
171
|
-
def message
|
|
172
|
-
<<~error
|
|
173
|
-
#{ERROR}: Invalid key
|
|
174
|
-
Double check your session key. It should start with "session="
|
|
175
|
-
error
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
class ConfigExist < StandardError
|
|
179
|
-
def message
|
|
180
|
-
<<~error
|
|
181
|
-
#{ERROR}: A config file already exists in #{Paths::Config.path.blue}
|
|
182
|
-
error
|
|
183
|
-
end
|
|
184
|
-
end
|
|
185
|
-
class AtmptDup < StandardError
|
|
186
|
-
attr_reader :answer
|
|
187
|
-
def initialize(answer)
|
|
188
|
-
@answer = answer
|
|
189
|
-
end
|
|
190
|
-
def message
|
|
191
|
-
<<~error
|
|
192
|
-
#{ERROR}: You have already tried #{answer.red}
|
|
193
|
-
To see previous attempts run #{"aoc -a".yellow}
|
|
194
|
-
error
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
class Validate
|
|
199
|
-
E = Errors
|
|
200
|
-
def self.cmd(cmd)
|
|
201
|
-
raise E::CmdNil if cmd.nil?
|
|
202
|
-
cmd
|
|
203
|
-
end
|
|
204
|
-
def self.user(user)
|
|
205
|
-
raise E::UserNil if user.nil?
|
|
206
|
-
raise E::UserInv.new(user) unless user_in_config?(user)
|
|
207
|
-
user
|
|
208
|
-
end
|
|
209
|
-
def self.set_user(user)
|
|
210
|
-
raise E::UserNil if user.nil?
|
|
211
|
-
raise E::UserDup.new(user) if user_in_config?(user)
|
|
212
|
-
user
|
|
213
|
-
end
|
|
214
|
-
def self.year(year)
|
|
215
|
-
raise E::YearNil if year.nil?
|
|
216
|
-
raise E::YearInv.new(year) if year.to_i < 2015 ||
|
|
217
|
-
year.to_i > 2020
|
|
218
|
-
year
|
|
219
|
-
end
|
|
220
|
-
def self.day(day)
|
|
221
|
-
raise E::DayNil if day.nil? || day == 0
|
|
222
|
-
raise E::DayInv.new(day) if day.to_i < 1 ||
|
|
223
|
-
day.to_i > 25
|
|
224
|
-
day
|
|
225
|
-
end
|
|
226
|
-
def self.part(part)
|
|
227
|
-
raise E::PartNil if part.nil?
|
|
228
|
-
raise E::PuzzComp if part.to_i == 3
|
|
229
|
-
raise E::PartInv if part.to_i < 1 || part.to_i > 2
|
|
230
|
-
part
|
|
231
|
-
end
|
|
232
|
-
def self.set_key(key)
|
|
233
|
-
raise E::KeyNil if key.nil?
|
|
234
|
-
raise E::KeyDup.new(key) if Files::Config::Tools
|
|
235
|
-
.is_set?(val:"#{key}(\b|$)")
|
|
236
|
-
raise E::KeyInv unless valid_key?(key)
|
|
237
|
-
key
|
|
238
|
-
end
|
|
239
|
-
def self.key(key)
|
|
240
|
-
raise E::KeyNil if key.nil?
|
|
241
|
-
raise E::KeyInv unless valid_key?(key)
|
|
242
|
-
key
|
|
243
|
-
end
|
|
244
|
-
def self.ans(attempt:, ans:)
|
|
245
|
-
raise E::AnsNil if ans.nil?
|
|
246
|
-
raise E::AtmptDup.new(ans) if Database::Attempt
|
|
247
|
-
.new(attempt:attempt).duplicate?(ans:ans)
|
|
248
|
-
ans
|
|
249
|
-
end
|
|
250
|
-
def self.day_dir(day)
|
|
251
|
-
raise E::DayExist.new(day) if Dir.exist?(day)
|
|
252
|
-
day
|
|
253
|
-
end
|
|
254
|
-
def self.init(dir)
|
|
255
|
-
raise E::NotInit unless File.exist?("#{dir}/.meta")
|
|
256
|
-
dir
|
|
257
|
-
end
|
|
258
|
-
def self.not_init(dir:, year:)
|
|
259
|
-
raise E::AlrInit if File.exist?("#{dir}/.meta") &&
|
|
260
|
-
Metafile.get(:year) != year.to_s
|
|
261
|
-
dir
|
|
262
|
-
end
|
|
263
|
-
def self.no_config
|
|
264
|
-
raise E::ConfigExist if File.exist?(Paths::Config.path)
|
|
265
|
-
Paths::Config.path
|
|
266
|
-
end
|
|
267
|
-
private
|
|
268
|
-
def self.valid_key?(key)
|
|
269
|
-
/session=(?:[a-f0-9]){96}/.match?(key)
|
|
270
|
-
end
|
|
271
|
-
def self.user_in_config?(user)
|
|
272
|
-
Files::Config::Tools.is_set?(key:"cookie=>#{user}")
|
|
273
|
-
end
|
|
274
|
-
end
|
|
275
|
-
end
|