advent 0.1.3 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +57 -0
- data/lib/advent/cli/downloader.rb +32 -0
- data/lib/advent/cli/solver.rb +5 -9
- data/lib/advent/cli.rb +30 -30
- data/lib/advent/configuration.rb +30 -0
- data/lib/advent/input.rb +50 -0
- data/lib/advent/session.rb +39 -0
- data/lib/advent/solution.rb +3 -2
- data/lib/advent/version.rb +1 -1
- data/lib/advent.rb +30 -0
- metadata +14 -4
- data/Rakefile +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ffa503d42078237632f9e87e404a67ba1e1a09b4a9e4cf2fee9ce9b647e89cb7
|
4
|
+
data.tar.gz: d147b5bbc31d6759fdf9441c69b2921d43037cff3258f7ef42d0c01d77ecce0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc70be78e2d488a49fd0bdce22ac3b53016757516fc6aa6fc307e26aacd1899f2026d0b6c7f78d81dc1269f0dc568f571b645deb819dd23f7f25f78b0df7313e
|
7
|
+
data.tar.gz: 23900afcbe9288005d5ec925106c9a0ae20e3ffcc99fb3b04f17b4434af2d6b2437bc492287d28fd5d51d3c7560b73ab4eea94261c8521040be4d47b6be4afd7
|
data/README.md
CHANGED
@@ -16,10 +16,67 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
16
16
|
|
17
17
|
## Usage
|
18
18
|
|
19
|
+
Initialise a new project somewhere:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
mkdir advent_of_code && cd advent_of_code
|
23
|
+
|
24
|
+
# create a blank advent.yml config file
|
25
|
+
advent init
|
26
|
+
```
|
27
|
+
|
28
|
+
Configuration values and format are explained in the [Config](#config) section.
|
29
|
+
|
30
|
+
Advent expects you to have a working directory resembling something like:
|
31
|
+
|
32
|
+
$ tree
|
33
|
+
.
|
34
|
+
├── 2015
|
35
|
+
├── 2016
|
36
|
+
└── advent.yml
|
37
|
+
|
38
|
+
You can run commands from anywhere under this directory.
|
39
|
+
|
40
|
+
The typical flow for tackling a daily challenge would be:
|
41
|
+
|
42
|
+
$ advent generate 2015 1 # generate files to work in
|
43
|
+
$ advent download 2015 1 # download the input file
|
44
|
+
|
45
|
+
$ vim 2015/day1.rb 2015/day1_test.rb # do your work
|
46
|
+
|
47
|
+
$ ruby 2015/day1_test.rb # run any tests you may have
|
48
|
+
$ advent solve 2015/day1.rb # get your answers to submit
|
49
|
+
|
19
50
|
A list of commands and help is available using `advent`:
|
20
51
|
|
21
52
|
$ advent help
|
22
53
|
|
54
|
+
## Config
|
55
|
+
|
56
|
+
The config file should be at the root of your working directory called
|
57
|
+
`advent.yml`. The default values if you don't provide an override are:
|
58
|
+
|
59
|
+
```yaml
|
60
|
+
download_when_generating: true
|
61
|
+
remember_session: true
|
62
|
+
```
|
63
|
+
|
64
|
+
### Config explained
|
65
|
+
|
66
|
+
<dl>
|
67
|
+
<dt>download_when_generating</dt>
|
68
|
+
<dd>
|
69
|
+
When you run `advent generate` it will automatically download the input file to
|
70
|
+
go with it
|
71
|
+
</dd>
|
72
|
+
|
73
|
+
<dt>remember_session</dt>
|
74
|
+
<dd>
|
75
|
+
Save your session cookie in `.advent_session` when prompted so you don't need to
|
76
|
+
find it again
|
77
|
+
</dd>
|
78
|
+
</dl>
|
79
|
+
|
23
80
|
## Development
|
24
81
|
|
25
82
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Advent::CLI::Downloader
|
4
|
+
def initialize(command, year, day)
|
5
|
+
@command = command
|
6
|
+
@year = year
|
7
|
+
@day = day
|
8
|
+
end
|
9
|
+
|
10
|
+
def download
|
11
|
+
ask_for_session_cookie_if_needed
|
12
|
+
input = Advent::Input.new(Advent.root.join(@year), day: @day.to_i)
|
13
|
+
|
14
|
+
if input.download(Advent.session.value, @command.options.http_module)
|
15
|
+
@command.say "Input downloaded to #{input.file_path}.", :green
|
16
|
+
@command.say "\nUsing #load_input in your daily solution will load the input file for you."
|
17
|
+
else
|
18
|
+
@command.say_error "Something went wrong, maybe an old session cookie?", :red
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def ask_for_session_cookie_if_needed
|
25
|
+
return if Advent.session.exist?
|
26
|
+
|
27
|
+
session = @command.ask "What is your Advent of Code session cookie value?", echo: false
|
28
|
+
Advent.session.value = session
|
29
|
+
|
30
|
+
@command.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"
|
31
|
+
end
|
32
|
+
end
|
data/lib/advent/cli/solver.rb
CHANGED
@@ -18,7 +18,7 @@ class Advent::CLI::Solver
|
|
18
18
|
load @path, Solutions
|
19
19
|
solution = Solutions.const_get(solution_class_name).new
|
20
20
|
else
|
21
|
-
require @path
|
21
|
+
require @path.expand_path
|
22
22
|
solution = Object.const_get(solution_class_name).new
|
23
23
|
end
|
24
24
|
|
@@ -37,15 +37,11 @@ class Advent::CLI::Solver
|
|
37
37
|
|
38
38
|
private
|
39
39
|
|
40
|
-
def day
|
41
|
-
@_day ||= @path.basename.to_s.match(/day([0-9]+)\.rb/)[1]
|
42
|
-
end
|
43
|
-
|
44
|
-
def solution_file_name
|
45
|
-
"day#{day}.rb"
|
46
|
-
end
|
47
|
-
|
48
40
|
def solution_class_name
|
49
41
|
"Day#{day}"
|
50
42
|
end
|
43
|
+
|
44
|
+
def day
|
45
|
+
@_day ||= @path.basename.to_s.match(/day([0-9]+)\.rb/)[1]
|
46
|
+
end
|
51
47
|
end
|
data/lib/advent/cli.rb
CHANGED
@@ -9,13 +9,17 @@ module Advent
|
|
9
9
|
class CLI < Thor
|
10
10
|
include Thor::Actions
|
11
11
|
|
12
|
-
class_option :
|
12
|
+
class_option :http_module, default: Net::HTTP, check_default_type: false
|
13
13
|
|
14
14
|
def initialize(*args)
|
15
15
|
super
|
16
16
|
|
17
|
-
self.destination_root = root_path
|
18
17
|
source_paths << File.expand_path("templates", __dir__)
|
18
|
+
|
19
|
+
# Don't try to load Advent.root if we're running init
|
20
|
+
unless args.last[:current_command]&.name == "init"
|
21
|
+
self.destination_root = Advent.root
|
22
|
+
end
|
19
23
|
end
|
20
24
|
|
21
25
|
# @return [Boolean] defines whether an exit status is set if a command fails
|
@@ -23,20 +27,12 @@ module Advent
|
|
23
27
|
true
|
24
28
|
end
|
25
29
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
def in_year_directory?
|
30
|
-
dir = root_path.basename.to_s
|
31
|
-
dir =~ /^20[0-9]{2}/
|
32
|
-
end
|
30
|
+
desc "download YEAR DAY", "Download the input for YEAR and DAY"
|
31
|
+
def download(year, day)
|
32
|
+
require "advent/cli/downloader"
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
options.root_path
|
37
|
-
else
|
38
|
-
Pathname.new(options.root_path)
|
39
|
-
end
|
34
|
+
Dir.chdir Advent.root do
|
35
|
+
Downloader.new(self, year, day).download
|
40
36
|
end
|
41
37
|
end
|
42
38
|
|
@@ -44,33 +40,37 @@ module Advent
|
|
44
40
|
# Generates a new solution file. If within a year directory, only the day
|
45
41
|
# is used, otherwise both the year and day will be required to generate the
|
46
42
|
# output.
|
47
|
-
def generate(
|
48
|
-
year
|
49
|
-
|
50
|
-
else
|
51
|
-
[year_or_day, parse_number(day)]
|
52
|
-
end
|
43
|
+
def generate(year, day)
|
44
|
+
year = parse_number year
|
45
|
+
day = parse_number day
|
53
46
|
|
54
|
-
if (
|
55
|
-
say_error
|
47
|
+
if (message = validate(year, day))
|
48
|
+
say_error message, :red
|
56
49
|
return
|
57
50
|
end
|
58
51
|
|
59
|
-
|
52
|
+
template "solution.rb.tt", "#{year}/day#{day}.rb", context: binding
|
53
|
+
template "solution_test.rb.tt", "#{year}/test/day#{day}_test.rb", context: binding
|
54
|
+
|
55
|
+
download year, day if Advent.config.download_when_generating
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "init DIR", "Initialise a new advent project in DIR"
|
59
|
+
def init(dir = ".")
|
60
|
+
create_file Pathname.getwd.join(dir).join(Advent::Configuration::FILE_NAME) do
|
60
61
|
""
|
61
|
-
else
|
62
|
-
"#{year}/"
|
63
62
|
end
|
64
|
-
|
65
|
-
template "solution.rb.tt", "#{subpath}day#{day}.rb", context: binding
|
66
|
-
template "solution_test.rb.tt", "#{subpath}test/day#{day}_test.rb", context: binding
|
67
63
|
end
|
68
64
|
|
69
65
|
desc "solve FILE", "Solve your solution"
|
70
66
|
# Runs a solution file, outputting both :part1 and :part2 method return values.
|
71
67
|
def solve(path)
|
72
68
|
require "advent/cli/solver"
|
73
|
-
|
69
|
+
file_path = Pathname.getwd.join(path)
|
70
|
+
|
71
|
+
Dir.chdir Advent.root do
|
72
|
+
Solver.new(self, file_path.relative_path_from(Advent.root)).solve
|
73
|
+
end
|
74
74
|
end
|
75
75
|
|
76
76
|
desc "version", "Prints the current version of the gem"
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "psych"
|
2
|
+
|
3
|
+
module Advent
|
4
|
+
class Configuration
|
5
|
+
DEFAULTS = {
|
6
|
+
"download_when_generating" => true,
|
7
|
+
"remember_session" => true
|
8
|
+
}
|
9
|
+
FILE_NAME = "advent.yml"
|
10
|
+
|
11
|
+
attr_reader :download_when_generating, :remember_session
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def from_file(file = FILE_NAME)
|
15
|
+
if RUBY_VERSION >= "3.1"
|
16
|
+
new Psych.safe_load_file(file)
|
17
|
+
else
|
18
|
+
new Psych.safe_load(File.read(file))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(conf)
|
24
|
+
config = DEFAULTS.merge(conf || {})
|
25
|
+
|
26
|
+
@download_when_generating = config.dig("download_when_generating")
|
27
|
+
@remember_session = config.dig("remember_session")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
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,39 @@
|
|
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
|
+
if save_to_disk?
|
22
|
+
File.write file_name, val
|
23
|
+
else
|
24
|
+
@_value = val
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def value
|
29
|
+
return @_value unless save_to_disk?
|
30
|
+
return File.read(file_name) if exist?
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def save_to_disk?
|
36
|
+
Advent.config.remember_session
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/advent/solution.rb
CHANGED
@@ -16,11 +16,12 @@ module Advent
|
|
16
16
|
|
17
17
|
@year = year
|
18
18
|
@day = day
|
19
|
+
|
20
|
+
@input = Input.new(source_location.dirname, day: day)
|
19
21
|
end
|
20
22
|
|
21
23
|
def load_input
|
22
|
-
|
23
|
-
File.read(dir.join(".day#{@day}.input.txt"))
|
24
|
+
File.read(@input.file_path)
|
24
25
|
end
|
25
26
|
|
26
27
|
private
|
data/lib/advent/version.rb
CHANGED
data/lib/advent.rb
CHANGED
@@ -1,9 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "advent/configuration"
|
4
|
+
require_relative "advent/input"
|
5
|
+
require_relative "advent/session"
|
3
6
|
require_relative "advent/solution"
|
4
7
|
require_relative "advent/test_case"
|
5
8
|
require_relative "advent/version"
|
6
9
|
|
7
10
|
module Advent
|
8
11
|
class Error < StandardError; end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def config
|
15
|
+
@_config ||= Configuration.from_file(root.join(Configuration::FILE_NAME))
|
16
|
+
end
|
17
|
+
|
18
|
+
def root
|
19
|
+
if (location = find_config_location)
|
20
|
+
location
|
21
|
+
else
|
22
|
+
raise Error, "Cannot find advent.yml config file in current or parent directories."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def session
|
27
|
+
@_session ||= Session.new
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def find_config_location
|
33
|
+
Pathname.new(Dir.pwd).ascend do |path|
|
34
|
+
return path if File.exist? path.join(Configuration::FILE_NAME)
|
35
|
+
return nil if path.to_s == "/"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
9
39
|
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.5
|
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-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -34,11 +34,14 @@ extra_rdoc_files: []
|
|
34
34
|
files:
|
35
35
|
- LICENSE.txt
|
36
36
|
- README.md
|
37
|
-
- Rakefile
|
38
37
|
- exe/advent
|
39
38
|
- lib/advent.rb
|
40
39
|
- lib/advent/cli.rb
|
40
|
+
- lib/advent/cli/downloader.rb
|
41
41
|
- lib/advent/cli/solver.rb
|
42
|
+
- lib/advent/configuration.rb
|
43
|
+
- lib/advent/input.rb
|
44
|
+
- lib/advent/session.rb
|
42
45
|
- lib/advent/solution.rb
|
43
46
|
- lib/advent/templates/solution.rb.tt
|
44
47
|
- lib/advent/templates/solution_test.rb.tt
|
@@ -48,7 +51,13 @@ homepage: https://github.com/dnlgrv/advent-rb
|
|
48
51
|
licenses:
|
49
52
|
- MIT
|
50
53
|
metadata: {}
|
51
|
-
post_install_message:
|
54
|
+
post_install_message: |2+
|
55
|
+
|
56
|
+
advent v0.1.5 requires a config file in your working directory.
|
57
|
+
|
58
|
+
See https://github.com/dnlgrv/advent-rb/blob/main/README.md#usage or if you're
|
59
|
+
brave run `advent init` in your current directory.
|
60
|
+
|
52
61
|
rdoc_options: []
|
53
62
|
require_paths:
|
54
63
|
- lib
|
@@ -68,3 +77,4 @@ signing_key:
|
|
68
77
|
specification_version: 4
|
69
78
|
summary: Have fun with the Advent of Code using Ruby.
|
70
79
|
test_files: []
|
80
|
+
...
|
data/Rakefile
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "bundler/gem_tasks"
|
4
|
-
require "rake/testtask"
|
5
|
-
require "standard/rake"
|
6
|
-
|
7
|
-
Rake::TestTask.new(:test) do |t|
|
8
|
-
t.libs << "test"
|
9
|
-
t.libs << "lib"
|
10
|
-
t.options = "-p"
|
11
|
-
t.test_files = FileList["test/**/*_test.rb"]
|
12
|
-
end
|
13
|
-
|
14
|
-
task default: %i[test]
|