advent 0.1.2 → 0.1.4
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/README.md +20 -0
- data/lib/advent/cli/solver.rb +18 -10
- data/lib/advent/cli.rb +91 -15
- data/lib/advent/input.rb +50 -0
- data/lib/advent/session.rb +28 -0
- data/lib/advent/solution.rb +9 -3
- data/lib/advent/templates/solution_test.rb.tt +20 -0
- data/lib/advent/test_case.rb +6 -0
- data/lib/advent/version.rb +1 -1
- data/lib/advent.rb +9 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 360b1871cc09fd664dd8562fd1a29afd9b2e8bbc7a83d9d711c7933a6c62b5ec
|
4
|
+
data.tar.gz: 2f9cde07fa43650354a3f11c7cb869efa7c969d4254083ca807bd7a855fcf9d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e27b9323e1ad7a07484fe9302dfd49b430bd4fc5433ef0e412e1af14f734bdd1c0a8c719803e108e4b7b3aec144ec942119bc6a07bc93381f4aae9ef634324b1
|
7
|
+
data.tar.gz: b8e99258c57406a1cf945e868a1642d8ed8636c983fd960fd3f889bc6760c170bb346e3cdb0cc82e547f880dbd8c6f71898e941defdfd41b97a73974bc4cdec0
|
data/README.md
CHANGED
@@ -16,6 +16,26 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
16
16
|
|
17
17
|
## Usage
|
18
18
|
|
19
|
+
Advent expects you to have a working directory resembling something like:
|
20
|
+
|
21
|
+
$ tree
|
22
|
+
.
|
23
|
+
├── 2015
|
24
|
+
└── 2016
|
25
|
+
|
26
|
+
Some commands can be run from within a directory for a specific year, but it's
|
27
|
+
better to run from the parent directory where possible.
|
28
|
+
|
29
|
+
The typical flow for tackling a daily challenge would be:
|
30
|
+
|
31
|
+
$ advent generate 2015 1 # generate files to work in
|
32
|
+
$ advent download 2015 1 # download the input file
|
33
|
+
|
34
|
+
$ vim 2015/day1.rb 2015/day1_test.rb # do your work
|
35
|
+
|
36
|
+
$ ruby 2015/day1_test.rb # run any tests you may have
|
37
|
+
$ advent solve 2015/day1.rb # get your answers to submit
|
38
|
+
|
19
39
|
A list of commands and help is available using `advent`:
|
20
40
|
|
21
41
|
$ advent help
|
data/lib/advent/cli/solver.rb
CHANGED
@@ -3,21 +3,25 @@
|
|
3
3
|
class Advent::CLI::Solver
|
4
4
|
PARTS = [1, 2]
|
5
5
|
|
6
|
-
|
6
|
+
if RUBY_VERSION >= "3.1"
|
7
|
+
module Solutions
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(command, path)
|
7
12
|
@command = command
|
8
|
-
@
|
9
|
-
@day = day
|
13
|
+
@path = path
|
10
14
|
end
|
11
15
|
|
12
16
|
def solve
|
13
|
-
if
|
14
|
-
|
17
|
+
if RUBY_VERSION >= "3.1"
|
18
|
+
load @path, Solutions
|
19
|
+
solution = Solutions.const_get(solution_class_name).new
|
15
20
|
else
|
16
|
-
require @
|
21
|
+
require @path
|
22
|
+
solution = Object.const_get(solution_class_name).new
|
17
23
|
end
|
18
24
|
|
19
|
-
solution = Object.const_get(solution_class_name).new
|
20
|
-
|
21
25
|
PARTS.each do |n|
|
22
26
|
method_name = "part#{n}".to_sym
|
23
27
|
|
@@ -33,11 +37,15 @@ class Advent::CLI::Solver
|
|
33
37
|
|
34
38
|
private
|
35
39
|
|
40
|
+
def day
|
41
|
+
@_day ||= @path.basename.to_s.match(/day([0-9]+)\.rb/)[1]
|
42
|
+
end
|
43
|
+
|
36
44
|
def solution_file_name
|
37
|
-
"day#{
|
45
|
+
"day#{day}.rb"
|
38
46
|
end
|
39
47
|
|
40
48
|
def solution_class_name
|
41
|
-
"Day#{
|
49
|
+
"Day#{day}"
|
42
50
|
end
|
43
51
|
end
|
data/lib/advent/cli.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "advent"
|
4
|
+
require "date"
|
4
5
|
require "pathname"
|
5
6
|
require "thor"
|
6
7
|
|
@@ -9,6 +10,7 @@ module Advent
|
|
9
10
|
include Thor::Actions
|
10
11
|
|
11
12
|
class_option :root_path, default: Dir.pwd, hide: true, check_default_type: false
|
13
|
+
class_option :http_module, default: Net::HTTP, check_default_type: false
|
12
14
|
|
13
15
|
def initialize(*args)
|
14
16
|
super
|
@@ -17,45 +19,119 @@ module Advent
|
|
17
19
|
source_paths << File.expand_path("templates", __dir__)
|
18
20
|
end
|
19
21
|
|
22
|
+
# @return [Boolean] defines whether an exit status is set if a command fails
|
20
23
|
def self.exit_on_failure?
|
21
24
|
true
|
22
25
|
end
|
23
26
|
|
24
27
|
no_commands do
|
28
|
+
# @return [Boolean] whether the current root_path option is in a
|
29
|
+
# directory that looks like a year (eg. 2015)
|
25
30
|
def in_year_directory?
|
26
31
|
dir = root_path.basename.to_s
|
27
32
|
dir =~ /^20[0-9]{2}/
|
28
33
|
end
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "download YEAR DAY", "Download the input for YEAR and DAY"
|
37
|
+
def download(year_or_day, day = nil)
|
38
|
+
year, day = determine_year_and_day(year_or_day, day)
|
39
|
+
|
40
|
+
if (error_message = validate(year, day))
|
41
|
+
say_error error_message, :red
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
subpath = if in_year_directory?
|
46
|
+
""
|
47
|
+
else
|
48
|
+
"#{year}/"
|
49
|
+
end
|
50
|
+
|
51
|
+
unless Advent.session.exist?
|
52
|
+
session = ask "What is your Advent of Code session cookie value?", echo: false
|
53
|
+
Advent.session.value = session
|
29
54
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
55
|
+
say "\n\nThanks. Psst, we're going to save this for next time. It's in .advent_session if you need to update or delete it.\n\n"
|
56
|
+
end
|
57
|
+
|
58
|
+
input = Advent::Input.new(root_path.join(subpath), day: day.to_i)
|
59
|
+
|
60
|
+
if input.download(Advent.session.value, options.http_module)
|
61
|
+
say "Input downloaded to #{input.file_path}.", :green
|
62
|
+
say "\nUsing #load_input in your daily solution will load the input file for you."
|
63
|
+
else
|
64
|
+
say_error "Something went wrong, maybe an old session cookie?", :red
|
36
65
|
end
|
37
66
|
end
|
38
67
|
|
39
|
-
desc "generate YEAR DAY
|
68
|
+
desc "generate YEAR DAY", "Generate a new solution for YEAR and DAY"
|
69
|
+
# Generates a new solution file. If within a year directory, only the day
|
70
|
+
# is used, otherwise both the year and day will be required to generate the
|
71
|
+
# output.
|
40
72
|
def generate(year_or_day, day = nil)
|
41
|
-
|
42
|
-
|
73
|
+
year, day = determine_year_and_day(year_or_day, day)
|
74
|
+
|
75
|
+
if (error_message = validate(year, day))
|
76
|
+
say_error error_message, :red
|
77
|
+
return
|
78
|
+
end
|
79
|
+
|
80
|
+
subpath = if in_year_directory?
|
81
|
+
""
|
43
82
|
else
|
44
|
-
"#{
|
83
|
+
"#{year}/"
|
45
84
|
end
|
46
85
|
|
47
|
-
template "solution.rb.tt",
|
86
|
+
template "solution.rb.tt", "#{subpath}day#{day}.rb", context: binding
|
87
|
+
template "solution_test.rb.tt", "#{subpath}test/day#{day}_test.rb", context: binding
|
48
88
|
end
|
49
89
|
|
50
|
-
desc "solve
|
51
|
-
|
90
|
+
desc "solve FILE", "Solve your solution"
|
91
|
+
# Runs a solution file, outputting both :part1 and :part2 method return values.
|
92
|
+
def solve(path)
|
52
93
|
require "advent/cli/solver"
|
53
|
-
Solver.new(self,
|
94
|
+
Solver.new(self, root_path.join(path)).solve
|
54
95
|
end
|
55
96
|
|
56
|
-
desc "version", "Prints the current version of
|
97
|
+
desc "version", "Prints the current version of the gem"
|
98
|
+
# Prints the current version of the gem
|
57
99
|
def version
|
58
100
|
say Advent::VERSION
|
59
101
|
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def determine_year_and_day(year_or_day, day)
|
106
|
+
if in_year_directory?
|
107
|
+
[root_path.basename.to_s, parse_number(year_or_day)]
|
108
|
+
else
|
109
|
+
[year_or_day, parse_number(day)]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def root_path
|
114
|
+
@_root_path ||= if options.root_path.is_a?(Pathname)
|
115
|
+
options.root_path
|
116
|
+
else
|
117
|
+
Pathname.new(options.root_path)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def parse_number(str)
|
122
|
+
if (m = str.match(/[0-9]+/))
|
123
|
+
m[0]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def validate(year, day)
|
128
|
+
if year.to_i < 2014
|
129
|
+
"Advent of Code only started in 2014!"
|
130
|
+
elsif year.to_i > Date.today.year
|
131
|
+
"Future years are not supported."
|
132
|
+
elsif !(1..25).cover? day.to_i
|
133
|
+
"Day must be between 1 and 25 (inclusive)."
|
134
|
+
end
|
135
|
+
end
|
60
136
|
end
|
61
137
|
end
|
data/lib/advent/input.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cgi/cookie"
|
4
|
+
require "fileutils"
|
5
|
+
require "net/http"
|
6
|
+
require "uri"
|
7
|
+
|
8
|
+
module Advent
|
9
|
+
class Input
|
10
|
+
def initialize(dir, day:)
|
11
|
+
@dir = dir
|
12
|
+
@day = day
|
13
|
+
end
|
14
|
+
|
15
|
+
def file_path
|
16
|
+
@dir.join(".day#{@day}.input.txt")
|
17
|
+
end
|
18
|
+
|
19
|
+
def exist?
|
20
|
+
File.exist? file_path
|
21
|
+
end
|
22
|
+
|
23
|
+
def download(session, http = Net::HTTP)
|
24
|
+
session_cookie = CGI::Cookie.new("session", session)
|
25
|
+
response = http.get_response(input_url, {"Cookie" => session_cookie.to_s})
|
26
|
+
|
27
|
+
if success?(response)
|
28
|
+
FileUtils.mkdir_p file_path.dirname
|
29
|
+
File.write file_path, response.body
|
30
|
+
true
|
31
|
+
else
|
32
|
+
false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def input_url
|
39
|
+
URI("https://adventofcode.com/#{year}/day/#{@day}/input")
|
40
|
+
end
|
41
|
+
|
42
|
+
def year
|
43
|
+
@_year ||= @dir.basename
|
44
|
+
end
|
45
|
+
|
46
|
+
def success?(response)
|
47
|
+
response.code >= "200" && response.code < "300"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Advent
|
2
|
+
# Simple class for handling the session cookie file
|
3
|
+
class Session
|
4
|
+
FILE_NAME = ".advent_session"
|
5
|
+
|
6
|
+
attr_reader :file_name
|
7
|
+
|
8
|
+
def initialize(file_name = FILE_NAME)
|
9
|
+
@file_name = file_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def clear
|
13
|
+
File.delete file_name if exist?
|
14
|
+
end
|
15
|
+
|
16
|
+
def exist?
|
17
|
+
File.exist? file_name
|
18
|
+
end
|
19
|
+
|
20
|
+
def value=(val)
|
21
|
+
File.write file_name, val
|
22
|
+
end
|
23
|
+
|
24
|
+
def value
|
25
|
+
File.read file_name if exist?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/advent/solution.rb
CHANGED
@@ -3,19 +3,25 @@
|
|
3
3
|
require "pathname"
|
4
4
|
|
5
5
|
module Advent
|
6
|
+
# Baes class for an Advent of Code solution attempt. If subclass is in a
|
7
|
+
# directory matching a year (eg. 2015) and the filename is for a particular
|
8
|
+
# day (eg. day1.rb) then the @year and @day instance variables are
|
9
|
+
# automatically inferred.
|
6
10
|
class Solution
|
7
|
-
attr_reader :year
|
11
|
+
attr_reader :year # @return [Numeric] the year this solution is from
|
12
|
+
attr_reader :day # @return [Numeric] the day this solution is for
|
8
13
|
|
9
14
|
def initialize
|
10
15
|
year, day = infer_year_and_day_from_file_system
|
11
16
|
|
12
17
|
@year = year
|
13
18
|
@day = day
|
19
|
+
|
20
|
+
@input = Input.new(source_location.dirname, day: day)
|
14
21
|
end
|
15
22
|
|
16
23
|
def load_input
|
17
|
-
|
18
|
-
File.read(dir.join(".day#{@day}.input.txt"))
|
24
|
+
File.read(@input.file_path)
|
19
25
|
end
|
20
26
|
|
21
27
|
private
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "advent"
|
4
|
+
require "minitest/autorun"
|
5
|
+
|
6
|
+
require_relative "../day<%= day %>"
|
7
|
+
|
8
|
+
class Day<%= day %>Test < Advent::TestCase
|
9
|
+
def setup
|
10
|
+
@solution = Day<%= day %>.new
|
11
|
+
end
|
12
|
+
|
13
|
+
# def test_part1
|
14
|
+
# assert_equal 123, @solution.part1
|
15
|
+
# end
|
16
|
+
|
17
|
+
# def test_part2
|
18
|
+
# assert_equal 123, @solution.part2
|
19
|
+
# end
|
20
|
+
end
|
data/lib/advent/version.rb
CHANGED
data/lib/advent.rb
CHANGED
@@ -1,8 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "advent/input"
|
4
|
+
require_relative "advent/session"
|
3
5
|
require_relative "advent/solution"
|
6
|
+
require_relative "advent/test_case"
|
4
7
|
require_relative "advent/version"
|
5
8
|
|
6
9
|
module Advent
|
7
10
|
class Error < StandardError; end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def session
|
14
|
+
@_session = Session.new
|
15
|
+
end
|
16
|
+
end
|
8
17
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: advent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Grieve
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-11-
|
11
|
+
date: 2022-11-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -39,8 +39,12 @@ files:
|
|
39
39
|
- lib/advent.rb
|
40
40
|
- lib/advent/cli.rb
|
41
41
|
- lib/advent/cli/solver.rb
|
42
|
+
- lib/advent/input.rb
|
43
|
+
- lib/advent/session.rb
|
42
44
|
- lib/advent/solution.rb
|
43
45
|
- lib/advent/templates/solution.rb.tt
|
46
|
+
- lib/advent/templates/solution_test.rb.tt
|
47
|
+
- lib/advent/test_case.rb
|
44
48
|
- lib/advent/version.rb
|
45
49
|
homepage: https://github.com/dnlgrv/advent-rb
|
46
50
|
licenses:
|