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.
Files changed (152) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/.rubocop.yml +88 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +4 -0
  6. data/Gemfile +8 -0
  7. data/Gemfile.lock +187 -0
  8. data/README.md +88 -282
  9. data/Rakefile +9 -2
  10. data/Steepfile +13 -0
  11. data/aoc_cli.gemspec +36 -26
  12. data/db/migrate/1_create_events.rb +14 -0
  13. data/db/migrate/2_create_puzzles.rb +21 -0
  14. data/db/migrate/3_create_stats.rb +19 -0
  15. data/db/migrate/4_create_attempts.rb +19 -0
  16. data/db/migrate/5_create_locations.rb +17 -0
  17. data/db/migrate/6_create_puzzle_dir_sync_logs.rb +18 -0
  18. data/exe/aoc +5 -0
  19. data/lib/aoc_cli/components/attempts_table.erb +5 -0
  20. data/lib/aoc_cli/components/attempts_table.rb +58 -0
  21. data/lib/aoc_cli/components/docs_component.erb +19 -0
  22. data/lib/aoc_cli/components/docs_component.rb +41 -0
  23. data/lib/aoc_cli/components/errors_component.erb +8 -0
  24. data/lib/aoc_cli/components/errors_component.rb +36 -0
  25. data/lib/aoc_cli/components/progress_table.erb +1 -0
  26. data/lib/aoc_cli/components/progress_table.rb +43 -0
  27. data/lib/aoc_cli/components/puzzle_sync_component.erb +2 -0
  28. data/lib/aoc_cli/components/puzzle_sync_component.rb +26 -0
  29. data/lib/aoc_cli/configurators/session_configurator.rb +7 -0
  30. data/lib/aoc_cli/controllers/application_controller.rb +27 -0
  31. data/lib/aoc_cli/controllers/concerns/error_concern.rb +17 -0
  32. data/lib/aoc_cli/controllers/concerns/location_concern.rb +79 -0
  33. data/lib/aoc_cli/controllers/default_controller.rb +9 -0
  34. data/lib/aoc_cli/controllers/event_controller.rb +35 -0
  35. data/lib/aoc_cli/controllers/help/event_controller.rb +11 -0
  36. data/lib/aoc_cli/controllers/help/puzzle_controller.rb +13 -0
  37. data/lib/aoc_cli/controllers/puzzle_controller.rb +39 -0
  38. data/lib/aoc_cli/core/attempt_parser.rb +69 -0
  39. data/lib/aoc_cli/core/processor.rb +32 -0
  40. data/lib/aoc_cli/core/repository.rb +74 -0
  41. data/lib/aoc_cli/core/request.rb +37 -0
  42. data/lib/aoc_cli/core/resource.rb +39 -0
  43. data/lib/aoc_cli/core/stats_parser.rb +43 -0
  44. data/lib/aoc_cli/helpers/table_generator.rb +64 -0
  45. data/lib/aoc_cli/helpers/view_helper.rb +35 -0
  46. data/lib/aoc_cli/models/attempt.rb +67 -0
  47. data/lib/aoc_cli/models/event.rb +9 -0
  48. data/lib/aoc_cli/models/location.rb +24 -0
  49. data/lib/aoc_cli/models/puzzle.rb +28 -0
  50. data/lib/aoc_cli/models/puzzle_dir_sync_log.rb +14 -0
  51. data/lib/aoc_cli/models/stats.rb +43 -0
  52. data/lib/aoc_cli/presenters/attempt_presenter.rb +29 -0
  53. data/lib/aoc_cli/presenters/puzzle_presenter.rb +29 -0
  54. data/lib/aoc_cli/presenters/stats_presenter.rb +32 -0
  55. data/lib/aoc_cli/processors/event_initialiser.rb +64 -0
  56. data/lib/aoc_cli/processors/puzzle_dir_synchroniser.rb +80 -0
  57. data/lib/aoc_cli/processors/puzzle_initialiser.rb +91 -0
  58. data/lib/aoc_cli/processors/puzzle_refresher.rb +27 -0
  59. data/lib/aoc_cli/processors/resource_attacher.rb +22 -0
  60. data/lib/aoc_cli/processors/solution_poster.rb +72 -0
  61. data/lib/aoc_cli/processors/stats_initialiser.rb +36 -0
  62. data/lib/aoc_cli/processors/stats_refresher.rb +23 -0
  63. data/lib/aoc_cli/validators/collection_type_validator.rb +57 -0
  64. data/lib/aoc_cli/validators/event_year_validator.rb +42 -0
  65. data/lib/aoc_cli/validators/included_validator.rb +21 -0
  66. data/lib/aoc_cli/validators/integer_validator.rb +32 -0
  67. data/lib/aoc_cli/validators/path_validator.rb +39 -0
  68. data/lib/aoc_cli/validators/type_validator.rb +54 -0
  69. data/lib/aoc_cli/version.rb +1 -1
  70. data/lib/aoc_cli/views/event/attach.erb +3 -0
  71. data/lib/aoc_cli/views/event/init.erb +3 -0
  72. data/lib/aoc_cli/views/help/event/attach.erb +32 -0
  73. data/lib/aoc_cli/views/help/event/init.erb +38 -0
  74. data/lib/aoc_cli/views/help/event/progress.erb +12 -0
  75. data/lib/aoc_cli/views/help/puzzle/attempts.erb +12 -0
  76. data/lib/aoc_cli/views/help/puzzle/init.erb +31 -0
  77. data/lib/aoc_cli/views/help/puzzle/solve.erb +33 -0
  78. data/lib/aoc_cli/views/help/puzzle/sync.erb +32 -0
  79. data/lib/aoc_cli/views/puzzle/init.erb +3 -0
  80. data/lib/aoc_cli/views/puzzle/solve.erb +10 -0
  81. data/lib/aoc_cli.rb +32 -16
  82. data/rbs_collection.lock.yaml +168 -0
  83. data/rbs_collection.yaml +28 -0
  84. data/sig/aoc_cli/components/attempts_table.rbs +29 -0
  85. data/sig/aoc_cli/components/docs_component.rbs +15 -0
  86. data/sig/aoc_cli/components/errors_component.rbs +19 -0
  87. data/sig/aoc_cli/components/progress_table.rbs +28 -0
  88. data/sig/aoc_cli/components/puzzle_sync_component.rbs +19 -0
  89. data/sig/aoc_cli/configurators/session_configurator.rbs +7 -0
  90. data/sig/aoc_cli/controllers/application_controller.rbs +12 -0
  91. data/sig/aoc_cli/controllers/concerns/error_concern.rbs +9 -0
  92. data/sig/aoc_cli/controllers/concerns/location_concern.rbs +35 -0
  93. data/sig/aoc_cli/controllers/default_controller.rbs +7 -0
  94. data/sig/aoc_cli/controllers/event_controller.rbs +18 -0
  95. data/sig/aoc_cli/controllers/help/event_controller.rbs +11 -0
  96. data/sig/aoc_cli/controllers/help/puzzle_controller.rbs +13 -0
  97. data/sig/aoc_cli/controllers/puzzle_controller.rbs +15 -0
  98. data/sig/aoc_cli/core/attempt_parser.rbs +41 -0
  99. data/sig/aoc_cli/core/processor.rbs +25 -0
  100. data/sig/aoc_cli/core/repository.rbs +25 -0
  101. data/sig/aoc_cli/core/request.rbs +29 -0
  102. data/sig/aoc_cli/core/resource.rbs +25 -0
  103. data/sig/aoc_cli/core/stats_parser.rbs +23 -0
  104. data/sig/aoc_cli/helpers/table_generator.rbs +36 -0
  105. data/sig/aoc_cli/helpers/view_helper.rbs +15 -0
  106. data/sig/aoc_cli/models/attempt.rbs +35 -0
  107. data/sig/aoc_cli/models/event.rbs +17 -0
  108. data/sig/aoc_cli/models/location.rbs +19 -0
  109. data/sig/aoc_cli/models/puzzle.rbs +28 -0
  110. data/sig/aoc_cli/models/puzzle_dir_sync_log.rbs +11 -0
  111. data/sig/aoc_cli/models/stats.rbs +53 -0
  112. data/sig/aoc_cli/presenters/attempt_presenter.rbs +13 -0
  113. data/sig/aoc_cli/presenters/puzzle_presenter.rbs +19 -0
  114. data/sig/aoc_cli/presenters/stats_presenter.rbs +19 -0
  115. data/sig/aoc_cli/processors/event_initialiser.rbs +26 -0
  116. data/sig/aoc_cli/processors/puzzle_dir_synchroniser.rbs +40 -0
  117. data/sig/aoc_cli/processors/puzzle_initialiser.rbs +37 -0
  118. data/sig/aoc_cli/processors/puzzle_refresher.rbs +21 -0
  119. data/sig/aoc_cli/processors/resource_attacher.rbs +16 -0
  120. data/sig/aoc_cli/processors/solution_poster.rbs +34 -0
  121. data/sig/aoc_cli/processors/stats_initialiser.rbs +15 -0
  122. data/sig/aoc_cli/processors/stats_refresher.rbs +19 -0
  123. data/sig/aoc_cli/validators/collection_type_validator.rbs +24 -0
  124. data/sig/aoc_cli/validators/event_year_validator.rbs +19 -0
  125. data/sig/aoc_cli/validators/included_validator.rbs +11 -0
  126. data/sig/aoc_cli/validators/integer_validator.rbs +15 -0
  127. data/sig/aoc_cli/validators/path_validator.rbs +17 -0
  128. data/sig/aoc_cli/validators/type_validator.rbs +22 -0
  129. data/sig/aoc_cli.rbs +6 -0
  130. data/sig/http.rbs +3 -0
  131. data/sig/kangaru.rbs +5 -0
  132. data/sig/nokogiri.rbs +3 -0
  133. data/sig/reverse_markdown.rbs +3 -0
  134. metadata +142 -34
  135. data/.gitignore +0 -5
  136. data/bin/aoc +0 -4
  137. data/bin/console +0 -15
  138. data/bin/setup +0 -7
  139. data/lib/aoc_cli/commands.rb +0 -232
  140. data/lib/aoc_cli/database.rb +0 -224
  141. data/lib/aoc_cli/day.rb +0 -124
  142. data/lib/aoc_cli/db/reddit.db +0 -0
  143. data/lib/aoc_cli/errors.rb +0 -275
  144. data/lib/aoc_cli/files.rb +0 -163
  145. data/lib/aoc_cli/help.rb +0 -77
  146. data/lib/aoc_cli/interface.rb +0 -81
  147. data/lib/aoc_cli/paths.rb +0 -101
  148. data/lib/aoc_cli/solve.rb +0 -104
  149. data/lib/aoc_cli/tables.rb +0 -138
  150. data/lib/aoc_cli/tools.rb +0 -120
  151. data/lib/aoc_cli/year.rb +0 -116
  152. 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")
@@ -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
@@ -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