@sun-asterisk/sunlint 1.3.41 → 1.3.43
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/rules/security/S024_xpath_xxe_protection/typescript/regex-based-analyzer.js +4 -4
- package/rules/security/S024_xpath_xxe_protection/typescript/symbol-based-analyzer.js +1 -1
- package/rules/security/S025_server_side_validation/typescript/regex-based-analyzer.js +5 -5
- package/rules/security/S025_server_side_validation/typescript/symbol-based-analyzer.js +6 -6
- package/rules/security/S032_httponly_session_cookies/typescript/regex-based-analyzer.js +8 -8
- package/rules/security/S033_samesite_session_cookies/typescript/regex-based-analyzer.js +12 -12
- package/rules/security/S033_samesite_session_cookies/typescript/symbol-based-analyzer.js +1 -1
- package/rules/security/S034_host_prefix_session_cookies/typescript/regex-based-analyzer.js +1 -1
- package/rules/security/S041_session_token_invalidation/typescript/regex-based-analyzer.js +4 -4
- package/rules/security/S041_session_token_invalidation/typescript/symbol-based-analyzer.js +1 -1
- package/rules/security/S044_re_authentication_required/typescript/regex-based-analyzer.js +1 -1
- package/rules/security/S044_re_authentication_required/typescript/symbol-based-analyzer.js +1 -1
- package/rules/security/S045_brute_force_protection/typescript/analyzer.js +1 -1
- package/rules/security/S045_brute_force_protection/typescript/symbol-based-analyzer.js +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,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`)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid SQL injection with parameterized queries
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
impactDescription: Prevent SQL injection vulnerabilities.
|
|
5
|
+
tags: ruby, rails, security, sql-injection, active-record
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid SQL injection with parameterized queries
|
|
9
|
+
|
|
10
|
+
Prevent SQL injection vulnerabilities. Never use string interpolation in SQL queries. Use parameterized queries with `?` or named placeholders (`:name`). Use hash conditions for `where` clauses instead of SQL fragments.
|
|
11
|
+
|
|
12
|
+
**Incorrect (Vulnerable):**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
# Direct interpolation is dangerous
|
|
16
|
+
User.where("name = '#{params[:name]}'")
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (Safe):**
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
# Parameterized
|
|
23
|
+
User.where("name = ?", params[:name])
|
|
24
|
+
|
|
25
|
+
# Hash-based (Recommended)
|
|
26
|
+
User.where(name: params[:name])
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Tools:** Brakeman, RuboCop (`Rails/SquishedSQLHeredocs`)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Prefer has_many :through over HABTM
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Allow for additional attributes and validations on join models.
|
|
5
|
+
tags: rails, database, associations, active-record
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Prefer has_many :through over HABTM
|
|
9
|
+
|
|
10
|
+
Allow for additional attributes and validations on join models. Use `has_many :through` instead of `has_and_belongs_to_many` for many-to-many relationships. This provides more flexibility for adding attributes or validations to the join table later.
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
class User < ApplicationRecord
|
|
16
|
+
has_and_belongs_to_many :roles
|
|
17
|
+
end
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct:**
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
class User < ApplicationRecord
|
|
24
|
+
has_many :assignments
|
|
25
|
+
has_many :roles, through: :assignments
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class Assignment < ApplicationRecord
|
|
29
|
+
belongs_to :user
|
|
30
|
+
belongs_to :role
|
|
31
|
+
# Can add validations or extra fields here
|
|
32
|
+
end
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Tools:** RuboCop (`Rails/HasAndBelongsToMany`)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Always define dependent option for associations
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Prevent orphaned records and ensure data integrity.
|
|
5
|
+
tags: rails, database, data-integrity, active-record
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Always define dependent option for associations
|
|
9
|
+
|
|
10
|
+
Prevent orphaned records and ensure data integrity. Always specify the `dependent` option for `has_many` and `has_one` associations to define what happens to associated records when the parent is deleted.
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
class User < ApplicationRecord
|
|
16
|
+
has_many :posts # No dependent option
|
|
17
|
+
end
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct:**
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
class User < ApplicationRecord
|
|
24
|
+
has_many :posts, dependent: :destroy
|
|
25
|
+
end
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Tools:** Custom linter, Manual Review
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use new-style validations
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Follow modern Rails conventions for model validations.
|
|
5
|
+
tags: rails, conventions, validations, active-record
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use new-style validations
|
|
9
|
+
|
|
10
|
+
Follow modern Rails conventions for model validations. Use the `validates` method with a hash of options. Avoid old-style validations like `validates_presence_of`.
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
class User < ApplicationRecord
|
|
16
|
+
validates_presence_of :email
|
|
17
|
+
validates_uniqueness_of :email
|
|
18
|
+
end
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Correct:**
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
class User < ApplicationRecord
|
|
25
|
+
validates :email, presence: true, uniqueness: true
|
|
26
|
+
end
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Tools:** RuboCop (`Rails/Validation`)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Keep controllers thin
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Maintain single responsibility and improve testability.
|
|
5
|
+
tags: rails, architecture, controllers, mvc
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Keep controllers thin
|
|
9
|
+
|
|
10
|
+
Maintain single responsibility and improve testability. Controllers should only handle HTTP requests and responses (parsing params, calling logic, redirecting/rendering). Extract complex business logic into service objects, models, or concerns.
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
class OrdersController < ApplicationController
|
|
16
|
+
def create
|
|
17
|
+
@order = Order.new(order_params)
|
|
18
|
+
# Complex business logic in controller
|
|
19
|
+
if @order.save
|
|
20
|
+
Inventory.decrease(@order.product_id)
|
|
21
|
+
EmailService.send_confirmation(@order.user)
|
|
22
|
+
redirect_to @order
|
|
23
|
+
else
|
|
24
|
+
render :new
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Correct:**
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
class OrdersController < ApplicationController
|
|
34
|
+
def create
|
|
35
|
+
@order = Order.new(order_params)
|
|
36
|
+
if OrderCreationService.call(@order)
|
|
37
|
+
redirect_to @order
|
|
38
|
+
else
|
|
39
|
+
render :new
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Tools:** RuboCop (`Metrics/MethodLength`)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid fat models
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Prevent models from becoming monolithic and hard to maintain.
|
|
5
|
+
tags: rails, architecture, models, mvc
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid fat models
|
|
9
|
+
|
|
10
|
+
Prevent models from becoming monolithic and hard to maintain. Keep models focused on associations, validations, and simple domain logic. Extract complex workflows or unrelated concerns into service objects or specific classes.
|
|
11
|
+
|
|
12
|
+
**Incorrect:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
# User model handling too many things (auth, analytics, profile, etc.)
|
|
16
|
+
class User < ApplicationRecord
|
|
17
|
+
def generate_analytics_report
|
|
18
|
+
# complex logic unrelated to core User state
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def process_subscription_upgrade
|
|
22
|
+
# complex workflow
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Correct:**
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
class User < ApplicationRecord
|
|
31
|
+
# core logic only
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class AnalyticsReportGenerator
|
|
35
|
+
def self.call(user)
|
|
36
|
+
# complex logic
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Tools:** RuboCop (`Metrics/ClassLength`)
|