opencode-skills-collection 3.0.49 → 3.0.51
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/bundled-skills/.antigravity-install-manifest.json +27 -1
- package/bundled-skills/ab-test-setup/SKILL.md +14 -0
- package/bundled-skills/apple-notes-search/SKILL.md +122 -0
- package/bundled-skills/astropy/references/coordinates.md +9 -0
- package/bundled-skills/astropy/references/cosmology.md +8 -0
- package/bundled-skills/astropy/references/fits.md +8 -0
- package/bundled-skills/astropy/references/tables.md +8 -0
- package/bundled-skills/astropy/references/time.md +7 -0
- package/bundled-skills/astropy/references/units.md +9 -0
- package/bundled-skills/astropy/references/wcs_and_other_modules.md +9 -0
- package/bundled-skills/browser-extension-builder/SKILL.md +1 -1
- package/bundled-skills/ckw-design/SKILL.md +129 -0
- package/bundled-skills/deterministic-design/SKILL.md +56 -0
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/users/bundles.md +1 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/lint-and-validate/SKILL.md +3 -1
- package/bundled-skills/lookdev/SKILL.md +229 -0
- package/bundled-skills/lookdev-auto/SKILL.md +102 -0
- package/bundled-skills/macos-screen-recorder/SKILL.md +59 -0
- package/bundled-skills/pr-merge-champion/SKILL.md +116 -0
- package/bundled-skills/programmatic-seo/SKILL.md +11 -0
- package/bundled-skills/schema-markup/SKILL.md +11 -0
- package/bundled-skills/screenstudio-alt/SKILL.md +91 -0
- package/bundled-skills/super-code/SKILL.md +209 -0
- package/bundled-skills/super-code/bash/SKILL.md +292 -0
- package/bundled-skills/super-code/c/SKILL.md +263 -0
- package/bundled-skills/super-code/cpp/SKILL.md +271 -0
- package/bundled-skills/super-code/csharp/SKILL.md +276 -0
- package/bundled-skills/super-code/dart/SKILL.md +327 -0
- package/bundled-skills/super-code/elixir/SKILL.md +366 -0
- package/bundled-skills/super-code/go/SKILL.md +234 -0
- package/bundled-skills/super-code/java/SKILL.md +230 -0
- package/bundled-skills/super-code/kotlin/SKILL.md +281 -0
- package/bundled-skills/super-code/php/SKILL.md +316 -0
- package/bundled-skills/super-code/python/SKILL.md +315 -0
- package/bundled-skills/super-code/ruby/SKILL.md +306 -0
- package/bundled-skills/super-code/rust/SKILL.md +289 -0
- package/bundled-skills/super-code/scala/SKILL.md +302 -0
- package/bundled-skills/super-code/swift/SKILL.md +299 -0
- package/bundled-skills/super-code/typescript/SKILL.md +286 -0
- package/bundled-skills/web-media-getter/SKILL.md +119 -0
- package/bundled-skills/youtube-seo-optimizer/SKILL.md +9 -9
- package/package.json +1 -1
- package/skills_index.json +574 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ruby
|
|
3
|
+
description: "Language-specific super-code guidelines for ruby."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-06-16"
|
|
7
|
+
---
|
|
8
|
+
# Ruby: Idiomatic Efficiency Reference
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
1. [Enumerable & Collections](#enumerable)
|
|
12
|
+
2. [Blocks, Procs & Lambdas](#blocks)
|
|
13
|
+
3. [String Handling](#strings)
|
|
14
|
+
4. [Error Handling](#errors)
|
|
15
|
+
5. [Classes & Modules](#classes)
|
|
16
|
+
6. [Ruby Idioms](#idioms)
|
|
17
|
+
7. [Anti-patterns specific to Ruby](#antipatterns)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Enumerable & Collections {#enumerable}
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
# ❌ Manual accumulation
|
|
25
|
+
result = []
|
|
26
|
+
items.each do |item|
|
|
27
|
+
result << item.name.upcase if item.active?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# ✅
|
|
31
|
+
result = items.select(&:active?).map { |i| i.name.upcase }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
# ❌ Manual grouping
|
|
36
|
+
grouped = {}
|
|
37
|
+
items.each do |item|
|
|
38
|
+
grouped[item.category] ||= []
|
|
39
|
+
grouped[item.category] << item
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# ✅
|
|
43
|
+
grouped = items.group_by(&:category)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
# ❌ Manual sum
|
|
48
|
+
total = 0
|
|
49
|
+
orders.each { |o| total += o.amount }
|
|
50
|
+
|
|
51
|
+
# ✅
|
|
52
|
+
total = orders.sum(&:amount)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
# ❌ Checking existence then accessing
|
|
57
|
+
if hash.key?(key)
|
|
58
|
+
value = hash[key]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# ✅
|
|
62
|
+
value = hash[key] # returns nil if missing
|
|
63
|
+
# or with default:
|
|
64
|
+
value = hash.fetch(key, default_value)
|
|
65
|
+
# or raising on missing:
|
|
66
|
+
value = hash.fetch(key) # raises KeyError
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Prefer `map`/`select`/`reject`/`sum` over manual loops. Use `&:method` for single-method blocks.**
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 2. Blocks, Procs & Lambdas {#blocks}
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
# ❌ Explicit block-to-proc conversion when unnecessary
|
|
77
|
+
items.map { |item| item.to_s }
|
|
78
|
+
|
|
79
|
+
# ✅
|
|
80
|
+
items.map(&:to_s)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
# ❌ Proc.new when lambda is safer (arity check + return behavior)
|
|
85
|
+
handler = Proc.new { |x| x * 2 }
|
|
86
|
+
|
|
87
|
+
# ✅
|
|
88
|
+
handler = ->(x) { x * 2 }
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
# ❌ Multi-line block with { }
|
|
93
|
+
items.map { |item|
|
|
94
|
+
result = transform(item)
|
|
95
|
+
validate(result)
|
|
96
|
+
result
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# ✅ — do/end for multi-line, { } for single-line
|
|
100
|
+
items.map do |item|
|
|
101
|
+
result = transform(item)
|
|
102
|
+
validate(result)
|
|
103
|
+
result
|
|
104
|
+
end
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 3. String Handling {#strings}
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
# ❌ String concatenation in loop
|
|
113
|
+
result = ""
|
|
114
|
+
items.each { |i| result += i.name + ", " }
|
|
115
|
+
|
|
116
|
+
# ✅
|
|
117
|
+
result = items.map(&:name).join(", ")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
# ❌ String concatenation for assembly
|
|
122
|
+
greeting = "Hello, " + name + "! You have " + count.to_s + " messages."
|
|
123
|
+
|
|
124
|
+
# ✅
|
|
125
|
+
greeting = "Hello, #{name}! You have #{count} messages."
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
# ❌ Mutable string where frozen is fine (Ruby 3+ encourages frozen)
|
|
130
|
+
SEPARATOR = ", "
|
|
131
|
+
|
|
132
|
+
# ✅
|
|
133
|
+
SEPARATOR = ", ".freeze
|
|
134
|
+
# or add `# frozen_string_literal: true` at file top
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Use heredocs (`<<~HEREDOC`) for multi-line strings. `<<~` strips indentation.**
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 4. Error Handling {#errors}
|
|
142
|
+
|
|
143
|
+
```ruby
|
|
144
|
+
# ❌ Rescuing Exception (catches EVERYTHING including SignalException, SystemExit)
|
|
145
|
+
begin
|
|
146
|
+
risky
|
|
147
|
+
rescue Exception => e
|
|
148
|
+
log(e)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# ✅ — rescue StandardError (the default)
|
|
152
|
+
begin
|
|
153
|
+
risky
|
|
154
|
+
rescue StandardError => e
|
|
155
|
+
log(e)
|
|
156
|
+
raise
|
|
157
|
+
end
|
|
158
|
+
# or just: rescue => e (same as StandardError)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```ruby
|
|
162
|
+
# ❌ Using rescue as flow control
|
|
163
|
+
begin
|
|
164
|
+
value = hash.fetch(key)
|
|
165
|
+
rescue KeyError
|
|
166
|
+
value = default
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# ✅
|
|
170
|
+
value = hash.fetch(key, default)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```ruby
|
|
174
|
+
# ❌ Inline rescue hiding errors
|
|
175
|
+
result = dangerous_operation rescue nil
|
|
176
|
+
|
|
177
|
+
# ✅ — inline rescue only for truly trivial fallbacks
|
|
178
|
+
result = Integer(input) rescue nil # acceptable for parsing
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 5. Classes & Modules {#classes}
|
|
184
|
+
|
|
185
|
+
```ruby
|
|
186
|
+
# ❌ Manual accessors
|
|
187
|
+
class User
|
|
188
|
+
def name
|
|
189
|
+
@name
|
|
190
|
+
end
|
|
191
|
+
def name=(value)
|
|
192
|
+
@name = value
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# ✅
|
|
197
|
+
class User
|
|
198
|
+
attr_accessor :name
|
|
199
|
+
end
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```ruby
|
|
203
|
+
# ❌ Deep inheritance for shared behavior
|
|
204
|
+
class Animal; end
|
|
205
|
+
class Pet < Animal; end
|
|
206
|
+
class Dog < Pet; end
|
|
207
|
+
|
|
208
|
+
# ✅ — mixins for shared behavior, inheritance for "is-a"
|
|
209
|
+
module Trainable
|
|
210
|
+
def train = puts("Training #{name}")
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
class Dog
|
|
214
|
+
include Trainable
|
|
215
|
+
attr_reader :name
|
|
216
|
+
def initialize(name) = @name = name
|
|
217
|
+
end
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
```ruby
|
|
221
|
+
# ❌ Class with only class methods (namespace via class)
|
|
222
|
+
class MathUtils
|
|
223
|
+
def self.square(x) = x * x
|
|
224
|
+
def self.cube(x) = x ** 3
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# ✅
|
|
228
|
+
module MathUtils
|
|
229
|
+
module_function
|
|
230
|
+
def square(x) = x * x
|
|
231
|
+
def cube(x) = x ** 3
|
|
232
|
+
end
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## 6. Ruby Idioms {#idioms}
|
|
238
|
+
|
|
239
|
+
```ruby
|
|
240
|
+
# ❌ Explicit boolean return
|
|
241
|
+
def active?
|
|
242
|
+
if status == :active
|
|
243
|
+
true
|
|
244
|
+
else
|
|
245
|
+
false
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# ✅
|
|
250
|
+
def active? = status == :active
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
```ruby
|
|
254
|
+
# ❌ nil check before method call
|
|
255
|
+
if user && user.name
|
|
256
|
+
puts user.name
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# ✅ (Ruby 2.3+)
|
|
260
|
+
puts user&.name if user&.name
|
|
261
|
+
# or with safe navigation:
|
|
262
|
+
user&.name&.then { |n| puts n }
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
```ruby
|
|
266
|
+
# ❌ Conditional assignment verbosely
|
|
267
|
+
if @cache.nil?
|
|
268
|
+
@cache = expensive_compute
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# ✅
|
|
272
|
+
@cache ||= expensive_compute
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
```ruby
|
|
276
|
+
# ❌ Multiple assignment from array manually
|
|
277
|
+
first = arr[0]
|
|
278
|
+
second = arr[1]
|
|
279
|
+
|
|
280
|
+
# ✅
|
|
281
|
+
first, second = arr
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## 7. Anti-patterns specific to Ruby {#antipatterns}
|
|
287
|
+
|
|
288
|
+
| Anti-pattern | Preferred |
|
|
289
|
+
|---|---|
|
|
290
|
+
| `rescue Exception` | `rescue StandardError` |
|
|
291
|
+
| `for x in collection` | `collection.each` |
|
|
292
|
+
| Manual `attr_reader`/`writer` | `attr_accessor` / `attr_reader` |
|
|
293
|
+
| `class` for pure namespace | `module` |
|
|
294
|
+
| String concatenation with `+` | string interpolation `#{}` |
|
|
295
|
+
| `if !condition` | `unless condition` |
|
|
296
|
+
| `== true` / `== false` | truthy/falsy check directly |
|
|
297
|
+
| `and`/`or` for control flow | `&&`/`||` (different precedence) |
|
|
298
|
+
| `return` at end of method | implicit return (last expression) |
|
|
299
|
+
| Monkey-patching core classes in production | refinements or wrapper |
|
|
300
|
+
| `eval` / `send` for known methods | direct method call |
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
## Limitations
|
|
305
|
+
- These are language-specific guidelines and do not cover overall architectural decisions.
|
|
306
|
+
- Over-compression might reduce readability; apply judgement.
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust
|
|
3
|
+
description: "Language-specific super-code guidelines for rust."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-06-16"
|
|
7
|
+
---
|
|
8
|
+
# Rust: Idiomatic Efficiency Reference
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
1. [Ownership & Borrowing](#ownership)
|
|
12
|
+
2. [Error Handling](#errors)
|
|
13
|
+
3. [Iterators](#iterators)
|
|
14
|
+
4. [Pattern Matching](#patterns)
|
|
15
|
+
5. [Structs & Enums](#structs)
|
|
16
|
+
6. [Concurrency](#concurrency)
|
|
17
|
+
7. [Anti-patterns specific to Rust](#antipatterns)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Ownership & Borrowing {#ownership}
|
|
22
|
+
|
|
23
|
+
```rust
|
|
24
|
+
// ❌ Cloning to avoid thinking about lifetimes
|
|
25
|
+
fn get_name(user: &User) -> String {
|
|
26
|
+
user.name.clone()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ✅ — return a reference when the data lives long enough
|
|
30
|
+
fn get_name(user: &User) -> &str {
|
|
31
|
+
&user.name
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```rust
|
|
36
|
+
// ❌ Taking ownership when borrowing suffices
|
|
37
|
+
fn print_name(name: String) {
|
|
38
|
+
println!("{name}");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ✅
|
|
42
|
+
fn print_name(name: &str) {
|
|
43
|
+
println!("{name}");
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```rust
|
|
48
|
+
// ❌ Unnecessary .to_string() / .to_owned() in hot paths
|
|
49
|
+
let key = id.to_string();
|
|
50
|
+
map.get(&key)
|
|
51
|
+
|
|
52
|
+
// ✅ — use Borrow trait; HashMap<String, V> accepts &str as key
|
|
53
|
+
map.get(id)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Prefer `&str` over `String` in function parameters unless the function needs to own the data.**
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 2. Error Handling {#errors}
|
|
61
|
+
|
|
62
|
+
```rust
|
|
63
|
+
// ❌ .unwrap() in production code
|
|
64
|
+
let file = File::open(path).unwrap();
|
|
65
|
+
|
|
66
|
+
// ✅
|
|
67
|
+
let file = File::open(path)
|
|
68
|
+
.map_err(|e| AppError::Io { path: path.to_owned(), source: e })?;
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
```rust
|
|
72
|
+
// ❌ Manual match on Result for every call
|
|
73
|
+
match do_thing() {
|
|
74
|
+
Ok(v) => v,
|
|
75
|
+
Err(e) => return Err(e),
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ✅ — the ? operator
|
|
79
|
+
let v = do_thing()?;
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```rust
|
|
83
|
+
// ❌ Box<dyn Error> everywhere (loses type info)
|
|
84
|
+
fn run() -> Result<(), Box<dyn std::error::Error>> { ... }
|
|
85
|
+
|
|
86
|
+
// ✅ — use thiserror for library errors, anyhow for application errors
|
|
87
|
+
use anyhow::{Context, Result};
|
|
88
|
+
fn run() -> Result<()> {
|
|
89
|
+
do_thing().context("failed during run")?;
|
|
90
|
+
Ok(())
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```rust
|
|
95
|
+
// ❌ Separate error enum variant for every call site
|
|
96
|
+
enum Error { FileOpen, FileRead, Parse, Network, ... }
|
|
97
|
+
|
|
98
|
+
// ✅ — use thiserror with #[from] for automatic conversion
|
|
99
|
+
#[derive(thiserror::Error, Debug)]
|
|
100
|
+
enum Error {
|
|
101
|
+
#[error("io error")] Io(#[from] std::io::Error),
|
|
102
|
+
#[error("parse error")] Parse(#[from] serde_json::Error),
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 3. Iterators {#iterators}
|
|
109
|
+
|
|
110
|
+
```rust
|
|
111
|
+
// ❌ Imperative accumulation
|
|
112
|
+
let mut result = Vec::new();
|
|
113
|
+
for item in &items {
|
|
114
|
+
if item.active {
|
|
115
|
+
result.push(item.name.to_uppercase());
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ✅
|
|
120
|
+
let result: Vec<_> = items.iter()
|
|
121
|
+
.filter(|i| i.active)
|
|
122
|
+
.map(|i| i.name.to_uppercase())
|
|
123
|
+
.collect();
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
```rust
|
|
127
|
+
// ❌ Manual sum
|
|
128
|
+
let mut total = 0;
|
|
129
|
+
for order in &orders { total += order.amount; }
|
|
130
|
+
|
|
131
|
+
// ✅
|
|
132
|
+
let total: u64 = orders.iter().map(|o| o.amount).sum();
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
```rust
|
|
136
|
+
// ❌ Index-based loop
|
|
137
|
+
for i in 0..items.len() {
|
|
138
|
+
process(&items[i]);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ✅
|
|
142
|
+
for item in &items {
|
|
143
|
+
process(item);
|
|
144
|
+
}
|
|
145
|
+
// With index:
|
|
146
|
+
for (i, item) in items.iter().enumerate() {
|
|
147
|
+
process(i, item);
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Chain iterators lazily; only `.collect()` when you actually need a concrete collection.**
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 4. Pattern Matching {#patterns}
|
|
156
|
+
|
|
157
|
+
```rust
|
|
158
|
+
// ❌ if-let chain that should be match
|
|
159
|
+
if let Some(x) = opt {
|
|
160
|
+
if x > 0 {
|
|
161
|
+
use(x)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ✅
|
|
166
|
+
if let Some(x) = opt.filter(|&x| x > 0) {
|
|
167
|
+
use(x)
|
|
168
|
+
}
|
|
169
|
+
// or match with guard:
|
|
170
|
+
match opt {
|
|
171
|
+
Some(x) if x > 0 => use(x),
|
|
172
|
+
_ => {}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
```rust
|
|
177
|
+
// ❌ match with identical arms
|
|
178
|
+
match status {
|
|
179
|
+
Status::Active => true,
|
|
180
|
+
Status::Pending => true,
|
|
181
|
+
Status::Inactive => false,
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ✅
|
|
185
|
+
matches!(status, Status::Active | Status::Pending)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
```rust
|
|
189
|
+
// ❌ Destructuring in body instead of pattern
|
|
190
|
+
fn area(shape: &Shape) -> f64 {
|
|
191
|
+
match shape {
|
|
192
|
+
Shape::Circle(c) => { let r = c.radius; r * r * PI }
|
|
193
|
+
Shape::Rect(r) => { let w = r.width; let h = r.height; w * h }
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ✅ — destructure in pattern
|
|
198
|
+
match shape {
|
|
199
|
+
Shape::Circle(Circle { radius, .. }) => radius * radius * PI,
|
|
200
|
+
Shape::Rect(Rect { width, height }) => width * height,
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 5. Structs & Enums {#structs}
|
|
207
|
+
|
|
208
|
+
```rust
|
|
209
|
+
// ❌ Enum variant carrying bool for binary state
|
|
210
|
+
enum State { Running(bool) } // true = paused?
|
|
211
|
+
|
|
212
|
+
// ✅ — explicit variants
|
|
213
|
+
enum State { Running, Paused, Stopped }
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
```rust
|
|
217
|
+
// ❌ Struct with many Option fields (stringly optional)
|
|
218
|
+
struct Config {
|
|
219
|
+
timeout: Option<u64>,
|
|
220
|
+
retries: Option<u32>,
|
|
221
|
+
base_url: Option<String>,
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ✅ — use Default + builder pattern or #[derive(Default)] with sensible defaults
|
|
225
|
+
#[derive(Default)]
|
|
226
|
+
struct Config {
|
|
227
|
+
timeout: u64, // default 0 = no timeout
|
|
228
|
+
retries: u32, // default 0
|
|
229
|
+
base_url: String,
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```rust
|
|
234
|
+
// ❌ pub fields on a type that needs invariants
|
|
235
|
+
pub struct Percentage { pub value: f64 }
|
|
236
|
+
|
|
237
|
+
// ✅ — private field, constructor enforces invariant
|
|
238
|
+
pub struct Percentage(f64);
|
|
239
|
+
impl Percentage {
|
|
240
|
+
pub fn new(v: f64) -> Option<Self> {
|
|
241
|
+
(0.0..=100.0).contains(&v).then_some(Self(v))
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## 6. Concurrency {#concurrency}
|
|
249
|
+
|
|
250
|
+
```rust
|
|
251
|
+
// ❌ Arc<Mutex<T>> for read-heavy data
|
|
252
|
+
let data = Arc::new(Mutex::new(vec![...]));
|
|
253
|
+
|
|
254
|
+
// ✅ — RwLock for read-heavy
|
|
255
|
+
let data = Arc::new(RwLock::new(vec![...]));
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
```rust
|
|
259
|
+
// ❌ Spawning OS threads for many small tasks
|
|
260
|
+
for item in items {
|
|
261
|
+
std::thread::spawn(|| process(item));
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// ✅ — use rayon for CPU-bound parallel iteration
|
|
265
|
+
use rayon::prelude::*;
|
|
266
|
+
items.par_iter().for_each(|item| process(item));
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**For async: prefer `tokio::spawn` + `JoinHandle` over manual channels for structured concurrency. Use `tokio::join!` for concurrent awaits.**
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 7. Anti-patterns specific to Rust {#antipatterns}
|
|
274
|
+
|
|
275
|
+
| Anti-pattern | Preferred |
|
|
276
|
+
|---|---|
|
|
277
|
+
| `.clone()` to appease borrow checker | reconsider lifetime or restructure |
|
|
278
|
+
| `.unwrap()` in non-test code | `?` operator or explicit handling |
|
|
279
|
+
| `impl Trait` in return position hiding complex type | name the type or use `Box<dyn Trait>` intentionally |
|
|
280
|
+
| `String` parameter when `&str` suffices | `&str` for params, `String` for owned storage |
|
|
281
|
+
| Nested `Option<Option<T>>` | rethink the data model |
|
|
282
|
+
| `unsafe` block without a safety comment | always document the invariant being upheld |
|
|
283
|
+
| `Vec<Box<T>>` when `Vec<T>` works | avoid heap allocation inside collections unless T is unsized |
|
|
284
|
+
| Manual `Drop` for cleanup that `?` handles | let RAII + `?` do it |
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
## Limitations
|
|
288
|
+
- These are language-specific guidelines and do not cover overall architectural decisions.
|
|
289
|
+
- Over-compression might reduce readability; apply judgement.
|