aoc_generator 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7c7406ac54325c97120e78a4eb03b1b6cf1ffaa17729bbee090459eb1c41ea69
4
+ data.tar.gz: ddb0ddd4e9b6756fbc085b33497e937d1f5cbb6a0c8322c466cb58dfba9c97fb
5
+ SHA512:
6
+ metadata.gz: f7be5d7348c737ed8c29a4f9ce2607b36c750341694d67022a558a38b252a27d41e0d69ba8aa2536a7004c0c19a1078de66c19e46b95c19ce26f86a0fc5094f5
7
+ data.tar.gz: 53ac78a563c392c9833d2b5dfc38da6e9bfadd3d508aa730c596353ab8f0d1447f9374f4bb0555b96ffd72276edc2c8df09ce5162fd888c8d12a74a181af7fc2
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,20 @@
1
+ require:
2
+ - rubocop-rake
3
+ - rubocop-rspec
4
+
5
+ AllCops:
6
+ DisplayCopNames: true
7
+ NewCops: enable
8
+ TargetRubyVersion: 3.3
9
+
10
+ Metrics/MethodLength:
11
+ CountAsOne: heredoc
12
+
13
+ Style/StringLiterals:
14
+ EnforcedStyle: double_quotes
15
+
16
+ Style/StringLiteralsInInterpolation:
17
+ EnforcedStyle: double_quotes
18
+
19
+ RSpec/ExampleLength:
20
+ Enabled: false
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.3.4
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
6
+
7
+ ruby file: ".tool-versions"
8
+
9
+ gem "debug", "~> 1.9"
10
+ gem "nokogiri", "~> 1.16"
11
+ gem "rake", "~> 13.2"
12
+ gem "rspec", "~> 3.13"
13
+ gem "rubocop", "~> 1.68"
14
+ gem "rubocop-rake", "~> 0.6.0"
15
+ gem "rubocop-rspec", "~> 3.2"
16
+ gem "thor", "~> 1.3"
17
+ gem "webmock", "~> 3.24"
data/Gemfile.lock ADDED
@@ -0,0 +1,107 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ aoc_generator (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ addressable (2.8.7)
10
+ public_suffix (>= 2.0.2, < 7.0)
11
+ ast (2.4.2)
12
+ bigdecimal (3.1.8)
13
+ crack (1.0.0)
14
+ bigdecimal
15
+ rexml
16
+ debug (1.9.2)
17
+ irb (~> 1.10)
18
+ reline (>= 0.3.8)
19
+ diff-lcs (1.5.1)
20
+ hashdiff (1.1.2)
21
+ io-console (0.7.2)
22
+ irb (1.14.1)
23
+ rdoc (>= 4.0.0)
24
+ reline (>= 0.4.2)
25
+ json (2.8.2)
26
+ language_server-protocol (3.17.0.3)
27
+ mini_portile2 (2.8.8)
28
+ nokogiri (1.16.7)
29
+ mini_portile2 (~> 2.8.2)
30
+ racc (~> 1.4)
31
+ nokogiri (1.16.7-arm64-darwin)
32
+ racc (~> 1.4)
33
+ parallel (1.26.3)
34
+ parser (3.3.6.0)
35
+ ast (~> 2.4.1)
36
+ racc
37
+ psych (5.2.0)
38
+ stringio
39
+ public_suffix (6.0.1)
40
+ racc (1.8.1)
41
+ rainbow (3.1.1)
42
+ rake (13.2.1)
43
+ rdoc (6.8.1)
44
+ psych (>= 4.0.0)
45
+ regexp_parser (2.9.2)
46
+ reline (0.5.11)
47
+ io-console (~> 0.5)
48
+ rexml (3.3.9)
49
+ rspec (3.13.0)
50
+ rspec-core (~> 3.13.0)
51
+ rspec-expectations (~> 3.13.0)
52
+ rspec-mocks (~> 3.13.0)
53
+ rspec-core (3.13.2)
54
+ rspec-support (~> 3.13.0)
55
+ rspec-expectations (3.13.3)
56
+ diff-lcs (>= 1.2.0, < 2.0)
57
+ rspec-support (~> 3.13.0)
58
+ rspec-mocks (3.13.2)
59
+ diff-lcs (>= 1.2.0, < 2.0)
60
+ rspec-support (~> 3.13.0)
61
+ rspec-support (3.13.1)
62
+ rubocop (1.68.0)
63
+ json (~> 2.3)
64
+ language_server-protocol (>= 3.17.0)
65
+ parallel (~> 1.10)
66
+ parser (>= 3.3.0.2)
67
+ rainbow (>= 2.2.2, < 4.0)
68
+ regexp_parser (>= 2.4, < 3.0)
69
+ rubocop-ast (>= 1.32.2, < 2.0)
70
+ ruby-progressbar (~> 1.7)
71
+ unicode-display_width (>= 2.4.0, < 3.0)
72
+ rubocop-ast (1.36.1)
73
+ parser (>= 3.3.1.0)
74
+ rubocop-rake (0.6.0)
75
+ rubocop (~> 1.0)
76
+ rubocop-rspec (3.2.0)
77
+ rubocop (~> 1.61)
78
+ ruby-progressbar (1.13.0)
79
+ stringio (3.1.2)
80
+ thor (1.3.2)
81
+ unicode-display_width (2.6.0)
82
+ webmock (3.24.0)
83
+ addressable (>= 2.8.0)
84
+ crack (>= 0.3.2)
85
+ hashdiff (>= 0.4.0, < 2.0.0)
86
+
87
+ PLATFORMS
88
+ arm64-darwin-23
89
+ ruby
90
+
91
+ DEPENDENCIES
92
+ aoc_generator!
93
+ debug (~> 1.9)
94
+ nokogiri (~> 1.16)
95
+ rake (~> 13.2)
96
+ rspec (~> 3.13)
97
+ rubocop (~> 1.68)
98
+ rubocop-rake (~> 0.6.0)
99
+ rubocop-rspec (~> 3.2)
100
+ thor (~> 1.3)
101
+ webmock (~> 3.24)
102
+
103
+ RUBY VERSION
104
+ ruby 3.3.4p94
105
+
106
+ BUNDLED WITH
107
+ 2.5.22
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Advent of Code Generator
2
+
3
+ A Ruby gem that generates daily puzzle templates for Advent of Code.
4
+
5
+ ## Usage
6
+
7
+ ```sh
8
+ # With default arguments
9
+ aoc generate
10
+
11
+ # With custom arguments
12
+ aoc generate -y=2023 -d=1 -u=cheddachedda -s=$SESSION_KEY
13
+ ```
14
+
15
+ ### Options
16
+
17
+ ```sh
18
+ -y, [--year=N] # Defaults to the current year.
19
+ # Default: 2024
20
+ -d, [--day=N] # Defaults to the current day.
21
+ # Default: 28
22
+ -u, [--username=USERNAME] # Files will be generated in a directory with this name. Useful for multi-user repos.
23
+ # Default: advent_of_code
24
+ -s, [--session=SESSION] # Your adventofcode.com session key. Necessary for scraping data files and specs for part two.
25
+ ```
26
+
27
+ ## Generated file structure
28
+
29
+ ```sh
30
+ adventofcode/
31
+
32
+ └── year_2024/
33
+ |
34
+ └── day_01/
35
+ ├── main.rb
36
+ ├── spec.rb
37
+ ├── data.txt
38
+ └── README.md
39
+ ```
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
data/bin/console ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ Dir[File.join(__dir__, "../lib/**/*.rb")].each do |file|
5
+ require file
6
+ end
7
+
8
+ require "irb"
9
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
data/exe/aoc ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require_relative "../lib/advent_of_code_generator/cli"
6
+
7
+ AdventOfCodeGenerator::CLI.start(ARGV)
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+ require_relative "generator"
5
+ require_relative "scraper"
6
+
7
+ module AdventOfCodeGenerator
8
+ # Command Line Interface for generating Advent of Code puzzle templates
9
+ class CLI < Thor
10
+ desc "generate", "Generate files for a new Advent of Code puzzle"
11
+
12
+ method_option :year,
13
+ required: false,
14
+ aliases: "-y",
15
+ type: :numeric,
16
+ desc: "Defaults to the current year.",
17
+ default: Time.now.year
18
+
19
+ method_option :day,
20
+ required: false,
21
+ aliases: "-d",
22
+ type: :numeric,
23
+ desc: "Defaults to the current day.",
24
+ default: Time.now.day
25
+
26
+ method_option :username,
27
+ required: false,
28
+ aliases: "-u",
29
+ desc: "Files will be generated in a directory with this name. Useful for multi-user repos.",
30
+ default: "advent_of_code"
31
+
32
+ method_option :session,
33
+ required: false,
34
+ aliases: "-s",
35
+ desc: "Your adventofcode.com session key. Necessary for scraping data files and specs for part two."
36
+
37
+ def generate
38
+ scraper = AdventOfCodeGenerator::Scraper.new(options)
39
+ generator = AdventOfCodeGenerator::Generator.new(options, scraper)
40
+
41
+ generator.call
42
+ end
43
+
44
+ def self.exit_on_failure?
45
+ true
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AdventOfCodeGenerator
4
+ # Creates directory structure and files for daily Advent of Code puzzles:
5
+ #
6
+ # Generates a file structure like:
7
+ #
8
+ # username/
9
+ # │
10
+ # └── year_2024/
11
+ # |
12
+ # └── day_01/
13
+ # ├── main.rb
14
+ # ├── spec.rb
15
+ # ├── data.txt
16
+ # └── README.md
17
+ #
18
+ class Generator
19
+ FileData = Struct.new(:path, :content)
20
+
21
+ def initialize(options, scraper)
22
+ @year = options[:year].to_s
23
+ @day = options[:day].to_s.rjust(2, "0") # Ensures day is two digits (e.g., "01" instead of "1")
24
+ @username = options[:username].gsub(/[_\-\.\s]/, "")
25
+ @scraper = scraper
26
+ end
27
+
28
+ def call
29
+ FileUtils.mkdir_p(daily_directory)
30
+
31
+ [readme, data_file, main_file, spec_file].each do |file_data|
32
+ next if File.exist?(file_data.path)
33
+
34
+ File.write(file_data.path, file_data.content)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def daily_directory
41
+ @daily_directory ||= "#{@username}/year_#{@year}/day_#{@day}"
42
+ end
43
+
44
+ def readme
45
+ path = "#{daily_directory}/README.md"
46
+ content = @scraper.puzzle_description
47
+
48
+ FileData.new(path, content)
49
+ end
50
+
51
+ def data_file
52
+ path = "#{daily_directory}/data.txt"
53
+ content = @scraper.input_data
54
+
55
+ FileData.new(path, content)
56
+ end
57
+
58
+ def main_file
59
+ path = "#{daily_directory}/main.rb"
60
+ content = <<~RUBY
61
+ # frozen_string_literal: true
62
+
63
+ module #{@username.capitalize}
64
+ module Year#{@year}
65
+ class Day#{@day}
66
+ def initialize(input)
67
+ @input = input
68
+ end
69
+
70
+ def part_one
71
+ raise NotImplementedError
72
+ end
73
+
74
+ def part_two
75
+ raise NotImplementedError
76
+ end
77
+ end
78
+ end
79
+ end
80
+ RUBY
81
+
82
+ FileData.new(path, content)
83
+ end
84
+
85
+ def spec_file
86
+ path = "#{daily_directory}/spec.rb"
87
+ content = <<~RUBY
88
+ # frozen_string_literal: true
89
+
90
+ require_relative "main"
91
+
92
+ RSpec.describe #{@username.capitalize}::Year#{@year}::Day#{@day} do
93
+ subject(:puzzle) { described_class.new(input) }
94
+
95
+ let(:input) { File.read("\#{__dir__}/data.txt") }
96
+
97
+ it "solves Part One" do
98
+ expect(puzzle.part_one).to eq("")
99
+ end
100
+
101
+ xit "solves Part Two" do
102
+ expect(puzzle.part_two).to eq("some other value")
103
+ end
104
+ end
105
+ RUBY
106
+
107
+ FileData.new(path, content)
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+
5
+ module AdventOfCodeGenerator
6
+ # Fetches puzzle descriptions and input data from adventofcode.com.
7
+ class Scraper
8
+ def initialize(options)
9
+ @year = options[:year]
10
+ @day = options[:day]
11
+ @session_key = options[:session]
12
+ end
13
+
14
+ def puzzle_description
15
+ warn "You'll need to provide a session key to scrape Part Two." unless @session_key
16
+
17
+ uri = URI("https://adventofcode.com/#{@year}/day/#{@day}")
18
+ response = Net::HTTP.get_response(uri, headers)
19
+
20
+ response.body
21
+ end
22
+
23
+ def input_data
24
+ return @input_data if @input_data
25
+ return warn "No session key provided; unable to download data file." unless @session_key
26
+
27
+ uri = URI("https://adventofcode.com/#{@year}/day/#{@day}/input")
28
+ response = Net::HTTP.get_response(uri, headers)
29
+ @input_data ||= response.body
30
+ end
31
+
32
+ private
33
+
34
+ def headers
35
+ return {} unless @session_key
36
+
37
+ @headers ||= { cookie: "session=#{@session_key}" }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AdventOfCodeGenerator
4
+ VERSION = "0.1.0"
5
+
6
+ class Error < StandardError; end
7
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aoc_generator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Nguyen
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-11-27 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |
14
+ Automatically creates daily puzzle files and test templates for Advent of Code challenges,
15
+ helping developers focus on solving the puzzles rather than project setup.
16
+ Includes support for multiple years and customizable templates.
17
+ email:
18
+ - daniel.n.q.nguyen@gmail.com
19
+ executables:
20
+ - aoc
21
+ extensions: []
22
+ extra_rdoc_files: []
23
+ files:
24
+ - ".rspec"
25
+ - ".rubocop.yml"
26
+ - ".tool-versions"
27
+ - Gemfile
28
+ - Gemfile.lock
29
+ - README.md
30
+ - Rakefile
31
+ - bin/console
32
+ - bin/setup
33
+ - exe/aoc
34
+ - lib/advent_of_code_generator.rb
35
+ - lib/advent_of_code_generator/cli.rb
36
+ - lib/advent_of_code_generator/generator.rb
37
+ - lib/advent_of_code_generator/scraper.rb
38
+ homepage: https://github.com/cheddachedda/advent_of_code_generator
39
+ licenses: []
40
+ metadata:
41
+ rubygems_mfa_required: 'true'
42
+ allowed_push_host: https://rubygems.org
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '3.3'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubygems_version: 3.5.23
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: A Ruby gem that generates daily puzzle templates for Advent of Code.
62
+ test_files: []