katagen 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []