advent 0.1.2 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44488f23b0a385b7060d3a2d64d6538dc1e738bbd8600bcc405e1735ace44ff2
4
- data.tar.gz: aa26c72769ec2cc0eeb05bf4ed67e3619470e7e1e7e77465c0b19c69b65abe2b
3
+ metadata.gz: 360b1871cc09fd664dd8562fd1a29afd9b2e8bbc7a83d9d711c7933a6c62b5ec
4
+ data.tar.gz: 2f9cde07fa43650354a3f11c7cb869efa7c969d4254083ca807bd7a855fcf9d0
5
5
  SHA512:
6
- metadata.gz: 8be6f552d4fd5930143da51281cf204b7e93f680358578927094f97dde8443d1d5c4307641286edf14fa2454fde7058abd2a2422afe107d4a857b1bdfdd5129b
7
- data.tar.gz: 51575d6fd1d772627c00e199c69f07c4069429787345fa239312effbeac090604c35bf9ab3c1dada8a13de0e75c8a41c83afccfe91723507eb06c36ee6692f8d
6
+ metadata.gz: e27b9323e1ad7a07484fe9302dfd49b430bd4fc5433ef0e412e1af14f734bdd1c0a8c719803e108e4b7b3aec144ec942119bc6a07bc93381f4aae9ef634324b1
7
+ data.tar.gz: b8e99258c57406a1cf945e868a1642d8ed8636c983fd960fd3f889bc6760c170bb346e3cdb0cc82e547f880dbd8c6f71898e941defdfd41b97a73974bc4cdec0
data/README.md CHANGED
@@ -16,6 +16,26 @@ If bundler is not being used to manage dependencies, install the gem by executin
16
16
 
17
17
  ## Usage
18
18
 
19
+ Advent expects you to have a working directory resembling something like:
20
+
21
+ $ tree
22
+ .
23
+ ├── 2015
24
+ └── 2016
25
+
26
+ Some commands can be run from within a directory for a specific year, but it's
27
+ better to run from the parent directory where possible.
28
+
29
+ The typical flow for tackling a daily challenge would be:
30
+
31
+ $ advent generate 2015 1 # generate files to work in
32
+ $ advent download 2015 1 # download the input file
33
+
34
+ $ vim 2015/day1.rb 2015/day1_test.rb # do your work
35
+
36
+ $ ruby 2015/day1_test.rb # run any tests you may have
37
+ $ advent solve 2015/day1.rb # get your answers to submit
38
+
19
39
  A list of commands and help is available using `advent`:
20
40
 
21
41
  $ advent help
@@ -3,21 +3,25 @@
3
3
  class Advent::CLI::Solver
4
4
  PARTS = [1, 2]
5
5
 
6
- def initialize(command, year:, day:)
6
+ if RUBY_VERSION >= "3.1"
7
+ module Solutions
8
+ end
9
+ end
10
+
11
+ def initialize(command, path)
7
12
  @command = command
8
- @year = year
9
- @day = day
13
+ @path = path
10
14
  end
11
15
 
12
16
  def solve
13
- if @command.in_year_directory?
14
- require @command.root_path.join(solution_file_name).to_s
17
+ if RUBY_VERSION >= "3.1"
18
+ load @path, Solutions
19
+ solution = Solutions.const_get(solution_class_name).new
15
20
  else
16
- require @command.root_path.join(@year.to_s, solution_file_name)
21
+ require @path
22
+ solution = Object.const_get(solution_class_name).new
17
23
  end
18
24
 
19
- solution = Object.const_get(solution_class_name).new
20
-
21
25
  PARTS.each do |n|
22
26
  method_name = "part#{n}".to_sym
23
27
 
@@ -33,11 +37,15 @@ class Advent::CLI::Solver
33
37
 
34
38
  private
35
39
 
40
+ def day
41
+ @_day ||= @path.basename.to_s.match(/day([0-9]+)\.rb/)[1]
42
+ end
43
+
36
44
  def solution_file_name
37
- "day#{@day}.rb"
45
+ "day#{day}.rb"
38
46
  end
39
47
 
40
48
  def solution_class_name
41
- "Day#{@day}"
49
+ "Day#{day}"
42
50
  end
43
51
  end
data/lib/advent/cli.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "advent"
4
+ require "date"
4
5
  require "pathname"
5
6
  require "thor"
6
7
 
@@ -9,6 +10,7 @@ module Advent
9
10
  include Thor::Actions
10
11
 
11
12
  class_option :root_path, default: Dir.pwd, hide: true, check_default_type: false
13
+ class_option :http_module, default: Net::HTTP, check_default_type: false
12
14
 
13
15
  def initialize(*args)
14
16
  super
@@ -17,45 +19,119 @@ module Advent
17
19
  source_paths << File.expand_path("templates", __dir__)
18
20
  end
19
21
 
22
+ # @return [Boolean] defines whether an exit status is set if a command fails
20
23
  def self.exit_on_failure?
21
24
  true
22
25
  end
23
26
 
24
27
  no_commands do
28
+ # @return [Boolean] whether the current root_path option is in a
29
+ # directory that looks like a year (eg. 2015)
25
30
  def in_year_directory?
26
31
  dir = root_path.basename.to_s
27
32
  dir =~ /^20[0-9]{2}/
28
33
  end
34
+ end
35
+
36
+ desc "download YEAR DAY", "Download the input for YEAR and DAY"
37
+ def download(year_or_day, day = nil)
38
+ year, day = determine_year_and_day(year_or_day, day)
39
+
40
+ if (error_message = validate(year, day))
41
+ say_error error_message, :red
42
+ return
43
+ end
44
+
45
+ subpath = if in_year_directory?
46
+ ""
47
+ else
48
+ "#{year}/"
49
+ end
50
+
51
+ unless Advent.session.exist?
52
+ session = ask "What is your Advent of Code session cookie value?", echo: false
53
+ Advent.session.value = session
29
54
 
30
- def root_path
31
- @_root_path ||= if options.root_path.is_a?(Pathname)
32
- options.root_path
33
- else
34
- Pathname.new(options.root_path)
35
- end
55
+ 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"
56
+ end
57
+
58
+ input = Advent::Input.new(root_path.join(subpath), day: day.to_i)
59
+
60
+ if input.download(Advent.session.value, options.http_module)
61
+ say "Input downloaded to #{input.file_path}.", :green
62
+ say "\nUsing #load_input in your daily solution will load the input file for you."
63
+ else
64
+ say_error "Something went wrong, maybe an old session cookie?", :red
36
65
  end
37
66
  end
38
67
 
39
- desc "generate YEAR DAY or generate DAY in a year directory", "Generate a new solution for YEAR and DAY"
68
+ desc "generate YEAR DAY", "Generate a new solution for YEAR and DAY"
69
+ # Generates a new solution file. If within a year directory, only the day
70
+ # is used, otherwise both the year and day will be required to generate the
71
+ # output.
40
72
  def generate(year_or_day, day = nil)
41
- destination = if in_year_directory?
42
- "day#{year_or_day}.rb"
73
+ year, day = determine_year_and_day(year_or_day, day)
74
+
75
+ if (error_message = validate(year, day))
76
+ say_error error_message, :red
77
+ return
78
+ end
79
+
80
+ subpath = if in_year_directory?
81
+ ""
43
82
  else
44
- "#{year_or_day}/day#{day}.rb"
83
+ "#{year}/"
45
84
  end
46
85
 
47
- template "solution.rb.tt", destination, context: binding
86
+ template "solution.rb.tt", "#{subpath}day#{day}.rb", context: binding
87
+ template "solution_test.rb.tt", "#{subpath}test/day#{day}_test.rb", context: binding
48
88
  end
49
89
 
50
- desc "solve YEAR DAY", "Solve your solution for YEAR and DAY"
51
- def solve(year, day)
90
+ desc "solve FILE", "Solve your solution"
91
+ # Runs a solution file, outputting both :part1 and :part2 method return values.
92
+ def solve(path)
52
93
  require "advent/cli/solver"
53
- Solver.new(self, year: year, day: day).solve
94
+ Solver.new(self, root_path.join(path)).solve
54
95
  end
55
96
 
56
- desc "version", "Prints the current version of Advent"
97
+ desc "version", "Prints the current version of the gem"
98
+ # Prints the current version of the gem
57
99
  def version
58
100
  say Advent::VERSION
59
101
  end
102
+
103
+ private
104
+
105
+ def determine_year_and_day(year_or_day, day)
106
+ if in_year_directory?
107
+ [root_path.basename.to_s, parse_number(year_or_day)]
108
+ else
109
+ [year_or_day, parse_number(day)]
110
+ end
111
+ end
112
+
113
+ def root_path
114
+ @_root_path ||= if options.root_path.is_a?(Pathname)
115
+ options.root_path
116
+ else
117
+ Pathname.new(options.root_path)
118
+ end
119
+ end
120
+
121
+ def parse_number(str)
122
+ if (m = str.match(/[0-9]+/))
123
+ m[0]
124
+ end
125
+ end
126
+
127
+ def validate(year, day)
128
+ if year.to_i < 2014
129
+ "Advent of Code only started in 2014!"
130
+ elsif year.to_i > Date.today.year
131
+ "Future years are not supported."
132
+ elsif !(1..25).cover? day.to_i
133
+ "Day must be between 1 and 25 (inclusive)."
134
+ end
135
+ end
60
136
  end
61
137
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cgi/cookie"
4
+ require "fileutils"
5
+ require "net/http"
6
+ require "uri"
7
+
8
+ module Advent
9
+ class Input
10
+ def initialize(dir, day:)
11
+ @dir = dir
12
+ @day = day
13
+ end
14
+
15
+ def file_path
16
+ @dir.join(".day#{@day}.input.txt")
17
+ end
18
+
19
+ def exist?
20
+ File.exist? file_path
21
+ end
22
+
23
+ def download(session, http = Net::HTTP)
24
+ session_cookie = CGI::Cookie.new("session", session)
25
+ response = http.get_response(input_url, {"Cookie" => session_cookie.to_s})
26
+
27
+ if success?(response)
28
+ FileUtils.mkdir_p file_path.dirname
29
+ File.write file_path, response.body
30
+ true
31
+ else
32
+ false
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def input_url
39
+ URI("https://adventofcode.com/#{year}/day/#{@day}/input")
40
+ end
41
+
42
+ def year
43
+ @_year ||= @dir.basename
44
+ end
45
+
46
+ def success?(response)
47
+ response.code >= "200" && response.code < "300"
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,28 @@
1
+ module Advent
2
+ # Simple class for handling the session cookie file
3
+ class Session
4
+ FILE_NAME = ".advent_session"
5
+
6
+ attr_reader :file_name
7
+
8
+ def initialize(file_name = FILE_NAME)
9
+ @file_name = file_name
10
+ end
11
+
12
+ def clear
13
+ File.delete file_name if exist?
14
+ end
15
+
16
+ def exist?
17
+ File.exist? file_name
18
+ end
19
+
20
+ def value=(val)
21
+ File.write file_name, val
22
+ end
23
+
24
+ def value
25
+ File.read file_name if exist?
26
+ end
27
+ end
28
+ end
@@ -3,19 +3,25 @@
3
3
  require "pathname"
4
4
 
5
5
  module Advent
6
+ # Baes class for an Advent of Code solution attempt. If subclass is in a
7
+ # directory matching a year (eg. 2015) and the filename is for a particular
8
+ # day (eg. day1.rb) then the @year and @day instance variables are
9
+ # automatically inferred.
6
10
  class Solution
7
- attr_reader :year, :day
11
+ attr_reader :year # @return [Numeric] the year this solution is from
12
+ attr_reader :day # @return [Numeric] the day this solution is for
8
13
 
9
14
  def initialize
10
15
  year, day = infer_year_and_day_from_file_system
11
16
 
12
17
  @year = year
13
18
  @day = day
19
+
20
+ @input = Input.new(source_location.dirname, day: day)
14
21
  end
15
22
 
16
23
  def load_input
17
- dir = source_location.dirname
18
- File.read(dir.join(".day#{@day}.input.txt"))
24
+ File.read(@input.file_path)
19
25
  end
20
26
 
21
27
  private
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "advent"
4
+ require "minitest/autorun"
5
+
6
+ require_relative "../day<%= day %>"
7
+
8
+ class Day<%= day %>Test < Advent::TestCase
9
+ def setup
10
+ @solution = Day<%= day %>.new
11
+ end
12
+
13
+ # def test_part1
14
+ # assert_equal 123, @solution.part1
15
+ # end
16
+
17
+ # def test_part2
18
+ # assert_equal 123, @solution.part2
19
+ # end
20
+ end
@@ -0,0 +1,6 @@
1
+ require "minitest"
2
+
3
+ module Advent
4
+ class TestCase < Minitest::Test
5
+ end
6
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Advent
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.4"
5
5
  end
data/lib/advent.rb CHANGED
@@ -1,8 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "advent/input"
4
+ require_relative "advent/session"
3
5
  require_relative "advent/solution"
6
+ require_relative "advent/test_case"
4
7
  require_relative "advent/version"
5
8
 
6
9
  module Advent
7
10
  class Error < StandardError; end
11
+
12
+ class << self
13
+ def session
14
+ @_session = Session.new
15
+ end
16
+ end
8
17
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: advent
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 Grieve
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-21 00:00:00.000000000 Z
11
+ date: 2022-11-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -39,8 +39,12 @@ files:
39
39
  - lib/advent.rb
40
40
  - lib/advent/cli.rb
41
41
  - lib/advent/cli/solver.rb
42
+ - lib/advent/input.rb
43
+ - lib/advent/session.rb
42
44
  - lib/advent/solution.rb
43
45
  - lib/advent/templates/solution.rb.tt
46
+ - lib/advent/templates/solution_test.rb.tt
47
+ - lib/advent/test_case.rb
44
48
  - lib/advent/version.rb
45
49
  homepage: https://github.com/dnlgrv/advent-rb
46
50
  licenses: