dopstick 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.github/FUNDING.yml +4 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
  5. data/.github/PULL_REQUEST_TEMPLATE.md +38 -0
  6. data/.github/workflows/tests.yml +55 -0
  7. data/.gitignore +11 -0
  8. data/.rubocop.yml +21 -0
  9. data/CHANGELOG.md +16 -0
  10. data/CODE_OF_CONDUCT.md +74 -0
  11. data/CONTRIBUTING.md +79 -0
  12. data/Gemfile +5 -0
  13. data/LICENSE.md +20 -0
  14. data/README.md +56 -0
  15. data/Rakefile +15 -0
  16. data/bin/console +16 -0
  17. data/bin/setup +10 -0
  18. data/dopstick.gemspec +45 -0
  19. data/exe/dopstick +5 -0
  20. data/lib/dopstick.rb +12 -0
  21. data/lib/dopstick/cli.rb +89 -0
  22. data/lib/dopstick/generator.rb +214 -0
  23. data/lib/dopstick/refinements.rb +24 -0
  24. data/lib/dopstick/templates/CHANGELOG.md +16 -0
  25. data/lib/dopstick/templates/active_record.erb +23 -0
  26. data/lib/dopstick/templates/bin.erb +5 -0
  27. data/lib/dopstick/templates/bug_report.erb +41 -0
  28. data/lib/dopstick/templates/cli.erb +3 -0
  29. data/lib/dopstick/templates/cli_class.erb +19 -0
  30. data/lib/dopstick/templates/coc.erb +74 -0
  31. data/lib/dopstick/templates/console.erb +16 -0
  32. data/lib/dopstick/templates/contributing.erb +80 -0
  33. data/lib/dopstick/templates/entry_file.erb +3 -0
  34. data/lib/dopstick/templates/feature_request.erb +23 -0
  35. data/lib/dopstick/templates/funding.erb +4 -0
  36. data/lib/dopstick/templates/gem_entry_file.erb +3 -0
  37. data/lib/dopstick/templates/gemfile.erb +5 -0
  38. data/lib/dopstick/templates/gemspec.erb +53 -0
  39. data/lib/dopstick/templates/generator.erb +3 -0
  40. data/lib/dopstick/templates/generator_class.erb +13 -0
  41. data/lib/dopstick/templates/gitignore.erb +11 -0
  42. data/lib/dopstick/templates/issue.erb +26 -0
  43. data/lib/dopstick/templates/license.erb +20 -0
  44. data/lib/dopstick/templates/pull_request.erb +38 -0
  45. data/lib/dopstick/templates/rakefile.erb +15 -0
  46. data/lib/dopstick/templates/readme.erb +50 -0
  47. data/lib/dopstick/templates/rubocop.erb +12 -0
  48. data/lib/dopstick/templates/setup.erb +10 -0
  49. data/lib/dopstick/templates/test_file.erb +9 -0
  50. data/lib/dopstick/templates/test_helper.erb +14 -0
  51. data/lib/dopstick/templates/tests_workflow.erb +73 -0
  52. data/lib/dopstick/templates/version.erb +3 -0
  53. data/lib/dopstick/version.rb +5 -0
  54. metadata +214 -0
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+ require "rubocop/rake_task"
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << "test"
9
+ t.libs << "lib"
10
+ t.test_files = FileList["test/**/*_test.rb"]
11
+ end
12
+
13
+ RuboCop::RakeTask.new
14
+
15
+ task default: %i[test rubocop]
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "dopstick"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ begin
11
+ require "pry"
12
+ Pry.start
13
+ rescue LoadError
14
+ require "irb"
15
+ IRB.start(__FILE__)
16
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euo pipefail
4
+
5
+ IFS=$'\n\t'
6
+ set -vx
7
+
8
+ bundle install
9
+
10
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./lib/dopstick/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "dopstick"
7
+ spec.version = Dopstick::VERSION
8
+ spec.authors = ["Nando Vieira"]
9
+ spec.email = ["me@fnando.com"]
10
+
11
+ spec.summary = "Generate a project skeleton for creating a rubygem"
12
+ spec.description = spec.summary
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
15
+
16
+ github_url = "https://github.com/fnando/dopstick"
17
+ github_tree_url = "#{github_url}/blob/v#{spec.version}"
18
+
19
+ spec.homepage = github_url
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ spec.metadata["bug_tracker_uri"] = "#{github_url}/issues"
22
+ spec.metadata["source_code_uri"] = github_tree_url
23
+ spec.metadata["changelog_uri"] = "#{github_tree_url}/CHANGELOG.md"
24
+ spec.metadata["documentation_uri"] = "#{github_tree_url}/README.md"
25
+ spec.metadata["license_uri"] = "#{github_tree_url}/LICENSE.md"
26
+
27
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
28
+ `git ls-files -z`
29
+ .split("\x0")
30
+ .reject {|f| f.match(%r{^(test|spec|features)/}) }
31
+ end
32
+
33
+ spec.bindir = "exe"
34
+ spec.executables = spec.files.grep(%r{^exe/}) {|f| File.basename(f) }
35
+ spec.require_paths = ["lib"]
36
+
37
+ spec.add_dependency "thor"
38
+ spec.add_development_dependency "minitest"
39
+ spec.add_development_dependency "minitest-utils"
40
+ spec.add_development_dependency "pry-meta"
41
+ spec.add_development_dependency "rake"
42
+ spec.add_development_dependency "rubocop"
43
+ spec.add_development_dependency "rubocop-fnando"
44
+ spec.add_development_dependency "simplecov"
45
+ end
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../lib/dopstick"
5
+ Dopstick::CLI.start
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "pathname"
5
+ require "thor"
6
+
7
+ module Dopstick
8
+ require_relative "dopstick/refinements"
9
+ require_relative "dopstick/version"
10
+ require_relative "dopstick/generator"
11
+ require_relative "dopstick/cli"
12
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dopstick
4
+ class CLI < Thor
5
+ using Dopstick::Refinements
6
+ check_unknown_options!
7
+
8
+ def self.exit_on_failure?
9
+ true
10
+ end
11
+
12
+ desc "new PATH", "Create a new gem"
13
+ option :name,
14
+ default: "",
15
+ desc: "Set the gem name. Defaults to path's basename."
16
+ option :active_record,
17
+ default: false,
18
+ type: :boolean,
19
+ desc: "Set up ActiveRecord for testing."
20
+ option :author_name,
21
+ default: "",
22
+ desc: "Set author name. Defaults to `git config user.name`."
23
+ option :author_email,
24
+ default: "",
25
+ desc: "Set author email. Defaults to `git config user.email`."
26
+ option :author_github,
27
+ default: "",
28
+ desc: "Set Github username. Defaults to `git config user.github`."
29
+ option :author_paypal,
30
+ default: "",
31
+ desc: "Set Paypal account for donations. Defaults to " \
32
+ "`git config user.paypal`."
33
+ option :repository,
34
+ default: "",
35
+ desc: "Set Github repository name. Defaults to gem name."
36
+ option :description,
37
+ default: "",
38
+ desc: "Set gem description."
39
+ option :version,
40
+ default: "0.0.0",
41
+ desc: "Set package initial version."
42
+ option :bin,
43
+ default: "",
44
+ desc: "Set binary name. Also sets up Thor CLI and generator."
45
+ option :namespace,
46
+ default: "",
47
+ desc: "Set the codebase namespace. By default, it's inferred from " \
48
+ "the gem name."
49
+ option :ruby_versions,
50
+ default: %w[2.6 2.7],
51
+ type: :array,
52
+ desc: "Set Ruby versions that are officially supported. Multiple " \
53
+ "versions must separated by space."
54
+ def new(path)
55
+ options = dup_options
56
+ gem_name, namespace = expand_gem_name_and_namespace(path)
57
+
58
+ generator = Generator.new
59
+ generator.destination_root = File.expand_path(path)
60
+ generator.options = options.merge(
61
+ gem_name: gem_name,
62
+ namespace: namespace,
63
+ entry_path: namespace.underscore("/")
64
+ )
65
+
66
+ generator.invoke_all
67
+ end
68
+
69
+ no_commands do
70
+ private def dup_options
71
+ options.each_with_object({}) do |(key, value), buffer|
72
+ buffer[key.to_sym] = value
73
+ end
74
+ end
75
+
76
+ private def expand_gem_name_and_namespace(path) # rubocop:disable Metrics/AbcSize
77
+ if options[:name].presence && options[:namespace].presence
78
+ [options[:name], options[:namespace]]
79
+ elsif options[:name].presence
80
+ [options[:name], options[:name].camelize]
81
+ elsif options[:namespace].presence
82
+ [options[:namespace].underscore("-"), options[:namespace]]
83
+ else
84
+ [File.basename(path), File.basename(path).camelize]
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,214 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dopstick
4
+ class Generator < Thor::Group # rubocop:disable Metrics/ClassLength
5
+ using Dopstick::Refinements
6
+
7
+ include Thor::Actions
8
+
9
+ def self.exit_on_failure?
10
+ true
11
+ end
12
+
13
+ attr_accessor :options
14
+
15
+ desc "Generate a new gem folder structure"
16
+
17
+ def self.source_root
18
+ File.join(__dir__, "templates")
19
+ end
20
+
21
+ def copy_gemspec
22
+ template "gemspec.erb", "#{gem_name}.gemspec"
23
+ end
24
+
25
+ def copy_license
26
+ template "license.erb", "LICENSE.md"
27
+ end
28
+
29
+ def copy_coc
30
+ template "coc.erb", "CODE_OF_CONDUCT.md"
31
+ end
32
+
33
+ def copy_readme
34
+ template "readme.erb", "README.md"
35
+ end
36
+
37
+ def copy_changelog
38
+ copy_file "CHANGELOG.md"
39
+ end
40
+
41
+ def copy_contributing
42
+ template "contributing.erb", "CONTRIBUTING.md"
43
+ end
44
+
45
+ def copy_github_templates
46
+ template "funding.erb", ".github/FUNDING.yml"
47
+ template "tests_workflow.erb", ".github/workflows/tests.yml"
48
+ template "bug_report.erb", ".github/ISSUE_TEMPLATE/bug_report.md"
49
+ template "feature_request.erb",
50
+ ".github/ISSUE_TEMPLATE/feature_request.md"
51
+ template "pull_request.erb", ".github/PULL_REQUEST_TEMPLATE.md"
52
+ end
53
+
54
+ def copy_rakefile
55
+ template "rakefile.erb", "Rakefile"
56
+ end
57
+
58
+ def copy_rubocop
59
+ template "rubocop.erb", ".rubocop.yml"
60
+ end
61
+
62
+ def copy_gitignore
63
+ template "gitignore.erb", ".gitignore"
64
+ end
65
+
66
+ def copy_gemfile
67
+ template "gemfile.erb", "Gemfile"
68
+ end
69
+
70
+ def copy_bins
71
+ template "console.erb", "bin/console"
72
+ template "setup.erb", "bin/setup"
73
+ in_root { run "chmod +x bin/*" }
74
+ end
75
+
76
+ def create_entry_file
77
+ if entry_path.include?("/")
78
+ template "gem_entry_file.erb", "lib/#{gem_name}.rb"
79
+ end
80
+
81
+ template "entry_file.erb", "lib/#{entry_path}.rb"
82
+ end
83
+
84
+ def create_version_file
85
+ template "version.erb", "lib/#{entry_path}/version.rb"
86
+ end
87
+
88
+ def copy_test_files
89
+ template "test_helper.erb", "test/test_helper.rb"
90
+ template "test_file.erb", "test/#{entry_path}_test.rb"
91
+ end
92
+
93
+ def copy_binary_files
94
+ return unless options[:bin].presence
95
+
96
+ template "cli.erb", "lib/#{entry_path}/cli.rb"
97
+ template "generator.erb", "lib/#{entry_path}/generator.rb"
98
+ template "bin.erb", "exe/#{options[:bin]}"
99
+ create_file "lib/#{entry_path}/templates/.keep"
100
+ in_root { run "chmod +x exe/*" }
101
+ end
102
+
103
+ def copy_active_record_files
104
+ return unless options[:active_record]
105
+
106
+ template "active_record.erb", "test/support/active_record.rb"
107
+ end
108
+
109
+ def initialize_repo
110
+ in_root do
111
+ run "git init --initial-branch=main", capture: true
112
+ run "git add .", capture: true
113
+ run "git add bin --force", capture: true
114
+ end
115
+ end
116
+
117
+ no_commands do # rubocop:disable Metrics/BlockLength
118
+ def gem_name
119
+ options[:gem_name]
120
+ end
121
+
122
+ def entry_path
123
+ options[:entry_path]
124
+ end
125
+
126
+ def user_name
127
+ @user_name ||= options[:author_name].presence ||
128
+ `git config --global user.name`.chomp
129
+ end
130
+
131
+ def user_email
132
+ @user_email ||= options[:author_email].presence ||
133
+ `git config --global user.email`.chomp
134
+ end
135
+
136
+ def github_user
137
+ @github_user ||= options[:author_github].presence || begin
138
+ user = `git config --global user.github`.chomp
139
+ user.empty? ? "[USER]" : user
140
+ end
141
+ end
142
+
143
+ def paypal_user
144
+ @paypal_user ||= options[:author_paypal].presence || begin
145
+ user = `git config --global user.paypal`.chomp
146
+ user.empty? ? "[USER]" : user
147
+ end
148
+ end
149
+
150
+ def github_url
151
+ "https://github.com/#{github_user}/#{gem_name}"
152
+ end
153
+
154
+ def ruby_versions
155
+ options[:ruby_versions]
156
+ end
157
+
158
+ def const_names
159
+ @const_names ||= options[:namespace].split("::")
160
+ end
161
+
162
+ def const_names_size
163
+ @const_names_size ||= const_names.size
164
+ end
165
+
166
+ def render_tree(skip_content_spaces = false, &block) # rubocop:disable Style/OptionalBooleanParameter
167
+ content = []
168
+
169
+ const_names.each_with_index do |name, count|
170
+ content << (" " * count) + "module #{name}"
171
+ end
172
+
173
+ spacer = skip_content_spaces ? "" : " "
174
+
175
+ content << (spacer * const_names_size) + block.call
176
+
177
+ (const_names_size - 1).downto(0) do |count|
178
+ content << "#{' ' * count}end"
179
+ end
180
+
181
+ content.join("\n")
182
+ end
183
+
184
+ def erb(file)
185
+ ERB.new(File.read("#{__dir__}/templates/#{file}")).result binding
186
+ end
187
+
188
+ def render_cli
189
+ cli_class = erb("cli_class.erb")
190
+ .chomp
191
+ .gsub(/^(.)/m, "#{' ' * const_names_size}\\1")
192
+
193
+ render_tree(true) { cli_class }
194
+ end
195
+
196
+ def render_generator
197
+ generator_class = erb("generator_class.erb")
198
+ .chomp
199
+ .gsub(/^(.)/m, "#{' ' * const_names_size}\\1")
200
+
201
+ render_tree(true) { generator_class }
202
+ end
203
+
204
+ def oldest_ruby_version
205
+ version = options[:ruby_versions]
206
+ .map {|v| Gem::Version.new(v) }
207
+ .min
208
+ .canonical_segments
209
+
210
+ [*version, 0].take(3).join(".")
211
+ end
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dopstick
4
+ module Refinements
5
+ refine String do
6
+ def presence
7
+ empty? ? nil : self
8
+ end
9
+
10
+ def camelize
11
+ split("-")
12
+ .map {|word| word.split("_").map(&:capitalize).join }
13
+ .join("::")
14
+ end
15
+
16
+ def underscore(separator = "/")
17
+ split("::")
18
+ .map {|word| word.gsub(/([A-Z]+)/m, "_\\1")[1..-1] }
19
+ .join(separator)
20
+ .downcase
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ <!--
4
+ Prefix your message with one of the following:
5
+
6
+ - [Added] for new features.
7
+ - [Changed] for changes in existing functionality.
8
+ - [Deprecated] for soon-to-be removed features.
9
+ - [Removed] for now removed features.
10
+ - [Fixed] for any bug fixes.
11
+ - [Security] in case of vulnerabilities.
12
+ -->
13
+
14
+ ## Unreleased
15
+
16
+ - Initial release.