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 +4 -4
- data/config/default.yml +300 -60
- data/config/obsoletion.yml +7 -3
- data/lib/dev_doc/i18n/tasks.rb +68 -0
- data/lib/dev_doc/railtie.rb +19 -0
- data/lib/dev_doc/test/lints/cross_tenant_canary_sweep.rb +2 -0
- data/lib/dev_doc/test/lints/http_driven_controller_tests.rb +2 -0
- data/lib/dev_doc/test/pseudo_i18n_crawler.rb +5 -0
- data/lib/rubocop/cop/dev_doc/i18n/hardcoded_text.rb +243 -0
- data/lib/rubocop/cop/dev_doc/i18n/localizable_props.rb +69 -19
- data/lib/rubocop/cop/dev_doc/i18n/require_translation.rb +13 -17
- data/lib/rubocop/cop/dev_doc/i18n/text_shape.rb +94 -0
- data/lib/rubocop/cop/dev_doc/rails/avoid_bypassing_validation.rb +81 -26
- data/lib/rubocop/cop/dev_doc/rails/no_errors_add_in_controller.rb +177 -0
- data/lib/rubocop/cop/dev_doc/rails/no_form_param_lookup_in_controller.rb +236 -0
- data/lib/rubocop/cop/dev_doc/style/in_memory_association_find.rb +162 -0
- data/lib/rubocop/cop/dev_doc/style/no_silent_rescue.rb +269 -0
- data/lib/rubocop/cop/dev_doc/style/prefer_allowlist_symbol_param.rb +193 -0
- data/lib/rubocop/cop/dev_doc/style/use_g_log.rb +133 -0
- data/lib/rubocop/cop/dev_doc/test/prefer_find_sole_by.rb +146 -0
- data/lib/rubocop/cop/dev_doc/test/test_name_special_characters.rb +108 -0
- data/lib/rubocop/cop/dev_doc/view/prefer_prop_over_name.rb +11 -1
- data/lib/rubocop/dev_doc/version.rb +1 -1
- metadata +14 -3
- data/lib/rubocop/cop/dev_doc/i18n/report_text.rb +0 -76
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3852833893968d60a5c0c198ffd3a2f34cb524a71998464a27803de2d56b44de
|
|
4
|
+
data.tar.gz: 1b4f675aa6967bca65d6f706997c06c73fe3b954b4092f6f8586e5c17b1e16b8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
-
|
|
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
|
-
-
|
|
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
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
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
|
|
1082
|
-
- "
|
|
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
|
data/config/obsoletion.yml
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
# Cop renames across rubocop-dev_doc versions. RuboCop surfaces
|
|
2
|
-
# actionable "has been renamed" errors when a
|
|
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
|
|
@@ -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
|