aoc_generator 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/CHANGELOG.md +9 -1
- data/Gemfile.lock +1 -1
- data/lib/advent_of_code_generator/cli.rb +10 -2
- data/lib/advent_of_code_generator/generator.rb +19 -17
- data/lib/advent_of_code_generator/html_parser.rb +27 -6
- data/lib/advent_of_code_generator/scraper.rb +18 -12
- data/lib/advent_of_code_generator.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ae6b1d2734c4a21d5608955e4bc5c36d6a2226644834eebbade401de59ebe87
|
4
|
+
data.tar.gz: fc64a51413098fc34a5b33a5ab7d6df042bef03800a134b9ab06c3c950e289d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6165ed4974b4f84a8500530ca257e757bf61ccb932233e8d34e7237ab36f5e0208bc89b592e09844252e86b4253659197d5322799ff184224ab292c97d93c0a
|
7
|
+
data.tar.gz: 44620d63c9fcf49970148ae4ae4335bc1e9d97a942c33310df4a0dc860c353322ad229981dbbb9f6bcba2e0e7de7a2ac904d32ca283ba9ef45e45ae3c968a7b6
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## [0.1.
|
3
|
+
## [0.1.5] - 2024-11-28
|
4
|
+
|
5
|
+
- Generate main file with class methods, rather than instance methods
|
6
|
+
|
7
|
+
## [0.1.4]
|
8
|
+
|
9
|
+
- Add test data to spec file
|
10
|
+
|
11
|
+
## [0.1.3]
|
4
12
|
|
5
13
|
- Allow to read a AOC_SESSION environment variable
|
6
14
|
- Change file names
|
data/Gemfile.lock
CHANGED
@@ -38,8 +38,7 @@ module AdventOfCodeGenerator
|
|
38
38
|
default: ENV.fetch("AOC_SESSION", nil)
|
39
39
|
|
40
40
|
def generate
|
41
|
-
|
42
|
-
generator = AdventOfCodeGenerator::Generator.new(options, scraper)
|
41
|
+
generator = AdventOfCodeGenerator::Generator.new(options, content)
|
43
42
|
|
44
43
|
generator.call
|
45
44
|
end
|
@@ -47,5 +46,14 @@ module AdventOfCodeGenerator
|
|
47
46
|
def self.exit_on_failure?
|
48
47
|
true
|
49
48
|
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def content
|
53
|
+
scraped_data = AdventOfCodeGenerator::Scraper.new(options).call
|
54
|
+
parsed_data = AdventOfCodeGenerator::HTMLParser.new(scraped_data[:puzzle_description]).call
|
55
|
+
|
56
|
+
scraped_data.merge(parsed_data)
|
57
|
+
end
|
50
58
|
end
|
51
59
|
end
|
@@ -20,11 +20,11 @@ module AdventOfCodeGenerator
|
|
20
20
|
class Generator
|
21
21
|
FileData = Struct.new(:path, :content)
|
22
22
|
|
23
|
-
def initialize(options,
|
23
|
+
def initialize(options, scraped_data)
|
24
24
|
@year = options[:year].to_s
|
25
25
|
@day = options[:day].to_s.rjust(2, "0") # Ensures day is two digits (e.g., "01" instead of "1")
|
26
26
|
@username = options[:username].gsub(/[_\-\.\s]/, "")
|
27
|
-
@
|
27
|
+
@scraped_data = scraped_data
|
28
28
|
end
|
29
29
|
|
30
30
|
def call
|
@@ -45,14 +45,14 @@ module AdventOfCodeGenerator
|
|
45
45
|
|
46
46
|
def readme
|
47
47
|
path = "#{daily_directory}/README.md"
|
48
|
-
content = @
|
48
|
+
content = @scraped_data[:puzzle_description]
|
49
49
|
|
50
50
|
FileData.new(path, content)
|
51
51
|
end
|
52
52
|
|
53
53
|
def data_file
|
54
54
|
path = "#{daily_directory}/data.txt"
|
55
|
-
content = @
|
55
|
+
content = @scraped_data[:input_data]
|
56
56
|
|
57
57
|
FileData.new(path, content)
|
58
58
|
end
|
@@ -65,15 +65,11 @@ module AdventOfCodeGenerator
|
|
65
65
|
module #{@username.capitalize}
|
66
66
|
module Year#{@year}
|
67
67
|
class Day#{@day}
|
68
|
-
def
|
69
|
-
@input = input
|
70
|
-
end
|
71
|
-
|
72
|
-
def part_one
|
68
|
+
def self.part_one(input)
|
73
69
|
raise NotImplementedError
|
74
70
|
end
|
75
71
|
|
76
|
-
def part_two
|
72
|
+
def self.part_two(input)
|
77
73
|
raise NotImplementedError
|
78
74
|
end
|
79
75
|
end
|
@@ -86,22 +82,28 @@ module AdventOfCodeGenerator
|
|
86
82
|
|
87
83
|
def spec_file
|
88
84
|
path = "#{daily_directory}/day_#{@day}_spec.rb"
|
85
|
+
input, expectations = @scraped_data.values_at(:test_input, :test_expectations)
|
86
|
+
input ||= ["", ""]
|
89
87
|
content = <<~RUBY
|
90
88
|
# frozen_string_literal: true
|
91
89
|
|
92
90
|
require_relative "day_#{@day}"
|
93
91
|
|
94
92
|
RSpec.describe #{@username.capitalize}::Year#{@year}::Day#{@day} do
|
95
|
-
subject(:puzzle) { described_class.new(input) }
|
96
|
-
|
97
|
-
let(:input) { File.read("\#{__dir__}/data.txt") }
|
98
|
-
|
99
93
|
it "solves Part One" do
|
100
|
-
|
94
|
+
input = <<~INPUT
|
95
|
+
#{input[0]&.gsub("\n", "\n ")}
|
96
|
+
INPUT
|
97
|
+
|
98
|
+
expect(described_class.part_one(input)).to eq(#{expectations[0]})
|
101
99
|
end
|
102
100
|
|
103
|
-
|
104
|
-
|
101
|
+
it "solves Part Two", skip: "not implemented yet" do
|
102
|
+
input = <<~INPUT
|
103
|
+
#{input[1]&.gsub("\n", "\n ")}
|
104
|
+
INPUT
|
105
|
+
|
106
|
+
expect(described_class.part_two(input)).to eq(#{expectations[1]})
|
105
107
|
end
|
106
108
|
end
|
107
109
|
RUBY
|
@@ -5,20 +5,41 @@ require "nokogiri"
|
|
5
5
|
module AdventOfCodeGenerator
|
6
6
|
# Converts HTML puzzle descriptions from adventofcode.com into markdown format.
|
7
7
|
class HTMLParser
|
8
|
-
def initialize(
|
9
|
-
@
|
8
|
+
def initialize(html_content)
|
9
|
+
@html_content = html_content
|
10
10
|
end
|
11
11
|
|
12
12
|
def call
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
{
|
14
|
+
puzzle_description: part_descriptions.join("\n"),
|
15
|
+
test_input:,
|
16
|
+
test_expectations:
|
17
|
+
}
|
16
18
|
end
|
17
19
|
|
18
20
|
private
|
19
21
|
|
22
|
+
def part_descriptions
|
23
|
+
@part_descriptions ||= articles.map do |node|
|
24
|
+
process_article(node).join("\n")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_input
|
29
|
+
part_descriptions.map { |desc| desc.scan(/```sh\n(.*?)\n```/m) }.flatten
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_expectations
|
33
|
+
part_descriptions
|
34
|
+
.flat_map { |desc| desc.scan(/\*\*`(.*?)`\*\*/) }
|
35
|
+
.map do |matches|
|
36
|
+
match = matches.first
|
37
|
+
match&.match?(/\A\d+\z/) ? match.to_i : match
|
38
|
+
end.compact
|
39
|
+
end
|
40
|
+
|
20
41
|
def articles
|
21
|
-
doc = Nokogiri::HTML(@
|
42
|
+
doc = Nokogiri::HTML(@html_content)
|
22
43
|
doc.css("article")
|
23
44
|
end
|
24
45
|
|
@@ -6,11 +6,25 @@ require_relative "html_parser"
|
|
6
6
|
module AdventOfCodeGenerator
|
7
7
|
# Fetches puzzle descriptions and input data from adventofcode.com.
|
8
8
|
class Scraper
|
9
|
-
def initialize(options
|
9
|
+
def initialize(options)
|
10
10
|
@year = options[:year]
|
11
11
|
@day = options[:day]
|
12
12
|
@session_key = options[:session]
|
13
|
-
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
{
|
17
|
+
puzzle_description:,
|
18
|
+
input_data:
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def headers
|
25
|
+
return {} unless @session_key
|
26
|
+
|
27
|
+
@headers ||= { cookie: "session=#{@session_key}" }
|
14
28
|
end
|
15
29
|
|
16
30
|
def puzzle_description
|
@@ -19,24 +33,16 @@ module AdventOfCodeGenerator
|
|
19
33
|
uri = URI("https://adventofcode.com/#{@year}/day/#{@day}")
|
20
34
|
response = Net::HTTP.get_response(uri, headers)
|
21
35
|
|
22
|
-
|
36
|
+
response.body
|
23
37
|
end
|
24
38
|
|
25
39
|
def input_data
|
26
|
-
return @input_data if @input_data
|
27
40
|
return warn "No session key provided; unable to download data file." unless @session_key
|
28
41
|
|
29
42
|
uri = URI("https://adventofcode.com/#{@year}/day/#{@day}/input")
|
30
43
|
response = Net::HTTP.get_response(uri, headers)
|
31
|
-
@input_data ||= response.body
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
44
|
|
36
|
-
|
37
|
-
return {} unless @session_key
|
38
|
-
|
39
|
-
@headers ||= { cookie: "session=#{@session_key}" }
|
45
|
+
response.body
|
40
46
|
end
|
41
47
|
end
|
42
48
|
end
|