@sun-asterisk/sunlint 1.3.40 → 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.
Files changed (172) hide show
  1. package/core/rule-selection-service.js +11 -0
  2. package/package.json +1 -1
  3. package/skill-assets/sunlint-code-quality/rules/dart/D001-recommended-lints.md +36 -0
  4. package/skill-assets/sunlint-code-quality/rules/dart/D002-dispose-resources.md +44 -0
  5. package/skill-assets/sunlint-code-quality/rules/dart/D003-prefer-widget-classes.md +53 -0
  6. package/skill-assets/sunlint-code-quality/rules/dart/D004-avoid-shrinkwrap.md +31 -0
  7. package/skill-assets/sunlint-code-quality/rules/dart/D005-widget-nesting.md +62 -0
  8. package/skill-assets/sunlint-code-quality/rules/dart/D006-large-callbacks.md +54 -0
  9. package/skill-assets/sunlint-code-quality/rules/dart/D007-lifecycle-order.md +44 -0
  10. package/skill-assets/sunlint-code-quality/rules/dart/D008-long-functions.md +37 -0
  11. package/skill-assets/sunlint-code-quality/rules/dart/D009-function-parameters.md +38 -0
  12. package/skill-assets/sunlint-code-quality/rules/dart/D010-cyclomatic-complexity.md +46 -0
  13. package/skill-assets/sunlint-code-quality/rules/dart/D011-named-parameters.md +31 -0
  14. package/skill-assets/sunlint-code-quality/rules/dart/D012-named-booleans.md +28 -0
  15. package/skill-assets/sunlint-code-quality/rules/dart/D013-single-public-class.md +34 -0
  16. package/skill-assets/sunlint-code-quality/rules/dart/D014-safe-collection-access.md +30 -0
  17. package/skill-assets/sunlint-code-quality/rules/dart/D015-copywith-consistency.md +52 -0
  18. package/skill-assets/sunlint-code-quality/rules/dart/D016-project-tests.md +32 -0
  19. package/skill-assets/sunlint-code-quality/rules/dart/D017-review-dependencies.md +24 -0
  20. package/skill-assets/sunlint-code-quality/rules/dart/D018-no-commented-code.md +34 -0
  21. package/skill-assets/sunlint-code-quality/rules/dart/D019-single-child-wrappers.md +31 -0
  22. package/skill-assets/sunlint-code-quality/rules/dart/D020-if-else-limit.md +41 -0
  23. package/skill-assets/sunlint-code-quality/rules/dart/D021-negated-booleans.md +26 -0
  24. package/skill-assets/sunlint-code-quality/rules/dart/D022-setstate-usage.md +35 -0
  25. package/skill-assets/sunlint-code-quality/rules/dart/D023-unnecessary-overrides.md +32 -0
  26. package/skill-assets/sunlint-code-quality/rules/dart/D024-avoid-unnecessary-statefulwidget.md +45 -0
  27. package/skill-assets/sunlint-code-quality/rules/dart/D025-nested-ternaries.md +35 -0
  28. package/skill-assets/sunlint-code-quality/rules/go/C006-verb-noun-functions.md +45 -0
  29. package/skill-assets/sunlint-code-quality/rules/go/C013-no-dead-code.md +48 -0
  30. package/skill-assets/sunlint-code-quality/rules/go/C014-dependency-injection.md +85 -0
  31. package/skill-assets/sunlint-code-quality/rules/go/C017-no-constructor-logic.md +67 -0
  32. package/skill-assets/sunlint-code-quality/rules/go/C018-generic-errors.md +63 -0
  33. package/skill-assets/sunlint-code-quality/rules/go/C019-error-log-level.md +50 -0
  34. package/skill-assets/sunlint-code-quality/rules/go/C020-no-unused-imports.md +45 -0
  35. package/skill-assets/sunlint-code-quality/rules/go/C022-no-unused-variables.md +34 -0
  36. package/skill-assets/sunlint-code-quality/rules/go/C023-no-duplicate-names.md +41 -0
  37. package/skill-assets/sunlint-code-quality/rules/go/C024-centralize-constants.md +55 -0
  38. package/skill-assets/sunlint-code-quality/rules/go/C029-catch-log-root-cause.md +56 -0
  39. package/skill-assets/sunlint-code-quality/rules/go/C030-custom-error-classes.md +69 -0
  40. package/skill-assets/sunlint-code-quality/rules/go/C033-separate-data-access.md +68 -0
  41. package/skill-assets/sunlint-code-quality/rules/go/C035-error-context-logging.md +48 -0
  42. package/skill-assets/sunlint-code-quality/rules/go/C041-no-hardcoded-secrets.md +45 -0
  43. package/skill-assets/sunlint-code-quality/rules/go/C042-boolean-naming.md +42 -0
  44. package/skill-assets/sunlint-code-quality/rules/go/C052-controller-parsing.md +62 -0
  45. package/skill-assets/sunlint-code-quality/rules/go/C060-superclass-logic.md +60 -0
  46. package/skill-assets/sunlint-code-quality/rules/go/C067-no-hardcoded-config.md +51 -0
  47. package/skill-assets/sunlint-code-quality/rules/go/S003-open-redirect.md +80 -0
  48. package/skill-assets/sunlint-code-quality/rules/go/S004-no-log-credentials.md +66 -0
  49. package/skill-assets/sunlint-code-quality/rules/go/S005-server-authorization.md +55 -0
  50. package/skill-assets/sunlint-code-quality/rules/go/S006-default-credentials.md +47 -0
  51. package/skill-assets/sunlint-code-quality/rules/go/S007-output-encoding.md +50 -0
  52. package/skill-assets/sunlint-code-quality/rules/go/S009-approved-crypto.md +63 -0
  53. package/skill-assets/sunlint-code-quality/rules/go/S010-csprng.md +53 -0
  54. package/skill-assets/sunlint-code-quality/rules/go/S011-encrypted-client-hello.md +34 -0
  55. package/skill-assets/sunlint-code-quality/rules/go/S012-secrets-management.md +49 -0
  56. package/skill-assets/sunlint-code-quality/rules/go/S013-tls-connections.md +61 -0
  57. package/skill-assets/sunlint-code-quality/rules/go/S016-no-sensitive-query-string.md +42 -0
  58. package/skill-assets/sunlint-code-quality/rules/go/S017-parameterized-queries.md +36 -0
  59. package/skill-assets/sunlint-code-quality/rules/go/S019-email-input-sanitization.md +44 -0
  60. package/skill-assets/sunlint-code-quality/rules/go/S020-eval-code-execution.md +47 -0
  61. package/skill-assets/sunlint-code-quality/rules/go/S022-context-escaping.md +49 -0
  62. package/skill-assets/sunlint-code-quality/rules/go/S023-dynamic-js-encoding.md +51 -0
  63. package/skill-assets/sunlint-code-quality/rules/go/S025-server-validation.md +57 -0
  64. package/skill-assets/sunlint-code-quality/rules/go/S026-tls-encryption.md +46 -0
  65. package/skill-assets/sunlint-code-quality/rules/go/S027-mtls-validation.md +52 -0
  66. package/skill-assets/sunlint-code-quality/rules/go/S028-upload-limits.md +58 -0
  67. package/skill-assets/sunlint-code-quality/rules/go/S029-csrf-protection.md +53 -0
  68. package/skill-assets/sunlint-code-quality/rules/go/S030-directory-browsing.md +53 -0
  69. package/skill-assets/sunlint-code-quality/rules/go/S031-secure-cookie-flag.md +48 -0
  70. package/skill-assets/sunlint-code-quality/rules/go/S032-httponly-cookie.md +42 -0
  71. package/skill-assets/sunlint-code-quality/rules/go/S033-samesite-cookie.md +49 -0
  72. package/skill-assets/sunlint-code-quality/rules/go/S034-host-prefix-cookie.md +44 -0
  73. package/skill-assets/sunlint-code-quality/rules/go/S035-app-hostnames.md +50 -0
  74. package/skill-assets/sunlint-code-quality/rules/go/S036-internal-file-paths.md +56 -0
  75. package/skill-assets/sunlint-code-quality/rules/go/S037-anti-cache-headers.md +43 -0
  76. package/skill-assets/sunlint-code-quality/rules/go/S039-tls-certificate-validation.md +41 -0
  77. package/skill-assets/sunlint-code-quality/rules/go/S041-logout-invalidation.md +46 -0
  78. package/skill-assets/sunlint-code-quality/rules/go/S042-long-lived-sessions.md +58 -0
  79. package/skill-assets/sunlint-code-quality/rules/go/S044-critical-changes-reauth.md +53 -0
  80. package/skill-assets/sunlint-code-quality/rules/go/S045-brute-force-protection.md +55 -0
  81. package/skill-assets/sunlint-code-quality/rules/go/S047-oauth-csrf-protection.md +51 -0
  82. package/skill-assets/sunlint-code-quality/rules/go/S048-oauth-redirect-validation.md +58 -0
  83. package/skill-assets/sunlint-code-quality/rules/go/S049-auth-code-expiry.md +52 -0
  84. package/skill-assets/sunlint-code-quality/rules/go/S050-token-entropy.md +53 -0
  85. package/skill-assets/sunlint-code-quality/rules/go/S051-password-length.md +49 -0
  86. package/skill-assets/sunlint-code-quality/rules/go/S052-otp-entropy.md +48 -0
  87. package/skill-assets/sunlint-code-quality/rules/go/S053-generic-error-messages.md +51 -0
  88. package/skill-assets/sunlint-code-quality/rules/go/S054-no-default-admin.md +43 -0
  89. package/skill-assets/sunlint-code-quality/rules/go/S055-content-type-validation.md +52 -0
  90. package/skill-assets/sunlint-code-quality/rules/go/S056-log-injection.md +40 -0
  91. package/skill-assets/sunlint-code-quality/rules/go/S057-synchronized-time.md +40 -0
  92. package/skill-assets/sunlint-code-quality/rules/go/S058-ssrf-protection.md +70 -0
  93. package/skill-assets/sunlint-code-quality/rules/ruby/RB001-use-snake-case.md +30 -0
  94. package/skill-assets/sunlint-code-quality/rules/ruby/RB002-use-camel-case.md +38 -0
  95. package/skill-assets/sunlint-code-quality/rules/ruby/RB003-use-screaming-snake-case.md +26 -0
  96. package/skill-assets/sunlint-code-quality/rules/ruby/RB004-predicate-methods.md +36 -0
  97. package/skill-assets/sunlint-code-quality/rules/ruby/RB005-dangerous-methods.md +36 -0
  98. package/skill-assets/sunlint-code-quality/rules/ruby/RB006-indentation.md +32 -0
  99. package/skill-assets/sunlint-code-quality/rules/ruby/RB007-line-length.md +25 -0
  100. package/skill-assets/sunlint-code-quality/rules/ruby/RB008-rescue-exception.md +36 -0
  101. package/skill-assets/sunlint-code-quality/rules/ruby/RB009-save-bang.md +41 -0
  102. package/skill-assets/sunlint-code-quality/rules/ruby/RB010-avoid-n-plus-one.md +32 -0
  103. package/skill-assets/sunlint-code-quality/rules/ruby/RB011-use-find-each.md +30 -0
  104. package/skill-assets/sunlint-code-quality/rules/ruby/RB012-sql-injection.md +29 -0
  105. package/skill-assets/sunlint-code-quality/rules/ruby/RB013-prefer-has-many-through.md +35 -0
  106. package/skill-assets/sunlint-code-quality/rules/ruby/RB014-dependent-associations.md +28 -0
  107. package/skill-assets/sunlint-code-quality/rules/ruby/RB015-modern-validations.md +29 -0
  108. package/skill-assets/sunlint-code-quality/rules/ruby/RB016-thin-controllers.md +45 -0
  109. package/skill-assets/sunlint-code-quality/rules/ruby/RB017-avoid-fat-models.md +41 -0
  110. package/skill-assets/sunlint-code-quality/rules/ruby/RB018-service-objects.md +36 -0
  111. package/skill-assets/sunlint-code-quality/rules/ruby/RB019-avoid-metaprogramming.md +40 -0
  112. package/skill-assets/sunlint-code-quality/rules/ruby/RB020-use-pluck.md +29 -0
  113. package/skill-assets/sunlint-code-quality/rules/ruby/RB021-use-size.md +27 -0
  114. package/skill-assets/sunlint-code-quality/rules/ruby/RB022-order-by-timestamps.md +24 -0
  115. package/skill-assets/sunlint-code-quality/rules/ruby/RB023-where-missing.md +24 -0
  116. package/skill-assets/sunlint-code-quality/rules/ruby/RB024-method-length.md +41 -0
  117. package/skill-assets/sunlint-code-quality/rules/ruby/RB025-parameter-limits.md +28 -0
  118. package/skill-assets/sunlint-code-quality/rules/ruby/RB026-avoid-deep-nesting.md +38 -0
  119. package/skill-assets/sunlint-code-quality/rules/ruby/RB027-guard-clauses.md +37 -0
  120. package/skill-assets/sunlint-code-quality/rules/ruby/RB028-class-length.md +32 -0
  121. package/skill-assets/sunlint-code-quality/rules/ruby/RB029-meaningful-names.md +30 -0
  122. package/skill-assets/sunlint-code-quality/rules/ruby/RB030-dry-principle.md +37 -0
  123. package/skill-assets/sunlint-code-quality/rules/ruby/RB031-mvc-architecture.md +37 -0
  124. package/skill-assets/sunlint-code-quality/rules/ruby/RB032-use-concerns.md +31 -0
  125. package/skill-assets/sunlint-code-quality/rules/ruby/RB033-moderate-callbacks.md +31 -0
  126. package/skill-assets/sunlint-code-quality/rules/ruby/RB034-use-decorators.md +33 -0
  127. package/skill-assets/sunlint-code-quality/rules/ruby/RB035-comprehensive-tests.md +32 -0
  128. package/skill-assets/sunlint-code-quality/rules/ruby/RB036-frozen-string-literal.md +29 -0
  129. package/skill-assets/sunlint-code-quality/rules/ruby/RB037-it-parameter.md +25 -0
  130. package/skill-assets/sunlint-code-quality/rules/ruby/RB038-modern-enum-syntax.md +28 -0
  131. package/skill-assets/sunlint-code-quality/rules/ruby/RB039-solid-adapters.md +29 -0
  132. package/skill-assets/sunlint-code-quality/rules/ruby/RB040-rails-authentication.md +26 -0
  133. package/skill-assets/sunlint-code-quality/rules/ruby/RB041-async-query-loading.md +29 -0
  134. package/skill-assets/sunlint-code-quality/rules/ruby/RB042-hotwire-turbo.md +30 -0
  135. package/skill-assets/sunlint-code-quality/rules/ruby/RB043-use-propshaft.md +27 -0
  136. package/skill-assets/sunlint-code-quality/rules/ruby/RB044-structured-logging.md +35 -0
  137. package/skill-assets/sunlint-code-quality/rules/ruby/RB045-prism-parser.md +29 -0
  138. package/skill-assets/sunlint-code-quality/rules/swift/SW001-block-based-kvo.md +40 -0
  139. package/skill-assets/sunlint-code-quality/rules/swift/SW002-class-delegate-protocol.md +36 -0
  140. package/skill-assets/sunlint-code-quality/rules/swift/SW003-compiler-protocol-init.md +28 -0
  141. package/skill-assets/sunlint-code-quality/rules/swift/SW004-contains-over-filter-count.md +28 -0
  142. package/skill-assets/sunlint-code-quality/rules/swift/SW005-convenience-type.md +34 -0
  143. package/skill-assets/sunlint-code-quality/rules/swift/SW006-discarded-notification-center-observer.md +41 -0
  144. package/skill-assets/sunlint-code-quality/rules/swift/SW007-discouraged-direct-init.md +28 -0
  145. package/skill-assets/sunlint-code-quality/rules/swift/SW008-discouraged-optional-boolean.md +32 -0
  146. package/skill-assets/sunlint-code-quality/rules/swift/SW009-empty-count.md +30 -0
  147. package/skill-assets/sunlint-code-quality/rules/swift/SW010-empty-string.md +30 -0
  148. package/skill-assets/sunlint-code-quality/rules/swift/SW011-explicit-init.md +26 -0
  149. package/skill-assets/sunlint-code-quality/rules/swift/SW012-fatal-error-message.md +28 -0
  150. package/skill-assets/sunlint-code-quality/rules/swift/SW013-for-where.md +30 -0
  151. package/skill-assets/sunlint-code-quality/rules/swift/SW014-force-cast.md +26 -0
  152. package/skill-assets/sunlint-code-quality/rules/swift/SW015-force-try.md +30 -0
  153. package/skill-assets/sunlint-code-quality/rules/swift/SW016-force-unwrapping.md +32 -0
  154. package/skill-assets/sunlint-code-quality/rules/swift/SW017-function-parameter-count.md +37 -0
  155. package/skill-assets/sunlint-code-quality/rules/swift/SW018-large-tuple.md +41 -0
  156. package/skill-assets/sunlint-code-quality/rules/swift/SW019-legacy-constructor.md +28 -0
  157. package/skill-assets/sunlint-code-quality/rules/swift/SW020-nesting.md +38 -0
  158. package/skill-assets/sunlint-code-quality/rules/swift/SW021-no-extension-access-modifier.md +28 -0
  159. package/skill-assets/sunlint-code-quality/rules/swift/SW022-overridden-super-call.md +30 -0
  160. package/skill-assets/sunlint-code-quality/rules/swift/SW023-override-in-extension.md +32 -0
  161. package/skill-assets/sunlint-code-quality/rules/swift/SW024-private-over-fileprivate.md +28 -0
  162. package/skill-assets/sunlint-code-quality/rules/swift/SW025-private-unit-test.md +32 -0
  163. package/skill-assets/sunlint-code-quality/rules/swift/SW026-prohibited-super-call.md +29 -0
  164. package/skill-assets/sunlint-code-quality/rules/swift/SW027-sorted-first-last.md +28 -0
  165. package/skill-assets/sunlint-code-quality/rules/swift/SW028-syntactic-sugar.md +28 -0
  166. package/skill-assets/sunlint-code-quality/rules/swift/SW029-unused-closure-parameter.md +28 -0
  167. package/skill-assets/sunlint-code-quality/rules/swift/SW030-unused-enumerated.md +28 -0
  168. package/skill-assets/sunlint-code-quality/rules/swift/SW031-unused-optional-binding.md +26 -0
  169. package/skill-assets/sunlint-code-quality/rules/swift/SW032-valid-ibinspectable.md +26 -0
  170. package/skill-assets/sunlint-code-quality/rules/swift/SW033-vertical-parameter-alignment.md +36 -0
  171. package/skill-assets/sunlint-code-quality/rules/swift/SW034-void-return.md +28 -0
  172. package/skill-assets/sunlint-code-quality/rules/swift/SW035-weak-delegate.md +28 -0
@@ -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`)
@@ -0,0 +1,36 @@
1
+ ---
2
+ title: Use service objects for complex business logic
3
+ impact: HIGH
4
+ impactDescription: Improve code organization and testability.
5
+ tags: rails, architecture, service-objects, patterns
6
+ ---
7
+
8
+ ## Use service objects for complex business logic
9
+
10
+ Improve code organization and testability. Extract complex business logic (payments, onboarding, multi-step processes) into service objects. Service objects should have a single public method (e.g., `call`, `execute`) and reside in `app/services/`.
11
+
12
+ **Incorrect (Logic inside model):**
13
+
14
+ ```ruby
15
+ class Payment < ApplicationRecord
16
+ def process!
17
+ # API calls, state changes, email triggers...
18
+ end
19
+ end
20
+ ```
21
+
22
+ **Correct (Decoupled Service):**
23
+
24
+ ```ruby
25
+ class PaymentProcessor
26
+ def initialize(payment)
27
+ @payment = payment
28
+ end
29
+
30
+ def call
31
+ # API calls, state changes, email triggers...
32
+ end
33
+ end
34
+ ```
35
+
36
+ **Tools:** Custom linter, Manual Review
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: Avoid needless metaprogramming
3
+ impact: MEDIUM
4
+ impactDescription: Maintain code clarity and debuggability.
5
+ tags: ruby, metaprogramming, readability, simplicity
6
+ ---
7
+
8
+ ## Avoid needless metaprogramming
9
+
10
+ Maintain code clarity and debuggability. Avoid using metaprogramming (`define_method`, `method_missing`, `class_eval`) unless absolutely necessary. Metaprogramming makes code harder to understand, debug, and maintain.
11
+
12
+ **Incorrect (Over-engineered):**
13
+
14
+ ```ruby
15
+ class User
16
+ [:name, :email, :phone].each do |attr|
17
+ define_method("display_#{attr}") do
18
+ send(attr) || "N/A"
19
+ end
20
+ end
21
+ end
22
+ ```
23
+
24
+ **Correct (Explicit):**
25
+
26
+ ```ruby
27
+ class User
28
+ def display_name
29
+ name || "N/A"
30
+ end
31
+
32
+ def display_email
33
+ email || "N/A"
34
+ end
35
+
36
+ # ...
37
+ end
38
+ ```
39
+
40
+ **Tools:** RuboCop (`Style/MethodMissingSuper`)
@@ -0,0 +1,29 @@
1
+ ---
2
+ title: Use pluck for selecting specific columns
3
+ impact: MEDIUM
4
+ impactDescription: Improve query performance by selecting only needed columns.
5
+ tags: rails, performance, database, active-record
6
+ ---
7
+
8
+ ## Use pluck for selecting specific columns
9
+
10
+ Improve query performance by selecting only needed columns. Use `pluck` to select columns from multiple records. Use `pick` for a single value from a single record.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ # Loads whole User objects into memory just to get ids
16
+ User.all.map(&:id)
17
+ ```
18
+
19
+ **Correct:**
20
+
21
+ ```ruby
22
+ # Only selects 'id' in SQL
23
+ User.pluck(:id)
24
+
25
+ # Even better for IDs specifically
26
+ User.ids
27
+ ```
28
+
29
+ **Tools:** RuboCop (`Rails/Pluck`, `Rails/PluckId`)
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: Use size over count or length
3
+ impact: LOW
4
+ impactDescription: Optimize performance by using the most efficient method.
5
+ tags: rails, performance, active-record, database
6
+ ---
7
+
8
+ ## Use size over count or length
9
+
10
+ Optimize performance by using the most efficient method. Use `size` instead of `count` or `length` for ActiveRecord collections. `size` intelligently chooses between `count` (SQL query if not loaded) and `length` (array size if already loaded).
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ # Always triggers a SELECT COUNT(*) query even if data is already loaded
16
+ users = User.all.to_a
17
+ puts users.count
18
+ ```
19
+
20
+ **Correct:**
21
+
22
+ ```ruby
23
+ # Uses the array size if already loaded, otherwise queries DB
24
+ puts User.all.size
25
+ ```
26
+
27
+ **Tools:** RuboCop (`Rails/SkipsModelValidations`)
@@ -0,0 +1,24 @@
1
+ ---
2
+ title: Order by timestamp columns, not id
3
+ impact: MEDIUM
4
+ impactDescription: Ensure consistent ordering across database systems.
5
+ tags: database, rails, active-record, ordering
6
+ ---
7
+
8
+ ## Order by timestamp columns, not id
9
+
10
+ Ensure consistent ordering across database systems. Order records chronologically by timestamp columns (`created_at`, `updated_at`) instead of `id`. IDs may not be sequential in distributed systems (e.g., UUIDs).
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ scope :recent, -> { order(id: :desc) }
16
+ ```
17
+
18
+ **Correct:**
19
+
20
+ ```ruby
21
+ scope :recent, -> { order(created_at: :desc) }
22
+ ```
23
+
24
+ **Tools:** Manual Review
@@ -0,0 +1,24 @@
1
+ ---
2
+ title: Use where.missing for Rails 6.1+
3
+ impact: LOW
4
+ impactDescription: Use modern Rails APIs for finding records with missing associations.
5
+ tags: rails, active-record, simplicity, associations
6
+ ---
7
+
8
+ ## Use where.missing for Rails 6.1+
9
+
10
+ Use modern Rails APIs for finding records with missing associations. Use `where.missing(:association)` instead of left joins with null checks. This is more readable and expressive.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ Post.left_outer_joins(:comments).where(comments: { id: nil })
16
+ ```
17
+
18
+ **Correct:**
19
+
20
+ ```ruby
21
+ Post.where.missing(:comments)
22
+ ```
23
+
24
+ **Tools:** RuboCop (`Rails/WhereMissing`)
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Keep methods under 10 lines
3
+ impact: MEDIUM
4
+ impactDescription: Improve code readability and maintainability.
5
+ tags: ruby, quality, metrics, readability
6
+ ---
7
+
8
+ ## Keep methods under 10 lines
9
+
10
+ Improve code readability and maintainability. Limit methods to 10 lines of code (excluding blank lines and comments). Extract complex logic into smaller, well-named private methods.
11
+
12
+ **Incorrect (Too long):**
13
+
14
+ ```ruby
15
+ def process_order(order)
16
+ validate_order(order)
17
+ apply_discount(order)
18
+ notify_user(order)
19
+ update_inventory(order)
20
+ generate_invoice(order)
21
+ archive_order(order)
22
+ # ... many more lines
23
+ end
24
+ ```
25
+
26
+ **Correct:**
27
+
28
+ ```ruby
29
+ def process_order(order)
30
+ prepare_order(order)
31
+ finalize_order(order)
32
+ end
33
+
34
+ private
35
+
36
+ def prepare_order(order)
37
+ # sub-logic < 10 lines
38
+ end
39
+ ```
40
+
41
+ **Tools:** RuboCop (`Metrics/MethodLength`)
@@ -0,0 +1,28 @@
1
+ ---
2
+ title: Limit method parameters to 4
3
+ impact: MEDIUM
4
+ impactDescription: Reduce method complexity and improve readability.
5
+ tags: ruby, quality, design, parameters
6
+ ---
7
+
8
+ ## Limit method parameters to 4
9
+
10
+ Reduce method complexity and improve readability. Limit methods to 4 parameters maximum. If more parameters are needed, consider using a hash or a specific parameter object.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ def send_email(to, from, subject, body, cc, bcc, attachments)
16
+ # logic
17
+ end
18
+ ```
19
+
20
+ **Correct:**
21
+
22
+ ```ruby
23
+ def send_email(to:, from:, subject:, body:, options: {})
24
+ # logic
25
+ end
26
+ ```
27
+
28
+ **Tools:** RuboCop (`Metrics/ParameterLists`)
@@ -0,0 +1,38 @@
1
+ ---
2
+ title: Avoid deep nesting (max 3 levels)
3
+ impact: MEDIUM
4
+ impactDescription: Improve code readability and reduce cyclomatic complexity.
5
+ tags: ruby, quality, metrics, nesting
6
+ ---
7
+
8
+ ## Avoid deep nesting (max 3 levels)
9
+
10
+ Improve code readability and reduce cyclomatic complexity. Limit nesting (if/else, blocks) to 3 levels maximum. Use guard clauses, early returns, or extract methods to flatten code.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ def update_user
16
+ if logged_in?
17
+ if admin?
18
+ if params[:id].present?
19
+ # 4th level nesting
20
+ end
21
+ end
22
+ end
23
+ end
24
+ ```
25
+
26
+ **Correct:**
27
+
28
+ ```ruby
29
+ def update_user
30
+ return unless logged_in?
31
+ return unless admin?
32
+ return if params[:id].blank?
33
+
34
+ # Logic at level 1
35
+ end
36
+ ```
37
+
38
+ **Tools:** RuboCop (`Metrics/BlockNesting`)
@@ -0,0 +1,37 @@
1
+ ---
2
+ title: Use guard clauses for early returns
3
+ impact: MEDIUM
4
+ impactDescription: Reduce nesting and improve code clarity.
5
+ tags: ruby, quality, style, clean-code
6
+ ---
7
+
8
+ ## Use guard clauses for early returns
9
+
10
+ Reduce nesting and improve code clarity. Use guard clauses to handle edge cases or invalid states early and return. This keeps the main happy path at the top level of the method.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ def notify(user)
16
+ if user.active?
17
+ if user.email_notifications?
18
+ # Main logic here
19
+ UserMailer.notification(user).deliver_now
20
+ end
21
+ end
22
+ end
23
+ ```
24
+
25
+ **Correct:**
26
+
27
+ ```ruby
28
+ def notify(user)
29
+ return unless user.active?
30
+ return unless user.email_notifications?
31
+
32
+ # Main logic here
33
+ UserMailer.notification(user).deliver_now
34
+ end
35
+ ```
36
+
37
+ **Tools:** RuboCop (`Style/GuardClause`)
@@ -0,0 +1,32 @@
1
+ ---
2
+ title: Keep classes under 100 lines
3
+ impact: MEDIUM
4
+ impactDescription: Maintain single responsibility and improve maintainability.
5
+ tags: ruby, quality, design, architecture
6
+ ---
7
+
8
+ ## Keep classes under 100 lines
9
+
10
+ Maintain single responsibility and improve maintainability. Limit classes to 100 lines of code (excluding blank lines and comments). Extract responsibilities into separate classes or modules if a class grows too large.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ class BigManager
16
+ # 200 lines of mixed logic
17
+ end
18
+ ```
19
+
20
+ **Correct:**
21
+
22
+ ```ruby
23
+ class OrderProcessor
24
+ # focused logic < 100 lines
25
+ end
26
+
27
+ class OrderNotifier
28
+ # focused logic < 100 lines
29
+ end
30
+ ```
31
+
32
+ **Tools:** RuboCop (`Metrics/ClassLength`)
@@ -0,0 +1,30 @@
1
+ ---
2
+ title: Use meaningful variable and method names
3
+ impact: MEDIUM
4
+ impactDescription: Improve code self-documentation and readability.
5
+ tags: ruby, naming, readability, quality
6
+ ---
7
+
8
+ ## Use meaningful variable and method names
9
+
10
+ Improve code self-documentation and readability. Use descriptive names that clearly convey purpose. Avoid single-letter variables except for common iterators (i, j, k).
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ def calc(a, b)
16
+ r = a * b
17
+ return r
18
+ end
19
+ ```
20
+
21
+ **Correct:**
22
+
23
+ ```ruby
24
+ def calculate_area(width, height)
25
+ area = width * height
26
+ return area
27
+ end
28
+ ```
29
+
30
+ **Tools:** RuboCop (`Naming/VariableName`)
@@ -0,0 +1,37 @@
1
+ ---
2
+ title: Don't Repeat Yourself (DRY)
3
+ impact: MEDIUM
4
+ impactDescription: Reduce code duplication and improve maintainability.
5
+ tags: ruby, abstraction, maintenance, quality
6
+ ---
7
+
8
+ ## Don't Repeat Yourself (DRY)
9
+
10
+ Reduce code duplication and improve maintainability. Extract repeated code into methods, helpers, concerns, or partials. Use inheritance or modules to share behavior instead of copy-pasting code blocks.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ def create_admin
16
+ user = User.new(admin: true)
17
+ user.save!
18
+ Log.create(action: "admin created")
19
+ end
20
+
21
+ def create_user
22
+ user = User.new(admin: false)
23
+ user.save!
24
+ Log.create(action: "user created")
25
+ end
26
+ ```
27
+
28
+ **Correct:**
29
+
30
+ ```ruby
31
+ def create_account(admin: false)
32
+ user = User.create!(admin: admin)
33
+ Log.create(action: "#{admin ? 'admin' : 'user'} created")
34
+ end
35
+ ```
36
+
37
+ **Tools:** Reek, RuboCop (`Style/IdenticalConditionalBranches`)