@sun-asterisk/sunlint 1.3.41 → 1.3.42
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 +1 -1
- package/skill-assets/sunlint-code-quality/rules/dart/D001-recommended-lints.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D002-dispose-resources.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D003-prefer-widget-classes.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D004-avoid-shrinkwrap.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D005-widget-nesting.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D006-large-callbacks.md +54 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D007-lifecycle-order.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D008-long-functions.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D009-function-parameters.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D010-cyclomatic-complexity.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D011-named-parameters.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D012-named-booleans.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D013-single-public-class.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D014-safe-collection-access.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D015-copywith-consistency.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D016-project-tests.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D017-review-dependencies.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D018-no-commented-code.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D019-single-child-wrappers.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D020-if-else-limit.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D021-negated-booleans.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D022-setstate-usage.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D023-unnecessary-overrides.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D024-avoid-unnecessary-statefulwidget.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D025-nested-ternaries.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB001-use-snake-case.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB002-use-camel-case.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB003-use-screaming-snake-case.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB004-predicate-methods.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB005-dangerous-methods.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB006-indentation.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB007-line-length.md +25 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB008-rescue-exception.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB009-save-bang.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB010-avoid-n-plus-one.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB011-use-find-each.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB012-sql-injection.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB013-prefer-has-many-through.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB014-dependent-associations.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB015-modern-validations.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB016-thin-controllers.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB017-avoid-fat-models.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB018-service-objects.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB019-avoid-metaprogramming.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB020-use-pluck.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB021-use-size.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB022-order-by-timestamps.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB023-where-missing.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB024-method-length.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB025-parameter-limits.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB026-avoid-deep-nesting.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB027-guard-clauses.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB028-class-length.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB029-meaningful-names.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB030-dry-principle.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB031-mvc-architecture.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB032-use-concerns.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB033-moderate-callbacks.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB034-use-decorators.md +33 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB035-comprehensive-tests.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB036-frozen-string-literal.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB037-it-parameter.md +25 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB038-modern-enum-syntax.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB039-solid-adapters.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB040-rails-authentication.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB041-async-query-loading.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB042-hotwire-turbo.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB043-use-propshaft.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB044-structured-logging.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB045-prism-parser.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW001-block-based-kvo.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW002-class-delegate-protocol.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW003-compiler-protocol-init.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW004-contains-over-filter-count.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW005-convenience-type.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW006-discarded-notification-center-observer.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW007-discouraged-direct-init.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW008-discouraged-optional-boolean.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW009-empty-count.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW010-empty-string.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW011-explicit-init.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW012-fatal-error-message.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW013-for-where.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW014-force-cast.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW015-force-try.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW016-force-unwrapping.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW017-function-parameter-count.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW018-large-tuple.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW019-legacy-constructor.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW020-nesting.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW021-no-extension-access-modifier.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW022-overridden-super-call.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW023-override-in-extension.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW024-private-over-fileprivate.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW025-private-unit-test.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW026-prohibited-super-call.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW027-sorted-first-last.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW028-syntactic-sugar.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW029-unused-closure-parameter.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW030-unused-enumerated.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW031-unused-optional-binding.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW032-valid-ibinspectable.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW033-vertical-parameter-alignment.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW034-void-return.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW035-weak-delegate.md +28 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pubspec dependencies should be reviewed regularly
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Ensure dependencies are kept up-to-date for security and stability
|
|
5
|
+
tags: maintenance, security, dependencies
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Pubspec dependencies should be reviewed regularly
|
|
9
|
+
|
|
10
|
+
Dependencies in `pubspec.yaml` should be reviewed and updated regularly (at least every 4 months). Outdated dependencies may contain security vulnerabilities or miss critical performance improvements.
|
|
11
|
+
|
|
12
|
+
**Incorrect (old lock file):**
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
# pubspec.lock last modified: 6 months ago
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Correct (regularly updated):**
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
# run 'flutter pub upgrade' and review dependencies regularly
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Tools:** Custom analyzer (D017)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Remove Commented-Out Code
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Keep codebase clean by removing commented-out code
|
|
5
|
+
tags: cleanliness, readability, maintenance
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Remove Commented-Out Code
|
|
9
|
+
|
|
10
|
+
Commented-out code should be removed instead of being left in the source files. Dead code comments create clutter and confusion. If you need to reference old code, rely on version control (Git).
|
|
11
|
+
|
|
12
|
+
**Incorrect (abandoned code):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
void calculate() {
|
|
16
|
+
final result = 10 + 5;
|
|
17
|
+
// print("Debug result: $result");
|
|
18
|
+
// if (result > 10) {
|
|
19
|
+
// doSomething();
|
|
20
|
+
// }
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Correct (clean file):**
|
|
26
|
+
|
|
27
|
+
```dart
|
|
28
|
+
void calculate() {
|
|
29
|
+
final result = 10 + 5;
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Tools:** Custom analyzer (D018)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Single Child in Multi-Child Widget
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Use appropriate widget types for the number of children
|
|
5
|
+
tags: performance, efficiency, best-practices
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Single Child in Multi-Child Widget
|
|
9
|
+
|
|
10
|
+
Multi-child widgets like `Column`, `Row`, `Stack`, `ListView`, or `GridView` are inefficient when used with only a single child. Use single-child optimized widgets like `SizedBox`, `Padding`, `Center`, or `Container` instead.
|
|
11
|
+
|
|
12
|
+
**Incorrect (inefficient Column):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
Column(
|
|
16
|
+
children: [
|
|
17
|
+
Text("Only one child here"),
|
|
18
|
+
],
|
|
19
|
+
)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (efficient wrapper):**
|
|
23
|
+
|
|
24
|
+
```dart
|
|
25
|
+
Padding(
|
|
26
|
+
padding: const EdgeInsets.all(8.0),
|
|
27
|
+
child: Text("Only one child here"),
|
|
28
|
+
)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Tools:** Custom analyzer (D019)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Limit If/Else Branches
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Reduce complexity by limiting the number of if/else branches
|
|
5
|
+
tags: readability, complexity, clean-code
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Limit If/Else Branches
|
|
9
|
+
|
|
10
|
+
Complex if/else chains with more than 3 branches reduce code readability and increase cyclomatic complexity. When facing multiple branches, consider using `switch` statements, lookup tables (Maps), or the Strategy pattern.
|
|
11
|
+
|
|
12
|
+
**Incorrect (long if/else chain):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
if (type == 'A') {
|
|
16
|
+
doA();
|
|
17
|
+
} else if (type == 'B') {
|
|
18
|
+
doB();
|
|
19
|
+
} else if (type == 'C') {
|
|
20
|
+
doC();
|
|
21
|
+
} else if (type == 'D') {
|
|
22
|
+
doD();
|
|
23
|
+
} else {
|
|
24
|
+
doDefault();
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Correct (using switch or Map):**
|
|
29
|
+
|
|
30
|
+
```dart
|
|
31
|
+
// Option 1: Switch (better readability)
|
|
32
|
+
switch (type) {
|
|
33
|
+
case 'A': doA(); break;
|
|
34
|
+
case 'B': doB(); break;
|
|
35
|
+
case 'C': doC(); break;
|
|
36
|
+
case 'D': doD(); break;
|
|
37
|
+
default: doDefault();
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Tools:** Custom analyzer (D020)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Negated Boolean Checks
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Improve code readability by avoiding inverted or negated boolean conditions
|
|
5
|
+
tags: readability, logic, clean-code
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Negated Boolean Checks
|
|
9
|
+
|
|
10
|
+
Negated boolean checks (using `!`) make code harder to read and understand. Replace negative conditions with positive ones wherever possible, and avoid double negations like `!!`.
|
|
11
|
+
|
|
12
|
+
**Incorrect (fragmented logic):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
if (!isNotAuthorized) { ... }
|
|
16
|
+
if (!(a == b)) { ... }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (clear logic):**
|
|
20
|
+
|
|
21
|
+
```dart
|
|
22
|
+
if (isAuthorized) { ... }
|
|
23
|
+
if (a != b) { ... }
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Tools:** Custom analyzer (D021)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use setState Correctly
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Ensure setState is used correctly in StatefulWidget to avoid performance issues and bugs
|
|
5
|
+
tags: performance, best-practices, lifecycle, state-management
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use setState Correctly
|
|
9
|
+
|
|
10
|
+
Common `setState` anti-patterns include: calling `setState` inside `build()`, nesting `setState` calls, making multiple `setState` calls in the same method, or using async callbacks inside `setState`. These lead to performance issues, unnecessary rebuilds, or hard-to-track UI bugs.
|
|
11
|
+
|
|
12
|
+
**Incorrect (async inside setState):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
setState(() async {
|
|
16
|
+
await fetchData(); // WRONG: setState should be synchronous
|
|
17
|
+
_data = "new data";
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Correct (sync update after async):**
|
|
22
|
+
|
|
23
|
+
```dart
|
|
24
|
+
// Fetch data first
|
|
25
|
+
final newData = await fetchData();
|
|
26
|
+
|
|
27
|
+
// Update state synchronously
|
|
28
|
+
if (mounted) {
|
|
29
|
+
setState(() {
|
|
30
|
+
_data = newData;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Tools:** Custom analyzer (D022)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Unnecessary Method Overrides
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Remove methods that only call super with the same parameters as they add no value
|
|
5
|
+
tags: readability, clean-code, refactoring
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Unnecessary Method Overrides
|
|
9
|
+
|
|
10
|
+
Methods that override a parent method but only call `super.methodName()` with the same parameters are unnecessary and should be removed. These empty overrides add no functionality and create unnecessary code clutter. Common examples include lifecycle methods like `initState()`, `dispose()`, or `didUpdateWidget()` that only call their super implementation.
|
|
11
|
+
|
|
12
|
+
**Incorrect (super call only):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
@override
|
|
16
|
+
void initState() {
|
|
17
|
+
super.initState();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@override
|
|
21
|
+
void dispose() {
|
|
22
|
+
super.dispose();
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Correct (remove if no logic):**
|
|
27
|
+
|
|
28
|
+
```dart
|
|
29
|
+
// Just remove the method override entirely if it only calls super
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Tools:** Custom analyzer (D023)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Unnecessary StatefulWidget
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Use StatelessWidget when no state management is needed to improve performance
|
|
5
|
+
tags: performance, flutter, widgets, best-practices
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Unnecessary StatefulWidget
|
|
9
|
+
|
|
10
|
+
StatefulWidget should only be used when the widget needs to maintain mutable state that changes over time. If a widget extends StatefulWidget but its State class has no mutable fields, never calls setState(), and doesn't use lifecycle methods beyond build(), it should be converted to StatelessWidget. StatelessWidget is more efficient as it doesn't maintain state and has less overhead.
|
|
11
|
+
|
|
12
|
+
**Incorrect (StatefulWidget with no state):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
class MyTitle extends StatefulWidget {
|
|
16
|
+
final String text;
|
|
17
|
+
const MyTitle({super.key, required this.text});
|
|
18
|
+
|
|
19
|
+
@override
|
|
20
|
+
State<MyTitle> createState() => _MyTitleState();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class _MyTitleState extends State<MyTitle> {
|
|
24
|
+
@override
|
|
25
|
+
Widget build(BuildContext context) {
|
|
26
|
+
return Text(widget.text);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Correct (StatelessWidget):**
|
|
32
|
+
|
|
33
|
+
```dart
|
|
34
|
+
class MyTitle extends StatelessWidget {
|
|
35
|
+
final String text;
|
|
36
|
+
const MyTitle({super.key, required this.text});
|
|
37
|
+
|
|
38
|
+
@override
|
|
39
|
+
Widget build(BuildContext context) {
|
|
40
|
+
return Text(text);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Tools:** Custom analyzer (D024)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Nested Conditional Expressions
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Improve code readability by avoiding nested ternary operators
|
|
5
|
+
tags: readability, maintainability, clean-code
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Nested Conditional Expressions
|
|
9
|
+
|
|
10
|
+
Nested conditional expressions (ternary operators like `a ? b : c ? d : e`) reduce code readability significantly. When logic is complex, use if-else statements or extract the logic into a well-named variable or function.
|
|
11
|
+
|
|
12
|
+
**Incorrect (hard to follow):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
final color = isAdmin ? Colors.red : isLogged ? Colors.green : Colors.grey;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Correct (descriptive logic):**
|
|
19
|
+
|
|
20
|
+
```dart
|
|
21
|
+
// Option 1: if-else
|
|
22
|
+
Color userColor;
|
|
23
|
+
if (isAdmin) {
|
|
24
|
+
userColor = Colors.red;
|
|
25
|
+
} else if (isLogged) {
|
|
26
|
+
userColor = Colors.green;
|
|
27
|
+
} else {
|
|
28
|
+
userColor = Colors.grey;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Option 2: Extracted getter
|
|
32
|
+
Color get userColor => _calculateUserColor();
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Tools:** Custom analyzer (D025)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use snake_case for symbols, methods, and variables
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Follow Ruby community naming conventions for consistency and readability.
|
|
5
|
+
tags: ruby, naming, snake_case, convention
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use snake_case for symbols, methods, and variables
|
|
9
|
+
|
|
10
|
+
Follow Ruby community naming conventions for consistency and readability. Use `snake_case` (all lowercase with underscores) for symbols, methods, and variables. Avoid camelCase or other naming styles for these elements.
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
def calculateTotal(price, taxRate)
|
|
16
|
+
totalAmount = price * taxRate
|
|
17
|
+
:orderStatus
|
|
18
|
+
end
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Correct:**
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
def calculate_total(price, tax_rate)
|
|
25
|
+
total_amount = price * tax_rate
|
|
26
|
+
:order_status
|
|
27
|
+
end
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Tools:** RuboCop (`Naming/VariableName`, `Naming/MethodName`)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use CamelCase for classes and modules
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Follow Ruby community naming conventions for classes and modules.
|
|
5
|
+
tags: ruby, naming, CamelCase, architecture
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use CamelCase for classes and modules
|
|
9
|
+
|
|
10
|
+
Use `CamelCase` (also known as PascalCase) for class and module names. Keep acronyms uppercase (e.g., `HTTPClient`, `XMLParser`).
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
class User_profile
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module Api_Helper
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class HttpClient # Acronym 'HTTP' should be all caps
|
|
22
|
+
end
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Correct:**
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
class UserProfile
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
module ApiHelper
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class HTTPClient
|
|
35
|
+
end
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Tools:** RuboCop (`Naming/ClassName`)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use SCREAMING_SNAKE_CASE for constants
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Clearly distinguish constants from other identifiers.
|
|
5
|
+
tags: ruby, naming, constants, readability
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use SCREAMING_SNAKE_CASE for constants
|
|
9
|
+
|
|
10
|
+
Clearly distinguish constants from other identifiers. Use `SCREAMING_SNAKE_CASE` for constants that do not refer to classes or modules.
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
DefaultTimeout = 30
|
|
16
|
+
Max_Retry_Count = 5
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct:**
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
DEFAULT_TIMEOUT = 30
|
|
23
|
+
MAX_RETRY_COUNT = 5
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Tools:** RuboCop (`Naming/ConstantName`)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Predicate methods should end with ?
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Make boolean-returning methods immediately recognizable.
|
|
5
|
+
tags: ruby, naming, predicate, boolean
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Predicate methods should end with ?
|
|
9
|
+
|
|
10
|
+
Make boolean-returning methods immediately recognizable. Methods that return boolean values should end with a question mark (`?`). Avoid prefixing with auxiliary verbs like `is_`, `does_`, or `can_`.
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
def is_valid
|
|
16
|
+
# logic
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
if user.is_authenticated
|
|
20
|
+
# logic
|
|
21
|
+
end
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Correct:**
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
def valid?
|
|
28
|
+
# logic
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
if user.authenticated?
|
|
32
|
+
# logic
|
|
33
|
+
end
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Tools:** RuboCop (`Naming/PredicateName`)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Dangerous methods should end with !
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Clearly indicate methods that modify the receiver or can raise exceptions.
|
|
5
|
+
tags: ruby, naming, bang, side-effect
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Dangerous methods should end with !
|
|
9
|
+
|
|
10
|
+
Clearly indicate methods that modify the receiver or can raise exceptions. Methods that modify the object in place or can raise exceptions should end with a bang (`!`).
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
# Method raises an exception if validation fails
|
|
16
|
+
def save
|
|
17
|
+
# complex logic
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# In-place sort
|
|
21
|
+
values.sort
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Correct:**
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
# Recommends save! for raising exceptions
|
|
28
|
+
def save!
|
|
29
|
+
# complex logic
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Indicates in-place sort
|
|
33
|
+
values.sort!
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Tools:** RuboCop (`Style/BangPredicate`)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use 2 spaces for indentation
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Follow Ruby community standard for code formatting.
|
|
5
|
+
tags: ruby, formatting, indentation, style
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use 2 spaces for indentation
|
|
9
|
+
|
|
10
|
+
Follow Ruby community standard for code formatting. Use 2 spaces for indentation, never tabs. Ensure consistent indentation throughout the codebase.
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
def hello
|
|
16
|
+
puts "hello" # Tab used
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def world
|
|
20
|
+
puts "world" # 4 spaces used
|
|
21
|
+
end
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Correct:**
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
def hello
|
|
28
|
+
puts "hello" # 2 spaces
|
|
29
|
+
end
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Tools:** RuboCop (`Layout/IndentationWidth`)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Keep lines under 120 characters
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Improve code readability and prevent horizontal scrolling.
|
|
5
|
+
tags: ruby, formatting, readability, side-scrolling
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Keep lines under 120 characters
|
|
9
|
+
|
|
10
|
+
Improve code readability and prevent horizontal scrolling. Limit line length to 120 characters maximum. Break long lines into multiple lines when necessary.
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
puts "This is an extremely long string that definitely exceeds the recommended limit of one hundred and twenty characters that we have set for our coding standards in this project."
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Correct:**
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
puts "This is an extremely long string that definitely exceeds " \
|
|
22
|
+
"the recommended limit of one hundred and twenty characters..."
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Tools:** RuboCop (`Layout/LineLength`)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid rescuing the Exception class
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Prevent hiding critical system errors.
|
|
5
|
+
tags: ruby, errors, exception, safety
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid rescuing the Exception class
|
|
9
|
+
|
|
10
|
+
Prevent hiding critical system errors. Never rescue the generic `Exception` class as it catches system-level errors (like `SignalException`, `NoMemoryError`, `SystemExit`). Rescue specific exception classes or `StandardError` instead.
|
|
11
|
+
|
|
12
|
+
**Incorrect (Dangerous):**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
begin
|
|
16
|
+
do_something
|
|
17
|
+
rescue Exception => e
|
|
18
|
+
logger.error(e.message)
|
|
19
|
+
end
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (Safe):**
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
begin
|
|
26
|
+
do_something
|
|
27
|
+
rescue StandardError => e # Or just 'rescue => e' which defaults to StandardError
|
|
28
|
+
logger.error(e.message)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Or specific
|
|
32
|
+
rescue ActiveRecord::RecordNotFound => e
|
|
33
|
+
# handle
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Tools:** RuboCop (`Lint/RescueException`)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use save! or handle return values
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Ensure database operations are properly validated and errors are not silently ignored.
|
|
5
|
+
tags: rails, database, validations, active-record
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use save! or handle return values
|
|
9
|
+
|
|
10
|
+
Ensure database operations are properly validated and errors are not silently ignored. Use bang methods (`save!`, `create!`, `update!`, `destroy!`) to raise exceptions on failure. If using non-bang methods, always check the return value.
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
def create
|
|
16
|
+
@user = User.new(user_params)
|
|
17
|
+
@user.save # Failure will be silent
|
|
18
|
+
redirect_to @user
|
|
19
|
+
end
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct:**
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
def create
|
|
26
|
+
@user = User.new(user_params)
|
|
27
|
+
if @user.save
|
|
28
|
+
redirect_to @user
|
|
29
|
+
else
|
|
30
|
+
render :new
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Or using bang
|
|
35
|
+
def create
|
|
36
|
+
@user = User.create!(user_params)
|
|
37
|
+
redirect_to @user
|
|
38
|
+
end
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Tools:** RuboCop (`Rails/SaveBang`)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid N+1 queries with eager loading
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Prevent performance issues caused by N+1 query problems.
|
|
5
|
+
tags: rails, performance, database, n+1, active-record
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid N+1 queries with eager loading
|
|
9
|
+
|
|
10
|
+
Prevent performance issues caused by N+1 query problems. Use `includes`, `preload`, or `eager_load` to load associations upfront. Avoid iterating over collections and accessing associations without eager loading.
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
# Triggers N+1 queries (one query for users, and one query per user for posts)
|
|
16
|
+
users = User.limit(10)
|
|
17
|
+
users.each do |user|
|
|
18
|
+
puts user.posts.count
|
|
19
|
+
end
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct:**
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
# Eager loads posts in 2 queries total
|
|
26
|
+
users = User.includes(:posts).limit(10)
|
|
27
|
+
users.each do |user|
|
|
28
|
+
puts user.posts.count
|
|
29
|
+
end
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Tools:** Bullet gem, RuboCop Rails (`Rails/FindEach`)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use find_each for large collections
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Reduce memory consumption when iterating over large datasets.
|
|
5
|
+
tags: rails, performance, database, memory, active-record
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use find_each for large collections
|
|
9
|
+
|
|
10
|
+
Reduce memory consumption when iterating over large datasets. Use `find_each` or `find_in_batches` instead of `each` for large ActiveRecord collections. `find_each` loads records in batches (default 1000) to avoid loading all records into memory at once.
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
# Loads ALL users into memory, which can crash the process for large datasets
|
|
16
|
+
User.all.each do |user|
|
|
17
|
+
user.do_something
|
|
18
|
+
end
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Correct:**
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
# Loads users in batches of 1000
|
|
25
|
+
User.find_each do |user|
|
|
26
|
+
user.do_something
|
|
27
|
+
end
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Tools:** RuboCop (`Rails/FindEach`)
|