claude-code-templates 1.10.0 → 1.10.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-templates",
3
- "version": "1.10.0",
3
+ "version": "1.10.1",
4
4
  "description": "CLI tool to setup Claude Code configurations with framework-specific commands, automation hooks and MCP Servers for your projects",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -31,7 +31,7 @@
31
31
  "dev:link": "npm link",
32
32
  "dev:unlink": "npm unlink -g claude-code-templates",
33
33
  "pretest:commands": "npm run dev:link",
34
- "prepublishOnly": "echo 'Skipping tests for Health Check release'",
34
+ "prepublishOnly": "echo 'Skipping tests for Ruby on Rails 8 release'",
35
35
  "analytics:start": "node src/analytics.js",
36
36
  "analytics:test": "npm run test:analytics"
37
37
  },
@@ -123,6 +123,10 @@ function getHookDescription(hook, matcher, type) {
123
123
  return 'Block print() statements in Python files';
124
124
  }
125
125
 
126
+ if (command.includes('puts\\|p ') && command.includes('rb$')) {
127
+ return 'Block puts/p statements in Ruby files';
128
+ }
129
+
126
130
  if (command.includes('fmt.Print') && command.includes('go$')) {
127
131
  return 'Block fmt.Print statements in Go files';
128
132
  }
@@ -131,7 +135,7 @@ function getHookDescription(hook, matcher, type) {
131
135
  return 'Block println! macros in Rust files';
132
136
  }
133
137
 
134
- if (command.includes('npm audit') || command.includes('pip-audit') || command.includes('cargo audit')) {
138
+ if (command.includes('npm audit') || command.includes('pip-audit') || command.includes('bundle audit') || command.includes('cargo audit')) {
135
139
  return 'Security audit for dependencies';
136
140
  }
137
141
 
@@ -143,6 +147,18 @@ function getHookDescription(hook, matcher, type) {
143
147
  return 'Auto-format Python files with Black';
144
148
  }
145
149
 
150
+ if (command.includes('rubocop -A') && command.includes('rb$')) {
151
+ return 'Auto-format Ruby files with RuboCop';
152
+ }
153
+
154
+ if (command.includes('rubocop') && command.includes('rb$') && !command.includes('-A')) {
155
+ return 'Run Ruby linting with RuboCop';
156
+ }
157
+
158
+ if (command.includes('brakeman')) {
159
+ return 'Run Ruby security scan with Brakeman';
160
+ }
161
+
146
162
  if (command.includes('isort') && command.includes('py$')) {
147
163
  return 'Auto-sort Python imports with isort';
148
164
  }
@@ -195,6 +211,10 @@ function getHookDescription(hook, matcher, type) {
195
211
  return 'Auto-run Python tests for modified files';
196
212
  }
197
213
 
214
+ if (command.includes('rspec')) {
215
+ return 'Auto-run Ruby tests with RSpec';
216
+ }
217
+
198
218
  if (command.includes('go test')) {
199
219
  return 'Auto-run Go tests for modified files';
200
220
  }
package/src/templates.js CHANGED
@@ -76,6 +76,30 @@ const TEMPLATES_CONFIG = {
76
76
  }
77
77
  }
78
78
  },
79
+ 'ruby': {
80
+ name: 'Ruby',
81
+ description: 'Optimized for Ruby development with modern tools',
82
+ files: [
83
+ { source: 'ruby/CLAUDE.md', destination: 'CLAUDE.md' },
84
+ { source: 'ruby/.claude', destination: '.claude' },
85
+ { source: 'ruby/.mcp.json', destination: '.mcp.json' }
86
+ ],
87
+ frameworks: {
88
+ 'rails': {
89
+ name: 'Ruby on Rails 8',
90
+ additionalFiles: [
91
+ { source: 'ruby/examples/rails-app/.claude/commands', destination: '.claude/commands' },
92
+ { source: 'ruby/examples/rails-app/CLAUDE.md', destination: 'CLAUDE.md' }
93
+ ]
94
+ },
95
+ 'sinatra': {
96
+ name: 'Sinatra',
97
+ additionalFiles: [
98
+ { source: 'ruby/examples/sinatra-app/.claude/commands', destination: '.claude/commands' }
99
+ ]
100
+ }
101
+ }
102
+ },
79
103
  'rust': {
80
104
  name: 'Rust',
81
105
  description: 'Optimized for Rust development',
package/src/utils.js CHANGED
@@ -60,6 +60,50 @@ async function detectProject(targetDir) {
60
60
  }
61
61
  }
62
62
 
63
+ // Check for Ruby files
64
+ const rubyFiles = await findFilesByExtension(targetDir, ['.rb']);
65
+ const gemfilePath = path.join(targetDir, 'Gemfile');
66
+ const gemfileLockPath = path.join(targetDir, 'Gemfile.lock');
67
+
68
+ if (rubyFiles.length > 0 || await fs.pathExists(gemfilePath)) {
69
+ detectedLanguages.push('ruby');
70
+
71
+ // Check for Ruby frameworks
72
+ if (await fs.pathExists(gemfilePath)) {
73
+ try {
74
+ const gemfile = await fs.readFile(gemfilePath, 'utf-8');
75
+ if (gemfile.includes('rails')) {
76
+ detectedFrameworks.push('rails');
77
+ }
78
+ if (gemfile.includes('sinatra')) {
79
+ detectedFrameworks.push('sinatra');
80
+ }
81
+ } catch (error) {
82
+ console.warn('Could not parse Gemfile');
83
+ }
84
+ }
85
+
86
+ // Check for Rails application structure
87
+ const railsAppPath = path.join(targetDir, 'config', 'application.rb');
88
+ const railsRoutesPath = path.join(targetDir, 'config', 'routes.rb');
89
+ if (await fs.pathExists(railsAppPath) || await fs.pathExists(railsRoutesPath)) {
90
+ detectedFrameworks.push('rails');
91
+ }
92
+
93
+ // Check for Rakefile (common in Rails and Ruby projects)
94
+ const rakefilePath = path.join(targetDir, 'Rakefile');
95
+ if (await fs.pathExists(rakefilePath)) {
96
+ try {
97
+ const rakefile = await fs.readFile(rakefilePath, 'utf-8');
98
+ if (rakefile.includes('Rails.application.load_tasks')) {
99
+ detectedFrameworks.push('rails');
100
+ }
101
+ } catch (error) {
102
+ // Ignore parsing errors
103
+ }
104
+ }
105
+ }
106
+
63
107
  // Check for Rust files
64
108
  const rustFiles = await findFilesByExtension(targetDir, ['.rs']);
65
109
  const cargoPath = path.join(targetDir, 'Cargo.toml');
@@ -145,6 +189,7 @@ async function getProjectSummary(targetDir) {
145
189
  hasGit: await fs.pathExists(path.join(targetDir, '.git')),
146
190
  hasNodeModules: await fs.pathExists(path.join(targetDir, 'node_modules')),
147
191
  hasVenv: await fs.pathExists(path.join(targetDir, 'venv')) || await fs.pathExists(path.join(targetDir, '.venv')),
192
+ hasBundle: await fs.pathExists(path.join(targetDir, 'vendor', 'bundle')),
148
193
  configFiles: []
149
194
  };
150
195
 
@@ -152,6 +197,7 @@ async function getProjectSummary(targetDir) {
152
197
  const configFiles = [
153
198
  'package.json', 'tsconfig.json', 'webpack.config.js', 'vite.config.js',
154
199
  'requirements.txt', 'setup.py', 'pyproject.toml', 'Pipfile',
200
+ 'Gemfile', 'Gemfile.lock', 'Rakefile', 'config.ru',
155
201
  'Cargo.toml', 'go.mod', '.gitignore', 'README.md'
156
202
  ];
157
203
 
@@ -0,0 +1,360 @@
1
+ # Ruby Model Generator
2
+
3
+ Create Ruby classes and models with proper structure and best practices.
4
+
5
+ ## Purpose
6
+
7
+ This command helps you quickly create Ruby model classes with proper initialization, attributes, and methods following Ruby conventions.
8
+
9
+ ## Usage
10
+
11
+ ```
12
+ /model
13
+ ```
14
+
15
+ ## What this command does
16
+
17
+ 1. **Creates model classes** with proper initialization methods
18
+ 2. **Adds attribute accessors** and instance variables
19
+ 3. **Includes validation methods** and error handling
20
+ 4. **Follows Ruby conventions** and best practices
21
+ 5. **Generates related test files** when applicable
22
+
23
+ ## Example Output
24
+
25
+ ```ruby
26
+ # app/models/user.rb
27
+ class User
28
+ attr_accessor :name, :email, :age
29
+ attr_reader :id, :created_at
30
+
31
+ def initialize(attributes = {})
32
+ @id = attributes[:id] || generate_id
33
+ @name = attributes[:name]
34
+ @email = attributes[:email]
35
+ @age = attributes[:age]
36
+ @created_at = Time.now
37
+ @errors = []
38
+ end
39
+
40
+ def valid?
41
+ @errors.clear
42
+ validate_presence_of_name
43
+ validate_email_format
44
+ validate_age_range
45
+ @errors.empty?
46
+ end
47
+
48
+ def errors
49
+ @errors.dup
50
+ end
51
+
52
+ def save
53
+ return false unless valid?
54
+
55
+ # Persist logic here
56
+ true
57
+ end
58
+
59
+ def to_h
60
+ {
61
+ id: @id,
62
+ name: @name,
63
+ email: @email,
64
+ age: @age,
65
+ created_at: @created_at
66
+ }
67
+ end
68
+
69
+ def to_json(*args)
70
+ JSON.generate(to_h, *args)
71
+ end
72
+
73
+ private
74
+
75
+ def validate_presence_of_name
76
+ if @name.nil? || @name.strip.empty?
77
+ @errors << "Name cannot be blank"
78
+ end
79
+ end
80
+
81
+ def validate_email_format
82
+ if @email && !@email.match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i)
83
+ @errors << "Email format is invalid"
84
+ end
85
+ end
86
+
87
+ def validate_age_range
88
+ if @age && (@age < 0 || @age > 150)
89
+ @errors << "Age must be between 0 and 150"
90
+ end
91
+ end
92
+
93
+ def generate_id
94
+ SecureRandom.uuid
95
+ end
96
+ end
97
+
98
+ # Example with inheritance
99
+ class AdminUser < User
100
+ attr_accessor :permissions
101
+
102
+ def initialize(attributes = {})
103
+ super
104
+ @permissions = attributes[:permissions] || []
105
+ end
106
+
107
+ def admin?
108
+ true
109
+ end
110
+
111
+ def has_permission?(permission)
112
+ @permissions.include?(permission)
113
+ end
114
+
115
+ private
116
+
117
+ def validate_permissions
118
+ unless @permissions.is_a?(Array)
119
+ @errors << "Permissions must be an array"
120
+ end
121
+ end
122
+ end
123
+ ```
124
+
125
+ ## Advanced Features
126
+
127
+ ### Module Inclusion
128
+ ```ruby
129
+ module Timestamps
130
+ def self.included(base)
131
+ base.extend(ClassMethods)
132
+ end
133
+
134
+ module ClassMethods
135
+ def with_timestamps
136
+ attr_reader :created_at, :updated_at
137
+
138
+ define_method :initialize do |*args|
139
+ super(*args)
140
+ @created_at ||= Time.now
141
+ @updated_at = @created_at
142
+ end
143
+
144
+ define_method :touch do
145
+ @updated_at = Time.now
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ class Post
152
+ include Timestamps
153
+ with_timestamps
154
+
155
+ attr_accessor :title, :content
156
+
157
+ def initialize(attributes = {})
158
+ @title = attributes[:title]
159
+ @content = attributes[:content]
160
+ super
161
+ end
162
+ end
163
+ ```
164
+
165
+ ### Class Methods and Scopes
166
+ ```ruby
167
+ class User
168
+ @@users = []
169
+
170
+ def self.all
171
+ @@users.dup
172
+ end
173
+
174
+ def self.find_by_email(email)
175
+ @@users.find { |user| user.email == email }
176
+ end
177
+
178
+ def self.where(conditions = {})
179
+ @@users.select do |user|
180
+ conditions.all? { |key, value| user.send(key) == value }
181
+ end
182
+ end
183
+
184
+ def self.create(attributes = {})
185
+ user = new(attributes)
186
+ if user.save
187
+ @@users << user
188
+ user
189
+ else
190
+ nil
191
+ end
192
+ end
193
+
194
+ def save
195
+ return false unless valid?
196
+
197
+ unless @@users.include?(self)
198
+ @@users << self
199
+ end
200
+ true
201
+ end
202
+
203
+ def destroy
204
+ @@users.delete(self)
205
+ end
206
+ end
207
+ ```
208
+
209
+ ## Testing Template
210
+
211
+ ```ruby
212
+ # spec/models/user_spec.rb
213
+ require 'spec_helper'
214
+
215
+ RSpec.describe User do
216
+ let(:valid_attributes) do
217
+ {
218
+ name: 'John Doe',
219
+ email: 'john@example.com',
220
+ age: 30
221
+ }
222
+ end
223
+
224
+ describe '#initialize' do
225
+ it 'sets attributes correctly' do
226
+ user = User.new(valid_attributes)
227
+
228
+ expect(user.name).to eq('John Doe')
229
+ expect(user.email).to eq('john@example.com')
230
+ expect(user.age).to eq(30)
231
+ expect(user.id).not_to be_nil
232
+ expect(user.created_at).to be_a(Time)
233
+ end
234
+ end
235
+
236
+ describe '#valid?' do
237
+ it 'returns true for valid attributes' do
238
+ user = User.new(valid_attributes)
239
+ expect(user).to be_valid
240
+ end
241
+
242
+ it 'returns false when name is blank' do
243
+ user = User.new(valid_attributes.merge(name: ''))
244
+ expect(user).not_to be_valid
245
+ expect(user.errors).to include('Name cannot be blank')
246
+ end
247
+
248
+ it 'returns false for invalid email format' do
249
+ user = User.new(valid_attributes.merge(email: 'invalid-email'))
250
+ expect(user).not_to be_valid
251
+ expect(user.errors).to include('Email format is invalid')
252
+ end
253
+
254
+ it 'returns false for invalid age' do
255
+ user = User.new(valid_attributes.merge(age: -5))
256
+ expect(user).not_to be_valid
257
+ expect(user.errors).to include('Age must be between 0 and 150')
258
+ end
259
+ end
260
+
261
+ describe '#save' do
262
+ it 'saves valid user' do
263
+ user = User.new(valid_attributes)
264
+ expect(user.save).to be true
265
+ end
266
+
267
+ it 'does not save invalid user' do
268
+ user = User.new(name: '')
269
+ expect(user.save).to be false
270
+ end
271
+ end
272
+
273
+ describe '#to_h' do
274
+ it 'returns hash representation' do
275
+ user = User.new(valid_attributes)
276
+ hash = user.to_h
277
+
278
+ expect(hash).to include(
279
+ name: 'John Doe',
280
+ email: 'john@example.com',
281
+ age: 30
282
+ )
283
+ expect(hash[:id]).not_to be_nil
284
+ expect(hash[:created_at]).to be_a(Time)
285
+ end
286
+ end
287
+ end
288
+ ```
289
+
290
+ ## Best Practices Included
291
+
292
+ - **Proper initialization** with hash parameters
293
+ - **Attribute accessors** for public attributes
294
+ - **Validation methods** with error collection
295
+ - **JSON serialization** support
296
+ - **Class and instance methods** separation
297
+ - **Error handling** and reporting
298
+ - **Ruby naming conventions** (snake_case)
299
+ - **Encapsulation** with private methods
300
+
301
+ ## Common Patterns
302
+
303
+ ### Value Objects
304
+ ```ruby
305
+ class Money
306
+ include Comparable
307
+
308
+ attr_reader :amount, :currency
309
+
310
+ def initialize(amount, currency = 'USD')
311
+ @amount = amount.to_f
312
+ @currency = currency.to_s.upcase
313
+ end
314
+
315
+ def +(other)
316
+ raise ArgumentError, "Currency mismatch" unless currency == other.currency
317
+ Money.new(amount + other.amount, currency)
318
+ end
319
+
320
+ def <=>(other)
321
+ raise ArgumentError, "Currency mismatch" unless currency == other.currency
322
+ amount <=> other.amount
323
+ end
324
+
325
+ def to_s
326
+ "#{currency} #{format('%.2f', amount)}"
327
+ end
328
+ end
329
+ ```
330
+
331
+ ### Service Objects
332
+ ```ruby
333
+ class UserRegistrationService
334
+ attr_reader :user, :errors
335
+
336
+ def initialize(user_params)
337
+ @user_params = user_params
338
+ @errors = []
339
+ end
340
+
341
+ def call
342
+ @user = User.new(@user_params)
343
+
344
+ if @user.valid?
345
+ @user.save
346
+ send_welcome_email
347
+ true
348
+ else
349
+ @errors = @user.errors
350
+ false
351
+ end
352
+ end
353
+
354
+ private
355
+
356
+ def send_welcome_email
357
+ # Email sending logic
358
+ end
359
+ end
360
+ ```