advent 0.1.3 → 0.1.5
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 +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]
|