supplies 0.1.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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +271 -0
- data/config/rubocop/base.yml +264 -0
- data/config/rubocop/performance.yml +153 -0
- data/config/rubocop/rails.yml +23 -0
- data/config/rubocop/rspec.yml +79 -0
- data/lib/generators/supplies/install_generator.rb +100 -0
- data/lib/generators/supplies/templates/rubocop.yml.tt +20 -0
- data/lib/supplies/functional.rb +116 -0
- data/lib/supplies/railtie.rb +15 -0
- data/lib/supplies/version.rb +5 -0
- data/lib/supplies.rb +39 -0
- metadata +169 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 9e11cbc6df13eb326ec0edb3173745f8587491ed655c118452d703f01ac6f63f
|
|
4
|
+
data.tar.gz: 62e11a3e89ff59487d48966ce4b7025e2b2e19ef501ed41d92330daa17e5e377
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c63d3e472513b2d286c9cc38849e39dafc25612889a5db4d7c468334d1f0eb9594e1415cc0b657ac97cde91c76059a0fda24de490890f64710b3811060050078
|
|
7
|
+
data.tar.gz: f3b9d9524a0e3d44fc0fea7e98eb637e3302b429d278b9486a4a218b12440b94aee0d4000eae4daa61aa9dec9e1669bddb2b7f5e55494192d8326b51b9a5448c
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Launch Supply
|
|
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.
|
data/README.md
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Supplies
|
|
2
|
+
|
|
3
|
+
Shared Ruby patterns, linting configuration, and AI workflows for Launch Supply Rails development.
|
|
4
|
+
|
|
5
|
+
## What's in This Repo
|
|
6
|
+
|
|
7
|
+
Supplies serves two purposes with **different distribution paths**:
|
|
8
|
+
|
|
9
|
+
| Purpose | Distribution | What it includes |
|
|
10
|
+
|---------|--------------|------------------|
|
|
11
|
+
| **Ruby code** | Public gem on RubyGems | `Supplies::Functional`, RuboCop configs, generators |
|
|
12
|
+
| **AI workflows** | Local clone only | CLAUDE.md, commands, CLI |
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
### For Ruby Code (Public Gem)
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
# Gemfile
|
|
20
|
+
gem 'supplies'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
bundle install
|
|
25
|
+
rails g supplies:install # Sets up RuboCop config
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### For AI Workflows (Local Clone)
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# One-time setup per developer machine
|
|
32
|
+
cd ~/Source/launch-supply
|
|
33
|
+
git clone git@github.com:launch-supply/supplies.git
|
|
34
|
+
|
|
35
|
+
# Add to ~/.zshrc or ~/.bashrc
|
|
36
|
+
export SUPPLIES_ROOT="$HOME/Source/launch-supply/supplies"
|
|
37
|
+
export PATH="$SUPPLIES_ROOT/bin:$PATH"
|
|
38
|
+
|
|
39
|
+
# Reload shell
|
|
40
|
+
source ~/.zshrc
|
|
41
|
+
|
|
42
|
+
# Initialize the hub (once per workspace)
|
|
43
|
+
cd ~/Source/launch-supply
|
|
44
|
+
supplies hub init
|
|
45
|
+
|
|
46
|
+
# Initialize each project
|
|
47
|
+
cd mission-control
|
|
48
|
+
supplies project init
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Terminology
|
|
52
|
+
|
|
53
|
+
| Term | Definition |
|
|
54
|
+
|------|------------|
|
|
55
|
+
| **Supply Hub** | Directory with shared CLAUDE.md symlink. All projects under it inherit shared workflows. |
|
|
56
|
+
| **Supplied Project** | A project initialized with `supplies project init`. Has its own CLAUDE.md with variables. |
|
|
57
|
+
| **Supply Root** | Local clone of this repo. Set via `$SUPPLIES_ROOT`. |
|
|
58
|
+
|
|
59
|
+
## Directory Structure
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
$SUPPLIES_ROOT/
|
|
63
|
+
├── lib/ # Published to RubyGems
|
|
64
|
+
│ ├── supplies.rb
|
|
65
|
+
│ └── supplies/
|
|
66
|
+
│ ├── functional.rb
|
|
67
|
+
│ └── version.rb
|
|
68
|
+
├── config/rubocop/ # Published to RubyGems
|
|
69
|
+
│ ├── base.yml
|
|
70
|
+
│ ├── rails.yml
|
|
71
|
+
│ └── ...
|
|
72
|
+
├── ai/ # Local clone only (NOT in gem)
|
|
73
|
+
│ ├── CLAUDE.md # Shared AI workflow base
|
|
74
|
+
│ └── commands/ # Shared command templates
|
|
75
|
+
└── bin/
|
|
76
|
+
└── supplies # CLI (local clone only)
|
|
77
|
+
|
|
78
|
+
Supply Hub (~/Source/launch-supply/)
|
|
79
|
+
├── CLAUDE.md → $SUPPLIES_ROOT/ai/CLAUDE.md
|
|
80
|
+
├── mission-control/
|
|
81
|
+
│ ├── CLAUDE.md # Project-specific
|
|
82
|
+
│ └── .claude/commands/ # Symlinks to shared
|
|
83
|
+
└── batch-table/
|
|
84
|
+
├── CLAUDE.md
|
|
85
|
+
└── .claude/commands/
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## CLI Commands
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Hub Commands (run from the hub directory)
|
|
92
|
+
supplies hub init # Create symlink to shared CLAUDE.md
|
|
93
|
+
supplies hub status # Show hub health and projects
|
|
94
|
+
|
|
95
|
+
# Project Commands (run from within a project)
|
|
96
|
+
supplies project init # Initialize project with CLAUDE.md and command symlinks
|
|
97
|
+
supplies project link # Add symlinks for new commands after updating supplies
|
|
98
|
+
supplies project status # Show project setup status
|
|
99
|
+
supplies project eject # Convert symlinked command to local file for customization
|
|
100
|
+
|
|
101
|
+
# Global Options
|
|
102
|
+
--dry-run # Preview without making changes
|
|
103
|
+
--quiet # Suppress non-essential output
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## How Variable Substitution Works
|
|
107
|
+
|
|
108
|
+
The base CLAUDE.md (in supplies) uses placeholder variables. Each project's CLAUDE.md defines the values:
|
|
109
|
+
|
|
110
|
+
**Base (supplies):**
|
|
111
|
+
```markdown
|
|
112
|
+
Create branch: `feature/PROJECT_PREFIX-123-description`
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Project (mission-control):**
|
|
116
|
+
```markdown
|
|
117
|
+
## Project Variables
|
|
118
|
+
- **PROJECT_PREFIX**: MC
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**No preprocessing required.** Claude Code loads both files, sees `PROJECT_PREFIX` in the instructions and `MC` as the defined value, and performs contextual substitution.
|
|
122
|
+
|
|
123
|
+
## Workflow Examples
|
|
124
|
+
|
|
125
|
+
### Setting Up a New Developer Machine
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Clone supplies
|
|
129
|
+
cd ~/Source/launch-supply
|
|
130
|
+
git clone git@github.com:launch-supply/supplies.git
|
|
131
|
+
|
|
132
|
+
# Add to shell profile
|
|
133
|
+
export SUPPLIES_ROOT="$HOME/Source/launch-supply/supplies"
|
|
134
|
+
export PATH="$SUPPLIES_ROOT/bin:$PATH"
|
|
135
|
+
|
|
136
|
+
# Initialize hub
|
|
137
|
+
supplies hub init
|
|
138
|
+
|
|
139
|
+
# Initialize each project
|
|
140
|
+
cd mission-control && supplies project init
|
|
141
|
+
cd ../batch-table && supplies project init
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Starting a New Rails Project
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
cd ~/Source/launch-supply
|
|
148
|
+
rails new my-app
|
|
149
|
+
cd my-app
|
|
150
|
+
|
|
151
|
+
# Add gem (Ruby code)
|
|
152
|
+
bundle add supplies
|
|
153
|
+
rails g supplies:install
|
|
154
|
+
|
|
155
|
+
# Add AI workflows
|
|
156
|
+
supplies project init
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### After Updating Supplies
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
# Pull latest changes
|
|
163
|
+
cd $SUPPLIES_ROOT
|
|
164
|
+
git pull
|
|
165
|
+
|
|
166
|
+
# Existing symlinks auto-update (CLAUDE.md, existing commands)
|
|
167
|
+
# Only need to run this if NEW commands were added:
|
|
168
|
+
cd ~/Source/launch-supply/mission-control
|
|
169
|
+
supplies project link
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Ejecting a Command for Customization
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# Convert symlink to local file
|
|
176
|
+
supplies project eject implement-issue
|
|
177
|
+
|
|
178
|
+
# Now you can customize .claude/commands/implement-issue.md
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Gem Features
|
|
184
|
+
|
|
185
|
+
### RuboCop Configuration
|
|
186
|
+
|
|
187
|
+
The generator creates `.rubocop.yml` that inherits from the gem:
|
|
188
|
+
|
|
189
|
+
```yaml
|
|
190
|
+
inherit_gem:
|
|
191
|
+
supplies:
|
|
192
|
+
- config/rubocop/base.yml
|
|
193
|
+
- config/rubocop/rails.yml
|
|
194
|
+
- config/rubocop/rspec.yml
|
|
195
|
+
- config/rubocop/performance.yml
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Updates to RuboCop rules propagate automatically when you update the gem.
|
|
199
|
+
|
|
200
|
+
### Supplies::Functional
|
|
201
|
+
|
|
202
|
+
Service object pattern support:
|
|
203
|
+
|
|
204
|
+
```ruby
|
|
205
|
+
class SendsWelcomeEmail
|
|
206
|
+
include Supplies::Functional
|
|
207
|
+
|
|
208
|
+
def initialize(user:)
|
|
209
|
+
@user = user
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def call
|
|
213
|
+
UserMailer.welcome(@user).deliver_now
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Usage
|
|
218
|
+
SendsWelcomeEmail.(user: user)
|
|
219
|
+
|
|
220
|
+
# Currying
|
|
221
|
+
send_email = SendsWelcomeEmail.curry(template: :welcome)
|
|
222
|
+
users.each { |user| send_email.(user: user) }
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## AI Workflow Features
|
|
228
|
+
|
|
229
|
+
### Shared CLAUDE.md
|
|
230
|
+
|
|
231
|
+
The base CLAUDE.md at `ai/CLAUDE.md` provides:
|
|
232
|
+
|
|
233
|
+
- TDD workflow (red-green-refactor)
|
|
234
|
+
- Linear integration patterns
|
|
235
|
+
- Git conventions (branch naming, commit messages)
|
|
236
|
+
- Code style guidelines
|
|
237
|
+
- PR creation workflow
|
|
238
|
+
|
|
239
|
+
### Shared Commands
|
|
240
|
+
|
|
241
|
+
Commands in `ai/commands/` include:
|
|
242
|
+
|
|
243
|
+
| Command | Purpose |
|
|
244
|
+
|---------|---------|
|
|
245
|
+
| `implement-issue` | Full issue implementation with TDD |
|
|
246
|
+
| `fix-ci-failure` | Diagnose and fix failing CI checks |
|
|
247
|
+
| `handle-pr-feedback` | Address review comments |
|
|
248
|
+
| `process-issues` | Start parallel issue processing |
|
|
249
|
+
| `orchestrate-issues` | Coordinate multiple sub-agents |
|
|
250
|
+
| `rebase-pr` | Rebase PRs with merge conflicts |
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Requirements
|
|
255
|
+
|
|
256
|
+
- Ruby 3.2+
|
|
257
|
+
- Rails 7.1+ (for generator)
|
|
258
|
+
- `linctl` CLI for Linear integration (optional)
|
|
259
|
+
|
|
260
|
+
## Development
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
cd supplies
|
|
264
|
+
bundle install
|
|
265
|
+
bundle exec rspec
|
|
266
|
+
bundle exec rubocop
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## License
|
|
270
|
+
|
|
271
|
+
MIT License
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# LsStandards Base RuboCop Configuration
|
|
4
|
+
# Core Ruby style rules for all projects
|
|
5
|
+
|
|
6
|
+
AllCops:
|
|
7
|
+
NewCops: enable
|
|
8
|
+
DisplayCopNames: true
|
|
9
|
+
TargetRubyVersion: 3.2
|
|
10
|
+
SuggestExtensions: false
|
|
11
|
+
Exclude:
|
|
12
|
+
- "bin/**/*"
|
|
13
|
+
- "db/schema.rb"
|
|
14
|
+
- "db/migrate/**/*"
|
|
15
|
+
- "config/importmap.rb"
|
|
16
|
+
- "node_modules/**/*"
|
|
17
|
+
- "tmp/**/*"
|
|
18
|
+
- "vendor/**/*"
|
|
19
|
+
|
|
20
|
+
# Layout Cops
|
|
21
|
+
Layout/ParameterAlignment:
|
|
22
|
+
EnforcedStyle: with_fixed_indentation
|
|
23
|
+
|
|
24
|
+
Layout/ArgumentAlignment:
|
|
25
|
+
EnforcedStyle: with_fixed_indentation
|
|
26
|
+
|
|
27
|
+
Layout/EmptyLinesAroundAttributeAccessor:
|
|
28
|
+
Enabled: true
|
|
29
|
+
|
|
30
|
+
Layout/SpaceAroundMethodCallOperator:
|
|
31
|
+
Enabled: true
|
|
32
|
+
|
|
33
|
+
Layout/MultilineMethodCallIndentation:
|
|
34
|
+
EnforcedStyle: indented
|
|
35
|
+
|
|
36
|
+
Layout/MultilineOperationIndentation:
|
|
37
|
+
EnforcedStyle: indented
|
|
38
|
+
|
|
39
|
+
Layout/FirstArrayElementIndentation:
|
|
40
|
+
EnforcedStyle: consistent
|
|
41
|
+
|
|
42
|
+
Layout/FirstHashElementIndentation:
|
|
43
|
+
EnforcedStyle: consistent
|
|
44
|
+
|
|
45
|
+
Layout/HashAlignment:
|
|
46
|
+
EnforcedLastArgumentHashStyle: ignore_explicit
|
|
47
|
+
|
|
48
|
+
Layout/FirstArrayElementLineBreak:
|
|
49
|
+
Enabled: true
|
|
50
|
+
|
|
51
|
+
Layout/FirstHashElementLineBreak:
|
|
52
|
+
Enabled: true
|
|
53
|
+
|
|
54
|
+
Layout/FirstMethodArgumentLineBreak:
|
|
55
|
+
Enabled: false
|
|
56
|
+
|
|
57
|
+
Layout/FirstMethodParameterLineBreak:
|
|
58
|
+
Enabled: true
|
|
59
|
+
|
|
60
|
+
Layout/MultilineAssignmentLayout:
|
|
61
|
+
Enabled: true
|
|
62
|
+
|
|
63
|
+
# Lint Cops
|
|
64
|
+
Lint/RaiseException:
|
|
65
|
+
Enabled: true
|
|
66
|
+
|
|
67
|
+
Lint/StructNewOverride:
|
|
68
|
+
Enabled: true
|
|
69
|
+
|
|
70
|
+
Lint/DeprecatedOpenSSLConstant:
|
|
71
|
+
Enabled: true
|
|
72
|
+
|
|
73
|
+
Lint/MixedRegexpCaptureTypes:
|
|
74
|
+
Enabled: true
|
|
75
|
+
|
|
76
|
+
Lint/AssignmentInCondition:
|
|
77
|
+
Enabled: false
|
|
78
|
+
|
|
79
|
+
Lint/EmptyBlock:
|
|
80
|
+
Enabled: false
|
|
81
|
+
|
|
82
|
+
Lint/MissingCopEnableDirective:
|
|
83
|
+
Exclude:
|
|
84
|
+
- "spec/fixtures/**/*"
|
|
85
|
+
|
|
86
|
+
# Metrics Cops - All disabled per team agreement
|
|
87
|
+
Metrics/AbcSize:
|
|
88
|
+
Enabled: false
|
|
89
|
+
|
|
90
|
+
Metrics/BlockLength:
|
|
91
|
+
Enabled: false
|
|
92
|
+
|
|
93
|
+
Metrics/ClassLength:
|
|
94
|
+
Enabled: false
|
|
95
|
+
|
|
96
|
+
Metrics/MethodLength:
|
|
97
|
+
Enabled: false
|
|
98
|
+
|
|
99
|
+
Metrics/ModuleLength:
|
|
100
|
+
Enabled: false
|
|
101
|
+
|
|
102
|
+
Metrics/ParameterLists:
|
|
103
|
+
Enabled: false
|
|
104
|
+
|
|
105
|
+
Metrics/CyclomaticComplexity:
|
|
106
|
+
Enabled: false
|
|
107
|
+
|
|
108
|
+
Metrics/PerceivedComplexity:
|
|
109
|
+
Enabled: false
|
|
110
|
+
|
|
111
|
+
# Naming Cops
|
|
112
|
+
Naming/PredicatePrefix:
|
|
113
|
+
Enabled: false
|
|
114
|
+
|
|
115
|
+
Naming/AccessorMethodName:
|
|
116
|
+
Enabled: false
|
|
117
|
+
|
|
118
|
+
Naming/VariableNumber:
|
|
119
|
+
Enabled: false
|
|
120
|
+
|
|
121
|
+
Naming/FileName:
|
|
122
|
+
Exclude:
|
|
123
|
+
- "spec/views/**/*_spec.rb"
|
|
124
|
+
|
|
125
|
+
# Style Cops
|
|
126
|
+
Style/Documentation:
|
|
127
|
+
Enabled: false
|
|
128
|
+
|
|
129
|
+
Style/BlockDelimiters:
|
|
130
|
+
EnforcedStyle: semantic
|
|
131
|
+
AllowBracesOnProceduralOneLiners: true
|
|
132
|
+
FunctionalMethods:
|
|
133
|
+
- let
|
|
134
|
+
- let!
|
|
135
|
+
- subject
|
|
136
|
+
- watch
|
|
137
|
+
- find
|
|
138
|
+
Exclude:
|
|
139
|
+
- "spec/factories/*.rb"
|
|
140
|
+
|
|
141
|
+
Style/FormatString:
|
|
142
|
+
EnforcedStyle: percent
|
|
143
|
+
|
|
144
|
+
Style/FormatStringToken:
|
|
145
|
+
Enabled: false
|
|
146
|
+
|
|
147
|
+
Style/DoubleNegation:
|
|
148
|
+
Enabled: false
|
|
149
|
+
|
|
150
|
+
Style/EmptyMethod:
|
|
151
|
+
EnforcedStyle: expanded
|
|
152
|
+
|
|
153
|
+
Style/Alias:
|
|
154
|
+
EnforcedStyle: prefer_alias_method
|
|
155
|
+
|
|
156
|
+
Style/NumericPredicate:
|
|
157
|
+
EnforcedStyle: comparison
|
|
158
|
+
|
|
159
|
+
Style/RegexpLiteral:
|
|
160
|
+
Enabled: false
|
|
161
|
+
|
|
162
|
+
Style/ModuleFunction:
|
|
163
|
+
EnforcedStyle: extend_self
|
|
164
|
+
|
|
165
|
+
Style/TrailingCommaInArguments:
|
|
166
|
+
EnforcedStyleForMultiline: comma
|
|
167
|
+
|
|
168
|
+
Style/TrailingCommaInArrayLiteral:
|
|
169
|
+
EnforcedStyleForMultiline: comma
|
|
170
|
+
|
|
171
|
+
Style/TrailingCommaInHashLiteral:
|
|
172
|
+
EnforcedStyleForMultiline: comma
|
|
173
|
+
|
|
174
|
+
Style/MultilineBlockChain:
|
|
175
|
+
Enabled: false
|
|
176
|
+
|
|
177
|
+
Style/ExponentialNotation:
|
|
178
|
+
Enabled: true
|
|
179
|
+
EnforcedStyle: scientific
|
|
180
|
+
|
|
181
|
+
Style/GuardClause:
|
|
182
|
+
MinBodyLength: 3
|
|
183
|
+
|
|
184
|
+
Style/IfUnlessModifier:
|
|
185
|
+
Enabled: false
|
|
186
|
+
|
|
187
|
+
Style/InlineComment:
|
|
188
|
+
Enabled: true
|
|
189
|
+
Exclude:
|
|
190
|
+
- "config/importmap.rb"
|
|
191
|
+
- "Gemfile"
|
|
192
|
+
|
|
193
|
+
Style/Lambda:
|
|
194
|
+
EnforcedStyle: literal
|
|
195
|
+
|
|
196
|
+
Style/LambdaCall:
|
|
197
|
+
EnforcedStyle: braces
|
|
198
|
+
|
|
199
|
+
Style/AutoResourceCleanup:
|
|
200
|
+
Enabled: true
|
|
201
|
+
|
|
202
|
+
Style/CollectionMethods:
|
|
203
|
+
Enabled: true
|
|
204
|
+
|
|
205
|
+
Style/Copyright:
|
|
206
|
+
Enabled: false
|
|
207
|
+
|
|
208
|
+
Style/DocumentationMethod:
|
|
209
|
+
Enabled: false
|
|
210
|
+
Exclude:
|
|
211
|
+
- "spec/**/*"
|
|
212
|
+
- "test/**/*"
|
|
213
|
+
|
|
214
|
+
Style/MethodCallWithArgsParentheses:
|
|
215
|
+
Enabled: false
|
|
216
|
+
|
|
217
|
+
Style/MethodCalledOnDoEndBlock:
|
|
218
|
+
Enabled: true
|
|
219
|
+
Exclude:
|
|
220
|
+
- "spec/**/*"
|
|
221
|
+
|
|
222
|
+
Style/MissingElse:
|
|
223
|
+
Enabled: false
|
|
224
|
+
|
|
225
|
+
Style/OptionHash:
|
|
226
|
+
Enabled: false
|
|
227
|
+
|
|
228
|
+
Style/ReturnNil:
|
|
229
|
+
Enabled: true
|
|
230
|
+
|
|
231
|
+
Style/Send:
|
|
232
|
+
Enabled: true
|
|
233
|
+
Exclude:
|
|
234
|
+
- "spec/**/*"
|
|
235
|
+
|
|
236
|
+
Style/StringMethods:
|
|
237
|
+
Enabled: false
|
|
238
|
+
|
|
239
|
+
Style/SignalException:
|
|
240
|
+
EnforcedStyle: semantic
|
|
241
|
+
|
|
242
|
+
Style/SingleLineBlockParams:
|
|
243
|
+
Enabled: false
|
|
244
|
+
|
|
245
|
+
Style/OpenStructUse:
|
|
246
|
+
Enabled: false
|
|
247
|
+
|
|
248
|
+
Style/HashEachMethods:
|
|
249
|
+
Enabled: true
|
|
250
|
+
|
|
251
|
+
Style/HashTransformKeys:
|
|
252
|
+
Enabled: true
|
|
253
|
+
|
|
254
|
+
Style/HashTransformValues:
|
|
255
|
+
Enabled: true
|
|
256
|
+
|
|
257
|
+
Style/RedundantRegexpCharacterClass:
|
|
258
|
+
Enabled: true
|
|
259
|
+
|
|
260
|
+
Style/RedundantRegexpEscape:
|
|
261
|
+
Enabled: true
|
|
262
|
+
|
|
263
|
+
Style/SlicingWithRange:
|
|
264
|
+
Enabled: true
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# LsStandards Performance RuboCop Configuration
|
|
4
|
+
# Performance-focused rules for optimized Ruby code
|
|
5
|
+
|
|
6
|
+
inherit_from:
|
|
7
|
+
- base.yml
|
|
8
|
+
|
|
9
|
+
# Performance Cops
|
|
10
|
+
Performance:
|
|
11
|
+
Enabled: true
|
|
12
|
+
|
|
13
|
+
Performance/AncestorsInclude:
|
|
14
|
+
Enabled: true
|
|
15
|
+
|
|
16
|
+
Performance/BigDecimalWithNumericArgument:
|
|
17
|
+
Enabled: true
|
|
18
|
+
|
|
19
|
+
Performance/BlockGivenWithExplicitBlock:
|
|
20
|
+
Enabled: true
|
|
21
|
+
|
|
22
|
+
Performance/CaseWhenSplat:
|
|
23
|
+
Enabled: true
|
|
24
|
+
|
|
25
|
+
Performance/Casecmp:
|
|
26
|
+
Enabled: true
|
|
27
|
+
|
|
28
|
+
Performance/ChainArrayAllocation:
|
|
29
|
+
Enabled: true
|
|
30
|
+
|
|
31
|
+
Performance/CollectionLiteralInLoop:
|
|
32
|
+
Enabled: true
|
|
33
|
+
MinSize: 2
|
|
34
|
+
|
|
35
|
+
Performance/CompareWithBlock:
|
|
36
|
+
Enabled: true
|
|
37
|
+
|
|
38
|
+
Performance/ConcurrentMonotonicTime:
|
|
39
|
+
Enabled: true
|
|
40
|
+
|
|
41
|
+
Performance/ConstantRegexp:
|
|
42
|
+
Enabled: true
|
|
43
|
+
|
|
44
|
+
Performance/Count:
|
|
45
|
+
Enabled: true
|
|
46
|
+
|
|
47
|
+
Performance/DeletePrefix:
|
|
48
|
+
Enabled: true
|
|
49
|
+
|
|
50
|
+
Performance/DeleteSuffix:
|
|
51
|
+
Enabled: true
|
|
52
|
+
|
|
53
|
+
Performance/Detect:
|
|
54
|
+
Enabled: true
|
|
55
|
+
|
|
56
|
+
Performance/DoubleStartEndWith:
|
|
57
|
+
Enabled: true
|
|
58
|
+
|
|
59
|
+
Performance/EndWith:
|
|
60
|
+
Enabled: true
|
|
61
|
+
|
|
62
|
+
Performance/FixedSize:
|
|
63
|
+
Enabled: true
|
|
64
|
+
|
|
65
|
+
Performance/FlatMap:
|
|
66
|
+
Enabled: true
|
|
67
|
+
|
|
68
|
+
Performance/InefficientHashSearch:
|
|
69
|
+
Enabled: true
|
|
70
|
+
|
|
71
|
+
Performance/IoReadlines:
|
|
72
|
+
Enabled: true
|
|
73
|
+
|
|
74
|
+
Performance/MapCompact:
|
|
75
|
+
Enabled: true
|
|
76
|
+
|
|
77
|
+
Performance/MapMethodChain:
|
|
78
|
+
Enabled: true
|
|
79
|
+
|
|
80
|
+
Performance/MethodObjectAsBlock:
|
|
81
|
+
Enabled: true
|
|
82
|
+
|
|
83
|
+
Performance/OpenStruct:
|
|
84
|
+
Enabled: true
|
|
85
|
+
|
|
86
|
+
Performance/RangeInclude:
|
|
87
|
+
Enabled: true
|
|
88
|
+
|
|
89
|
+
Performance/RedundantBlockCall:
|
|
90
|
+
Enabled: true
|
|
91
|
+
|
|
92
|
+
Performance/RedundantEqualityComparisonBlock:
|
|
93
|
+
Enabled: true
|
|
94
|
+
|
|
95
|
+
Performance/RedundantMatch:
|
|
96
|
+
Enabled: true
|
|
97
|
+
|
|
98
|
+
Performance/RedundantMerge:
|
|
99
|
+
Enabled: true
|
|
100
|
+
|
|
101
|
+
Performance/RedundantSortBlock:
|
|
102
|
+
Enabled: true
|
|
103
|
+
|
|
104
|
+
Performance/RedundantSplitRegexpArgument:
|
|
105
|
+
Enabled: true
|
|
106
|
+
|
|
107
|
+
Performance/RedundantStringChars:
|
|
108
|
+
Enabled: true
|
|
109
|
+
|
|
110
|
+
Performance/RegexpMatch:
|
|
111
|
+
Enabled: true
|
|
112
|
+
|
|
113
|
+
Performance/ReverseEach:
|
|
114
|
+
Enabled: true
|
|
115
|
+
|
|
116
|
+
Performance/ReverseFirst:
|
|
117
|
+
Enabled: true
|
|
118
|
+
|
|
119
|
+
Performance/SelectMap:
|
|
120
|
+
Enabled: true
|
|
121
|
+
|
|
122
|
+
Performance/Size:
|
|
123
|
+
Enabled: true
|
|
124
|
+
|
|
125
|
+
Performance/SortReverse:
|
|
126
|
+
Enabled: true
|
|
127
|
+
|
|
128
|
+
Performance/Squeeze:
|
|
129
|
+
Enabled: true
|
|
130
|
+
|
|
131
|
+
Performance/StartWith:
|
|
132
|
+
Enabled: true
|
|
133
|
+
|
|
134
|
+
Performance/StringIdentifierArgument:
|
|
135
|
+
Enabled: true
|
|
136
|
+
|
|
137
|
+
Performance/StringInclude:
|
|
138
|
+
Enabled: true
|
|
139
|
+
|
|
140
|
+
Performance/StringReplacement:
|
|
141
|
+
Enabled: true
|
|
142
|
+
|
|
143
|
+
Performance/Sum:
|
|
144
|
+
Enabled: true
|
|
145
|
+
|
|
146
|
+
Performance/TimesMap:
|
|
147
|
+
Enabled: true
|
|
148
|
+
|
|
149
|
+
Performance/UnfreezeString:
|
|
150
|
+
Enabled: true
|
|
151
|
+
|
|
152
|
+
Performance/UriDefaultParser:
|
|
153
|
+
Enabled: true
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# LsStandards Rails RuboCop Configuration
|
|
4
|
+
# Rails-specific rules for web applications
|
|
5
|
+
|
|
6
|
+
require:
|
|
7
|
+
- rubocop-rails
|
|
8
|
+
|
|
9
|
+
inherit_from:
|
|
10
|
+
- base.yml
|
|
11
|
+
|
|
12
|
+
# Rails Cops
|
|
13
|
+
Rails/FindEach:
|
|
14
|
+
Enabled: false
|
|
15
|
+
|
|
16
|
+
Rails/SkipsModelValidations:
|
|
17
|
+
Enabled: false
|
|
18
|
+
|
|
19
|
+
Rails/RedundantActiveRecordAllMethod:
|
|
20
|
+
Enabled: false
|
|
21
|
+
|
|
22
|
+
Rails/FilePath:
|
|
23
|
+
Enabled: false
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# LsStandards RSpec RuboCop Configuration
|
|
4
|
+
# Testing-specific rules for RSpec test suites
|
|
5
|
+
|
|
6
|
+
inherit_from:
|
|
7
|
+
- base.yml
|
|
8
|
+
|
|
9
|
+
# RSpec Cops
|
|
10
|
+
RSpec/ExampleLength:
|
|
11
|
+
Enabled: false
|
|
12
|
+
|
|
13
|
+
RSpec/MessageSpies:
|
|
14
|
+
Enabled: false
|
|
15
|
+
|
|
16
|
+
RSpec/NestedGroups:
|
|
17
|
+
Enabled: false
|
|
18
|
+
|
|
19
|
+
RSpec/MultipleExpectations:
|
|
20
|
+
Enabled: false
|
|
21
|
+
|
|
22
|
+
RSpec/MultipleMemoizedHelpers:
|
|
23
|
+
Enabled: false
|
|
24
|
+
|
|
25
|
+
RSpec/ContextWording:
|
|
26
|
+
Enabled: false
|
|
27
|
+
|
|
28
|
+
RSpec/EmptyExampleGroup:
|
|
29
|
+
Enabled: false
|
|
30
|
+
|
|
31
|
+
RSpec/LetSetup:
|
|
32
|
+
Enabled: false
|
|
33
|
+
|
|
34
|
+
RSpec/InstanceVariable:
|
|
35
|
+
Enabled: false
|
|
36
|
+
|
|
37
|
+
RSpec/MessageChain:
|
|
38
|
+
Enabled: false
|
|
39
|
+
|
|
40
|
+
RSpec/DescribedClass:
|
|
41
|
+
Enabled: false
|
|
42
|
+
|
|
43
|
+
RSpec/VerifiedDoubles:
|
|
44
|
+
IgnoreNameless: true
|
|
45
|
+
IgnoreSymbolicNames: true
|
|
46
|
+
|
|
47
|
+
RSpec/DescribeClass:
|
|
48
|
+
Enabled: false
|
|
49
|
+
|
|
50
|
+
RSpec/RepeatedExample:
|
|
51
|
+
Exclude:
|
|
52
|
+
- "spec/integration/**/*"
|
|
53
|
+
|
|
54
|
+
RSpec/RepeatedDescription:
|
|
55
|
+
Exclude:
|
|
56
|
+
- "spec/integration/**/*"
|
|
57
|
+
|
|
58
|
+
RSpec/ScatteredSetup:
|
|
59
|
+
Exclude:
|
|
60
|
+
- "spec/integration/**/*"
|
|
61
|
+
|
|
62
|
+
RSpec/StubbedMock:
|
|
63
|
+
Enabled: false
|
|
64
|
+
|
|
65
|
+
RSpec/NoExpectationExample:
|
|
66
|
+
Enabled: false
|
|
67
|
+
|
|
68
|
+
RSpec/SpecFilePathFormat:
|
|
69
|
+
Enabled: false
|
|
70
|
+
|
|
71
|
+
RSpec/SpecFilePathSuffix:
|
|
72
|
+
Enabled: false
|
|
73
|
+
|
|
74
|
+
# Capybara Cops
|
|
75
|
+
Capybara/SpecificActions:
|
|
76
|
+
Enabled: false
|
|
77
|
+
|
|
78
|
+
Capybara/ClickLinkOrButtonStyle:
|
|
79
|
+
Enabled: false
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
|
|
5
|
+
module Supplies
|
|
6
|
+
module Generators
|
|
7
|
+
# Installs Supplies RuboCop configuration into a Rails application.
|
|
8
|
+
#
|
|
9
|
+
# This generator:
|
|
10
|
+
# - Adds RuboCop gems to Gemfile (development/test group)
|
|
11
|
+
# - Creates `.rubocop.yml` that inherits from the gem's configurations
|
|
12
|
+
#
|
|
13
|
+
# RuboCop rules auto-update when the gem is updated.
|
|
14
|
+
#
|
|
15
|
+
# AI workflows (CLAUDE.md, commands) are managed separately via the
|
|
16
|
+
# `supplies` CLI from a local clone of the supplies repo.
|
|
17
|
+
#
|
|
18
|
+
# @example Running the generator
|
|
19
|
+
# rails g supplies:install
|
|
20
|
+
#
|
|
21
|
+
class InstallGenerator < Rails::Generators::Base
|
|
22
|
+
source_root File.expand_path('templates', __dir__)
|
|
23
|
+
|
|
24
|
+
desc 'Installs Supplies RuboCop configuration'
|
|
25
|
+
|
|
26
|
+
RUBOCOP_GEMS = [
|
|
27
|
+
"gem 'rubocop', '~> 1.60', require: false",
|
|
28
|
+
"gem 'rubocop-capybara', '~> 2.20', require: false",
|
|
29
|
+
"gem 'rubocop-factory_bot', '~> 2.25', require: false",
|
|
30
|
+
"gem 'rubocop-md', '~> 2.0', require: false",
|
|
31
|
+
"gem 'rubocop-performance', '~> 1.20', require: false",
|
|
32
|
+
"gem 'rubocop-rails', '~> 2.23', require: false",
|
|
33
|
+
"gem 'rubocop-rspec', '~> 3.8', require: false",
|
|
34
|
+
].freeze
|
|
35
|
+
|
|
36
|
+
# Adds RuboCop gems to the Gemfile in the development/test group.
|
|
37
|
+
#
|
|
38
|
+
# @return [void]
|
|
39
|
+
def add_rubocop_gems
|
|
40
|
+
gemfile_content = File.read('Gemfile')
|
|
41
|
+
|
|
42
|
+
# Check if gems are already present
|
|
43
|
+
if gemfile_content.include?("gem 'rubocop'") || gemfile_content.include?('gem "rubocop"')
|
|
44
|
+
say 'RuboCop gems already in Gemfile, skipping...', :yellow
|
|
45
|
+
return
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
gem_entries = RUBOCOP_GEMS.map { |g| " #{g}" }.join("\n")
|
|
49
|
+
append_to_file 'Gemfile', <<~GEMS
|
|
50
|
+
|
|
51
|
+
# RuboCop linting (added by supplies:install)
|
|
52
|
+
group :development, :test do
|
|
53
|
+
#{gem_entries}
|
|
54
|
+
end
|
|
55
|
+
GEMS
|
|
56
|
+
|
|
57
|
+
say 'Added RuboCop gems to Gemfile', :green
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Creates the .rubocop.yml configuration file.
|
|
61
|
+
#
|
|
62
|
+
# @return [void]
|
|
63
|
+
def create_rubocop_config
|
|
64
|
+
template 'rubocop.yml.tt', '.rubocop.yml'
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Displays post-install instructions.
|
|
68
|
+
#
|
|
69
|
+
# @return [void]
|
|
70
|
+
def show_post_install_message
|
|
71
|
+
say ''
|
|
72
|
+
say '=' * 60, :green
|
|
73
|
+
say 'Supplies RuboCop configuration installed!', :green
|
|
74
|
+
say '=' * 60, :green
|
|
75
|
+
say ''
|
|
76
|
+
say 'Files created/modified:'
|
|
77
|
+
say ' - Gemfile (RuboCop gems added to development/test group)'
|
|
78
|
+
say ' - .rubocop.yml (inherits from gem - auto-updates)'
|
|
79
|
+
say ''
|
|
80
|
+
say 'Next steps:', :yellow
|
|
81
|
+
say " 1. Run 'bundle install' to install RuboCop gems"
|
|
82
|
+
say " 2. Run 'bundle exec rubocop' to check your code"
|
|
83
|
+
say " 3. Run 'bundle exec rubocop -a' to auto-fix issues"
|
|
84
|
+
say ''
|
|
85
|
+
say 'For AI workflows (CLAUDE.md, commands), use the supplies CLI:', :yellow
|
|
86
|
+
say ' supplies project init'
|
|
87
|
+
say ''
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
# Returns the current Ruby version (major.minor).
|
|
93
|
+
#
|
|
94
|
+
# @return [String] the Ruby version
|
|
95
|
+
def ruby_version
|
|
96
|
+
RUBY_VERSION.split('.').take(2).join('.')
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# RuboCop configuration
|
|
4
|
+
# Generated by supplies gem - inherits from gem, auto-updates
|
|
5
|
+
#
|
|
6
|
+
# To customize, add your overrides below.
|
|
7
|
+
# See: https://docs.rubocop.org/rubocop/configuration.html
|
|
8
|
+
|
|
9
|
+
inherit_gem:
|
|
10
|
+
supplies:
|
|
11
|
+
- config/rubocop/base.yml
|
|
12
|
+
- config/rubocop/rails.yml
|
|
13
|
+
- config/rubocop/rspec.yml
|
|
14
|
+
- config/rubocop/performance.yml
|
|
15
|
+
|
|
16
|
+
AllCops:
|
|
17
|
+
TargetRubyVersion: <%= ruby_version %>
|
|
18
|
+
NewCops: enable
|
|
19
|
+
|
|
20
|
+
# Add your project-specific overrides below:
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Supplies
|
|
4
|
+
# Functional module for service objects that provides a consistent `.call`
|
|
5
|
+
# class method interface and support for currying.
|
|
6
|
+
#
|
|
7
|
+
# This module enables the service object pattern where business logic is
|
|
8
|
+
# encapsulated in classes with a single public `#call` method. Including
|
|
9
|
+
# this module provides:
|
|
10
|
+
#
|
|
11
|
+
# - A class-level `.call` method that instantiates and invokes the service
|
|
12
|
+
# - A `.curry` method for partial application of arguments
|
|
13
|
+
#
|
|
14
|
+
# @example Basic usage
|
|
15
|
+
# class SendsWelcomeEmail
|
|
16
|
+
# include Supplies::Functional
|
|
17
|
+
#
|
|
18
|
+
# def initialize(user:)
|
|
19
|
+
# @user = user
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# def call
|
|
23
|
+
# UserMailer.welcome(@user).deliver_now
|
|
24
|
+
# end
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# # Invoke with class method
|
|
28
|
+
# SendsWelcomeEmail.call(user: user)
|
|
29
|
+
#
|
|
30
|
+
# @example Using curry for partial application
|
|
31
|
+
# class SendsNotification
|
|
32
|
+
# include Supplies::Functional
|
|
33
|
+
#
|
|
34
|
+
# def initialize(user:, message:)
|
|
35
|
+
# @user = user
|
|
36
|
+
# @message = message
|
|
37
|
+
# end
|
|
38
|
+
#
|
|
39
|
+
# def call
|
|
40
|
+
# NotificationService.send(@user, @message)
|
|
41
|
+
# end
|
|
42
|
+
# end
|
|
43
|
+
#
|
|
44
|
+
# # Create a curried version with preset message
|
|
45
|
+
# notify_welcome = SendsNotification.curry(message: "Welcome!")
|
|
46
|
+
# users.each { |user| notify_welcome.call(user: user) }
|
|
47
|
+
#
|
|
48
|
+
# @example With block support
|
|
49
|
+
# class ProcessesItems
|
|
50
|
+
# include Supplies::Functional
|
|
51
|
+
#
|
|
52
|
+
# def initialize(items:)
|
|
53
|
+
# @items = items
|
|
54
|
+
# end
|
|
55
|
+
#
|
|
56
|
+
# def call(&block)
|
|
57
|
+
# @items.each { |item| block.call(item) }
|
|
58
|
+
# end
|
|
59
|
+
# end
|
|
60
|
+
#
|
|
61
|
+
# ProcessesItems.call(items: items) { |item| puts item }
|
|
62
|
+
#
|
|
63
|
+
# @see ADR-0001 for the full architectural decision record
|
|
64
|
+
module Functional
|
|
65
|
+
# Hook called when this module is included in a class.
|
|
66
|
+
# Extends the including class with ClassMethods.
|
|
67
|
+
#
|
|
68
|
+
# @param base [Class] the class including this module
|
|
69
|
+
def self.included(base)
|
|
70
|
+
base.extend(ClassMethods)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Class methods added to any class that includes Functional.
|
|
74
|
+
module ClassMethods
|
|
75
|
+
# Instantiates the service and calls it with the provided arguments.
|
|
76
|
+
#
|
|
77
|
+
# This method supports both positional and keyword arguments, as well
|
|
78
|
+
# as blocks that are passed through to the instance's `#call` method.
|
|
79
|
+
#
|
|
80
|
+
# @param args [Array] positional arguments passed to initialize
|
|
81
|
+
# @param kwargs [Hash] keyword arguments passed to initialize
|
|
82
|
+
# @param block [Proc] optional block passed to the instance's call method
|
|
83
|
+
# @return [Object] the return value of the instance's `#call` method
|
|
84
|
+
#
|
|
85
|
+
# @example
|
|
86
|
+
# SendsEmail.call(user: user, template: :welcome)
|
|
87
|
+
#
|
|
88
|
+
# @example With hash as first argument (merged with kwargs)
|
|
89
|
+
# base_args = { user: user }
|
|
90
|
+
# SendsEmail.call(base_args, template: :welcome)
|
|
91
|
+
def call(*args, **kwargs, &)
|
|
92
|
+
if args.first.is_a?(Hash)
|
|
93
|
+
# Merge hash with kwargs (kwargs take precedence)
|
|
94
|
+
kwargs = args.shift.merge(kwargs)
|
|
95
|
+
end
|
|
96
|
+
new(*args, **kwargs).(&)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Creates a lambda that calls the service with preset arguments.
|
|
100
|
+
#
|
|
101
|
+
# This enables partial application, where some arguments are provided
|
|
102
|
+
# upfront and the rest are supplied later when the lambda is called.
|
|
103
|
+
#
|
|
104
|
+
# @param args [Hash] keyword arguments to preset
|
|
105
|
+
# @return [Proc] a lambda that accepts remaining arguments and calls the service
|
|
106
|
+
#
|
|
107
|
+
# @example
|
|
108
|
+
# # Preset the admin_user, supply user later
|
|
109
|
+
# send_reset = SendsPasswordResetEmail.curry(admin_user: admin)
|
|
110
|
+
# users.each { |user| send_reset.call(user: user) }
|
|
111
|
+
def curry(**args)
|
|
112
|
+
->(**next_args) { call(**args, **next_args) }
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/railtie'
|
|
4
|
+
|
|
5
|
+
module Supplies
|
|
6
|
+
# Railtie for integrating Supplies with Rails applications.
|
|
7
|
+
#
|
|
8
|
+
# This railtie ensures proper initialization of the gem within
|
|
9
|
+
# the Rails boot process and makes generators available.
|
|
10
|
+
class Railtie < Rails::Railtie
|
|
11
|
+
generators do
|
|
12
|
+
require 'generators/supplies/install_generator'
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/supplies.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'supplies/version'
|
|
4
|
+
require_relative 'supplies/functional'
|
|
5
|
+
require_relative 'supplies/railtie' if defined?(Rails::Railtie)
|
|
6
|
+
|
|
7
|
+
# Supplies provides shared coding conventions, linting configuration,
|
|
8
|
+
# and AI tool context files for Rails development.
|
|
9
|
+
#
|
|
10
|
+
# @example Installation
|
|
11
|
+
# # Add to Gemfile
|
|
12
|
+
# gem "supplies", group: [:development, :test]
|
|
13
|
+
#
|
|
14
|
+
# # Run the install generator
|
|
15
|
+
# rails g supplies:install
|
|
16
|
+
#
|
|
17
|
+
module Supplies
|
|
18
|
+
class Error < StandardError; end
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
# Returns the root path of the gem installation.
|
|
22
|
+
#
|
|
23
|
+
# @return [Pathname] the gem's root directory path
|
|
24
|
+
# @example
|
|
25
|
+
# Supplies.root #=> #<Pathname:/path/to/supplies>
|
|
26
|
+
def root
|
|
27
|
+
Pathname.new(__dir__).parent
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Returns the path to the RuboCop configuration directory.
|
|
31
|
+
#
|
|
32
|
+
# @return [Pathname] path to config/rubocop within the gem
|
|
33
|
+
# @example
|
|
34
|
+
# Supplies.rubocop_config_path #=> #<Pathname:/path/to/supplies/config/rubocop>
|
|
35
|
+
def rubocop_config_path
|
|
36
|
+
root.join('config', 'rubocop')
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: supplies
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Launch Supply
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: railties
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '7.1'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '7.1'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: rubocop
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.60'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.60'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: rubocop-capybara
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '2.20'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '2.20'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: rubocop-factory_bot
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '2.25'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '2.25'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: rubocop-md
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '2.0'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '2.0'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: rubocop-performance
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '1.20'
|
|
89
|
+
type: :development
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '1.20'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: rubocop-rails
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '2.23'
|
|
103
|
+
type: :development
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - "~>"
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '2.23'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: rubocop-rspec
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - "~>"
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '3.8'
|
|
117
|
+
type: :development
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - "~>"
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '3.8'
|
|
124
|
+
description: A collection of tools used by Launch Supply for Ruby developmentand Rubocop
|
|
125
|
+
configs for consistent Rails development practices.
|
|
126
|
+
email:
|
|
127
|
+
- dev@launchsupply.com
|
|
128
|
+
executables: []
|
|
129
|
+
extensions: []
|
|
130
|
+
extra_rdoc_files: []
|
|
131
|
+
files:
|
|
132
|
+
- LICENSE.txt
|
|
133
|
+
- README.md
|
|
134
|
+
- config/rubocop/base.yml
|
|
135
|
+
- config/rubocop/performance.yml
|
|
136
|
+
- config/rubocop/rails.yml
|
|
137
|
+
- config/rubocop/rspec.yml
|
|
138
|
+
- lib/generators/supplies/install_generator.rb
|
|
139
|
+
- lib/generators/supplies/templates/rubocop.yml.tt
|
|
140
|
+
- lib/supplies.rb
|
|
141
|
+
- lib/supplies/functional.rb
|
|
142
|
+
- lib/supplies/railtie.rb
|
|
143
|
+
- lib/supplies/version.rb
|
|
144
|
+
homepage: https://www.launchsupply.com/
|
|
145
|
+
licenses:
|
|
146
|
+
- MIT
|
|
147
|
+
metadata:
|
|
148
|
+
homepage_uri: https://www.launchsupply.com/
|
|
149
|
+
source_code_uri: https://www.launchsupply.com/
|
|
150
|
+
changelog_uri: https://www.launchsupply.com//blob/main/CHANGELOG.md
|
|
151
|
+
rubygems_mfa_required: 'true'
|
|
152
|
+
rdoc_options: []
|
|
153
|
+
require_paths:
|
|
154
|
+
- lib
|
|
155
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - ">="
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: 3.2.0
|
|
160
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
161
|
+
requirements:
|
|
162
|
+
- - ">="
|
|
163
|
+
- !ruby/object:Gem::Version
|
|
164
|
+
version: '0'
|
|
165
|
+
requirements: []
|
|
166
|
+
rubygems_version: 4.0.0
|
|
167
|
+
specification_version: 4
|
|
168
|
+
summary: Shared Ruby patterns and linting for Rails development
|
|
169
|
+
test_files: []
|