From 66d1df83b9646f1a855aea72420ec63ddb4c9583 Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Mon, 28 Nov 2022 08:50:02 +0000 Subject: [PATCH 01/15] Add config class --- lib/advent.rb | 1 + lib/advent/configuration.rb | 24 ++++++++++++++++++++++++ test/advent/configuration_test.rb | 23 +++++++++++++++++++++++ test/dummy/advent.yml | 2 ++ 4 files changed, 50 insertions(+) create mode 100644 lib/advent/configuration.rb create mode 100644 test/advent/configuration_test.rb create mode 100644 test/dummy/advent.yml diff --git a/lib/advent.rb b/lib/advent.rb index 3e8ab1f..e996fe9 100644 --- a/lib/advent.rb +++ b/lib/advent.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require_relative "advent/configuration" require_relative "advent/input" require_relative "advent/session" require_relative "advent/solution" diff --git a/lib/advent/configuration.rb b/lib/advent/configuration.rb new file mode 100644 index 0000000..bed6e99 --- /dev/null +++ b/lib/advent/configuration.rb @@ -0,0 +1,24 @@ +require "psych" + +module Advent + class Configuration + DEFAULTS = { + "download_when_generating" => true, + "remember_session" => true + } + FILE_NAME = "advent.yml" + + attr_reader :download_when_generating, :remember_session + + class << self + def from_file(file = FILE_NAME) + new Psych.safe_load_file(file) + end + end + + def initialize(config = DEFAULTS) + @download_when_generating = config.dig("download_when_generating") + @remember_session = config.dig("remember_session") + end + end +end diff --git a/test/advent/configuration_test.rb b/test/advent/configuration_test.rb new file mode 100644 index 0000000..044c4ff --- /dev/null +++ b/test/advent/configuration_test.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require "test_helper" + +class Advent::ConfigurationTest < Advent::TestCase + def setup + @config_file = DUMMY_ROOT_PATH.join("advent.yml") + end + + def test_initializing_with_defaults + config = Advent::Configuration.new + + assert config.download_when_generating + assert config.remember_session + end + + def test_initializing_from_file + config = Advent::Configuration.from_file(@config_file) + + refute config.download_when_generating + refute config.remember_session + end +end diff --git a/test/dummy/advent.yml b/test/dummy/advent.yml new file mode 100644 index 0000000..01bd645 --- /dev/null +++ b/test/dummy/advent.yml @@ -0,0 +1,2 @@ +download_when_generating: false +remember_session: false From 0954bf4b34ee1f43debab4259b9c6d2e190adb22 Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 08:33:34 +0000 Subject: [PATCH 02/15] Add root based on finding a config file --- lib/advent.rb | 17 +++++++++++++++++ test/advent_test.rb | 22 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/lib/advent.rb b/lib/advent.rb index e996fe9..b938c8c 100644 --- a/lib/advent.rb +++ b/lib/advent.rb @@ -11,8 +11,25 @@ module Advent class Error < StandardError; end class << self + def root + if (location = find_config_location) + location + else + raise Error, "Cannot find advent.yml config file in current or parent directories." + end + end + def session @_session = Session.new end + + private + + def find_config_location + Pathname.new(Dir.pwd).ascend do |path| + return path if File.exist? path.join(Configuration::FILE_NAME) + return nil if path.to_s == "/" + end + end end end diff --git a/test/advent_test.rb b/test/advent_test.rb index 46b6ea8..ff576c3 100644 --- a/test/advent_test.rb +++ b/test/advent_test.rb @@ -3,6 +3,28 @@ require "test_helper" class TestAdvent < Advent::TestCase + def teardown + Dir.chdir DUMMY_ROOT_PATH + end + + def test_finding_root_from_config_location + Dir.chdir DUMMY_ROOT_PATH do + assert_equal DUMMY_ROOT_PATH, Advent.root + end + + Dir.chdir DUMMY_ROOT_PATH.join("2015") do + assert_equal DUMMY_ROOT_PATH, Advent.root + end + + Dir.chdir DUMMY_ROOT_PATH.join("..") do + error = assert_raises Advent::Error do + Advent.root + end + + assert_equal "Cannot find advent.yml config file in current or parent directories.", error.message + end + end + def test_that_it_has_a_version_number refute_nil ::Advent::VERSION end From 6175e46625571b1c6920116d00c518b46c0103b0 Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 09:09:42 +0000 Subject: [PATCH 03/15] Path for solving is now consistent based on Advent.root --- lib/advent/cli.rb | 17 ++++++----------- lib/advent/cli/solver.rb | 12 ++++-------- test/advent/cli_test.rb | 14 ++++++++++---- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/lib/advent/cli.rb b/lib/advent/cli.rb index 8b6a1b5..05f9f0c 100644 --- a/lib/advent/cli.rb +++ b/lib/advent/cli.rb @@ -9,13 +9,12 @@ module Advent class CLI < Thor include Thor::Actions - class_option :root_path, default: Dir.pwd, hide: true, check_default_type: false class_option :http_module, default: Net::HTTP, check_default_type: false def initialize(*args) super - self.destination_root = root_path + self.destination_root = Advent.root source_paths << File.expand_path("templates", __dir__) end @@ -91,7 +90,11 @@ def generate(year_or_day, day = nil) # Runs a solution file, outputting both :part1 and :part2 method return values. def solve(path) require "advent/cli/solver" - Solver.new(self, root_path.join(path)).solve + file_path = Pathname.getwd.join(path) + + Dir.chdir Advent.root do + Solver.new(self, file_path.relative_path_from(Advent.root)).solve + end end desc "version", "Prints the current version of the gem" @@ -110,14 +113,6 @@ def determine_year_and_day(year_or_day, day) end end - def root_path - @_root_path ||= if options.root_path.is_a?(Pathname) - options.root_path - else - Pathname.new(options.root_path) - end - end - def parse_number(str) if (m = str.match(/[0-9]+/)) m[0] diff --git a/lib/advent/cli/solver.rb b/lib/advent/cli/solver.rb index f347351..9cafd98 100644 --- a/lib/advent/cli/solver.rb +++ b/lib/advent/cli/solver.rb @@ -37,15 +37,11 @@ def solve private - def day - @_day ||= @path.basename.to_s.match(/day([0-9]+)\.rb/)[1] - end - - def solution_file_name - "day#{day}.rb" - end - def solution_class_name "Day#{day}" end + + def day + @_day ||= @path.basename.to_s.match(/day([0-9]+)\.rb/)[1] + end end diff --git a/test/advent/cli_test.rb b/test/advent/cli_test.rb index 66128b2..69f0acf 100644 --- a/test/advent/cli_test.rb +++ b/test/advent/cli_test.rb @@ -26,8 +26,12 @@ def setup "day 5 input" ) - @cli = Advent::CLI.new([], root_path: DUMMY_ROOT_PATH, http_module: http_mock) - @year_cli = Advent::CLI.new([], root_path: DUMMY_ROOT_PATH.join("2015")) + Dir.chdir DUMMY_ROOT_PATH + @cli = Advent::CLI.new([], http_module: http_mock) + end + + def teardown + Dir.chdir DUMMY_ROOT_PATH end def test_version @@ -38,7 +42,7 @@ def test_version assert_equal Advent::VERSION, out.strip end - def test_solve_from_parent_directory + def test_solve_from_root_directory out, _err = capture_io do @cli.invoke(:solve, ["2015/day1.rb"]) end @@ -48,7 +52,9 @@ def test_solve_from_parent_directory def test_solve_from_year_directory out, _err = capture_io do - @year_cli.invoke(:solve, ["day2.rb"]) + Dir.chdir DUMMY_ROOT_PATH.join("2015") do + @cli.invoke(:solve, ["day2.rb"]) + end end assert_equal "Part 1: 789\nPart 2: Missing", out.strip From 001368c0fbad879bcee387927a31e5db1bf82875 Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 14:04:14 +0000 Subject: [PATCH 04/15] Move input downloading to dedicated class --- lib/advent/cli.rb | 31 ++++--------------------------- lib/advent/cli/downloader.rb | 32 ++++++++++++++++++++++++++++++++ test/advent/cli_test.rb | 29 ++++++++++++++--------------- test/test_helper.rb | 7 +++++++ 4 files changed, 57 insertions(+), 42 deletions(-) create mode 100644 lib/advent/cli/downloader.rb diff --git a/lib/advent/cli.rb b/lib/advent/cli.rb index 05f9f0c..be079f7 100644 --- a/lib/advent/cli.rb +++ b/lib/advent/cli.rb @@ -33,34 +33,11 @@ def in_year_directory? end desc "download YEAR DAY", "Download the input for YEAR and DAY" - def download(year_or_day, day = nil) - year, day = determine_year_and_day(year_or_day, day) - - if (error_message = validate(year, day)) - say_error error_message, :red - return - end - - subpath = if in_year_directory? - "" - else - "#{year}/" - end + def download(year, day) + require "advent/cli/downloader" - unless Advent.session.exist? - session = ask "What is your Advent of Code session cookie value?", echo: false - Advent.session.value = session - - 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" - end - - input = Advent::Input.new(root_path.join(subpath), day: day.to_i) - - if input.download(Advent.session.value, options.http_module) - say "Input downloaded to #{input.file_path}.", :green - say "\nUsing #load_input in your daily solution will load the input file for you." - else - say_error "Something went wrong, maybe an old session cookie?", :red + Dir.chdir Advent.root do + Downloader.new(self, year, day).download end end diff --git a/lib/advent/cli/downloader.rb b/lib/advent/cli/downloader.rb new file mode 100644 index 0000000..2930dea --- /dev/null +++ b/lib/advent/cli/downloader.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +class Advent::CLI::Downloader + def initialize(command, year, day) + @command = command + @year = year + @day = day + end + + def download + ask_for_session_cookie_if_needed + input = Advent::Input.new(Advent.root.join(@year), day: @day.to_i) + + if input.download(Advent.session.value, @command.options.http_module) + @command.say "Input downloaded to #{input.file_path}.", :green + @command.say "\nUsing #load_input in your daily solution will load the input file for you." + else + @command.say_error "Something went wrong, maybe an old session cookie?", :red + end + end + + private + + def ask_for_session_cookie_if_needed + return if Advent.session.exist? + + session = @command.ask "What is your Advent of Code session cookie value?", echo: false + Advent.session.value = session + + @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" + end +end diff --git a/test/advent/cli_test.rb b/test/advent/cli_test.rb index 69f0acf..e0d36c1 100644 --- a/test/advent/cli_test.rb +++ b/test/advent/cli_test.rb @@ -32,6 +32,7 @@ def setup def teardown Dir.chdir DUMMY_ROOT_PATH + Advent.session.clear end def test_version @@ -131,9 +132,9 @@ def test_generate_solution_valid_maximum_day assert_equal "Day must be between 1 and 25 (inclusive).", err.strip end - def test_download_input + def test_download_from_root_directory out, _err = capture_io do - with_stdin_input(@session) do + with_session(@session) do @cli.invoke(:download, ["2015", "3"]) end end @@ -143,10 +144,10 @@ def test_download_input assert_equal "day 3 input", File.read(input_path) assert_match(/Input downloaded to #{input_path}/, out.strip) ensure - File.delete input_path + File.delete input_path if File.exist? input_path end - def test_download_persists_session_cookie + def test_persisting_session_cookie with_stdin_input(@session) do capture_io do @cli.invoke(:download, ["2015", "4"]) @@ -155,11 +156,11 @@ def test_download_persists_session_cookie assert_equal @session, Advent.session.value ensure - File.delete DUMMY_ROOT_PATH.join("2015", ".day4.input.txt") - Advent.session.clear + input = DUMMY_ROOT_PATH.join("2015", ".day4.input.txt") + File.delete input if File.exist? input end - def test_download_skips_asking_for_session_cookie + def test_not_asking_for_session_cookie Advent.session.value = @session out, _err = capture_io do @@ -170,22 +171,20 @@ def test_download_skips_asking_for_session_cookie refute_match(/session cookie value/, out) ensure - File.delete DUMMY_ROOT_PATH.join("2015", ".day5.input.txt") - Advent.session.clear + input = DUMMY_ROOT_PATH.join("2015", ".day5.input.txt") + File.delete input if File.exist? input end - def test_download_input_failure + def test_download_error _out, err = capture_io do - with_stdin_input("invalid") do + with_session("invalid") do @cli.invoke(:download, ["2015", "6"]) end end - input_path = DUMMY_ROOT_PATH.join("2015", ".day6.input.txt") - refute File.exist?(input_path) assert_match(/Something went wrong/, err.strip) ensure - File.delete input_path if File.exist? input_path - Advent.session.clear + input = DUMMY_ROOT_PATH.join("2015", ".day6.input.txt") + File.delete input_path if File.exist? input end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 901ce7f..4fde7a2 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -8,6 +8,13 @@ DUMMY_ROOT_PATH = Pathname.new File.expand_path("dummy", __dir__) class Advent::TestCase < Minitest::Test + def with_session(value) + Advent.session.value = value + yield + ensure + Advent.session.clear + end + def with_stdin_input(input) require "stringio" From 3a93e15a86aec1ee048273f0aaa56940eae91397 Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 14:15:44 +0000 Subject: [PATCH 05/15] Final cleanup of generate command --- lib/advent/cli.rb | 36 +++++++----------------------------- test/advent/cli_test.rb | 29 ++++++++--------------------- 2 files changed, 15 insertions(+), 50 deletions(-) diff --git a/lib/advent/cli.rb b/lib/advent/cli.rb index be079f7..7e18cd8 100644 --- a/lib/advent/cli.rb +++ b/lib/advent/cli.rb @@ -23,15 +23,6 @@ def self.exit_on_failure? true end - no_commands do - # @return [Boolean] whether the current root_path option is in a - # directory that looks like a year (eg. 2015) - def in_year_directory? - dir = root_path.basename.to_s - dir =~ /^20[0-9]{2}/ - end - end - desc "download YEAR DAY", "Download the input for YEAR and DAY" def download(year, day) require "advent/cli/downloader" @@ -45,22 +36,17 @@ def download(year, day) # Generates a new solution file. If within a year directory, only the day # is used, otherwise both the year and day will be required to generate the # output. - def generate(year_or_day, day = nil) - year, day = determine_year_and_day(year_or_day, day) + def generate(year, day) + year = parse_number year + day = parse_number day - if (error_message = validate(year, day)) - say_error error_message, :red + if (message = validate(year, day)) + say_error message, :red return end - subpath = if in_year_directory? - "" - else - "#{year}/" - end - - template "solution.rb.tt", "#{subpath}day#{day}.rb", context: binding - template "solution_test.rb.tt", "#{subpath}test/day#{day}_test.rb", context: binding + template "solution.rb.tt", "#{year}/day#{day}.rb", context: binding + template "solution_test.rb.tt", "#{year}/test/day#{day}_test.rb", context: binding end desc "solve FILE", "Solve your solution" @@ -82,14 +68,6 @@ def version private - def determine_year_and_day(year_or_day, day) - if in_year_directory? - [root_path.basename.to_s, parse_number(year_or_day)] - else - [year_or_day, parse_number(day)] - end - end - def parse_number(str) if (m = str.match(/[0-9]+/)) m[0] diff --git a/test/advent/cli_test.rb b/test/advent/cli_test.rb index e0d36c1..e83b656 100644 --- a/test/advent/cli_test.rb +++ b/test/advent/cli_test.rb @@ -61,7 +61,7 @@ def test_solve_from_year_directory assert_equal "Part 1: 789\nPart 2: Missing", out.strip end - def test_generate_solution_with_year_and_day + def test_generate capture_io do @cli.invoke(:generate, ["2015", "3"]) end @@ -74,9 +74,9 @@ def test_generate_solution_with_year_and_day end end - def test_generate_solution_from_year_directory_with_day + def test_generate_day_parsing capture_io do - @year_cli.invoke(:generate, ["3"]) + @cli.invoke(:generate, ["2015", "day3"]) end ["day3.rb", "test/day3_test.rb"].each do |file_name| @@ -87,20 +87,7 @@ def test_generate_solution_from_year_directory_with_day end end - def test_generate_solution_with_non_numbers_in_day - capture_io do - @year_cli.invoke(:generate, ["day3"]) - end - - ["day3.rb", "test/day3_test.rb"].each do |file_name| - expected_file_path = DUMMY_ROOT_PATH.join("2015", file_name) - assert File.exist? expected_file_path - - File.delete expected_file_path - end - end - - def test_generate_solution_valid_minimum_year + def test_generate_valid_minimum_year _out, err = capture_io do @cli.invoke(:generate, ["2013", "1"]) end @@ -108,15 +95,15 @@ def test_generate_solution_valid_minimum_year assert_equal "Advent of Code only started in 2014!", err.strip end - def test_generate_solution_valid_maximum_year + def test_generate_valid_maximum_year _out, err = capture_io do - @cli.invoke(:generate, [Date.today.year + 1, "1"]) + @cli.invoke(:generate, [(Date.today.year + 1).to_s, "1"]) end assert_equal "Future years are not supported.", err.strip end - def test_generate_solution_valid_minimum_day + def test_generate_valid_minimum_day _out, err = capture_io do @cli.invoke(:generate, ["2015", "0"]) end @@ -124,7 +111,7 @@ def test_generate_solution_valid_minimum_day assert_equal "Day must be between 1 and 25 (inclusive).", err.strip end - def test_generate_solution_valid_maximum_day + def test_generate_valid_maximum_day _out, err = capture_io do @cli.invoke(:generate, ["2015", "26"]) end From 232470bb21051cd591641fb3ade7be3b27ac5ee0 Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 15:08:18 +0000 Subject: [PATCH 06/15] Add a module level config --- lib/advent.rb | 6 +++++- test/advent/configuration_test.rb | 2 +- test/advent_test.rb | 6 ++++++ test/dummy/advent.yml | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/advent.rb b/lib/advent.rb index b938c8c..c74411a 100644 --- a/lib/advent.rb +++ b/lib/advent.rb @@ -11,6 +11,10 @@ module Advent class Error < StandardError; end class << self + def config + @_config ||= Configuration.from_file(root.join(Configuration::FILE_NAME)) + end + def root if (location = find_config_location) location @@ -20,7 +24,7 @@ def root end def session - @_session = Session.new + @_session ||= Session.new end private diff --git a/test/advent/configuration_test.rb b/test/advent/configuration_test.rb index 044c4ff..84709c1 100644 --- a/test/advent/configuration_test.rb +++ b/test/advent/configuration_test.rb @@ -18,6 +18,6 @@ def test_initializing_from_file config = Advent::Configuration.from_file(@config_file) refute config.download_when_generating - refute config.remember_session + assert config.remember_session end end diff --git a/test/advent_test.rb b/test/advent_test.rb index ff576c3..6de001c 100644 --- a/test/advent_test.rb +++ b/test/advent_test.rb @@ -25,6 +25,12 @@ def test_finding_root_from_config_location end end + def test_config_initialization + Dir.chdir DUMMY_ROOT_PATH do + assert_kind_of Advent::Configuration, Advent.config + end + end + def test_that_it_has_a_version_number refute_nil ::Advent::VERSION end diff --git a/test/dummy/advent.yml b/test/dummy/advent.yml index 01bd645..e89a55d 100644 --- a/test/dummy/advent.yml +++ b/test/dummy/advent.yml @@ -1,2 +1,2 @@ download_when_generating: false -remember_session: false +remember_session: true From f0580034dc8b9f7ba3b3946ec6293eff70519099 Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 15:10:10 +0000 Subject: [PATCH 07/15] Session knows not to save cookie if configured so --- lib/advent/session.rb | 15 +++++++++++++-- test/advent/cli_test.rb | 2 +- test/advent/session_test.rb | 10 ++++++++++ test/test_helper.rb | 11 +++++++++++ 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/lib/advent/session.rb b/lib/advent/session.rb index e2c2f15..348b973 100644 --- a/lib/advent/session.rb +++ b/lib/advent/session.rb @@ -18,11 +18,22 @@ def exist? end def value=(val) - File.write file_name, val + if save_to_disk? + File.write file_name, val + else + @_value = val + end end def value - File.read file_name if exist? + return @_value unless save_to_disk? + return File.read(file_name) if exist? + end + + private + + def save_to_disk? + Advent.config.remember_session end end end diff --git a/test/advent/cli_test.rb b/test/advent/cli_test.rb index e83b656..ba35397 100644 --- a/test/advent/cli_test.rb +++ b/test/advent/cli_test.rb @@ -147,7 +147,7 @@ def test_persisting_session_cookie File.delete input if File.exist? input end - def test_not_asking_for_session_cookie + def test_not_asking_for_session_cookie_again Advent.session.value = @session out, _err = capture_io do diff --git a/test/advent/session_test.rb b/test/advent/session_test.rb index bec1ba3..92f6ecc 100644 --- a/test/advent/session_test.rb +++ b/test/advent/session_test.rb @@ -2,6 +2,7 @@ class Advent::SessionTest < Advent::TestCase def setup + Dir.chdir DUMMY_ROOT_PATH @session = Advent::Session.new(name) end @@ -26,6 +27,15 @@ def test_setting_value assert_equal "session value", File.read(@session.file_name) end + def test_setting_value_honouring_config + with_config({"remember_session" => false}) do + @session.value = "session value" + + assert_equal "session value", @session.value + refute @session.exist? + end + end + def test_value assert_nil @session.value File.write @session.file_name, "another session value" diff --git a/test/test_helper.rb b/test/test_helper.rb index 4fde7a2..ee8e04d 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -8,6 +8,17 @@ DUMMY_ROOT_PATH = Pathname.new File.expand_path("dummy", __dir__) class Advent::TestCase < Minitest::Test + def with_config(config) + original_config = Advent.config + + config_with_defaults = Advent::Configuration::DEFAULTS.merge(config) + Advent.instance_variable_set(:@_config, Advent::Configuration.new(config_with_defaults)) + + yield + ensure + Advent.instance_variable_set(:@_config, original_config) + end + def with_session(value) Advent.session.value = value yield From eab203316753e7a294654717f73a8a663f631262 Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 15:10:58 +0000 Subject: [PATCH 08/15] Fix standard linting whitespace --- lib/advent/cli/downloader.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/advent/cli/downloader.rb b/lib/advent/cli/downloader.rb index 2930dea..9c88277 100644 --- a/lib/advent/cli/downloader.rb +++ b/lib/advent/cli/downloader.rb @@ -20,7 +20,7 @@ def download end private - + def ask_for_session_cookie_if_needed return if Advent.session.exist? From 89616669345d6dab9a24fd06bada58596eba0459 Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 16:48:06 +0000 Subject: [PATCH 09/15] Add config section to README --- README.md | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6165886..3cf6724 100644 --- a/README.md +++ b/README.md @@ -16,15 +16,26 @@ If bundler is not being used to manage dependencies, install the gem by executin ## Usage +Create a config file that defines the root of your Advent of Code solutions: + +``` +mkdir /where/i/store/projects/advent_of_code +cd advent_of_code + +touch advent.yml +``` + +Configuration values and format are explained in the [Config](#config) section. + Advent expects you to have a working directory resembling something like: $ tree . ├── 2015 - └── 2016 + ├── 2016 + └── advent.yml -Some commands can be run from within a directory for a specific year, but it's -better to run from the parent directory where possible. +You can run commands from anywhere under this directory. The typical flow for tackling a daily challenge would be: @@ -40,6 +51,32 @@ A list of commands and help is available using `advent`: $ advent help +## Config + +The config file should be at the root of your working directory called +`advent.yml`. The default values if you don't provide an override are: + +```yaml +download_when_generating: true +remember_session: true +``` + +### Config explained + +
+
download_when_generating
+
+When you run `advent generate` it will automatically download the input file to +go with it +
+ +
remember_session
+
+Save your session cookie in `.advent_session` when prompted so you don't need to +find it again +
+
+ ## Development 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. From fd74f7ff27871e47c966c37e0e114979195c6d1d Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 17:01:34 +0000 Subject: [PATCH 10/15] Automatically download inputs when generating --- lib/advent/cli.rb | 2 ++ test/advent/cli_test.rb | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/lib/advent/cli.rb b/lib/advent/cli.rb index 7e18cd8..02ff02a 100644 --- a/lib/advent/cli.rb +++ b/lib/advent/cli.rb @@ -47,6 +47,8 @@ def generate(year, day) template "solution.rb.tt", "#{year}/day#{day}.rb", context: binding template "solution_test.rb.tt", "#{year}/test/day#{day}_test.rb", context: binding + + download year, day if Advent.config.download_when_generating end desc "solve FILE", "Solve your solution" diff --git a/test/advent/cli_test.rb b/test/advent/cli_test.rb index ba35397..088dc7f 100644 --- a/test/advent/cli_test.rb +++ b/test/advent/cli_test.rb @@ -74,6 +74,23 @@ def test_generate end end + def test_download_when_generating + with_session("abc123") do + with_config({"download_when_generating" => true}) do + capture_io do + @cli.invoke(:generate, ["2015", "3"]) + end + end + end + + assert File.exist? DUMMY_ROOT_PATH.join("2015", "day3.rb") + assert File.exist? DUMMY_ROOT_PATH.join("2015", ".day3.input.txt") + + File.delete DUMMY_ROOT_PATH.join("2015", "day3.rb") + File.delete DUMMY_ROOT_PATH.join("2015", "test", "day3_test.rb") + File.delete DUMMY_ROOT_PATH.join("2015", ".day3.input.txt") + end + def test_generate_day_parsing capture_io do @cli.invoke(:generate, ["2015", "day3"]) From daa1b67baa464d196b05a33fb4f034681f9021bf Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 17:02:53 +0000 Subject: [PATCH 11/15] Merge provided config with defaults --- lib/advent/configuration.rb | 4 +++- test/advent/configuration_test.rb | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/advent/configuration.rb b/lib/advent/configuration.rb index bed6e99..221a454 100644 --- a/lib/advent/configuration.rb +++ b/lib/advent/configuration.rb @@ -16,7 +16,9 @@ def from_file(file = FILE_NAME) end end - def initialize(config = DEFAULTS) + def initialize(conf) + config = DEFAULTS.merge(conf || {}) + @download_when_generating = config.dig("download_when_generating") @remember_session = config.dig("remember_session") end diff --git a/test/advent/configuration_test.rb b/test/advent/configuration_test.rb index 84709c1..8f11e77 100644 --- a/test/advent/configuration_test.rb +++ b/test/advent/configuration_test.rb @@ -7,8 +7,8 @@ def setup @config_file = DUMMY_ROOT_PATH.join("advent.yml") end - def test_initializing_with_defaults - config = Advent::Configuration.new + def test_config_is_merged_with_defaults + config = Advent::Configuration.new({}) assert config.download_when_generating assert config.remember_session From 9aaafe695959405590de949fbc9a949c8ef1b93e Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 17:17:38 +0000 Subject: [PATCH 12/15] Add init command to easily get started --- lib/advent/cli.rb | 7 +++++++ test/advent/cli_test.rb | 18 +++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/advent/cli.rb b/lib/advent/cli.rb index 02ff02a..9af6923 100644 --- a/lib/advent/cli.rb +++ b/lib/advent/cli.rb @@ -51,6 +51,13 @@ def generate(year, day) download year, day if Advent.config.download_when_generating end + desc "init DIR", "Initialise a new advent project in DIR" + def init(dir = ".") + create_file Pathname.getwd.join(dir).join(Advent::Configuration::FILE_NAME) do + "" + end + end + desc "solve FILE", "Solve your solution" # Runs a solution file, outputting both :part1 and :part2 method return values. def solve(path) diff --git a/test/advent/cli_test.rb b/test/advent/cli_test.rb index 088dc7f..4be6c2f 100644 --- a/test/advent/cli_test.rb +++ b/test/advent/cli_test.rb @@ -35,6 +35,22 @@ def teardown Advent.session.clear end + def test_init + path = DUMMY_ROOT_PATH.join("init") + Dir.mkdir path + + out, _err = capture_io do + Dir.chdir path do + @cli.invoke(:init) + end + end + + assert_match(/create.*advent.yml/, out.strip) + ensure + File.delete path.join("advent.yml") + Dir.rmdir path + end + def test_version out, _err = capture_io do @cli.invoke(:version) @@ -85,7 +101,7 @@ def test_download_when_generating assert File.exist? DUMMY_ROOT_PATH.join("2015", "day3.rb") assert File.exist? DUMMY_ROOT_PATH.join("2015", ".day3.input.txt") - + File.delete DUMMY_ROOT_PATH.join("2015", "day3.rb") File.delete DUMMY_ROOT_PATH.join("2015", "test", "day3_test.rb") File.delete DUMMY_ROOT_PATH.join("2015", ".day3.input.txt") From eeb0776c60b7edf7363c8f72eefe058bc56d73a7 Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 17:26:57 +0000 Subject: [PATCH 13/15] Only load Advent.root when not running init --- README.md | 10 +++++----- lib/advent/cli.rb | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3cf6724..d494cd7 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,13 @@ If bundler is not being used to manage dependencies, install the gem by executin ## Usage -Create a config file that defines the root of your Advent of Code solutions: +Initialise a new project somewhere: -``` -mkdir /where/i/store/projects/advent_of_code -cd advent_of_code +```bash +mkdir advent_of_code && cd advent_of_code -touch advent.yml +# create a blank advent.yml config file +advent init ``` Configuration values and format are explained in the [Config](#config) section. diff --git a/lib/advent/cli.rb b/lib/advent/cli.rb index 9af6923..60bb56b 100644 --- a/lib/advent/cli.rb +++ b/lib/advent/cli.rb @@ -14,8 +14,12 @@ class CLI < Thor def initialize(*args) super - self.destination_root = Advent.root source_paths << File.expand_path("templates", __dir__) + + # Don't try to load Advent.root if we're running init + unless args.last[:current_command]&.name == "init" + self.destination_root = Advent.root + end end # @return [Boolean] defines whether an exit status is set if a command fails From aa1fbce4f3dd6eca820ddddf36cf5ef6999dc073 Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 19:08:10 +0000 Subject: [PATCH 14/15] Add post-install message for init --- advent.gemspec | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/advent.gemspec b/advent.gemspec index bb250d6..7a8ec47 100644 --- a/advent.gemspec +++ b/advent.gemspec @@ -19,4 +19,12 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] spec.add_dependency "thor", "~> 1.2" + + spec.post_install_message = " +advent v0.1.5 requires a config file in your working directory. + +See #{spec.homepage}/blob/main/README.md#usage or if you're +brave run `advent init` in your current directory. + +" end From 06e2e5a24858c38dd304d6c55170f7a2ca8b2848 Mon Sep 17 00:00:00 2001 From: Daniel Grieve Date: Tue, 29 Nov 2022 19:26:19 +0000 Subject: [PATCH 15/15] Fix for ruby 2.7 and 3.0 --- Gemfile.lock | 1 + lib/advent/cli/solver.rb | 2 +- lib/advent/configuration.rb | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 934f84c..5b63ee5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -52,6 +52,7 @@ GEM PLATFORMS arm64-darwin-21 + ruby DEPENDENCIES advent! diff --git a/lib/advent/cli/solver.rb b/lib/advent/cli/solver.rb index 9cafd98..a45e376 100644 --- a/lib/advent/cli/solver.rb +++ b/lib/advent/cli/solver.rb @@ -18,7 +18,7 @@ def solve load @path, Solutions solution = Solutions.const_get(solution_class_name).new else - require @path + require @path.expand_path solution = Object.const_get(solution_class_name).new end diff --git a/lib/advent/configuration.rb b/lib/advent/configuration.rb index 221a454..90d246c 100644 --- a/lib/advent/configuration.rb +++ b/lib/advent/configuration.rb @@ -12,7 +12,11 @@ class Configuration class << self def from_file(file = FILE_NAME) - new Psych.safe_load_file(file) + if RUBY_VERSION >= "3.1" + new Psych.safe_load_file(file) + else + new Psych.safe_load(File.read(file)) + end end end