katagen 1.0.1

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.
@@ -0,0 +1,38 @@
1
+ module Katagen
2
+ module Generators
3
+ # Colorization for puts, no need for another gem
4
+ # TODO: should I move this into a small gem?
5
+ module Logging
6
+ COLOR_CODES = {
7
+ red: 31,
8
+ green: 32,
9
+ yellow: 33,
10
+ blue: 34,
11
+ pink: 35,
12
+ light_blue: 36
13
+ }
14
+
15
+ def info(message)
16
+ puts "#{colorize("info", :blue)} #{message}"
17
+ end
18
+
19
+ def success(message)
20
+ puts "#{colorize("success", :green)} #{message}"
21
+ end
22
+
23
+ def warning(message)
24
+ puts "#{colorize("warning", :yellow)} #{message}"
25
+ end
26
+
27
+ private
28
+
29
+ # :reek:UtilityFunction
30
+
31
+ # Colorize string with provided code. Defaults to none(0)
32
+ # NOTE: reek should not complain about this in a module IMO
33
+ def colorize(message, color)
34
+ "\e[#{COLOR_CODES[color] || 0}m#{message}\e[0m"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "erb"
5
+ require "time"
6
+ require_relative "utils"
7
+
8
+ module Katagen
9
+ module Generators
10
+ # Generates a solution package
11
+ class Solution
12
+ include Utils
13
+ #
14
+ # Initialize generator with chosen method.
15
+ #
16
+ # @param [#build_question_info] strategy: instance of FromId or FromUrl
17
+ # @param [Hash] options: see cli.rb
18
+ # @option options [String] cwd current working directory, defaults is "./"
19
+ # @option options [String] lang_ext solution file extension, defaults to "rb" (ruby)
20
+ def initialize(strategy, options)
21
+ @strategy = strategy
22
+ @lang_ext = options[:lang] || "rb"
23
+ @cwd = options[:cwd] || "./"
24
+ end
25
+
26
+ #
27
+ # Create the folder containing: solution.rb, solution_spec.rb (defaults to rb)
28
+ #
29
+ # @param [String] cwd: default to ./
30
+ #
31
+ def create_package
32
+ question_info = @strategy.build_question_info
33
+ root = File.expand_path(File.join(@cwd, question_info.root))
34
+ generate_folder(root)
35
+ create_solution(root, question_info.url)
36
+ create_solution_spec(root)
37
+ end
38
+
39
+ private
40
+
41
+ def create_solution(root, url)
42
+ solution_path = File.join(root, "solution.#{@lang_ext}")
43
+ template_path = File.join(File.dirname(__FILE__), "../templates/solution.#{@lang_ext}.erb")
44
+
45
+ @timestamp = Time.now.iso8601
46
+ @url = url
47
+
48
+ generate_file(solution_path, dup_when_exists: true) do |file|
49
+ write_template(file, template_path) if File.exist?(template_path)
50
+ end
51
+ end
52
+
53
+ def create_solution_spec(root)
54
+ solution_spec_path = File.join(root, "solution_spec.#{@lang_ext}")
55
+ template_path = File.join(File.dirname(__FILE__), "../templates/solution_spec.#{@lang_ext}.erb")
56
+
57
+ generate_file(solution_spec_path) do |file|
58
+ write_template(file, template_path) if File.exist?(template_path)
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def write_template(file, template_path)
65
+ template = File.read(template_path)
66
+ result = ERB.new(template).result(binding)
67
+ file.write(result)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,37 @@
1
+ require "fileutils"
2
+ require_relative "logging"
3
+
4
+ module Katagen
5
+ module Generators
6
+ # Common path utilities :reek:UtilityFunction
7
+ module Utils
8
+ include Generators::Logging
9
+ # Generate a file ifne with custom body
10
+ def generate_file(path, options = {}, &block)
11
+ if !File.exist?(path)
12
+ elsif options[:dup_when_exists]
13
+ _, folder, target_file, ext = path.match(/(.+)\/(.+)\.(.+)\Z/).to_a
14
+ count = Dir["#{folder}/*"].count { |file| file.match(/#{target_file}\d*\.#{ext}/) }
15
+ path = "#{folder}/#{target_file}#{count + 1}.#{ext}"
16
+ else
17
+ warning "File already exists: #{path}, skipping..."
18
+ return nil
19
+ end
20
+
21
+ block ||= ->(file) {} unless block_given?
22
+ File.open(path, "w", &block)
23
+ success "Created file #{path}"
24
+ end
25
+
26
+ # Mkdir ifne
27
+ def generate_folder(dir_path)
28
+ if File.directory?(dir_path)
29
+ warning "Dir already exists: #{dir_path}, skipping..."
30
+ else
31
+ FileUtils.mkdir_p(dir_path)
32
+ success "Created dir #{dir_path}"
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,12 @@
1
+ module Katagen
2
+ #
3
+ # Contains question info to create kata folder, can be extended further.
4
+ #
5
+ class QuestionInfo
6
+ attr_reader :root, :url
7
+ def initialize(root, url)
8
+ @root = root
9
+ @url = url
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module Katagen
2
+ module Strategy
3
+ #
4
+ # @abstract Interface for question
5
+ #
6
+ class Base
7
+ # @return [QuestionInfo] path for directory
8
+ def build_question_info = raise(NotImplementedError)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,49 @@
1
+ require_relative "../question_info"
2
+
3
+ module Katagen
4
+ module Strategy
5
+ # :reek:U
6
+ class InvalidIndex < StandardError
7
+ def initialize(input) = super("#{input} is not a valid index")
8
+ end
9
+
10
+ # :reek:U
11
+ class QuestionNotExist < StandardError
12
+ def initialize(input) = super("question #{input} does not exist")
13
+ end
14
+
15
+ #
16
+ # Generator for leetcode questions
17
+ #
18
+ class LeetCode
19
+ def initialize(id)
20
+ @id = id.to_i
21
+ raise InvalidIndex.new(@id) unless @id.positive?
22
+ end
23
+
24
+ def build_question_info
25
+ summary = questions_summary.find { |q| q["id"] == @id }
26
+ raise QuestionNotExist.new(@id) unless summary
27
+ topic, difficulty = summary.values_at("topic", "difficulty")
28
+
29
+ QuestionInfo.new(
30
+ "#{difficulty}/#{@id}.#{topic}",
31
+ "https:/leetcode.com/problems/#{topic}"
32
+ )
33
+ end
34
+
35
+ private
36
+
37
+ #
38
+ # @return [Array<Hash{String=>String}>] array of question summary
39
+ #
40
+ def questions_summary
41
+ @summary ||= begin
42
+ path = File.join(File.dirname(__FILE__), "../data/leetcode.json")
43
+ raw_summary_text = File.read(path)
44
+ JSON.parse(raw_summary_text)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,9 @@
1
+ # timestamp: <%= @timestamp %>
2
+ # question: <%= @url %>
3
+
4
+ # train of thought
5
+ TRAIN_OF_THOUGHT = <<DOC.freeze
6
+ <how I came up with this solution>
7
+ DOC
8
+
9
+ # code goes here
@@ -0,0 +1,27 @@
1
+ FILE_NAME = ENV["TESTEE"] || "solution.rb"
2
+ require_relative FILE_NAME
3
+
4
+ TEST_CASES = [
5
+ {
6
+ input: [],
7
+ output: 0
8
+ },
9
+ {
10
+ input: [],
11
+ output: 0
12
+ }
13
+ ].freeze
14
+
15
+ RSpec.describe FILE_NAME do
16
+ context TRAIN_OF_THOUGHT do
17
+ TEST_CASES.each do |tc|
18
+ case tc
19
+ in { input: input, output: output}
20
+ pending "TODO: assert solution output with expected"
21
+ # it "#{input} => #{output}" do
22
+ # expect(___).to eq(output)
23
+ # end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Katagen
4
+ VERSION = "1.0.1"
5
+ end
data/lib/katagen.rb ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "katagen/version"
4
+ require_relative "katagen/cli"
data/sig/katagen.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Katagen
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: katagen
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - harryuan65
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-12-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: erb
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: reek
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '6.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '6.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: standard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.29'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.29'
111
+ description: Generate a folder for a question to put all practice records for better
112
+ reviewing
113
+ email:
114
+ - harryuan.65@gmail.com
115
+ executables:
116
+ - katagen
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - ".rspec"
121
+ - ".rubocop.yml"
122
+ - CHANGELOG.md
123
+ - CODE_OF_CONDUCT.md
124
+ - Gemfile
125
+ - LICENSE.txt
126
+ - README.md
127
+ - Rakefile
128
+ - bin/console
129
+ - bin/katagen
130
+ - bin/setup
131
+ - lib/katagen.rb
132
+ - lib/katagen/cli.rb
133
+ - lib/katagen/command.rb
134
+ - lib/katagen/data/leetcode.json
135
+ - lib/katagen/generators/logging.rb
136
+ - lib/katagen/generators/solution.rb
137
+ - lib/katagen/generators/utils.rb
138
+ - lib/katagen/question_info.rb
139
+ - lib/katagen/strategy/base.rb
140
+ - lib/katagen/strategy/leetcode.rb
141
+ - lib/katagen/templates/solution.rb.erb
142
+ - lib/katagen/templates/solution_spec.rb.erb
143
+ - lib/katagen/version.rb
144
+ - sig/katagen.rbs
145
+ homepage: https://github.com/harryuan65/Katagen
146
+ licenses:
147
+ - MIT
148
+ metadata:
149
+ allowed_push_host: https://rubygems.org
150
+ homepage_uri: https://github.com/harryuan65/Katagen
151
+ source_code_uri: https://github.com/harryuan65/Katagen
152
+ changelog_uri: https://github.com/harryuan65/Katagen/blob/master/CHANGELOG.md
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: 2.6.0
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubygems_version: 3.2.32
169
+ signing_key:
170
+ specification_version: 4
171
+ summary: Generates a folder for leet code practice
172
+ test_files: []