rubocop-dev_doc 0.17.0 → 0.18.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 11175a594b0adb68ca20c3e2ff0ef414d1136d55152cd010a8d95ee26601a759
4
- data.tar.gz: 460f211f62e554bead8cd267a4c3e918159eccff748d2d03f0f06b56454d025e
3
+ metadata.gz: 3852833893968d60a5c0c198ffd3a2f34cb524a71998464a27803de2d56b44de
4
+ data.tar.gz: 1b4f675aa6967bca65d6f706997c06c73fe3b954b4092f6f8586e5c17b1e16b8
5
5
  SHA512:
6
- metadata.gz: 5b5a9ae0aed54ff1979d4deb8313ef53e0e8b3d831e9d3bbdabaf9c4d9c3897acd7486054cbd012222453c9e6dbcd0054821ea83ddac71c1231bc51d7be6072e
7
- data.tar.gz: e6acacc3e7f65769104c90d5043a08c6385983ab6c9f38db8088ff30193044ac1cd6e14b365c1cbf521de52d445b84e9c4312f75e2dcb6ab93370077a8134bed
6
+ metadata.gz: 3b4be761462f9974fa8caa317e1df9d71ead56160dc4d9d0e7b98407af11a8835f09a888e4b8677448981c6e8e032129312d6e469f7134426714351e594cdc64
7
+ data.tar.gz: 5aca39f093385aae489a8c1a18fcf43eff4995dd7a5d575d237e5a472a8477457789a9cb201ce5ba09abdc6c49fcbf80fbd761467ee2d46447f5ee943111292f
data/config/default.yml CHANGED
@@ -199,6 +199,29 @@ DevDoc/Rails/NoCollectionIdsWriterInController:
199
199
  Include:
200
200
  - "app/controllers/**/*.rb"
201
201
 
202
+ # Route params are resource identity (a bad URL SHOULD 404), but a
203
+ # form-submitted attribute fed to a finder turns an expected form state
204
+ # (nothing picked yet) into RecordNotFound, and drags the validity check
205
+ # into the controller. The remedy is assignment: put the id on the model
206
+ # and let its validations render the failure.
207
+ DevDoc/Rails/NoFormParamLookupInController:
208
+ Description: "A record finder in a controller must not be fed by a form-submitted attribute (`params[:form][:attribute]`, `params.dig(:form, :attribute)`); assign the id to the model and let its validations decide."
209
+ Enabled: true
210
+ Include:
211
+ - "app/controllers/**/*.rb"
212
+
213
+ # The controller is the assignment bridge, not the validity judge: a
214
+ # controller-side `errors.add` is a validation living in the wrong layer,
215
+ # guarded once for one POST while every other write path skips it. The
216
+ # three delivery shapes (rescue, policy guard, verification bang) are
217
+ # auto-exempted — there the check already lives in the right layer and the
218
+ # line only renders its outcome.
219
+ DevDoc/Rails/NoErrorsAddInController:
220
+ Description: "Controllers must not write errors onto a model (`record.errors.add`); the rule belongs in a model validation or form-object PORO. Delivery of an outcome from a rescue, policy, or verification method is auto-exempted."
221
+ Enabled: true
222
+ Include:
223
+ - "app/controllers/**/*.rb"
224
+
202
225
  DevDoc/Rails/EnumMustBeSymbolized:
203
226
  Description: "Declare enums with `enum_symbolize :foo, { … }` instead of a bare `enum`, so the attribute type is set before the enum and the reader returns a symbol."
204
227
  Enabled: true
@@ -240,6 +263,14 @@ DevDoc/Style/AvoidInsecureSend:
240
263
  Description: "Avoid insecure dynamic `send`/`public_send` — `send` is always flagged; `public_send` requires a prefix or trusted source (validator/mailer)."
241
264
  Enabled: true
242
265
 
266
+ DevDoc/Style/PreferAllowlistSymbolParam:
267
+ Description: "Flag a hand-rolled `find`/`detect` allow-list lookup against params/request.headers; use `glib_allowlist_symbol_param` instead."
268
+ Enabled: true
269
+
270
+ DevDoc/Style/InMemoryAssociationFind:
271
+ Description: "Flag block-form `find`/`detect` on an association declared in the same file; use `find_by` unless the in-memory view is required, or disable with a reason."
272
+ Enabled: true
273
+
243
274
  DevDoc/Style/PreferPublicSend:
244
275
  Description: "Prefer `public_send` over `send` — visibility-respecting dispatch surfaces typos/misconfig and documents intent."
245
276
  Enabled: true
@@ -605,6 +636,29 @@ Style/SafeNavigationChainLength:
605
636
  Enabled: true
606
637
  Max: 1
607
638
 
639
+ # Early returns over nesting. Core default is already on; listed here because
640
+ # best_practices/backend/en/01a_defensive_programming.md #2 relies on it (the
641
+ # doc dropped its nested-vs-early-return example in favour of this cop and
642
+ # keeps only the guard-SHAPE guidance the cop cannot judge).
643
+ Style/GuardClause:
644
+ Enabled: true
645
+
646
+ # Core default is `MinNameLength: 1`, which never fires. Raised to 3 so a bare
647
+ # `|e|` / `|u|` / `|s|` block parameter is an offense — the reader should not
648
+ # have to infer the type from the receiver (see
649
+ # best_practices/intro/en/01_principle.md, Code Intent). The core AllowedNames
650
+ # for this cop is empty (the `at/by/id/…` list belongs to
651
+ # Naming/MethodParameterName); the one exemption here is `t`, the
652
+ # `create_table do |t|` idiom, which made up half of the hits when this was
653
+ # measured against a consuming app (2026-09-09: 87 offenses, 44 of them `|t|`
654
+ # in db/; the other 43 were real). AllowNamesEndingInNumbers stays at its core
655
+ # default (true), so `emp1` passes; `e1` still fails on length.
656
+ Naming/BlockParameterName:
657
+ Enabled: true
658
+ MinNameLength: 3
659
+ AllowedNames:
660
+ - t
661
+
608
662
  # `has_X?` reads more naturally than the cop's preferred `X?` in many cases —
609
663
  # `has_active_subscription?` vs `active_subscription?`, `has_assignee?(member)`
610
664
  # vs `assignee?(member)`. Disabled cross-project so individual `.rubocop.yml`
@@ -696,6 +750,40 @@ DevDoc/Test/NoPersistenceInMailerPreviews:
696
750
  - "spec/mailers/previews/**/*.rb"
697
751
  - "lib/mailer_previews/**/*.rb"
698
752
 
753
+ # A test name containing shell- or regex-significant characters breaks running
754
+ # that single test by name: unquoted `-n name` is mis-parsed by the shell
755
+ # (syntax error, redirect, expansion, substitution), and in the `/name/` regex
756
+ # filter form the regex-significant ones match nothing, so the runner reports
757
+ # 0 runs — which reads as a pass. Every character in the default set has a
758
+ # verified failure in at least one of the two forms (checked against a real
759
+ # minitest single-test run); `? { } / !` are deliberately NOT forbidden — see
760
+ # the cop docstring for their caveats. ForbiddenCharacters must list the same
761
+ # characters, in the same order, as the cop's DEFAULT_FORBIDDEN_CHARACTERS
762
+ # (specs enforce set parity; order keeps runtime messages matching specs).
763
+ DevDoc/Test/TestNameSpecialCharacters:
764
+ Description: "Test names must not contain characters that break single-test runs (shell mis-parse unquoted; `/name/` regex form runs 0 tests)."
765
+ Enabled: true
766
+ ForbiddenCharacters: "()[]*+^$\\&;|<>'\"`"
767
+ Include:
768
+ - "test/**/*.rb"
769
+ - "spec/**/*.rb"
770
+
771
+ # A bare-class `find_by` in a test returns whichever matching row the database
772
+ # yields first. When the attribute is not unique across the table (an email in
773
+ # a tenant-scoped membership table, a slug that repeats per country) the test
774
+ # binds to a different fixture per seed and fails far from the cause — the
775
+ # observed case reproduced only under one seed and read as a flake.
776
+ # `find_sole_by` raises unless exactly one row matches, turning the assumption
777
+ # into an assertion. `find_by!` autocorrects; `find_by` (nil-returning) does
778
+ # not, because a test may assert the nil — rewrite those to `exists?`.
779
+ # Requires Rails 7.0+ (`find_sole_by`); disable on older consumers.
780
+ DevDoc/Test/PreferFindSoleBy:
781
+ Description: "In tests, `Model.find_by`/`find_by!` on a bare class must be `find_sole_by` — an unscoped lookup by a non-unique attribute silently picks a row per run. Primary-key lookups and association-scoped receivers are not flagged."
782
+ Enabled: true
783
+ Include:
784
+ - "test/**/*.rb"
785
+ - "spec/**/*.rb"
786
+
699
787
  DevDoc/Test/RequireUnitTestJustification:
700
788
  Description: "Every test file must live in a recognized directory; unit-test directories additionally require a justification header (marker phrase: 'deliberate exception')."
701
789
  Enabled: true
@@ -915,6 +1003,159 @@ DevDoc/I18n/AvoidTitleizeHumanize:
915
1003
  - "app/views/**/*.jbuilder"
916
1004
  - "app/views/**/*.rb"
917
1005
 
1006
+ DevDoc/I18n/HardcodedText:
1007
+ Description: "Warn on any string literal that reads like user-facing copy, in any position — not only glib text props. Use `t(...)`."
1008
+ # A review aid, not a clean lint: it judges strings by shape (prose vs
1009
+ # identifier) and position, so it cannot tell copy a user sees from prose
1010
+ # that never leaves the server. Off by default and `warning` severity; run
1011
+ # it during a localization pass alongside RequireTranslation, which is
1012
+ # precise for glib props but blind to ternary/`||` fallbacks, hashes built in
1013
+ # locals, controller/model/mailer strings and constants.
1014
+ Enabled: false
1015
+ Severity: warning
1016
+ # ExemptKeys: hash keys whose values are never copy (style, routing, model
1017
+ # metadata, i18n plumbing). Every value under them is skipped.
1018
+ ExemptKeys:
1019
+ - styleClass
1020
+ - styleClasses
1021
+ - style
1022
+ - class
1023
+ - id
1024
+ - targetId
1025
+ - name
1026
+ - url
1027
+ - href
1028
+ - src
1029
+ - path
1030
+ - partial
1031
+ - template
1032
+ - layout
1033
+ - controller
1034
+ - action
1035
+ - as
1036
+ - format
1037
+ - content_type
1038
+ - mime_type
1039
+ - accept
1040
+ - class_name
1041
+ - source_type
1042
+ - foreign_key
1043
+ - primary_key
1044
+ - table_name
1045
+ - inverse_of
1046
+ - scope
1047
+ - locale
1048
+ # ExemptMethods: string receivers and direct arguments of these are
1049
+ # patterns, SQL, lookup keys or formats rather than copy.
1050
+ ExemptMethods:
1051
+ - "where"
1052
+ - "rewhere"
1053
+ - "not"
1054
+ - "or"
1055
+ - "having"
1056
+ - "order"
1057
+ - "reorder"
1058
+ - "group"
1059
+ - "select"
1060
+ - "joins"
1061
+ - "left_joins"
1062
+ - "from"
1063
+ - "pluck"
1064
+ - "pick"
1065
+ - "find_by_sql"
1066
+ - "count_by_sql"
1067
+ - "exec_query"
1068
+ - "execute"
1069
+ - "sql"
1070
+ - "sanitize_sql"
1071
+ - "sanitize_sql_array"
1072
+ - "sanitize_sql_for_conditions"
1073
+ - "=="
1074
+ - "!="
1075
+ - "==="
1076
+ - "eql?"
1077
+ - "equal?"
1078
+ - "=~"
1079
+ - "!~"
1080
+ - "include?"
1081
+ - "in?"
1082
+ - "start_with?"
1083
+ - "end_with?"
1084
+ - "match?"
1085
+ - "match"
1086
+ - "casecmp"
1087
+ - "casecmp?"
1088
+ - "gsub"
1089
+ - "gsub!"
1090
+ - "sub"
1091
+ - "sub!"
1092
+ - "tr"
1093
+ - "tr_s"
1094
+ - "delete"
1095
+ - "delete_prefix"
1096
+ - "delete_suffix"
1097
+ - "split"
1098
+ - "squeeze"
1099
+ - "partition"
1100
+ - "rpartition"
1101
+ - "[]"
1102
+ - "[]="
1103
+ - "dig"
1104
+ - "fetch"
1105
+ - "key?"
1106
+ - "has_key?"
1107
+ - "slice"
1108
+ - "except"
1109
+ - "values_at"
1110
+ - "fetch_values"
1111
+ - "send"
1112
+ - "public_send"
1113
+ - "__send__"
1114
+ - "respond_to?"
1115
+ - "const_get"
1116
+ - "const_defined?"
1117
+ - "instance_variable_get"
1118
+ - "instance_variable_set"
1119
+ - "attribute"
1120
+ - "require"
1121
+ - "require_relative"
1122
+ - "load"
1123
+ - "autoload"
1124
+ - "strftime"
1125
+ - "strptime"
1126
+ - "parse"
1127
+ - "header"
1128
+ - "set_header"
1129
+ - "add_header"
1130
+ - "image_url"
1131
+ - "image_path"
1132
+ - "image_tag"
1133
+ - "asset_url"
1134
+ - "asset_path"
1135
+ # DeveloperFacingMethods: receiver-less calls whose whole subtree is
1136
+ # developer-facing (exception and console text). `logger.*` calls are
1137
+ # always skipped.
1138
+ DeveloperFacingMethods:
1139
+ - raise
1140
+ - fail
1141
+ - warn
1142
+ - abort
1143
+ - puts
1144
+ - print
1145
+ - p
1146
+ - pp
1147
+ # DeveloperFacingReceivers: constants whose every call reports to developers
1148
+ # (error trackers), so string arguments to them are never copy.
1149
+ DeveloperFacingReceivers:
1150
+ - Rollbar
1151
+ - Sentry
1152
+ - Honeybadger
1153
+ - Bugsnag
1154
+ - Airbrake
1155
+ Include:
1156
+ - "app/**/*.rb"
1157
+ - "app/**/*.jbuilder"
1158
+
918
1159
  DevDoc/View/PreferPropOverName:
919
1160
  Description: "Bind form fields to model attributes with `prop:` (i18n-resolved label/placeholder) instead of a raw `name: 'model[attr]'` with hardcoded text."
920
1161
  # Disabled by default (new department) — enable per consumer .rubocop.yml.
@@ -929,10 +1170,17 @@ DevDoc/View/PreferPropOverName:
929
1170
  # credit-card fields capture transient credentials that must never bind to
930
1171
  # a persisted model, and dynamic-group names are array-param structural keys
931
1172
  # with no label/placeholder to derive.
1173
+ # fields_file (deprecated field class) posts a raw upload the controller
1174
+ # often parses and discards (CSV imports, server-side processing) — its
1175
+ # prop: machinery calls `.attached?` on the bound model value, so a
1176
+ # conversion of a non-attachment param raises at render and the unsafe
1177
+ # autocorrect would produce exactly that. Attachment-backed uploads belong
1178
+ # on fields_upload, which binds prop: fine.
932
1179
  ExemptFieldMethods:
933
1180
  - fields_hidden
934
1181
  - fields_creditCard
935
1182
  - fields_dynamicGroup
1183
+ - fields_file
936
1184
  Include:
937
1185
  - "app/views/**/*.jbuilder"
938
1186
  - "app/views/**/*.rb"
@@ -961,17 +1209,35 @@ DevDoc/I18n/RequireTranslation:
961
1209
  - shareButton
962
1210
  - fields_text
963
1211
  - fields_number
964
- - fields_select
1212
+ - fields_email
1213
+ - fields_url
965
1214
  - fields_password
1215
+ - fields_timer
1216
+ - fields_submit
966
1217
  - fields_textarea
1218
+ - fields_richText
1219
+ - fields_select
1220
+ - fields_dynamicSelect
1221
+ - fields_dynamicGroup
967
1222
  - fields_check
968
1223
  - fields_checkGroup
969
1224
  - fields_chipGroup
970
- - fields_timeZone
1225
+ - fields_radio
971
1226
  - fields_radioGroup
1227
+ - fields_timeZone
972
1228
  - fields_date
973
1229
  - fields_datetime
1230
+ - fields_file
974
1231
  - fields_upload
1232
+ - fields_sign
1233
+ - fields_location
1234
+ - fields_phone
1235
+ - fields_otp
1236
+ - fields_captcha
1237
+ - fields_rating
1238
+ - fields_creditCard
1239
+ - fields_stripeToken
1240
+ - fields_stripeExternalAccount
975
1241
  - dialogs_alert
976
1242
  - dialogs_notification
977
1243
  - snackbars_alert
@@ -984,6 +1250,7 @@ DevDoc/I18n/RequireTranslation:
984
1250
  - subsubtitle
985
1251
  - label
986
1252
  - placeholder
1253
+ - hint
987
1254
  - text
988
1255
  - message
989
1256
  - description
@@ -1021,62 +1288,35 @@ DevDoc/Rails/NoManualRecordInvalid:
1021
1288
  Include:
1022
1289
  - "app/models/**/*.rb"
1023
1290
 
1024
- DevDoc/I18n/ReportText:
1025
- Description: "Report every user-facing glib text prop — hardcoded and already-localized — to collect all possible texts."
1026
- # A tooling aid, not a lint: unlike RequireTranslation it fires on *every*
1027
- # text value (including `t(...)` calls) so you can sweep the codebase and
1028
- # collect the full list of user-facing strings. Off by default and `info`
1029
- # severity. Mirrors RequireTranslation's WatchedMethods/LocalizableKeys.
1030
- Enabled: false
1031
- Severity: info
1032
- WatchedMethods:
1033
- - h1
1034
- - h2
1035
- - h3
1036
- - h4
1037
- - h5
1038
- - h6
1039
- - p
1040
- - label
1041
- - markdown
1042
- - html
1043
- - button
1044
- - switch
1045
- - chip
1046
- - progressCircle
1047
- - shareButton
1048
- - fields_text
1049
- - fields_number
1050
- - fields_select
1051
- - fields_password
1052
- - fields_textarea
1053
- - fields_check
1054
- - fields_checkGroup
1055
- - fields_chipGroup
1056
- - fields_timeZone
1057
- - fields_radioGroup
1058
- - fields_date
1059
- - fields_datetime
1060
- - fields_upload
1061
- - dialogs_alert
1062
- - dialogs_notification
1063
- - snackbars_alert
1064
- - snackbars_select
1065
- - banners_alert
1066
- - banners_select
1067
- LocalizableKeys:
1068
- - title
1069
- - subtitle
1070
- - subsubtitle
1071
- - label
1072
- - placeholder
1073
- - text
1074
- - message
1075
- - description
1076
- - uploadText
1077
- - leftText
1078
- - rightText
1079
- - onLabel
1291
+ # Strict superset of Lint/SuppressedException at its default settings — disable
1292
+ # the stock cop when enabling this one (see the cop docstring). Modifier
1293
+ # rescues stay out of scope: Style/RescueModifier owns them.
1294
+ DevDoc/Style/NoSilentRescue:
1295
+ Description: "A rescue body must re-raise, report the failure (a logger/error-monitor call), or state a justification — never swallow it silently."
1296
+ Enabled: true
1080
1297
  Include:
1081
- - "app/views/**/*.jbuilder"
1082
- - "app/views/**/*.rb"
1298
+ - "app/**/*.rb"
1299
+ - "lib/**/*.rb"
1300
+ JustificationMarker: "silent-rescue:"
1301
+ ReportingMethods:
1302
+ - "log"
1303
+ - "warn"
1304
+ - "error"
1305
+ - "errors"
1306
+ - "exception"
1307
+ - "fatal"
1308
+ - "critical"
1309
+ - "notify"
1310
+ - "notice"
1311
+ - "report"
1312
+ - "capture"
1313
+ - "track"
1314
+ - "instrument"
1315
+ - "monitor"
1316
+ - "alert"
1317
+ - "breadcrumb"
1318
+ - "handle"
1319
+
1320
+ DevDoc/Style/UseGLog:
1321
+ Description: "Route logging through GLog (glib-web) — flag Rails.logger.<any> and Rollbar's reporting methods (error/warning/info/debug/critical/log) outside the facade; Rollbar.configure and other setup calls are not reporting."
1322
+ Enabled: true
@@ -1,5 +1,9 @@
1
- # Cop renames across rubocop-dev_doc versions. RuboCop surfaces these as
2
- # actionable "has been renamed" errors when a project's config or inline
3
- # directives use the old name.
1
+ # Cop renames and removals across rubocop-dev_doc versions. RuboCop surfaces
2
+ # these as actionable "has been renamed"/"has been removed" errors when a
3
+ # project's config or inline directives use the old name.
4
4
  renamed:
5
5
  DevDoc/Migration/AvoidBypassingValidation: DevDoc/Rails/AvoidBypassingValidation
6
+
7
+ removed:
8
+ DevDoc/I18n/ReportText:
9
+ alternatives: DevDoc/I18n/HardcodedText
@@ -0,0 +1,68 @@
1
+ # Rake tasks wrapping the commands in docs/localization.md, so a project runs
2
+ # `bin/rails dev_doc:i18n:scan` instead of copying long rubocop invocations.
3
+ #
4
+ # Loaded by DevDoc::Railtie (lib/dev_doc/railtie.rb) in projects that bundle
5
+ # the gem with `require: 'dev_doc/railtie'`.
6
+ #
7
+ # Tasks (paths default to `app`; pass several as `[app/views,app/mailers]`):
8
+ #
9
+ # bin/rails dev_doc:i18n:scan[paths] Recipe A — hardcoded text
10
+ # bin/rails dev_doc:i18n:rekey[paths] Recipe B — keys to move
11
+ #
12
+ # Each task accepts OUT=<file> to save the findings instead of printing
13
+ # them (Recipe C hands that file to an AI assistant), and exit with rubocop's
14
+ # status: 0 clean, 1 findings, 2 error.
15
+ require 'rake'
16
+ require 'fileutils'
17
+
18
+ module DevDoc
19
+ module I18n
20
+ # `dev_doc:i18n:*` rake tasks: the localization recipes' commands, runnable
21
+ # from a project that bundles the gem.
22
+ module Tasks
23
+ extend Rake::DSL
24
+
25
+ HARDCODED_COPS = %w[
26
+ DevDoc/I18n/RequireTranslation
27
+ DevDoc/I18n/HardcodedText
28
+ DevDoc/I18n/AvoidTitleizeHumanize
29
+ ].freeze
30
+ RUBOCOP_TASKS = {
31
+ scan: [HARDCODED_COPS, 'List hardcoded user-facing text (Recipe A)'],
32
+ rekey: [%w[DevDoc/I18n/TranslationKeyPrefix], 'List lazy keys and keys outside AllowedPrefixes (Recipe B)']
33
+ }.freeze
34
+ DEFAULT_PATHS = %w[app].freeze
35
+
36
+ def self.define
37
+ namespace :dev_doc do
38
+ namespace :i18n do
39
+ RUBOCOP_TASKS.each do |name, (cops, summary)|
40
+ desc "#{summary}; OUT=<file> saves the findings"
41
+ task(name) { |_t, args| run_rubocop(cops, args.to_a) }
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ def self.rubocop_args(cops, paths, out: nil)
48
+ args = %w[--format clang]
49
+ # --out binds to the --format before it, so it must follow it directly.
50
+ args += ['--out', out] if out
51
+ args + ['--only', cops.join(','), *(paths.empty? ? DEFAULT_PATHS : paths)]
52
+ end
53
+
54
+ def self.run_rubocop(cops, paths)
55
+ require 'rubocop'
56
+
57
+ out = ENV.fetch('OUT', '')
58
+ out = nil if out.empty?
59
+ FileUtils.mkdir_p(File.dirname(out)) if out
60
+ status = RuboCop::CLI.new.run(rubocop_args(cops, paths, out: out))
61
+ puts "Findings written to #{out}" if out && status != 2
62
+ exit(status) unless status.zero?
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ DevDoc::I18n::Tasks.define
@@ -0,0 +1,19 @@
1
+ # Registers dev-doc's rake tasks in a Rails app. Projects name this file as the
2
+ # gem's require instead of `require: false`:
3
+ #
4
+ # group :development, :test do
5
+ # gem 'rubocop-dev_doc', require: 'dev_doc/railtie'
6
+ # end
7
+ #
8
+ # Booting the app loads only this Railtie; RuboCop itself is loaded when a task
9
+ # runs, so app boot stays as light as with `require: false`.
10
+ require 'rails/railtie'
11
+
12
+ module DevDoc
13
+ # Loads the `dev_doc:*` rake tasks when Rails loads the app's tasks.
14
+ class Railtie < Rails::Railtie
15
+ rake_tasks do
16
+ require 'dev_doc/i18n/tasks'
17
+ end
18
+ end
19
+ end
@@ -77,6 +77,8 @@ module DevDoc
77
77
  def __dev_doc_response_body
78
78
  response&.body.to_s
79
79
  rescue StandardError
80
+ # silent-rescue: the canary check must never fail on an unreadable
81
+ # response body; an empty body simply carries no markers to match.
80
82
  ''
81
83
  end
82
84
 
@@ -103,6 +103,8 @@ module DevDoc
103
103
  def __dev_doc_source_file
104
104
  method(name).source_location&.first
105
105
  rescue NameError
106
+ # silent-rescue: an unresolvable test-method name means the source
107
+ # file is unknown; the location line renders without it.
106
108
  nil
107
109
  end
108
110
 
@@ -123,6 +123,8 @@ module DevDoc
123
123
  def parse_json(body)
124
124
  JSON.parse(body)
125
125
  rescue JSON::ParserError
126
+ # silent-rescue: non-JSON bodies are expected here — scan_body only
127
+ # wants the parseable ones and skips the rest.
126
128
  nil
127
129
  end
128
130
 
@@ -170,6 +172,9 @@ module DevDoc
170
172
  data = YAML.safe_load_file(file, permitted_classes: [Date, Time], aliases: true)
171
173
  collect_strings(data, set)
172
174
  rescue Psych::Exception
175
+ # silent-rescue: an unparsable fixture is skipped; its strings
176
+ # then count as noise candidates instead of exclusions, which
177
+ # shows up in the report rather than hiding anything.
173
178
  next
174
179
  end
175
180
  end