betterlint 1.14.0 → 1.15.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/README.md +44 -0
- data/lib/rubocop/cop/betterment/internals_protection.rb +85 -0
- data/lib/rubocop/cop/betterment.rb +1 -0
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 834ddcd8893844db2ccbff0a1c0379f40e47f12fbbff9859831c342df1266d34
|
4
|
+
data.tar.gz: 8b8b7c4d49d7a961f042fc6941f6f55085b77a502441eb1c6ba7dfb8aa1af9cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1db7904622a80b0271e05f33f36c4667f720a9fd13253422dba34c70ecd2ef0f6973255d5506475cd942e3ab72b353a61121da4ed4fa871d2b546228881324f
|
7
|
+
data.tar.gz: 3cf27adfc7561156c5a11a5a54c58b1bb471e5e944aed955220aaa8c383bf0e155eeb56aa514d537da317e08943ac9b330bb510d8fcf85cc8f6bbe6d7dcbc1dc
|
data/README.md
CHANGED
@@ -130,6 +130,50 @@ end
|
|
130
130
|
```
|
131
131
|
|
132
132
|
All three `params.permit` calls will be flagged.
|
133
|
+
### Betterment/InternalsProtection
|
134
|
+
|
135
|
+
This cop is not enabled by default, and must be enabled from your `.rubocop.yml` file:
|
136
|
+
|
137
|
+
```yaml
|
138
|
+
Betterment/InternalsProtection:
|
139
|
+
Enabled: true
|
140
|
+
```
|
141
|
+
|
142
|
+
This cop enforces constants defined within `Internals` modules from being referenced from other modules.
|
143
|
+
|
144
|
+
For example, if you have a `Widget` ActiveRecord class that you don't want to be used directly,
|
145
|
+
you can place it into an Internals module such as:
|
146
|
+
```ruby
|
147
|
+
class Widgets::Internals::Widget < ApplicationRecord
|
148
|
+
end
|
149
|
+
```
|
150
|
+
|
151
|
+
Code outside of the `Widgets` module will not be allowed to reference Widget:
|
152
|
+
```ruby
|
153
|
+
class WidgetsController < ApplicationController
|
154
|
+
def create
|
155
|
+
Widgets::Internals::Widget.create!
|
156
|
+
^^^^^^^^^^^^^^^^^^ Internal constants may only be referenced from code within its containing module. [...]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
```
|
160
|
+
|
161
|
+
Non-Internal code within the module can be used to manage access.
|
162
|
+
```ruby
|
163
|
+
class Widgets::WidgetCreation
|
164
|
+
def save!
|
165
|
+
Widgets::Internals::Widget.create!
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
class WidgetsController < ApplicationController
|
170
|
+
def create
|
171
|
+
Widgets::WidgetCreation.new.save!
|
172
|
+
end
|
173
|
+
end
|
174
|
+
```
|
175
|
+
|
176
|
+
This cop inspects all direct constant references, and the `class_name` attribute on ActiveRecord associations.
|
133
177
|
|
134
178
|
### Betterment/UnsafeJob
|
135
179
|
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Betterment
|
6
|
+
class InternalsProtection < Base
|
7
|
+
MSG = <<~END.gsub(/\s+/, " ")
|
8
|
+
Internal constants may only be referenced from code within its containing module.
|
9
|
+
Constants defined within a module's Internals submodule may only be referenced by code in that module,
|
10
|
+
or nested classes and modules
|
11
|
+
(e.g. MyModule::Internals::MyClass may only be referenced from code in MyModule or MyModule::MyPublicClass).
|
12
|
+
END
|
13
|
+
|
14
|
+
# @!method association_with_class_name(node)
|
15
|
+
def_node_matcher :association_with_class_name, <<-PATTERN
|
16
|
+
(send nil? {:has_many :has_one :belongs_to} ... (hash <(pair (sym :class_name) ${str}) ...>))
|
17
|
+
PATTERN
|
18
|
+
|
19
|
+
# @!method rspec_describe(node)
|
20
|
+
def_node_matcher :rspec_describe, <<-PATTERN
|
21
|
+
(block (send (const nil? :RSpec) :describe ${const | str}) ...)
|
22
|
+
PATTERN
|
23
|
+
|
24
|
+
def on_const(node)
|
25
|
+
if node.children[1] == :Internals
|
26
|
+
module_path = const_path(node)
|
27
|
+
|
28
|
+
ensure_allowed_reference!(node, module_path)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_send(node)
|
33
|
+
class_name_node = association_with_class_name(node)
|
34
|
+
return unless class_name_node
|
35
|
+
|
36
|
+
full_path = string_path(class_name_node)
|
37
|
+
internals_index = full_path.find_index(:Internals)
|
38
|
+
if internals_index
|
39
|
+
module_path = full_path.take(internals_index)
|
40
|
+
ensure_allowed_reference!(class_name_node, module_path)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def ensure_allowed_reference!(node, module_path)
|
47
|
+
return if module_path.empty?
|
48
|
+
|
49
|
+
unless definition_context_path(node).each_cons(module_path.size).any?(module_path)
|
50
|
+
add_offense(node)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def const_path(const_node)
|
55
|
+
const_node.each_descendant(:const, :cbase).map { |n| n.children[1] }.reverse
|
56
|
+
end
|
57
|
+
|
58
|
+
def string_path(string_node)
|
59
|
+
string_node.children[0].split('::').map { |name| name == '' ? nil : name.to_sym }
|
60
|
+
end
|
61
|
+
|
62
|
+
def definition_context_path(node)
|
63
|
+
rspec_context_path(node) || module_class_definition_context_path(node)
|
64
|
+
end
|
65
|
+
|
66
|
+
def module_class_definition_context_path(node)
|
67
|
+
node.each_ancestor(:class, :module).flat_map { |anc|
|
68
|
+
anc.children[0].each_node(:const, :cbase).map { |c| c.children[1] }
|
69
|
+
}.push(nil).reverse
|
70
|
+
end
|
71
|
+
|
72
|
+
def rspec_context_path(node)
|
73
|
+
rspec_described_class = node.each_ancestor(:block).filter_map { |ancestor|
|
74
|
+
rspec_describe(ancestor)
|
75
|
+
}.first
|
76
|
+
case rspec_described_class&.type
|
77
|
+
when :const then const_path(rspec_described_class)
|
78
|
+
when :str then string_path(rspec_described_class)
|
79
|
+
else nil # rubocop:disable Style/EmptyElse
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -10,6 +10,7 @@ require 'rubocop/cop/betterment/dynamic_params'
|
|
10
10
|
require 'rubocop/cop/betterment/unscoped_find'
|
11
11
|
require 'rubocop/cop/betterment/unsafe_job'
|
12
12
|
require 'rubocop/cop/betterment/timeout'
|
13
|
+
require 'rubocop/cop/betterment/internals_protection'
|
13
14
|
require 'rubocop/cop/betterment/memoization_with_arguments'
|
14
15
|
require 'rubocop/cop/betterment/non_standard_actions'
|
15
16
|
require 'rubocop/cop/betterment/site_prism_loaded'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: betterlint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Development
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -113,6 +113,7 @@ files:
|
|
113
113
|
- lib/rubocop/cop/betterment/fetch_boolean.rb
|
114
114
|
- lib/rubocop/cop/betterment/hardcoded_id.rb
|
115
115
|
- lib/rubocop/cop/betterment/implicit_redirect_type.rb
|
116
|
+
- lib/rubocop/cop/betterment/internals_protection.rb
|
116
117
|
- lib/rubocop/cop/betterment/memoization_with_arguments.rb
|
117
118
|
- lib/rubocop/cop/betterment/non_standard_actions.rb
|
118
119
|
- lib/rubocop/cop/betterment/redirect_status.rb
|
@@ -133,10 +134,10 @@ licenses:
|
|
133
134
|
- MIT
|
134
135
|
metadata:
|
135
136
|
homepage_uri: https://github.com/Betterment/betterlint
|
136
|
-
source_code_uri: https://github.com/Betterment/betterlint/tree/v1.
|
137
|
-
changelog_uri: https://github.com/Betterment/betterlint/blob/v1.
|
137
|
+
source_code_uri: https://github.com/Betterment/betterlint/tree/v1.15.0
|
138
|
+
changelog_uri: https://github.com/Betterment/betterlint/blob/v1.15.0/CHANGELOG.md
|
138
139
|
bug_tracker_uri: https://github.com/Betterment/betterlint/issues
|
139
|
-
documentation_uri: https://www.rubydoc.info/gems/betterlint/1.
|
140
|
+
documentation_uri: https://www.rubydoc.info/gems/betterlint/1.15.0
|
140
141
|
rubygems_mfa_required: 'true'
|
141
142
|
post_install_message:
|
142
143
|
rdoc_options: []
|
@@ -153,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
153
154
|
- !ruby/object:Gem::Version
|
154
155
|
version: '0'
|
155
156
|
requirements: []
|
156
|
-
rubygems_version: 3.5.
|
157
|
+
rubygems_version: 3.5.21
|
157
158
|
signing_key:
|
158
159
|
specification_version: 4
|
159
160
|
summary: Betterment rubocop configuration
|