dopstick 0.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.
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.