aoc_rb 0.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 +7 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +62 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +21 -0
- data/README.md +44 -0
- data/Rakefile +6 -0
- data/aoc_rb.gemspec +35 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/aoc +4 -0
- data/lib/aoc_rb.rb +7 -0
- data/lib/aoc_rb/aoc_api.rb +38 -0
- data/lib/aoc_rb/app.rb +121 -0
- data/lib/aoc_rb/app_loader.rb +33 -0
- data/lib/aoc_rb/cli.rb +42 -0
- data/lib/aoc_rb/puzzle.rb +130 -0
- data/lib/aoc_rb/puzzle_input.rb +54 -0
- data/lib/aoc_rb/puzzle_solution.rb +49 -0
- data/lib/aoc_rb/puzzle_source.rb +33 -0
- data/lib/aoc_rb/version.rb +3 -0
- data/templates/.env-template +1 -0
- data/templates/Gemfile +7 -0
- data/templates/bin/aoc +35 -0
- data/templates/solution.rb.erb +12 -0
- data/templates/solution_spec.rb.erb +33 -0
- data/templates/spec/spec_helper.rb +9 -0
- metadata +162 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: c55b5953ec5f5609a93d35056a675811dd5777a71514b6f3ed90eb64223212a4
|
|
4
|
+
data.tar.gz: 1cc0e2404ad5efb0a38b5f4870785089fbd3b9d9edf86f8134cb793f43b47d2b
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: f1d9532728421583243011320330aeb9a5279627fd2c05b842ced50b92ff19650cbaf7e31aa336c71d35f80a6f1dc5e02060aafc9dfb6718cde52f519eb845de
|
|
7
|
+
data.tar.gz: d13d273694aa76935fd809ee3c7a777dbb9ba3449b2a18b411b905c06dd7876961b78e539fa33c4906d7ceaf929c8831615f2d818593cf32900553f6c16be3ff
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
|
10
|
+
orientation.
|
|
11
|
+
|
|
12
|
+
## Our Standards
|
|
13
|
+
|
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
|
15
|
+
include:
|
|
16
|
+
|
|
17
|
+
* Using welcoming and inclusive language
|
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
|
19
|
+
* Gracefully accepting constructive criticism
|
|
20
|
+
* Focusing on what is best for the community
|
|
21
|
+
* Showing empathy towards other community members
|
|
22
|
+
|
|
23
|
+
Examples of unacceptable behavior by participants include:
|
|
24
|
+
|
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
|
26
|
+
advances
|
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
28
|
+
* Public or private harassment
|
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
|
30
|
+
address, without explicit permission
|
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
|
32
|
+
professional setting
|
|
33
|
+
|
|
34
|
+
## Our Responsibilities
|
|
35
|
+
|
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
|
38
|
+
response to any instances of unacceptable behavior.
|
|
39
|
+
|
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
|
44
|
+
threatening, offensive, or harmful.
|
|
45
|
+
|
|
46
|
+
## Scope
|
|
47
|
+
|
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
|
49
|
+
when an individual is representing the project or its community. Examples of
|
|
50
|
+
representing a project or community include using an official project e-mail
|
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
|
53
|
+
further defined and clarified by project maintainers.
|
|
54
|
+
|
|
55
|
+
## Enforcement
|
|
56
|
+
|
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
58
|
+
reported by contacting the project team at TODO: Write your email address. All
|
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
|
63
|
+
|
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
|
66
|
+
members of the project's leadership.
|
|
67
|
+
|
|
68
|
+
## Attribution
|
|
69
|
+
|
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
71
|
+
available at [https://contributor-covenant.org/version/1/4][version]
|
|
72
|
+
|
|
73
|
+
[homepage]: https://contributor-covenant.org
|
|
74
|
+
[version]: https://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
aoc_rb (0.0.0)
|
|
5
|
+
dotenv (~> 2.7.6)
|
|
6
|
+
httparty (~> 0.18.1)
|
|
7
|
+
nokogiri (~> 1.10.10)
|
|
8
|
+
rspec (~> 3.0)
|
|
9
|
+
thor (~> 1.0.1)
|
|
10
|
+
|
|
11
|
+
GEM
|
|
12
|
+
remote: https://rubygems.org/
|
|
13
|
+
specs:
|
|
14
|
+
addressable (2.7.0)
|
|
15
|
+
public_suffix (>= 2.0.2, < 5.0)
|
|
16
|
+
byebug (11.1.3)
|
|
17
|
+
crack (0.4.4)
|
|
18
|
+
diff-lcs (1.4.4)
|
|
19
|
+
dotenv (2.7.6)
|
|
20
|
+
hashdiff (1.0.1)
|
|
21
|
+
httparty (0.18.1)
|
|
22
|
+
mime-types (~> 3.0)
|
|
23
|
+
multi_xml (>= 0.5.2)
|
|
24
|
+
mime-types (3.3.1)
|
|
25
|
+
mime-types-data (~> 3.2015)
|
|
26
|
+
mime-types-data (3.2020.1104)
|
|
27
|
+
mini_portile2 (2.4.0)
|
|
28
|
+
multi_xml (0.6.0)
|
|
29
|
+
nokogiri (1.10.10)
|
|
30
|
+
mini_portile2 (~> 2.4.0)
|
|
31
|
+
public_suffix (4.0.6)
|
|
32
|
+
rake (12.3.3)
|
|
33
|
+
rspec (3.10.0)
|
|
34
|
+
rspec-core (~> 3.10.0)
|
|
35
|
+
rspec-expectations (~> 3.10.0)
|
|
36
|
+
rspec-mocks (~> 3.10.0)
|
|
37
|
+
rspec-core (3.10.0)
|
|
38
|
+
rspec-support (~> 3.10.0)
|
|
39
|
+
rspec-expectations (3.10.0)
|
|
40
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
41
|
+
rspec-support (~> 3.10.0)
|
|
42
|
+
rspec-mocks (3.10.0)
|
|
43
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
44
|
+
rspec-support (~> 3.10.0)
|
|
45
|
+
rspec-support (3.10.0)
|
|
46
|
+
thor (1.0.1)
|
|
47
|
+
webmock (3.10.0)
|
|
48
|
+
addressable (>= 2.3.6)
|
|
49
|
+
crack (>= 0.3.2)
|
|
50
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
|
51
|
+
|
|
52
|
+
PLATFORMS
|
|
53
|
+
ruby
|
|
54
|
+
|
|
55
|
+
DEPENDENCIES
|
|
56
|
+
aoc_rb!
|
|
57
|
+
byebug
|
|
58
|
+
rake (~> 12.0)
|
|
59
|
+
webmock (~> 3.10.0)
|
|
60
|
+
|
|
61
|
+
BUNDLED WITH
|
|
62
|
+
2.1.4
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 Jon Pascoe
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 TODO: Write your name
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# AocRb
|
|
2
|
+
|
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/aoc_rb`. To experiment with that code, run `bin/console` for an interactive prompt.
|
|
4
|
+
|
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Add this line to your application's Gemfile:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
gem 'aoc_rb'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
And then execute:
|
|
16
|
+
|
|
17
|
+
$ bundle install
|
|
18
|
+
|
|
19
|
+
Or install it yourself as:
|
|
20
|
+
|
|
21
|
+
$ gem install aoc_rb
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
TODO: Write usage instructions here
|
|
26
|
+
|
|
27
|
+
## Development
|
|
28
|
+
|
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
30
|
+
|
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
32
|
+
|
|
33
|
+
## Contributing
|
|
34
|
+
|
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/aoc_rb. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/aoc_rb/blob/master/CODE_OF_CONDUCT.md).
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## License
|
|
39
|
+
|
|
40
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
41
|
+
|
|
42
|
+
## Code of Conduct
|
|
43
|
+
|
|
44
|
+
Everyone interacting in the AocRb project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/aoc_rb/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
data/aoc_rb.gemspec
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require_relative 'lib/aoc_rb/version'
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = "aoc_rb"
|
|
5
|
+
spec.version = AocRb::VERSION
|
|
6
|
+
spec.authors = ["Jon Pascoe"]
|
|
7
|
+
spec.email = ["jon.pascoe@me.com"]
|
|
8
|
+
|
|
9
|
+
spec.summary = %q{A Ruby toolkit for Advent of Code}
|
|
10
|
+
spec.description = %q{Tools for creating a new project for your Advent of Code solutions, built using Ruby.}
|
|
11
|
+
spec.homepage = "https://github.com/pacso/aoc_rb"
|
|
12
|
+
spec.license = "MIT"
|
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
|
14
|
+
|
|
15
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
16
|
+
spec.metadata["source_code_uri"] = "https://github.com/pacso/aoc_rb"
|
|
17
|
+
spec.metadata["changelog_uri"] = "https://github.com/pacso/aoc_rb/blob/main/CHANGELOG"
|
|
18
|
+
|
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
21
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
|
22
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
23
|
+
end
|
|
24
|
+
spec.bindir = "exe"
|
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
26
|
+
spec.require_paths = ["lib"]
|
|
27
|
+
|
|
28
|
+
spec.add_dependency "dotenv", "~> 2.7.6"
|
|
29
|
+
spec.add_dependency "httparty", "~> 0.18.1"
|
|
30
|
+
spec.add_dependency "thor", "~> 1.0.1"
|
|
31
|
+
spec.add_dependency "rspec", "~> 3.0"
|
|
32
|
+
spec.add_dependency "nokogiri", "~> 1.10.10"
|
|
33
|
+
|
|
34
|
+
spec.add_development_dependency "webmock", "~> 3.10.0"
|
|
35
|
+
end
|
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "aoc_rb"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/exe/aoc
ADDED
data/lib/aoc_rb.rb
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AocRb
|
|
4
|
+
class AocApi
|
|
5
|
+
include HTTParty
|
|
6
|
+
base_uri 'https://adventofcode.com'
|
|
7
|
+
|
|
8
|
+
def initialize(session)
|
|
9
|
+
@options = { headers: { 'Cookie' => "session=#{session}" }, follow_redirects: false }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def puzzle_instructions(year, day)
|
|
13
|
+
self.class.get(puzzle_path(year, day), @options)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def puzzle_input(year, day)
|
|
17
|
+
self.class.get(input_path(year, day), @options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def submit_answer(year, day, level, answer)
|
|
21
|
+
options_with_answer = @options.merge({ body: { level: level.to_s, answer: answer.to_s } })
|
|
22
|
+
self.class.post(answer_path(year, day), options_with_answer)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
def puzzle_path(year, day)
|
|
27
|
+
"/#{year}/day/#{day}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def input_path(year, day)
|
|
31
|
+
puzzle_path(year, day) + "/input"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def answer_path(year, day)
|
|
35
|
+
puzzle_path(year, day) + "/answer"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/aoc_rb/app.rb
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
require "httparty"
|
|
2
|
+
require 'dotenv/load'
|
|
3
|
+
require "thor"
|
|
4
|
+
|
|
5
|
+
require 'aoc_rb/aoc_api'
|
|
6
|
+
require 'aoc_rb/puzzle'
|
|
7
|
+
require 'aoc_rb/puzzle_input'
|
|
8
|
+
require 'aoc_rb/puzzle_solution'
|
|
9
|
+
require 'aoc_rb/puzzle_source'
|
|
10
|
+
|
|
11
|
+
src_files = File.join(Dir.getwd, "challenges", "**", "*.rb")
|
|
12
|
+
|
|
13
|
+
Dir[src_files].each do |file|
|
|
14
|
+
if File.exist? file
|
|
15
|
+
require file
|
|
16
|
+
else
|
|
17
|
+
puts "missing file #{file}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
module AocRb
|
|
22
|
+
class App < Thor
|
|
23
|
+
desc "fetch", "Downloads the input file and problem statement for today, or an optionally specified year / day", hide: true
|
|
24
|
+
method_option :year, aliases: "-y", type: :numeric, default: Time.now.year
|
|
25
|
+
method_option :day, aliases: "-d", type: :numeric, default: Time.now.day
|
|
26
|
+
|
|
27
|
+
def fetch(year = options[:year], day = options[:day])
|
|
28
|
+
fetch_input(year, day)
|
|
29
|
+
fetch_instructions(year, day)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
desc "download", "downloads an input file for today, or an optionally specified year & day", hide: true
|
|
33
|
+
method_option :year, aliases: "-y", type: :numeric, default: Time.now.year
|
|
34
|
+
method_option :day, aliases: "-d", type: :numeric, default: Time.now.day
|
|
35
|
+
|
|
36
|
+
def fetch_input(year = options[:year], day = options[:day])
|
|
37
|
+
AocRb::PuzzleInput.download(year, day)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
desc "fetch_instructions", "downloads the available instructions for today, or the specified date", hide: true
|
|
41
|
+
method_option :year, aliases: "-y", type: :numeric, default: Time.now.year
|
|
42
|
+
method_option :day, aliases: "-d", type: :numeric, default: Time.now.day
|
|
43
|
+
|
|
44
|
+
def fetch_instructions(year = options[:year], day = options[:day])
|
|
45
|
+
AocRb::Puzzle.fetch_instructions(year, day)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
desc "bootstrap", "sets up the boilerplate for a new daily challenge", hide: true
|
|
49
|
+
method_option :year, aliases: "-y", type: :numeric, default: Time.now.year
|
|
50
|
+
method_option :day, aliases: "-d", type: :numeric, default: Time.now.day
|
|
51
|
+
|
|
52
|
+
def bootstrap(year = options[:year], day = options[:day])
|
|
53
|
+
AocRb::Puzzle.create_templates(year, day)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
desc "exec", "executes and optionally submits the puzzle for today, or the specified date"
|
|
57
|
+
long_desc <<~LONGDESC
|
|
58
|
+
`exec` will check if you have instructions for PART 2 of today's puzzle.
|
|
59
|
+
If you don't it will execute part 1, and offer to submit it for you. If
|
|
60
|
+
you do have instructions for part 2, it will execute part 2 and offer to
|
|
61
|
+
submit that.
|
|
62
|
+
|
|
63
|
+
In the event that you've recently submitted an incorrect answer and are
|
|
64
|
+
being throttled, it will detect the remaining time you need to wait, and
|
|
65
|
+
automatically submit your solution 1s after that delay.
|
|
66
|
+
|
|
67
|
+
You can optionally specify another day/year to exec if you're not working on
|
|
68
|
+
today's puzzle.
|
|
69
|
+
LONGDESC
|
|
70
|
+
method_option :year, aliases: "-y", type: :numeric, default: Time.now.year
|
|
71
|
+
method_option :day, aliases: "-d", type: :numeric, default: Time.now.day
|
|
72
|
+
|
|
73
|
+
def exec(year = options[:year], day = options[:day])
|
|
74
|
+
puzzle = AocRb::PuzzleSource.create_puzzle(year, day)
|
|
75
|
+
input = AocRb::PuzzleInput.load(year, day)
|
|
76
|
+
|
|
77
|
+
level = Puzzle.instructions_exist?(year, day, :part_2) ? 2 : 1
|
|
78
|
+
puts "#{year} Day #{day}"
|
|
79
|
+
solution = PuzzleSource.run_part("part #{level}") { puzzle.send("part_#{level}", input) }
|
|
80
|
+
|
|
81
|
+
puts "Submit solution? #{solution} (y/N)"
|
|
82
|
+
submit = STDIN.gets.chomp.downcase
|
|
83
|
+
puts "We said #{submit}"
|
|
84
|
+
|
|
85
|
+
if submit == "y"
|
|
86
|
+
if PuzzleSolution.submit(level, year, day, solution)
|
|
87
|
+
puts "Correct!"
|
|
88
|
+
|
|
89
|
+
if level == 1
|
|
90
|
+
puts "Downloading part 2!"
|
|
91
|
+
fetch_instructions(year, day)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
desc "output", "outputs results from your solution for the given day"
|
|
98
|
+
method_option :year, aliases: "-y", type: :numeric, default: Time.now.year
|
|
99
|
+
method_option :day, aliases: "-d", type: :numeric, default: Time.now.day
|
|
100
|
+
|
|
101
|
+
def output(year = options[:year], day = options[:day])
|
|
102
|
+
puzzle = AocRb::PuzzleSource.create_puzzle(year, day)
|
|
103
|
+
input = AocRb::PuzzleInput.load(year, day)
|
|
104
|
+
|
|
105
|
+
AocRb::PuzzleSource.run_part('part 1') { puzzle.part_1(input) }
|
|
106
|
+
puts
|
|
107
|
+
AocRb::PuzzleSource.run_part('part 2') { puzzle.part_2(input) }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
desc "prep", "preps everything you need for a new puzzle"
|
|
111
|
+
method_option :year, aliases: "-y", type: :numeric, default: Time.now.year
|
|
112
|
+
method_option :day, aliases: "-d", type: :numeric, default: Time.now.day
|
|
113
|
+
|
|
114
|
+
def prep(year = options[:year], day = options[:day])
|
|
115
|
+
fetch(year, day)
|
|
116
|
+
bootstrap(year, day)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
AocRb::App.start
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AocRb
|
|
4
|
+
module AppLoader
|
|
5
|
+
extend self
|
|
6
|
+
|
|
7
|
+
RUBY = Gem.ruby
|
|
8
|
+
EXECUTABLES = ["bin/aoc", "script/aoc"]
|
|
9
|
+
|
|
10
|
+
def exec_app
|
|
11
|
+
original_cwd = Dir.pwd
|
|
12
|
+
|
|
13
|
+
loop do
|
|
14
|
+
if exe = find_executable
|
|
15
|
+
contents = File.read(exe)
|
|
16
|
+
|
|
17
|
+
if /THIS IS THE BIN FILE/.match?(contents)
|
|
18
|
+
exec RUBY, exe, *ARGV
|
|
19
|
+
break
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Dir.chdir(original_cwd) && return if Pathname.new(Dir.pwd).root?
|
|
24
|
+
|
|
25
|
+
Dir.chdir("..")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def find_executable
|
|
30
|
+
EXECUTABLES.find { |exe| File.file?(exe) }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/aoc_rb/cli.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "aoc_rb/app_loader"
|
|
4
|
+
AocRb::AppLoader.exec_app
|
|
5
|
+
|
|
6
|
+
require "thor"
|
|
7
|
+
|
|
8
|
+
module AocRb
|
|
9
|
+
class Cli < Thor
|
|
10
|
+
desc "new NAME", "Creates a new AoC project with the given name"
|
|
11
|
+
|
|
12
|
+
def new(name)
|
|
13
|
+
project_dir = File.join(Dir.getwd, name)
|
|
14
|
+
if File.exist?(project_dir)
|
|
15
|
+
puts "ERROR: #{project_dir} already exists!"
|
|
16
|
+
exit 0
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
bin_dir = File.join(project_dir, "bin")
|
|
20
|
+
bin_path = File.join(bin_dir, "aoc")
|
|
21
|
+
bin_template = File.join(File.dirname(__FILE__), "../../templates/bin/aoc")
|
|
22
|
+
FileUtils.mkdir_p bin_dir
|
|
23
|
+
File.open(bin_path, "w") { |f| f.write(File.read(bin_template)) }
|
|
24
|
+
|
|
25
|
+
spec_dir = File.join(project_dir, "spec")
|
|
26
|
+
spec_helper_path = File.join(spec_dir, "spec_helper.rb")
|
|
27
|
+
spec_helper_template = File.join(File.dirname(__FILE__), "../../templates/spec/spec_helper.rb")
|
|
28
|
+
FileUtils.mkdir_p spec_dir
|
|
29
|
+
File.open(spec_helper_path, "w") { |f| f.write(File.read(spec_helper_template)) }
|
|
30
|
+
|
|
31
|
+
env_template_path = File.join(project_dir, ".env-template")
|
|
32
|
+
env_template = File.join(File.dirname(__FILE__), "../../templates/.env-template")
|
|
33
|
+
File.open(env_template_path, "w") { |f| f.write(File.read(env_template)) }
|
|
34
|
+
|
|
35
|
+
gemfile_dst = File.join(project_dir, "Gemfile")
|
|
36
|
+
gemfile_src = File.join(File.dirname(__FILE__), "../../templates/Gemfile")
|
|
37
|
+
File.open(gemfile_dst, "w") { |f| f.write(File.read(gemfile_src))}
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
AocRb::Cli.start
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "nokogiri"
|
|
4
|
+
require "erb"
|
|
5
|
+
|
|
6
|
+
module AocRb
|
|
7
|
+
module Puzzle
|
|
8
|
+
extend self
|
|
9
|
+
|
|
10
|
+
def create_templates(year, day)
|
|
11
|
+
create_source(year, day)
|
|
12
|
+
create_spec(year, day)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def padded(day)
|
|
16
|
+
day.to_s.rjust(2, "0")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def create_source(year, day)
|
|
20
|
+
source_dir = File.join("challenges", year.to_s, padded(day))
|
|
21
|
+
source_path = File.join(source_dir, "solution.rb")
|
|
22
|
+
FileUtils.mkdir_p(source_dir) unless Dir.exist?(source_dir)
|
|
23
|
+
PuzzleInput.skip_if_exists(source_path) do
|
|
24
|
+
template = File.read(File.join(File.dirname(__FILE__), "../../templates", "solution.rb.erb"))
|
|
25
|
+
@year = year.to_s
|
|
26
|
+
@day = padded(day)
|
|
27
|
+
File.open(source_path, "w") do |f|
|
|
28
|
+
f.write ERB.new(template).result(binding)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def create_spec(year, day)
|
|
34
|
+
spec_dir = File.join("spec", year.to_s, padded(day))
|
|
35
|
+
spec_path = File.join(spec_dir, "solution_spec.rb")
|
|
36
|
+
FileUtils.mkdir_p(spec_dir) unless Dir.exist?(spec_dir)
|
|
37
|
+
PuzzleInput.skip_if_exists(spec_path) do
|
|
38
|
+
template = File.read(File.join(File.dirname(__FILE__), "../../templates", "solution_spec.rb.erb"))
|
|
39
|
+
@year = year.to_s
|
|
40
|
+
@day = padded(day)
|
|
41
|
+
File.open(spec_path, "w") do |f|
|
|
42
|
+
f.write ERB.new(template).result(binding)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def fetch_instructions(year, day)
|
|
48
|
+
create_required_directories year, day
|
|
49
|
+
|
|
50
|
+
api = AocRb::AocApi.new(ENV['AOC_COOKIE'])
|
|
51
|
+
content = api.puzzle_instructions(year, day)
|
|
52
|
+
|
|
53
|
+
parse_and_save_instructions(year, day, content.body)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def create_puzzle(year, day)
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def instructions_exist?(year, day, part)
|
|
61
|
+
filename = File.join("challenges", year.to_s, padded(day), "#{part}.md")
|
|
62
|
+
File.exist?(filename)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def create_required_directories(year, day)
|
|
66
|
+
year_directory = File.join("challenges", year.to_s, padded(day))
|
|
67
|
+
FileUtils.mkdir_p(year_directory) unless Dir.exist?(year_directory)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def parse_and_save_instructions(year, day, content)
|
|
71
|
+
doc = Nokogiri::HTML(content)
|
|
72
|
+
articles = doc.css("article.day-desc")
|
|
73
|
+
articles.each_with_index { |article, index| process_article(year, day, article, index) }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def process_article(year, day, article, index)
|
|
77
|
+
part_num = index + 1
|
|
78
|
+
filename = File.join("challenges", year.to_s, padded(day), "part_#{part_num}.md")
|
|
79
|
+
|
|
80
|
+
File.open(filename, "w") do |f|
|
|
81
|
+
process_page_content(f, article)
|
|
82
|
+
f.close
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def process_page_content(f, child, indent_level = 0, strip_em = false)
|
|
87
|
+
# byebug
|
|
88
|
+
return unless child.respond_to?(:name)
|
|
89
|
+
case child.name
|
|
90
|
+
when "text"
|
|
91
|
+
f.write child.content.chomp.gsub("\n", "\n" + (" " * indent_level))
|
|
92
|
+
when "h2"
|
|
93
|
+
f.write "## "
|
|
94
|
+
process_children f, child.children, indent_level, strip_em
|
|
95
|
+
f.write "\n\n"
|
|
96
|
+
when "p"
|
|
97
|
+
process_children f, child.children, indent_level, strip_em
|
|
98
|
+
f.write "\n\n"
|
|
99
|
+
when "ul"
|
|
100
|
+
process_children f, child.children, indent_level, strip_em
|
|
101
|
+
f.write "\n"
|
|
102
|
+
when "li"
|
|
103
|
+
f.write "* "
|
|
104
|
+
process_children f, child.children, indent_level, strip_em
|
|
105
|
+
f.write "\n"
|
|
106
|
+
when "em"
|
|
107
|
+
f.write "**" unless strip_em
|
|
108
|
+
process_children f, child.children
|
|
109
|
+
f.write "**" unless strip_em
|
|
110
|
+
when "code"
|
|
111
|
+
f.write " " * indent_level
|
|
112
|
+
f.write "``" unless indent_level > 0
|
|
113
|
+
process_children f, child.children, indent_level, true
|
|
114
|
+
f.write "``" unless indent_level > 0
|
|
115
|
+
when "pre"
|
|
116
|
+
process_children f, child.children, 4, strip_em
|
|
117
|
+
f.write "\n\n"
|
|
118
|
+
else
|
|
119
|
+
process_children f, child.children, indent_level, strip_em
|
|
120
|
+
# byebug
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def process_children(f, children, indent_level = 0, strip_em = false)
|
|
125
|
+
children.each do |child|
|
|
126
|
+
process_page_content f, child, indent_level, strip_em
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module AocRb
|
|
3
|
+
module PuzzleInput
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
def load(year, day)
|
|
7
|
+
file_path = puzzle_path(year, day)
|
|
8
|
+
download(year, day) unless File.exist? file_path
|
|
9
|
+
File.read(file_path)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def create_required_directories(year, day)
|
|
13
|
+
padded_day = day.to_s.rjust(2, "0")
|
|
14
|
+
year_directory = File.join("challenges", year.to_s, padded_day)
|
|
15
|
+
FileUtils.mkdir_p(year_directory) unless Dir.exist?(year_directory)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def puzzle_path(year, day)
|
|
19
|
+
padded_day = day.to_s.rjust(2, "0")
|
|
20
|
+
File.join("challenges", year.to_s, padded_day, "input.txt")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def download(year, day)
|
|
24
|
+
aoc_api = AocRb::AocApi.new(ENV['AOC_COOKIE'])
|
|
25
|
+
content = aoc_api.puzzle_input(year, day)
|
|
26
|
+
save_puzzle(year, day, content)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def save_puzzle(year, day, content)
|
|
30
|
+
protect_against_early_download(content)
|
|
31
|
+
create_required_directories year, day
|
|
32
|
+
skip_if_exists(puzzle_path(year, day)) do
|
|
33
|
+
File.open(puzzle_path(year, day), "w") { |f| f.write content }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def skip_if_exists(file)
|
|
38
|
+
unless File.exist? file
|
|
39
|
+
yield
|
|
40
|
+
else
|
|
41
|
+
puts "#{file} already exists, skipping"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def protect_against_early_download(content)
|
|
48
|
+
if /the link will be enabled on the calendar the instant this puzzle becomes available/.match?(content)
|
|
49
|
+
puts "ERROR: This resource is not available for download yet"
|
|
50
|
+
exit 0
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AocRb
|
|
4
|
+
module PuzzleSolution
|
|
5
|
+
extend self
|
|
6
|
+
|
|
7
|
+
def submit(level, year, day, answer = nil, allow_waiting = true)
|
|
8
|
+
if answer.nil?
|
|
9
|
+
puzzle = PuzzleSource.create_puzzle(year, day)
|
|
10
|
+
input = PuzzleInput.load(year, day)
|
|
11
|
+
answer = level == 1 ? puzzle.part_1(input) : puzzle.part_2(input)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
aoc_api = AocApi.new(ENV['AOC_COOKIE'])
|
|
15
|
+
response = aoc_api.submit_answer(year, day, level, answer)
|
|
16
|
+
# puts response.body
|
|
17
|
+
|
|
18
|
+
wrong = /not the right answer/.match?(response.body)
|
|
19
|
+
already_complete = /Did you already complete it/.match?(response.body)
|
|
20
|
+
waiting_regex = /You have (\d*m* *\d+s) left to wait/
|
|
21
|
+
waiting = waiting_regex.match?(response.body)
|
|
22
|
+
|
|
23
|
+
doc = Nokogiri::HTML(response.body)
|
|
24
|
+
articles = doc.css("article")
|
|
25
|
+
puts articles[0].content
|
|
26
|
+
|
|
27
|
+
puts "That's not the right answer" if wrong
|
|
28
|
+
puts "You have already completed this challenge" if already_complete
|
|
29
|
+
if waiting && allow_waiting
|
|
30
|
+
delay = 1
|
|
31
|
+
time = waiting_regex.match(response.body)[1]
|
|
32
|
+
time_parts = time.split(" ")
|
|
33
|
+
time_parts.each do |part|
|
|
34
|
+
if part.match?(/m/)
|
|
35
|
+
delay += part.match(/(\d+)m/)[1].to_i * 60
|
|
36
|
+
elsif part.match?(/s/)
|
|
37
|
+
delay += part.match(/(\d+)s/)[1].to_i
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
puts "WAITING for #{delay} seconds ..."
|
|
42
|
+
sleep delay
|
|
43
|
+
return submit(level, year, day, answer, false)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
!wrong && !already_complete && !waiting
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "benchmark"
|
|
3
|
+
|
|
4
|
+
module AocRb
|
|
5
|
+
module PuzzleSource
|
|
6
|
+
extend self
|
|
7
|
+
|
|
8
|
+
def create_puzzle(year, day)
|
|
9
|
+
padded_day = Puzzle.padded(day)
|
|
10
|
+
begin
|
|
11
|
+
Module.const_get("Year#{year}").const_get("Day#{padded_day}").new
|
|
12
|
+
rescue NameError
|
|
13
|
+
puts "There is no solution for this puzzle"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def run_part(part_name)
|
|
18
|
+
solution = nil
|
|
19
|
+
t = Benchmark.realtime do
|
|
20
|
+
solution = yield
|
|
21
|
+
if !solution.nil?
|
|
22
|
+
puts "Result for #{part_name}:"
|
|
23
|
+
puts solution
|
|
24
|
+
else
|
|
25
|
+
puts "no result for #{part_name}"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
puts "(obtained in #{t} seconds)" unless solution.nil?
|
|
29
|
+
|
|
30
|
+
solution
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
AOC_COOKIE=AOC_COOKIE
|
data/templates/Gemfile
ADDED
data/templates/bin/aoc
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'aoc' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
# THIS IS THE BIN FILE
|
|
12
|
+
|
|
13
|
+
require "pathname"
|
|
14
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
|
15
|
+
Pathname.new(__FILE__).realpath)
|
|
16
|
+
|
|
17
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
|
18
|
+
|
|
19
|
+
if File.file?(bundle_binstub)
|
|
20
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
|
21
|
+
load(bundle_binstub)
|
|
22
|
+
else
|
|
23
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
24
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
$LOAD_PATH.unshift File.expand_path("../..", __FILE__)
|
|
29
|
+
|
|
30
|
+
require "rubygems"
|
|
31
|
+
require "bundler/setup"
|
|
32
|
+
|
|
33
|
+
# load Gem.bin_path("aoc_rb", "aoc")
|
|
34
|
+
|
|
35
|
+
require 'aoc_rb/app'
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
RSpec.describe Year<%= @year %>::Day<%= @day %> do
|
|
5
|
+
let(:puzzle) { Year<%= @year %>::Day<%= @day %>.new }
|
|
6
|
+
let(:input) { File.read(File.join(File.dirname(__FILE__), "../../../challenges/<%= @year %>/<%= @day.to_s.rjust(2, "0") %>/input.txt")) }
|
|
7
|
+
let(:example_input) {
|
|
8
|
+
<<~EOF
|
|
9
|
+
change
|
|
10
|
+
me
|
|
11
|
+
EOF
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe "part 1" do
|
|
15
|
+
it "returns nil for the example input" do
|
|
16
|
+
expect(puzzle.part_1(example_input)).to eq(nil)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "returns nil for my input" do
|
|
20
|
+
expect(puzzle.part_1(input)).to eq(nil)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "part 2" do
|
|
25
|
+
it "returns nil for the example input" do
|
|
26
|
+
expect(puzzle.part_2(example_input)).to eq(nil)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "returns nil for my input" do
|
|
30
|
+
expect(puzzle.part_2(input)).to eq(nil)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: aoc_rb
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Jon Pascoe
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2020-12-02 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: dotenv
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 2.7.6
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 2.7.6
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: httparty
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 0.18.1
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 0.18.1
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: thor
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 1.0.1
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 1.0.1
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rspec
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '3.0'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '3.0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: nokogiri
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 1.10.10
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 1.10.10
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: webmock
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: 3.10.0
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: 3.10.0
|
|
97
|
+
description: Tools for creating a new project for your Advent of Code solutions, built
|
|
98
|
+
using Ruby.
|
|
99
|
+
email:
|
|
100
|
+
- jon.pascoe@me.com
|
|
101
|
+
executables:
|
|
102
|
+
- aoc
|
|
103
|
+
extensions: []
|
|
104
|
+
extra_rdoc_files: []
|
|
105
|
+
files:
|
|
106
|
+
- ".gitignore"
|
|
107
|
+
- ".rspec"
|
|
108
|
+
- ".travis.yml"
|
|
109
|
+
- CODE_OF_CONDUCT.md
|
|
110
|
+
- Gemfile
|
|
111
|
+
- Gemfile.lock
|
|
112
|
+
- LICENSE
|
|
113
|
+
- LICENSE.txt
|
|
114
|
+
- README.md
|
|
115
|
+
- Rakefile
|
|
116
|
+
- aoc_rb.gemspec
|
|
117
|
+
- bin/console
|
|
118
|
+
- bin/setup
|
|
119
|
+
- exe/aoc
|
|
120
|
+
- lib/aoc_rb.rb
|
|
121
|
+
- lib/aoc_rb/aoc_api.rb
|
|
122
|
+
- lib/aoc_rb/app.rb
|
|
123
|
+
- lib/aoc_rb/app_loader.rb
|
|
124
|
+
- lib/aoc_rb/cli.rb
|
|
125
|
+
- lib/aoc_rb/puzzle.rb
|
|
126
|
+
- lib/aoc_rb/puzzle_input.rb
|
|
127
|
+
- lib/aoc_rb/puzzle_solution.rb
|
|
128
|
+
- lib/aoc_rb/puzzle_source.rb
|
|
129
|
+
- lib/aoc_rb/version.rb
|
|
130
|
+
- templates/.env-template
|
|
131
|
+
- templates/Gemfile
|
|
132
|
+
- templates/bin/aoc
|
|
133
|
+
- templates/solution.rb.erb
|
|
134
|
+
- templates/solution_spec.rb.erb
|
|
135
|
+
- templates/spec/spec_helper.rb
|
|
136
|
+
homepage: https://github.com/pacso/aoc_rb
|
|
137
|
+
licenses:
|
|
138
|
+
- MIT
|
|
139
|
+
metadata:
|
|
140
|
+
homepage_uri: https://github.com/pacso/aoc_rb
|
|
141
|
+
source_code_uri: https://github.com/pacso/aoc_rb
|
|
142
|
+
changelog_uri: https://github.com/pacso/aoc_rb/blob/main/CHANGELOG
|
|
143
|
+
post_install_message:
|
|
144
|
+
rdoc_options: []
|
|
145
|
+
require_paths:
|
|
146
|
+
- lib
|
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
148
|
+
requirements:
|
|
149
|
+
- - ">="
|
|
150
|
+
- !ruby/object:Gem::Version
|
|
151
|
+
version: 2.3.0
|
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
153
|
+
requirements:
|
|
154
|
+
- - ">="
|
|
155
|
+
- !ruby/object:Gem::Version
|
|
156
|
+
version: '0'
|
|
157
|
+
requirements: []
|
|
158
|
+
rubygems_version: 3.1.2
|
|
159
|
+
signing_key:
|
|
160
|
+
specification_version: 4
|
|
161
|
+
summary: A Ruby toolkit for Advent of Code
|
|
162
|
+
test_files: []
|