gempilot 0.2.0

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 (69) hide show
  1. checksums.yaml +7 -0
  2. data/.claude/skills/using-command-kit/SKILL.md +119 -0
  3. data/.claude/skills/using-command-kit/cli-example.rb +84 -0
  4. data/.claude/skills/using-command-kit/generator-pattern.rb +62 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +281 -0
  7. data/.ruby-version +1 -0
  8. data/CLAUDE.md +45 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +140 -0
  11. data/Rakefile +44 -0
  12. data/data/templates/gem/Gemfile.erb +23 -0
  13. data/data/templates/gem/LICENSE.txt.erb +21 -0
  14. data/data/templates/gem/README.md.erb +25 -0
  15. data/data/templates/gem/Rakefile.erb +36 -0
  16. data/data/templates/gem/bin/console.erb +7 -0
  17. data/data/templates/gem/bin/setup.erb +5 -0
  18. data/data/templates/gem/dotfiles/github/workflows/ci.yml.erb +33 -0
  19. data/data/templates/gem/dotfiles/gitignore +11 -0
  20. data/data/templates/gem/dotfiles/rubocop.yml.erb +209 -0
  21. data/data/templates/gem/dotfiles/ruby-version.erb +1 -0
  22. data/data/templates/gem/exe/gem_name.erb +3 -0
  23. data/data/templates/gem/gemspec.erb +27 -0
  24. data/data/templates/gem/lib/gem_name/version.rb.erb +7 -0
  25. data/data/templates/gem/lib/gem_name.rb.erb +16 -0
  26. data/data/templates/gem/lib/gem_name_extension.rb.erb +20 -0
  27. data/data/templates/gem/rspec.erb +3 -0
  28. data/data/templates/gem/spec/gem_name_spec.rb.erb +5 -0
  29. data/data/templates/gem/spec/spec_helper.rb.erb +10 -0
  30. data/data/templates/gem/spec/zeitwerk_spec.rb.erb +5 -0
  31. data/data/templates/gem/test/gem_name_test.rb.erb +7 -0
  32. data/data/templates/gem/test/test_helper.rb.erb +7 -0
  33. data/data/templates/gem/test/zeitwerk_test.rb.erb +9 -0
  34. data/data/templates/new/.keep +0 -0
  35. data/data/templates/new/command.rb.erb +15 -0
  36. data/docs/command_kit_comparison.md +249 -0
  37. data/docs/command_kit_reference.md +517 -0
  38. data/docs/plans/2026-02-18-gempilot-add-command.md +718 -0
  39. data/docs/superpowers/plans/2026-04-01-rubocop-new-config.md +838 -0
  40. data/docs/superpowers/plans/2026-04-06-dogfood-inflectable.md +659 -0
  41. data/docs/superpowers/plans/2026-04-06-inflection-tests-and-erb-rename.md +166 -0
  42. data/docs/superpowers/plans/2026-04-06-integrate-version-tools.md +162 -0
  43. data/docs/superpowers/plans/2026-04-06-new-readme.md +185 -0
  44. data/docs/version-management-redesign.md +44 -0
  45. data/exe/gempilot +12 -0
  46. data/issues.rec +77 -0
  47. data/lib/core_ext/string/inflection_methods.rb +68 -0
  48. data/lib/core_ext/string/refinements/inflectable.rb +15 -0
  49. data/lib/gempilot/cli/command.rb +17 -0
  50. data/lib/gempilot/cli/commands/bump.rb +49 -0
  51. data/lib/gempilot/cli/commands/console.rb +38 -0
  52. data/lib/gempilot/cli/commands/create.rb +183 -0
  53. data/lib/gempilot/cli/commands/destroy.rb +136 -0
  54. data/lib/gempilot/cli/commands/new.rb +226 -0
  55. data/lib/gempilot/cli/commands/release.rb +40 -0
  56. data/lib/gempilot/cli/gem_builder.rb +105 -0
  57. data/lib/gempilot/cli/gem_context.rb +40 -0
  58. data/lib/gempilot/cli/generator.rb +90 -0
  59. data/lib/gempilot/cli.rb +19 -0
  60. data/lib/gempilot/github_release.rb +30 -0
  61. data/lib/gempilot/project/version.rb +39 -0
  62. data/lib/gempilot/project.rb +111 -0
  63. data/lib/gempilot/strict_shell.rb +18 -0
  64. data/lib/gempilot/version.rb +3 -0
  65. data/lib/gempilot/version_tag.rb +53 -0
  66. data/lib/gempilot/version_task.rb +108 -0
  67. data/lib/gempilot.rb +17 -0
  68. data/notes.md +31 -0
  69. metadata +165 -0
data/README.md ADDED
@@ -0,0 +1,140 @@
1
+ # Gempilot
2
+
3
+ A CLI toolkit for creating and managing Ruby gems with modern conventions.
4
+
5
+ Gempilot scaffolds production-ready gems with Zeitwerk autoloading, RuboCop,
6
+ GitHub Actions CI, and integrated version management. It also generates
7
+ classes, modules, and commands within existing gems.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ gem install gempilot
13
+ ```
14
+
15
+ Requires Ruby >= 3.4.
16
+
17
+ ## Quick Start
18
+
19
+ ```bash
20
+ gempilot create my_gem
21
+ cd my_gem
22
+ bundle exec rake
23
+ ```
24
+
25
+ This creates a fully configured gem with tests, linting, CI, and version
26
+ management — ready to develop.
27
+
28
+ ## Commands
29
+
30
+ ### `gempilot create`
31
+
32
+ Scaffold a new gem.
33
+
34
+ ```bash
35
+ gempilot create my_gem
36
+ gempilot create --test rspec --exe my_gem
37
+ gempilot create --test minitest --no-git my_gem
38
+ ```
39
+
40
+ Options:
41
+
42
+ | Option | Description | Default |
43
+ |--------|-------------|---------|
44
+ | `--test {minitest\|rspec}` | Test framework | prompted |
45
+ | `--[no-]exe` | Create executable in `exe/` | prompted |
46
+ | `--[no-]git` | Initialize git repo | prompted |
47
+ | `--branch NAME` | Git branch name | `master` |
48
+ | `--summary TEXT` | One-line gem description | prompted |
49
+ | `--author NAME` | Author name | `git config user.name` |
50
+ | `--email EMAIL` | Author email | `git config user.email` |
51
+ | `--ruby-version VER` | Minimum Ruby version | current Ruby |
52
+
53
+ All options are prompted interactively if omitted.
54
+
55
+ ### `gempilot new`
56
+
57
+ Generate a class, module, or command in an existing gem. Run from the gem root.
58
+
59
+ ```bash
60
+ gempilot new class MyGem::Services::Authentication
61
+ gempilot new module MyGem::Middleware
62
+ gempilot new command deploy
63
+ ```
64
+
65
+ Creates the source file under `lib/` and a corresponding test file. For
66
+ commands, generates a CommandKit command class in `lib/<gem>/cli/commands/`.
67
+
68
+ ### `gempilot destroy`
69
+
70
+ Remove a class, module, or command. Cleans up empty parent directories.
71
+
72
+ ```bash
73
+ gempilot destroy class MyGem::Services::Authentication
74
+ gempilot destroy command deploy
75
+ ```
76
+
77
+ ### `gempilot bump`
78
+
79
+ Bump the version in `lib/<gem>/version.rb`.
80
+
81
+ ```bash
82
+ gempilot bump # patch (default)
83
+ gempilot bump minor
84
+ gempilot bump major
85
+ ```
86
+
87
+ ### `gempilot release`
88
+
89
+ Delegates to `rake release` to build and push the gem.
90
+
91
+ ### `gempilot console`
92
+
93
+ Delegates to `bin/console` for an interactive IRB session with the gem loaded.
94
+
95
+ ## Generated Gem Features
96
+
97
+ Every gem scaffolded by `gempilot create` includes:
98
+
99
+ - **Zeitwerk autoloading** with `LOADER` constant and `rake zeitwerk:validate`
100
+ - **Test framework** — Minitest or RSpec, with a Zeitwerk eager-load test
101
+ - **RuboCop** with `rubocop-claude`, `rubocop-performance`, `rubocop-rake`, and
102
+ framework-specific plugins (`rubocop-minitest` or `rubocop-rspec`)
103
+ - **GitHub Actions CI** running tests and RuboCop
104
+ - **Version management** rake tasks (see below)
105
+ - **`bin/console`** and **`bin/setup`** scripts
106
+ - **Gemspec** with `git ls-files` and glob fallback, MFA required for RubyGems
107
+
108
+ ### Version Management Tasks
109
+
110
+ Generated gems include rake tasks for the full version lifecycle:
111
+
112
+ | Task | Description |
113
+ |------|-------------|
114
+ | `rake version:current` | Display the current version |
115
+ | `rake version:bump` | Increment the patch version |
116
+ | `rake version:commit` | Commit the version file change |
117
+ | `rake version:tag` | Create a git tag for the version |
118
+ | `rake version:untag` | Delete the version git tag |
119
+ | `rake version:reset` | Reset the last version bump commit |
120
+ | `rake version:revert` | Revert the last version bump commit |
121
+ | `rake version:release` | Bump, commit, and tag (combined) |
122
+ | `rake version:unrelease` | Untag and reset (combined) |
123
+ | `rake version:github:release` | Push and create a GitHub release |
124
+ | `rake version:github:unrelease` | Delete the GitHub release |
125
+ | `rake version:github:list` | List GitHub releases |
126
+
127
+ ## Development
128
+
129
+ ```bash
130
+ git clone https://github.com/gillisd/gempilot.git
131
+ cd gempilot
132
+ bundle install
133
+ bundle exec rake
134
+ ```
135
+
136
+ `rake` runs the Minitest suite, RSpec suite, and RuboCop.
137
+
138
+ ## License
139
+
140
+ MIT License. See [LICENSE.txt](LICENSE.txt).
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ require "bundler/gem_tasks"
2
+ Bundler::GemHelper.install_tasks name: "gempilot"
3
+
4
+ require "minitest/test_task"
5
+ Minitest::TestTask.create
6
+
7
+ require "rspec/core/rake_task"
8
+ RSpec::Core::RakeTask.new(:spec)
9
+
10
+ require_relative 'lib/gempilot'
11
+
12
+ namespace :spec do
13
+ desc "Prints the specification suite in documentation format and exits"
14
+ task :print do
15
+ exec("rspec", "--format", "documentation", "--dry-run")
16
+ end
17
+ end
18
+
19
+ namespace :zeitwerk do
20
+ desc "Verify all files follow Zeitwerk naming conventions"
21
+ task :validate do
22
+ ruby "-e", <<~RUBY
23
+ require 'gempilot'
24
+ Gempilot::LOADER.eager_load(force: true)
25
+ puts 'Zeitwerk: All files loaded successfully.'
26
+ RUBY
27
+ end
28
+ end
29
+
30
+ require "rubocop/rake_task"
31
+ RuboCop::RakeTask.new do |t|
32
+ t.patterns = [
33
+ 'lib/*.rb',
34
+ 'lib/**/*.rb',
35
+ 'spec/*.rb',
36
+ 'spec/**/*.rb',
37
+ 'test/*.rb',
38
+ 'test/**/*.rb',
39
+ ]
40
+ end
41
+
42
+ Gempilot::VersionTask.new
43
+
44
+ task default: [:test, :spec, :rubocop]
@@ -0,0 +1,23 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "gempilot", require: false
6
+ <% if @test_framework == :minitest -%>
7
+ gem "minitest"
8
+ gem "minitest-reporters"
9
+ <% end -%>
10
+ gem "rake"
11
+ <% if @test_framework == :rspec -%>
12
+ gem "rspec", "~> 3.0"
13
+ <% end -%>
14
+ gem "rubocop"
15
+ gem "rubocop-claude"
16
+ <% if @test_framework == :minitest -%>
17
+ gem "rubocop-minitest"
18
+ <% end -%>
19
+ gem "rubocop-performance"
20
+ gem "rubocop-rake"
21
+ <% if @test_framework == :rspec -%>
22
+ gem "rubocop-rspec"
23
+ <% end -%>
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) <%= Time.now.year %> <%= @author %>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,25 @@
1
+ # <%= @module_name %>
2
+
3
+ <%= @summary %>
4
+
5
+ ## Installation
6
+
7
+ Install the gem and add to the application's Gemfile by executing:
8
+
9
+ $ bundle add <%= @gem_name %>
10
+
11
+ If bundler is not being used to manage dependencies, install the gem by executing:
12
+
13
+ $ gem install <%= @gem_name %>
14
+
15
+ ## Usage
16
+
17
+ TODO: Write usage instructions here.
18
+
19
+ ## Development
20
+
21
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests.
22
+
23
+ ## License
24
+
25
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,36 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ <% if @test_framework == :minitest -%>
4
+ require "minitest/test_task"
5
+ <% elsif @test_framework == :rspec -%>
6
+ require "rspec/core/rake_task"
7
+ <% end -%>
8
+
9
+ <% if @test_framework == :minitest -%>
10
+ Minitest::TestTask.create
11
+ <% elsif @test_framework == :rspec -%>
12
+ RSpec::Core::RakeTask.new(:spec)
13
+ <% end -%>
14
+
15
+ require "rubocop/rake_task"
16
+ RuboCop::RakeTask.new
17
+
18
+ require "gempilot/version_task"
19
+ Gempilot::VersionTask.new
20
+
21
+ namespace :zeitwerk do
22
+ desc "Verify all files follow Zeitwerk naming conventions"
23
+ task :validate do
24
+ ruby "-e", <<~RUBY
25
+ require '<%= @require_path %>'
26
+ <%= @module_name %>::LOADER.eager_load(force: true)
27
+ puts 'Zeitwerk: All files loaded successfully.'
28
+ RUBY
29
+ end
30
+ end
31
+
32
+ <% if @test_framework == :minitest -%>
33
+ task default: [:test, :rubocop]
34
+ <% elsif @test_framework == :rspec -%>
35
+ task default: [:spec, :rubocop]
36
+ <% end -%>
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "<%= @require_path %>"
5
+ require "irb"
6
+
7
+ IRB.start(__FILE__)
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
@@ -0,0 +1,33 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+ branches: [main, master]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ matrix:
17
+ ruby-version: ['<%= @ruby_version %>']
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - name: Set up Ruby
21
+ uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: ${{ matrix.ruby-version }}
24
+ bundler-cache: true
25
+ <% if @test_framework == :minitest -%>
26
+ - name: Run tests
27
+ run: bundle exec rake test
28
+ <% elsif @test_framework == :rspec -%>
29
+ - name: Run specs
30
+ run: bundle exec rake spec
31
+ <% end -%>
32
+ - name: Run RuboCop
33
+ run: bundle exec rake rubocop
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ Gemfile.lock
10
+ *.gem
11
+ .rspec_status
@@ -0,0 +1,209 @@
1
+ # ===========================================================================
2
+ # RuboCop Configuration
3
+ #
4
+ # Base: Stock RuboCop defaults
5
+ # AI guardrails: rubocop-claude plugin (all Claude/ cops + stricter metrics)
6
+ # Performance: rubocop-performance (with chain-hostile cops disabled)
7
+ #
8
+ # Philosophy: idiomatic Ruby, pipeline-style chaining, strict for AI agents,
9
+ # readable for humans.
10
+ # ===========================================================================
11
+
12
+ plugins:
13
+ - rubocop-claude
14
+ <% if @test_framework == :minitest -%>
15
+ - rubocop-minitest
16
+ <% elsif @test_framework == :rspec -%>
17
+ - rubocop-rspec
18
+ <% end -%>
19
+ - rubocop-performance
20
+ - rubocop-rake
21
+
22
+ AllCops:
23
+ NewCops: enable
24
+ TargetRubyVersion: <%= minor_version_for @ruby_version %>
25
+ Exclude:
26
+ - bin/*
27
+ - vendor/**/*
28
+ - lib/core_ext/**/*
29
+ - rakelib/project.rb
30
+ - rakelib/project_version.rb
31
+ - rakelib/version_tag.rb
32
+ - rakelib/github_release.rb
33
+ - rakelib/strict_shell.rb
34
+ <% if @hyphenated -%>
35
+ - lib/<%= @gem_name %>.rb
36
+ <% end -%>
37
+
38
+ # ===========================================================================
39
+ # Overrides from stock — personal style preferences
40
+ # ===========================================================================
41
+
42
+ # Double quotes everywhere. One less decision to make.
43
+ Style/StringLiterals:
44
+ EnforcedStyle: double_quotes
45
+
46
+ Style/StringLiteralsInInterpolation:
47
+ EnforcedStyle: double_quotes
48
+
49
+ # Frozen string literal is transitional cruft. Ruby 3.4 has chilled strings,
50
+ # full default freeze is coming in a future Ruby.
51
+ Style/FrozenStringLiteralComment:
52
+ EnforcedStyle: never
53
+
54
+ # Pipeline style. Chaining multi-line blocks is the whole point.
55
+ Style/MultilineBlockChain:
56
+ Enabled: false
57
+
58
+ # Block delimiters are a taste call. Pipeline code uses braces for chaining,
59
+ # do/end for side effects. No cop captures this nuance.
60
+ Style/BlockDelimiters:
61
+ Enabled: false
62
+
63
+ # Write arrays like arrays.
64
+ Style/WordArray:
65
+ Enabled: false
66
+
67
+ Style/SymbolArray:
68
+ Enabled: false
69
+
70
+ # Argument indentation: consistent 2-space indent, not aligned to first arg.
71
+ Layout/FirstArgumentIndentation:
72
+ EnforcedStyle: consistent
73
+
74
+ # Dot-aligned chaining. Dots form a visual column.
75
+ Layout/MultilineMethodCallIndentation:
76
+ EnforcedStyle: aligned
77
+
78
+ # ===========================================================================
79
+ # Overrides from rubocop-claude — loosen where pipeline style conflicts
80
+ # ===========================================================================
81
+
82
+ Claude/NoOverlyDefensiveCode:
83
+ MaxSafeNavigationChain: 2
84
+
85
+ Style/SafeNavigation:
86
+ MaxChainLength: 2
87
+
88
+ # Allow `return a, b` for tuple-style returns.
89
+ Style/RedundantReturn:
90
+ AllowMultipleReturnValues: true
91
+
92
+ # ===========================================================================
93
+ # Overrides from rubocop-performance — disable chain-hostile cops
94
+ # ===========================================================================
95
+
96
+ Performance/ChainArrayAllocation:
97
+ Enabled: false
98
+
99
+ Performance/MapMethodChain:
100
+ Enabled: false
101
+
102
+ # ===========================================================================
103
+ # Additional tightening — not set by stock or rubocop-claude
104
+ # ===========================================================================
105
+
106
+ # Short blocks push toward small chained steps instead of fat lambdas.
107
+ Metrics/BlockLength:
108
+ Max: 8
109
+ CountAsOne:
110
+ - array
111
+ - hash
112
+ - heredoc
113
+ - method_call
114
+ AllowedMethods:
115
+ - command
116
+ <% if @test_framework == :minitest -%>
117
+ - test
118
+ <% elsif @test_framework == :rspec -%>
119
+ - describe
120
+ - context
121
+ - shared_examples
122
+ - shared_examples_for
123
+ - shared_context
124
+ <% end -%>
125
+ Exclude:
126
+ - "<%= @gem_name %>.gemspec"
127
+ - "rakelib/**/*"
128
+
129
+ # Gemspec and rake files use patterns that trigger Claude cops legitimately.
130
+ Claude/NoFancyUnicode:
131
+ Exclude:
132
+ - "<%= @gem_name %>.gemspec"
133
+
134
+ Claude/MysteryRegex:
135
+ Exclude:
136
+ - "rakelib/**/*"
137
+
138
+ # Zeitwerk loaders are mutable by design — only flag literal mutable values.
139
+ Style/MutableConstant:
140
+ EnforcedStyle: literals
141
+
142
+ <% if @test_framework == :minitest -%>
143
+ # Minitest tests can legitimately need many assertions per method
144
+ # when verifying multi-step operations.
145
+ Minitest/MultipleAssertions:
146
+ Max: 10
147
+ <% elsif @test_framework == :rspec -%>
148
+ # Shared test contexts legitimately define many helpers.
149
+ RSpec/MultipleMemoizedHelpers:
150
+ Max: 10
151
+ <% end -%>
152
+
153
+ # Anonymous forwarding (*, **, &) breaks TruffleRuby, JRuby, and
154
+ # Ruby < 3.2. Named args are explicit and portable.
155
+ Style/ArgumentsForwarding:
156
+ Enabled: false
157
+
158
+ # Explicit begin/rescue/end is clearer than implicit method-body rescue.
159
+ Style/RedundantBegin:
160
+ Enabled: false
161
+
162
+ # Compact class names are fine for small files and tests.
163
+ Style/ClassAndModuleChildren:
164
+ Enabled: false
165
+
166
+ # Classes get rdoc.
167
+ Style/Documentation:
168
+ Enabled: true
169
+ Exclude:
170
+ <% if @test_framework == :minitest -%>
171
+ - "test/**/*"
172
+ <% elsif @test_framework == :rspec -%>
173
+ - "spec/**/*"
174
+ <% end -%>
175
+
176
+ # Trailing commas in multiline literals and arguments.
177
+ Style/TrailingCommaInArrayLiteral:
178
+ EnforcedStyleForMultiline: comma
179
+
180
+ Style/TrailingCommaInHashLiteral:
181
+ EnforcedStyleForMultiline: comma
182
+
183
+ Style/TrailingCommaInArguments:
184
+ EnforcedStyleForMultiline: comma
185
+
186
+ <% if @test_framework == :rspec -%>
187
+ # ===========================================================================
188
+ # RSpec — rubocop-rspec overrides
189
+ # ===========================================================================
190
+
191
+ # Not every describe block wraps a class.
192
+ RSpec/DescribeClass:
193
+ Enabled: false
194
+
195
+ # Subject placement is a readability call, not a rule.
196
+ RSpec/LeadingSubject:
197
+ Enabled: false
198
+
199
+ # Block style for expect { }.to change { } reads like a sentence.
200
+ RSpec/ExpectChange:
201
+ EnforcedStyle: block
202
+
203
+ RSpec/NamedSubject:
204
+ Enabled: false
205
+
206
+ # have_file_content matcher accepts a filename string in expect()
207
+ RSpec/ExpectActual:
208
+ Enabled: false
209
+ <% end -%>
@@ -0,0 +1 @@
1
+ <%= @ruby_version %>
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "<%= @require_path %>"
@@ -0,0 +1,27 @@
1
+ require_relative "lib/<%= @require_path %>/version"
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "<%= @gem_name %>"
5
+ spec.version = <%= @module_name %>::VERSION
6
+ spec.authors = ["<%= @author %>"]
7
+ spec.email = ["<%= @email %>"]
8
+ spec.summary = "<%= @summary %>"
9
+ spec.license = "MIT"
10
+ spec.required_ruby_version = ">= <%= @ruby_version %>"
11
+
12
+ gemspec_file = File.basename(__FILE__)
13
+ files = IO.popen(["git", "ls-files", "-z"], chdir: __dir__, err: IO::NULL) { |ls|
14
+ ls.readlines("\x0", chomp: true).reject do |f|
15
+ (f == gemspec_file) ||
16
+ f.start_with?("bin/", "test/", "spec/", "features/", ".git", "Gemfile")
17
+ end
18
+ }
19
+ files = Dir.glob("{lib,exe}/**/*").push("README.md", "LICENSE.txt", "Rakefile") if files.empty?
20
+ spec.files = files
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_dependency "zeitwerk"
26
+ spec.metadata["rubygems_mfa_required"] = "true"
27
+ end
@@ -0,0 +1,7 @@
1
+ <% @module_parts.each_with_index do |part, i| -%>
2
+ <%= " " * i %>module <%= part %>
3
+ <% end -%>
4
+ <%= " " * @module_parts.size %>VERSION = "0.0.1".freeze
5
+ <% @module_parts.size.times do |i| -%>
6
+ <%= " " * (@module_parts.size - 1 - i) %>end
7
+ <% end -%>
@@ -0,0 +1,16 @@
1
+ <% if @hyphenated -%>
2
+ require "<%= @require_path %>"
3
+ <% else -%>
4
+ require "zeitwerk"
5
+
6
+ ##
7
+ # Top-level namespace for the <%= @gem_name %> gem.
8
+ module <%= @module_name %>
9
+ LOADER = Zeitwerk::Loader.for_gem
10
+ LOADER.setup
11
+
12
+ ##
13
+ # Base error class for <%= @gem_name %>.
14
+ class Error < StandardError; end
15
+ end
16
+ <% end -%>
@@ -0,0 +1,20 @@
1
+ require "zeitwerk"
2
+
3
+ <% @module_parts.each_with_index do |part, i| -%>
4
+ <%= " " * i %>##
5
+ <% if i == 0 -%>
6
+ <%= " " * i %># Top-level namespace for the <%= @gem_name %> gem.
7
+ <% else -%>
8
+ <%= " " * i %># Extension namespace for <%= @module_parts[0..i].join("::") %>.
9
+ <% end -%>
10
+ <%= " " * i %>module <%= part %>
11
+ <% end -%>
12
+ <%= " " * @module_parts.size %>LOADER = Zeitwerk::Loader.for_gem_extension(<%= @base_module %>)
13
+ <%= " " * @module_parts.size %>LOADER.setup
14
+
15
+ <%= " " * @module_parts.size %>##
16
+ <%= " " * @module_parts.size %># Base error class for <%= @gem_name %>.
17
+ <%= " " * @module_parts.size %>class Error < StandardError; end
18
+ <% @module_parts.size.times do |i| -%>
19
+ <%= " " * (@module_parts.size - 1 - i) %>end
20
+ <% end -%>
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ RSpec.describe <%= @module_name %> do
2
+ it "has a version number" do
3
+ expect(<%= @module_name %>::VERSION).not_to be_nil
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ require "<%= @require_path %>"
2
+
3
+ RSpec.configure do |config|
4
+ config.example_status_persistence_file_path = ".rspec_status"
5
+ config.disable_monkey_patching!
6
+
7
+ config.expect_with :rspec do |c|
8
+ c.syntax = :expect
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ RSpec.describe "Zeitwerk" do
2
+ it "eager loads all files without errors" do
3
+ expect { <%= @module_name %>::LOADER.eager_load(force: true) }.not_to raise_error
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ require "test_helper"
2
+
3
+ class <%= @module_name %>Test < Minitest::Test
4
+ def test_that_it_has_a_version_number
5
+ refute_nil <%= @module_name %>::VERSION
6
+ end
7
+ end