aoc_generator 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 938e976e4342e3115907290c0c0c90385ca25c67f80bde2befc904baeb510a56
4
- data.tar.gz: 2900af440cc153869f1f5575c8a162a53b60ff36b702b8628dcc22e8cdb3c814
3
+ metadata.gz: 4c2e50281fb4c3f191cbe11ca0417cb2ca969178f87a124572a5b34e07e01b17
4
+ data.tar.gz: b00f142cd08f4ca55e651974c7d923f2c62515a49a4f07c4d3443f5584f24e4d
5
5
  SHA512:
6
- metadata.gz: 11471565e51be4d99ad7e11cd4e1aa2bb43546301aa485c1fbd64d4b5ce9fc78c02b85128e0f6c608caddae2dbeb63ca59d676b5712e1c91d3de72b933d52360
7
- data.tar.gz: 66b8d3dc1df84f44f5600aa3ec497f75b4245c955e54f287431e200d1e34eec3cf2efe3a7ec16f7363be522ae140f18b2060b276882b043d39f9f7dd3e44f6e2
6
+ metadata.gz: ce6d572095bf2acc47c429e5ece1fee0c335ed0403c94c47f33063a996193d0848deacf49a981fa18546b418d05c2425a553317f1677c5fb714d3de9163caf18
7
+ data.tar.gz: 93ccfd82a61cb9ea1eb8b096cfa1c0a922a002abb923c93f06c25796a5af6d4356be28e06a88d9b62d4e489f04328e15d37569c24a7480cec366c57560bdd0ab
data/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # Changelog
2
2
 
3
- ## [0.1.2] - 2024-11-28
3
+ ## [0.1.4] - 2024-11-28
4
+
5
+ - Add test data to spec file
6
+
7
+ ## [0.1.3]
8
+
9
+ - Allow to read a AOC_SESSION environment variable
10
+ - Change file names
11
+ - Convert HTML to Markdown
12
+
13
+ ## [0.1.2]
4
14
 
5
15
  - [Fix] Add the correct FileUtils gem
6
16
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- aoc_generator (0.1.2)
4
+ aoc_generator (0.1.4)
5
5
  fileutils (~> 1.7)
6
6
  nokogiri (~> 1.16)
7
7
  thor (~> 1.3)
data/README.md CHANGED
@@ -16,12 +16,11 @@ A Ruby gem that generates daily puzzle templates for Advent of Code.
16
16
 
17
17
  ```sh
18
18
  -y, [--year=N] # Defaults to the current year.
19
- # Default: 2024
20
19
  -d, [--day=N] # Defaults to the current day.
21
- # Default: 28
22
20
  -u, [--username=USERNAME] # Files will be generated in a directory with this name. Useful for multi-user repos.
23
21
  # Default: advent_of_code
24
22
  -s, [--session=SESSION] # Your adventofcode.com session key. Necessary for scraping data files and specs for part two.
23
+ # Default: reads AOC_SESSION environment variable if it exists.
25
24
  ```
26
25
 
27
26
  ## Generated file structure
@@ -32,8 +31,8 @@ adventofcode/
32
31
  └── year_2024/
33
32
  |
34
33
  └── day_01/
35
- ├── main.rb
36
- ├── spec.rb
34
+ ├── day_01.rb
35
+ ├── day_01_spec.rb
37
36
  ├── data.txt
38
37
  └── README.md
39
38
  ```
@@ -32,11 +32,13 @@ module AdventOfCodeGenerator
32
32
  method_option :session,
33
33
  required: false,
34
34
  aliases: "-s",
35
- desc: "Your adventofcode.com session key. Necessary for scraping data files and specs for part two."
35
+ desc: "Your adventofcode.com session key. " \
36
+ "Necessary for scraping data files and specs for part two. " \
37
+ "Defaults to a AOC_SESSION environment variable if it exists.",
38
+ default: ENV.fetch("AOC_SESSION", nil)
36
39
 
37
40
  def generate
38
- scraper = AdventOfCodeGenerator::Scraper.new(options)
39
- generator = AdventOfCodeGenerator::Generator.new(options, scraper)
41
+ generator = AdventOfCodeGenerator::Generator.new(options, content)
40
42
 
41
43
  generator.call
42
44
  end
@@ -44,5 +46,14 @@ module AdventOfCodeGenerator
44
46
  def self.exit_on_failure?
45
47
  true
46
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
47
58
  end
48
59
  end
@@ -12,19 +12,19 @@ module AdventOfCodeGenerator
12
12
  # └── year_2024/
13
13
  # |
14
14
  # └── day_01/
15
- # ├── main.rb
16
- # ├── spec.rb
15
+ # ├── day_01.rb
16
+ # ├── day_01_spec.rb
17
17
  # ├── data.txt
18
18
  # └── README.md
19
19
  #
20
20
  class Generator
21
21
  FileData = Struct.new(:path, :content)
22
22
 
23
- def initialize(options, scraper)
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
- @scraper = scraper
27
+ @scraped_data = scraped_data
28
28
  end
29
29
 
30
30
  def call
@@ -45,20 +45,20 @@ module AdventOfCodeGenerator
45
45
 
46
46
  def readme
47
47
  path = "#{daily_directory}/README.md"
48
- content = @scraper.puzzle_description
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 = @scraper.input_data
55
+ content = @scraped_data[:input_data]
56
56
 
57
57
  FileData.new(path, content)
58
58
  end
59
59
 
60
60
  def main_file
61
- path = "#{daily_directory}/main.rb"
61
+ path = "#{daily_directory}/day_#{@day}.rb"
62
62
  content = <<~RUBY
63
63
  # frozen_string_literal: true
64
64
 
@@ -85,23 +85,29 @@ module AdventOfCodeGenerator
85
85
  end
86
86
 
87
87
  def spec_file
88
- path = "#{daily_directory}/spec.rb"
88
+ path = "#{daily_directory}/day_#{@day}_spec.rb"
89
+ input, expectations = @scraped_data.values_at(:test_input, :test_expectations)
90
+ input ||= ["", ""]
89
91
  content = <<~RUBY
90
92
  # frozen_string_literal: true
91
93
 
92
- require_relative "main"
94
+ require_relative "day_#{@day}"
93
95
 
94
96
  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
97
  it "solves Part One" do
100
- expect(puzzle.part_one).to eq("")
98
+ input = <<~INPUT
99
+ #{input[0]&.gsub("\n", "\n ")}
100
+ INPUT
101
+
102
+ expect(described_class.part_one(input)).to eq(#{expectations[0]})
101
103
  end
102
104
 
103
- xit "solves Part Two" do
104
- expect(puzzle.part_two).to eq("some other value")
105
+ it "solves Part Two", skip: "not implemented yet" do
106
+ input = <<~INPUT
107
+ #{input[1]&.gsub("\n", "\n ")}
108
+ INPUT
109
+
110
+ expect(described_class.part_two(input)).to eq(#{expectations[1]})
105
111
  end
106
112
  end
107
113
  RUBY
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "nokogiri"
4
+
5
+ module AdventOfCodeGenerator
6
+ # Converts HTML puzzle descriptions from adventofcode.com into markdown format.
7
+ class HTMLParser
8
+ def initialize(html_content)
9
+ @html_content = html_content
10
+ end
11
+
12
+ def call
13
+ {
14
+ puzzle_description: part_descriptions.join("\n"),
15
+ test_input:,
16
+ test_expectations:
17
+ }
18
+ end
19
+
20
+ private
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
+
41
+ def articles
42
+ doc = Nokogiri::HTML(@html_content)
43
+ doc.css("article")
44
+ end
45
+
46
+ def process_article(article)
47
+ article.children.map { |node| process_node(node) }.compact
48
+ end
49
+
50
+ def process_node(node)
51
+ case node.name
52
+ when "h2"
53
+ "## #{node.text}\n"
54
+ when "p"
55
+ "#{process_paragraph(node)}\n"
56
+ when "pre"
57
+ "```sh\n#{node.text.strip}\n```\n"
58
+ end
59
+ end
60
+
61
+ def process_paragraph(para)
62
+ para.inner_html
63
+ .gsub(%r{<a[^>]*href="([^"]*)"[^>]*>(.*?)</a>}, '[\2](\1)')
64
+ .gsub(%r{<code><em>(.*?)</em></code>}, '**`\1`**')
65
+ .gsub(%r{<em><code>(.*?)</code></em>}, '**`\1`**')
66
+ .gsub(%r{<em.*?>(.*?)</em>}, '**\1**')
67
+ .gsub(%r{<code>(.*?)</code>}, '`\1`')
68
+ .gsub(/<[^>]*>/, "")
69
+ end
70
+ end
71
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "net/http"
4
+ require_relative "html_parser"
4
5
 
5
6
  module AdventOfCodeGenerator
6
7
  # Fetches puzzle descriptions and input data from adventofcode.com.
@@ -11,6 +12,21 @@ module AdventOfCodeGenerator
11
12
  @session_key = options[:session]
12
13
  end
13
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}" }
28
+ end
29
+
14
30
  def puzzle_description
15
31
  warn "You'll need to provide a session key to scrape Part Two." unless @session_key
16
32
 
@@ -21,20 +37,12 @@ module AdventOfCodeGenerator
21
37
  end
22
38
 
23
39
  def input_data
24
- return @input_data if @input_data
25
40
  return warn "No session key provided; unable to download data file." unless @session_key
26
41
 
27
42
  uri = URI("https://adventofcode.com/#{@year}/day/#{@day}/input")
28
43
  response = Net::HTTP.get_response(uri, headers)
29
- @input_data ||= response.body
30
- end
31
44
 
32
- private
33
-
34
- def headers
35
- return {} unless @session_key
36
-
37
- @headers ||= { cookie: "session=#{@session_key}" }
45
+ response.body
38
46
  end
39
47
  end
40
48
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AdventOfCodeGenerator
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.4"
5
5
 
6
6
  class Error < StandardError; end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aoc_generator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-27 00:00:00.000000000 Z
11
+ date: 2024-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fileutils
@@ -74,6 +74,7 @@ files:
74
74
  - lib/advent_of_code_generator.rb
75
75
  - lib/advent_of_code_generator/cli.rb
76
76
  - lib/advent_of_code_generator/generator.rb
77
+ - lib/advent_of_code_generator/html_parser.rb
77
78
  - lib/advent_of_code_generator/scraper.rb
78
79
  homepage: https://github.com/cheddachedda/advent_of_code_generator
79
80
  licenses: []