bullematic 0.1.0 → 0.2.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/CHANGELOG.md +18 -1
- data/README.md +23 -11
- data/exe/bullematic +7 -0
- data/lib/bullematic/ast/finder.rb +190 -35
- data/lib/bullematic/ast/parser.rb +1 -17
- data/lib/bullematic/ast/rewriter.rb +90 -28
- data/lib/bullematic/cli.rb +185 -0
- data/lib/bullematic/configuration.rb +15 -4
- data/lib/bullematic/detection.rb +110 -13
- data/lib/bullematic/evidence_store.rb +78 -0
- data/lib/bullematic/fixer.rb +258 -31
- data/lib/bullematic/integrations/minitest.rb +20 -6
- data/lib/bullematic/integrations/rails.rb +23 -9
- data/lib/bullematic/integrations/rspec.rb +19 -7
- data/lib/bullematic/logger.rb +24 -12
- data/lib/bullematic/notifier.rb +131 -36
- data/lib/bullematic/version.rb +1 -1
- data/lib/bullematic.rb +12 -4
- data/sig/generated/bullematic/ast/finder.rbs +70 -11
- data/sig/generated/bullematic/ast/parser.rbs +0 -6
- data/sig/generated/bullematic/ast/rewriter.rbs +28 -11
- data/sig/generated/bullematic/cli.rbs +56 -0
- data/sig/generated/bullematic/configuration.rbs +16 -20
- data/sig/generated/bullematic/detection.rbs +77 -7
- data/sig/generated/bullematic/evidence_store.rbs +35 -0
- data/sig/generated/bullematic/fixer.rbs +59 -3
- data/sig/generated/bullematic/integrations/rails.rbs +7 -0
- data/sig/generated/bullematic/logger.rbs +5 -0
- data/sig/generated/bullematic/notifier.rbs +17 -13
- data/sig/generated/bullematic.rbs +5 -0
- data/sig/stubs/rails.rbs +60 -0
- metadata +161 -8
- data/Rakefile +0 -26
- data/Steepfile +0 -15
- data/assets/logo-header.svg +0 -28
- data/rbs_collection.lock.yaml +0 -24
- data/rbs_collection.yaml +0 -14
data/lib/bullematic/notifier.rb
CHANGED
|
@@ -6,71 +6,166 @@ module Bullematic
|
|
|
6
6
|
class << self
|
|
7
7
|
#: () -> void
|
|
8
8
|
def setup
|
|
9
|
-
return
|
|
9
|
+
return if compatible?
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Bullematic.configuration&.logger&.warn(
|
|
12
|
+
"[Bullematic] Disabled: Bullet notification API is unavailable"
|
|
13
|
+
)
|
|
12
14
|
end
|
|
13
15
|
|
|
14
|
-
#: () ->
|
|
15
|
-
def
|
|
16
|
-
return unless defined?(Bullet)
|
|
16
|
+
#: () -> bool
|
|
17
|
+
def compatible?
|
|
18
|
+
return false unless defined?(Bullet)
|
|
19
|
+
|
|
20
|
+
Bullet.respond_to?(:notification?, true) &&
|
|
21
|
+
Bullet.respond_to?(:notification_collector, true) &&
|
|
22
|
+
!defined?(Bullet::Notification::NPlusOneQuery).nil?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @rbs context_id: untyped
|
|
26
|
+
# @rbs return: void
|
|
27
|
+
def process_notifications(context_id: nil)
|
|
28
|
+
return unless compatible? && Bullet.notification?
|
|
29
|
+
|
|
30
|
+
context_id ||= Object.new.object_id
|
|
31
|
+
|
|
32
|
+
config = Bullematic.configuration
|
|
33
|
+
if config&.logger && config.debug
|
|
34
|
+
config.logger.debug "[Bullematic] Processing notifications..."
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
collector = Bullet.send(:notification_collector)
|
|
38
|
+
return unless collector&.respond_to?(:collection)
|
|
17
39
|
|
|
18
|
-
notifications =
|
|
40
|
+
notifications = collector.collection
|
|
19
41
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
42
|
+
if config&.logger && config.debug
|
|
43
|
+
config.logger.debug "[Bullematic] Notifications collection type: #{notifications.class}"
|
|
44
|
+
config.logger.debug "[Bullematic] Notifications count: #{notifications.respond_to?(:size) ? notifications.size : 'unknown'}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
n_plus_one_count = 0
|
|
48
|
+
unused_eager_loading_count = 0
|
|
23
49
|
|
|
24
|
-
|
|
50
|
+
case notifications
|
|
51
|
+
when Hash
|
|
52
|
+
notifications.each_value do |notification_set|
|
|
53
|
+
notification_set = [notification_set] unless notification_set.respond_to?(:each)
|
|
54
|
+
notification_set.each do |notification|
|
|
55
|
+
type = process_notification(notification, context_id)
|
|
56
|
+
n_plus_one_count += 1 if type == :n_plus_one
|
|
57
|
+
unused_eager_loading_count += 1 if type == :unused_eager_loading
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
when Enumerable
|
|
61
|
+
notifications.each do |notification|
|
|
62
|
+
type = process_notification(notification, context_id)
|
|
63
|
+
n_plus_one_count += 1 if type == :n_plus_one
|
|
64
|
+
unused_eager_loading_count += 1 if type == :unused_eager_loading
|
|
25
65
|
end
|
|
26
66
|
end
|
|
67
|
+
|
|
68
|
+
if config&.logger && config.debug
|
|
69
|
+
config.logger.debug "[Bullematic] Processed #{n_plus_one_count} N+1 notifications"
|
|
70
|
+
config.logger.debug "[Bullematic] Processed #{unused_eager_loading_count} UnusedEagerLoading notifications"
|
|
71
|
+
config.logger.debug "[Bullematic] Detection queue size: #{Fixer.detection_queue.size}"
|
|
72
|
+
end
|
|
73
|
+
rescue StandardError => error
|
|
74
|
+
begin
|
|
75
|
+
Bullematic.configuration&.logger&.warn(
|
|
76
|
+
"[Bullematic] Failed to process Bullet notifications: #{error.message}"
|
|
77
|
+
)
|
|
78
|
+
rescue StandardError
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
27
81
|
end
|
|
28
82
|
|
|
29
83
|
private
|
|
30
84
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
85
|
+
# @rbs notification: untyped
|
|
86
|
+
# @rbs context_id: untyped
|
|
87
|
+
# @rbs return: Symbol?
|
|
88
|
+
def process_notification(notification, context_id)
|
|
89
|
+
if notification.is_a?(Bullet::Notification::NPlusOneQuery)
|
|
90
|
+
process_n_plus_one(notification, context_id)
|
|
91
|
+
:n_plus_one
|
|
92
|
+
elsif defined?(Bullet::Notification::UnusedEagerLoading) &&
|
|
93
|
+
notification.is_a?(Bullet::Notification::UnusedEagerLoading)
|
|
94
|
+
process_unused_eager_loading(notification, context_id)
|
|
95
|
+
:unused_eager_loading
|
|
96
|
+
end
|
|
97
|
+
rescue StandardError => error
|
|
98
|
+
Bullematic.configuration&.logger&.warn(
|
|
99
|
+
"[Bullematic] Skipped invalid Bullet notification: #{error.message}"
|
|
100
|
+
)
|
|
101
|
+
nil
|
|
34
102
|
end
|
|
35
103
|
|
|
36
104
|
# @rbs notification: untyped
|
|
105
|
+
# @rbs context_id: untyped
|
|
37
106
|
# @rbs return: void
|
|
38
|
-
def process_n_plus_one(notification)
|
|
107
|
+
def process_n_plus_one(notification, context_id)
|
|
39
108
|
detection = Detection.new(
|
|
40
109
|
type: :n_plus_one,
|
|
41
110
|
base_class: notification.base_class,
|
|
42
111
|
associations: notification.associations,
|
|
43
|
-
call_stack: extract_call_stack(notification)
|
|
112
|
+
call_stack: extract_call_stack(notification),
|
|
113
|
+
context_id: context_id
|
|
44
114
|
)
|
|
45
115
|
|
|
46
|
-
|
|
47
|
-
|
|
116
|
+
config = Bullematic.configuration
|
|
117
|
+
if config&.logger && config.debug
|
|
118
|
+
config.logger.debug "[Bullematic] N+1 Detection created:"
|
|
119
|
+
config.logger.debug " Base class: #{notification.base_class}"
|
|
120
|
+
config.logger.debug " Associations: #{notification.associations.inspect}"
|
|
121
|
+
config.logger.debug " Source file: #{detection.source_file}"
|
|
122
|
+
config.logger.debug " Line number: #{detection.line_number}"
|
|
123
|
+
config.logger.debug " Method name: #{detection.method_name}"
|
|
124
|
+
config.logger.debug " Call stack: #{detection.call_stack.inspect}"
|
|
125
|
+
config.logger.debug " Fixable: #{detection.fixable?}"
|
|
126
|
+
config.logger.debug " Queue size before: #{Fixer.detection_queue.size}"
|
|
127
|
+
end
|
|
48
128
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
129
|
+
if detection.fixable?
|
|
130
|
+
Fixer.queue(detection)
|
|
131
|
+
if config&.logger && config.debug
|
|
132
|
+
config.logger.debug " Queue size after: #{Fixer.detection_queue.size}"
|
|
133
|
+
end
|
|
134
|
+
end
|
|
53
135
|
end
|
|
54
|
-
end
|
|
55
136
|
|
|
56
|
-
|
|
57
|
-
# @rbs
|
|
58
|
-
# @rbs associations: untyped
|
|
59
|
-
# @rbs path: untyped
|
|
137
|
+
# @rbs notification: untyped
|
|
138
|
+
# @rbs context_id: untyped
|
|
60
139
|
# @rbs return: void
|
|
61
|
-
def
|
|
62
|
-
|
|
63
|
-
return unless
|
|
140
|
+
def process_unused_eager_loading(notification, context_id)
|
|
141
|
+
config = Bullematic.configuration
|
|
142
|
+
return unless config
|
|
64
143
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
144
|
+
if EvidenceStore.recording?
|
|
145
|
+
detection = Detection.new(
|
|
146
|
+
type: :unused_eager_loading,
|
|
147
|
+
base_class: notification.base_class,
|
|
148
|
+
associations: notification.associations,
|
|
149
|
+
call_stack: extract_call_stack(notification),
|
|
150
|
+
context_id: context_id
|
|
151
|
+
)
|
|
152
|
+
Fixer.queue(detection) if detection.fixable?
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
if config.logger && config.debug
|
|
156
|
+
config.logger.debug "[Bullematic] UnusedEagerLoading detected:"
|
|
157
|
+
config.logger.debug " Base class: #{notification.base_class}"
|
|
158
|
+
config.logger.debug " Unused associations: #{notification.associations.inspect}"
|
|
159
|
+
end
|
|
160
|
+
end
|
|
71
161
|
|
|
72
|
-
|
|
162
|
+
# @rbs notification: untyped
|
|
163
|
+
# @rbs return: Array[String]
|
|
164
|
+
def extract_call_stack(notification)
|
|
165
|
+
callers = notification.instance_variable_get(:@callers)
|
|
166
|
+
callers.is_a?(Array) ? callers.map(&:to_s) : []
|
|
73
167
|
end
|
|
74
168
|
end
|
|
169
|
+
|
|
75
170
|
end
|
|
76
171
|
end
|
data/lib/bullematic/version.rb
CHANGED
data/lib/bullematic.rb
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# rbs_inline: enabled
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
+
require "bullet"
|
|
5
|
+
|
|
4
6
|
require_relative "bullematic/version"
|
|
5
7
|
require_relative "bullematic/configuration"
|
|
6
8
|
require_relative "bullematic/logger"
|
|
7
9
|
require_relative "bullematic/detection"
|
|
10
|
+
require_relative "bullematic/evidence_store"
|
|
8
11
|
require_relative "bullematic/ast/parser"
|
|
9
12
|
require_relative "bullematic/ast/finder"
|
|
10
13
|
require_relative "bullematic/ast/rewriter"
|
|
@@ -19,9 +22,15 @@ module Bullematic
|
|
|
19
22
|
# @rbs @configuration: Configuration?
|
|
20
23
|
|
|
21
24
|
class << self
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
#: () -> Configuration?
|
|
26
|
+
def configuration
|
|
27
|
+
@configuration
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
#: (Configuration?) -> Configuration?
|
|
31
|
+
def configuration=(configuration)
|
|
32
|
+
@configuration = configuration
|
|
33
|
+
end
|
|
25
34
|
|
|
26
35
|
#: () { (Configuration) -> void } -> void
|
|
27
36
|
def configure
|
|
@@ -46,7 +55,6 @@ module Bullematic
|
|
|
46
55
|
def reset!
|
|
47
56
|
@configuration = nil
|
|
48
57
|
Fixer.clear
|
|
49
|
-
AST::Parser.clear_cache
|
|
50
58
|
end
|
|
51
59
|
end
|
|
52
60
|
end
|
|
@@ -5,7 +5,7 @@ module Bullematic
|
|
|
5
5
|
class Finder
|
|
6
6
|
QUERY_METHODS: Array[Symbol]
|
|
7
7
|
|
|
8
|
-
type query_location = { node: untyped, location: untyped, receiver: untyped, method_name: Symbol }
|
|
8
|
+
type query_location = { node: untyped, location: untyped, receiver: untyped, method_name: Symbol, target_name: Symbol? }
|
|
9
9
|
|
|
10
10
|
class QueryLocation < Struct[untyped]
|
|
11
11
|
attr_accessor node(): untyped
|
|
@@ -16,8 +16,10 @@ module Bullematic
|
|
|
16
16
|
|
|
17
17
|
attr_accessor method_name(): untyped
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
attr_accessor target_name(): untyped
|
|
20
|
+
|
|
21
|
+
def self.new: (?node: untyped, ?location: untyped, ?receiver: untyped, ?method_name: untyped, ?target_name: untyped) -> instance
|
|
22
|
+
| ({ ?node: untyped, ?location: untyped, ?receiver: untyped, ?method_name: untyped, ?target_name: untyped }) -> instance
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
@parse_result: untyped
|
|
@@ -35,9 +37,17 @@ module Bullematic
|
|
|
35
37
|
# @rbs return: Array[QueryLocation]
|
|
36
38
|
def find_model_queries: (String model_class_name, ?line_number: Integer?) -> Array[QueryLocation]
|
|
37
39
|
|
|
40
|
+
# @rbs model_class_name: String
|
|
38
41
|
# @rbs line_number: Integer
|
|
39
|
-
# @rbs
|
|
40
|
-
|
|
42
|
+
# @rbs associations: Array[Symbol]
|
|
43
|
+
# @rbs return: Array[QueryLocation]
|
|
44
|
+
def find_model_queries_for_variables_at_line: (String model_class_name, Integer line_number, Array[Symbol] associations) -> Array[QueryLocation]
|
|
45
|
+
|
|
46
|
+
# @rbs parent_association: Symbol
|
|
47
|
+
# @rbs child_associations: Array[Symbol]
|
|
48
|
+
# @rbs line_number: Integer?
|
|
49
|
+
# @rbs return: bool
|
|
50
|
+
def nested_association?: (Symbol parent_association, Array[Symbol] child_associations, Integer? line_number) -> bool
|
|
41
51
|
|
|
42
52
|
private
|
|
43
53
|
|
|
@@ -54,12 +64,6 @@ module Bullematic
|
|
|
54
64
|
# @rbs return: void
|
|
55
65
|
def mark_descendant_calls: (untyped node, Set[Integer] skip_nodes) -> void
|
|
56
66
|
|
|
57
|
-
# @rbs node: untyped
|
|
58
|
-
# @rbs queries: Array[QueryLocation]
|
|
59
|
-
# @rbs target_line: Integer?
|
|
60
|
-
# @rbs return: void
|
|
61
|
-
def visit_all_queries: (untyped node, Array[QueryLocation] queries, Integer? target_line) -> void
|
|
62
|
-
|
|
63
67
|
# @rbs node: untyped
|
|
64
68
|
# @rbs queries: Array[QueryLocation]
|
|
65
69
|
# @rbs model_class_name: String
|
|
@@ -74,6 +78,37 @@ module Bullematic
|
|
|
74
78
|
# @rbs return: bool
|
|
75
79
|
def check_assignment_node: (untyped node, Array[QueryLocation] queries, String model_class_name, Integer? target_line) -> bool
|
|
76
80
|
|
|
81
|
+
# @rbs node: untyped
|
|
82
|
+
# @rbs line_number: Integer
|
|
83
|
+
# @rbs associations: Array[Symbol]
|
|
84
|
+
# @rbs return: Array[Symbol]
|
|
85
|
+
def association_receiver_names_at_line: (untyped node, Integer line_number, Array[Symbol] associations) -> Array[Symbol]
|
|
86
|
+
|
|
87
|
+
# @rbs node: untyped
|
|
88
|
+
# @rbs line_number: Integer
|
|
89
|
+
# @rbs names: Array[Symbol]
|
|
90
|
+
# @rbs return: void
|
|
91
|
+
def add_block_receiver_names: (untyped node, Integer line_number, Array[Symbol] names) -> void
|
|
92
|
+
|
|
93
|
+
# @rbs node: untyped
|
|
94
|
+
# @rbs name: Symbol
|
|
95
|
+
# @rbs line_number: Integer
|
|
96
|
+
# @rbs return: bool
|
|
97
|
+
def block_parameter_at_line?: (untyped node, Symbol name, Integer line_number) -> bool
|
|
98
|
+
|
|
99
|
+
# @rbs node: untyped
|
|
100
|
+
# @rbs line_number: Integer
|
|
101
|
+
# @rbs return: untyped
|
|
102
|
+
def method_scope_at_line: (untyped node, Integer line_number) -> untyped
|
|
103
|
+
|
|
104
|
+
# @rbs node: untyped
|
|
105
|
+
# @rbs name: Symbol
|
|
106
|
+
# @rbs start_line: Integer
|
|
107
|
+
# @rbs end_line: Integer
|
|
108
|
+
# @rbs scope: untyped
|
|
109
|
+
# @rbs return: bool
|
|
110
|
+
def variable_written_between?: (untyped node, Symbol name, Integer start_line, Integer end_line, untyped scope) -> bool
|
|
111
|
+
|
|
77
112
|
# @rbs node: untyped
|
|
78
113
|
# @rbs return: untyped
|
|
79
114
|
def find_root_receiver: (untyped node) -> untyped
|
|
@@ -86,6 +121,30 @@ module Bullematic
|
|
|
86
121
|
# @rbs method_name: Symbol
|
|
87
122
|
# @rbs return: bool
|
|
88
123
|
def query_method?: (Symbol method_name) -> bool
|
|
124
|
+
|
|
125
|
+
# @rbs node: untyped
|
|
126
|
+
# @rbs parent_association: Symbol
|
|
127
|
+
# @rbs child_associations: Array[Symbol]
|
|
128
|
+
# @rbs line_number: Integer
|
|
129
|
+
# @rbs return: bool
|
|
130
|
+
def nested_association_in_node?: (untyped node, Symbol parent_association, Array[Symbol] child_associations, Integer line_number) -> bool
|
|
131
|
+
|
|
132
|
+
# @rbs node: untyped
|
|
133
|
+
# @rbs method_name: Symbol
|
|
134
|
+
# @rbs names: Array[Symbol]
|
|
135
|
+
# @rbs line_number: Integer
|
|
136
|
+
# @rbs return: bool
|
|
137
|
+
def call_on_variable_at_line?: (untyped node, Symbol method_name, Array[Symbol] names, Integer line_number) -> bool
|
|
138
|
+
|
|
139
|
+
# @rbs node: untyped
|
|
140
|
+
# @rbs method_name: Symbol
|
|
141
|
+
# @rbs return: bool
|
|
142
|
+
def receiver_calls?: (untyped node, Symbol method_name) -> bool
|
|
143
|
+
|
|
144
|
+
# @rbs node: untyped
|
|
145
|
+
# @rbs names: Array[Symbol]
|
|
146
|
+
# @rbs return: bool
|
|
147
|
+
def variable_written?: (untyped node, Array[Symbol] names) -> bool
|
|
89
148
|
end
|
|
90
149
|
end
|
|
91
150
|
end
|
|
@@ -7,12 +7,6 @@ module Bullematic
|
|
|
7
7
|
|
|
8
8
|
@filepath: String?
|
|
9
9
|
|
|
10
|
-
# : () -> Hash[String, untyped]
|
|
11
|
-
def self.cache: () -> Hash[String, untyped]
|
|
12
|
-
|
|
13
|
-
# : () -> void
|
|
14
|
-
def self.clear_cache: () -> void
|
|
15
|
-
|
|
16
10
|
# @rbs filepath: String
|
|
17
11
|
# @rbs return: untyped
|
|
18
12
|
def self.parse_file: (String filepath) -> untyped
|
|
@@ -20,10 +20,10 @@ module Bullematic
|
|
|
20
20
|
| ({ ?type: untyped, ?offset: untyped, ?byte_length: untyped, ?new_text: untyped, ?associations: untyped }) -> instance
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
@source: String
|
|
24
|
-
|
|
25
23
|
@modifications: Array[Modification]
|
|
26
24
|
|
|
25
|
+
@source: String
|
|
26
|
+
|
|
27
27
|
# @rbs!
|
|
28
28
|
# attr_reader source: String
|
|
29
29
|
# attr_reader modifications: Array[Modification]
|
|
@@ -39,9 +39,9 @@ module Bullematic
|
|
|
39
39
|
def initialize: (String source) -> void
|
|
40
40
|
|
|
41
41
|
# @rbs query_location: Finder::QueryLocation
|
|
42
|
-
# @rbs associations: Array[
|
|
43
|
-
# @rbs return:
|
|
44
|
-
def add_includes: (Finder::QueryLocation query_location, Array[
|
|
42
|
+
# @rbs associations: Array[untyped]
|
|
43
|
+
# @rbs return: Symbol
|
|
44
|
+
def add_includes: (Finder::QueryLocation query_location, Array[untyped] associations) -> Symbol
|
|
45
45
|
|
|
46
46
|
# : () -> String
|
|
47
47
|
def rewrite: () -> String
|
|
@@ -57,21 +57,38 @@ module Bullematic
|
|
|
57
57
|
def find_chain_insert_point: (untyped node) -> Integer
|
|
58
58
|
|
|
59
59
|
# @rbs query_location: Finder::QueryLocation
|
|
60
|
-
# @rbs associations: Array[
|
|
60
|
+
# @rbs associations: Array[untyped]
|
|
61
61
|
# @rbs return: bool
|
|
62
|
-
def already_has_includes?: (Finder::QueryLocation query_location, Array[
|
|
62
|
+
def already_has_includes?: (Finder::QueryLocation query_location, Array[untyped] associations) -> bool
|
|
63
63
|
|
|
64
64
|
# @rbs node: untyped
|
|
65
65
|
# @rbs return: Array[Symbol]
|
|
66
66
|
def find_existing_includes: (untyped node) -> Array[Symbol]
|
|
67
67
|
|
|
68
68
|
# @rbs call_node: untyped
|
|
69
|
-
# @rbs return: Array[
|
|
70
|
-
def extract_associations_from_call: (untyped call_node) -> Array[
|
|
69
|
+
# @rbs return: Array[untyped]
|
|
70
|
+
def extract_associations_from_call: (untyped call_node) -> Array[untyped]
|
|
71
|
+
|
|
72
|
+
# @rbs node: untyped
|
|
73
|
+
# @rbs associations: Array[untyped]
|
|
74
|
+
# @rbs return: void
|
|
75
|
+
def collect_literal_associations: (untyped node, Array[untyped] associations) -> void
|
|
76
|
+
|
|
77
|
+
# @rbs node: untyped
|
|
78
|
+
# @rbs return: untyped
|
|
79
|
+
def literal_association: (untyped node) -> untyped
|
|
71
80
|
|
|
72
|
-
# @rbs associations: Array[
|
|
81
|
+
# @rbs associations: Array[untyped]
|
|
73
82
|
# @rbs return: String
|
|
74
|
-
def format_associations: (Array[
|
|
83
|
+
def format_associations: (Array[untyped] associations) -> String
|
|
84
|
+
|
|
85
|
+
# @rbs association: untyped
|
|
86
|
+
# @rbs braces: bool
|
|
87
|
+
# @rbs return: String
|
|
88
|
+
def format_association: (untyped association, ?bool braces) -> String
|
|
89
|
+
|
|
90
|
+
# : () -> void
|
|
91
|
+
def validate_modifications!: () -> void
|
|
75
92
|
end
|
|
76
93
|
end
|
|
77
94
|
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Generated from lib/bullematic/cli.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Bullematic
|
|
4
|
+
class CLI
|
|
5
|
+
# @rbs argv: Array[String]
|
|
6
|
+
# @rbs return: Integer
|
|
7
|
+
def self.run: (Array[String] argv) -> Integer
|
|
8
|
+
|
|
9
|
+
# @rbs argv: Array[String]
|
|
10
|
+
# @rbs return: Array[String]
|
|
11
|
+
private def self.command_args: (Array[String] argv) -> Array[String]
|
|
12
|
+
|
|
13
|
+
# @rbs command: Array[String]
|
|
14
|
+
# @rbs return: Integer
|
|
15
|
+
private def self.record: (Array[String] command) -> Integer
|
|
16
|
+
|
|
17
|
+
# @rbs dry_run: bool
|
|
18
|
+
# @rbs return: Integer
|
|
19
|
+
private def self.apply: (dry_run: bool) -> Integer
|
|
20
|
+
|
|
21
|
+
# @rbs argv: Array[String]
|
|
22
|
+
# @rbs return: Integer
|
|
23
|
+
private def self.fix: (Array[String] argv) -> Integer
|
|
24
|
+
|
|
25
|
+
# @rbs command: Array[String]
|
|
26
|
+
# @rbs return: Integer
|
|
27
|
+
private def self.verify: (Array[String] command) -> Integer
|
|
28
|
+
|
|
29
|
+
# : () -> Integer
|
|
30
|
+
private def self.doctor: () -> Integer
|
|
31
|
+
|
|
32
|
+
# @rbs command: Array[String]
|
|
33
|
+
# @rbs evidence_path: String
|
|
34
|
+
# @rbs return: Integer
|
|
35
|
+
private def self.run_command: (Array[String] command, String evidence_path) -> Integer
|
|
36
|
+
|
|
37
|
+
# : () -> void
|
|
38
|
+
private def self.load_application: () -> void
|
|
39
|
+
|
|
40
|
+
# @rbs dry_run: bool
|
|
41
|
+
# @rbs return: void
|
|
42
|
+
private def self.configure: (bool dry_run) -> void
|
|
43
|
+
|
|
44
|
+
# @rbs evidence_path: String
|
|
45
|
+
# @rbs command: Array[String]
|
|
46
|
+
# @rbs return: void
|
|
47
|
+
private def self.write_command: (String evidence_path, Array[String] command) -> void
|
|
48
|
+
|
|
49
|
+
# @rbs evidence_path: String
|
|
50
|
+
# @rbs return: Array[String]
|
|
51
|
+
private def self.read_command: (String evidence_path) -> Array[String]
|
|
52
|
+
|
|
53
|
+
# : (String, Integer) { (File) -> untyped } -> untyped
|
|
54
|
+
private def self.open_command: (String, Integer) { (File) -> untyped } -> untyped
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -2,26 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
module Bullematic
|
|
4
4
|
class Configuration
|
|
5
|
+
VALID_FIX_STRATEGIES: Array[Symbol]
|
|
6
|
+
|
|
5
7
|
# @rbs skip: to avoid empty array warning
|
|
6
8
|
DEFAULTS: untyped
|
|
7
9
|
|
|
8
|
-
@
|
|
10
|
+
@logger: Logger?
|
|
9
11
|
|
|
10
|
-
@
|
|
12
|
+
@debug: bool
|
|
11
13
|
|
|
12
|
-
@
|
|
14
|
+
@fix_strategy: Symbol
|
|
13
15
|
|
|
14
|
-
@
|
|
16
|
+
@backup: bool
|
|
15
17
|
|
|
16
18
|
@dry_run: bool
|
|
17
19
|
|
|
18
|
-
@
|
|
20
|
+
@skip_paths: Array[String]
|
|
19
21
|
|
|
20
|
-
@
|
|
22
|
+
@target_paths: Array[String]
|
|
21
23
|
|
|
22
|
-
@
|
|
24
|
+
@auto_fix: bool
|
|
23
25
|
|
|
24
|
-
@
|
|
26
|
+
@enabled: bool
|
|
25
27
|
|
|
26
28
|
# @rbs!
|
|
27
29
|
# attr_accessor enabled: bool
|
|
@@ -95,18 +97,6 @@ module Bullematic
|
|
|
95
97
|
# attr_writer logger: Logger?
|
|
96
98
|
attr_accessor backup: untyped
|
|
97
99
|
|
|
98
|
-
# @rbs!
|
|
99
|
-
# attr_accessor enabled: bool
|
|
100
|
-
# attr_accessor auto_fix: bool
|
|
101
|
-
# attr_accessor target_paths: Array[String]
|
|
102
|
-
# attr_accessor skip_paths: Array[String]
|
|
103
|
-
# attr_accessor dry_run: bool
|
|
104
|
-
# attr_accessor backup: bool
|
|
105
|
-
# attr_accessor fix_strategy: Symbol
|
|
106
|
-
# attr_accessor debug: bool
|
|
107
|
-
# attr_writer logger: Logger?
|
|
108
|
-
attr_accessor fix_strategy: untyped
|
|
109
|
-
|
|
110
100
|
# @rbs!
|
|
111
101
|
# attr_accessor enabled: bool
|
|
112
102
|
# attr_accessor auto_fix: bool
|
|
@@ -119,6 +109,8 @@ module Bullematic
|
|
|
119
109
|
# attr_writer logger: Logger?
|
|
120
110
|
attr_accessor debug: untyped
|
|
121
111
|
|
|
112
|
+
attr_reader fix_strategy: untyped
|
|
113
|
+
|
|
122
114
|
attr_writer logger: untyped
|
|
123
115
|
|
|
124
116
|
# : () -> void
|
|
@@ -127,6 +119,10 @@ module Bullematic
|
|
|
127
119
|
# : () -> Logger
|
|
128
120
|
def logger: () -> Logger
|
|
129
121
|
|
|
122
|
+
# @rbs strategy: Symbol
|
|
123
|
+
# @rbs return: Symbol
|
|
124
|
+
def fix_strategy=: (Symbol strategy) -> Symbol
|
|
125
|
+
|
|
130
126
|
private
|
|
131
127
|
|
|
132
128
|
# : () -> Logger
|