bulletmark_repairer 0.1.2 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 533eed3a74c78c89236e5c1355f588814c6a4017cf79af12f0a0e23fe030fcde
4
- data.tar.gz: bf8a718e822ba241ab3299f675db3809870d955257bc5279644285373a619141
3
+ metadata.gz: 4b793a019d2937170c113a1b95eeea035a23e0f85a36f5c86382628467d3b006
4
+ data.tar.gz: 0e513ae03aab2b2f21785d31be5141abe0a34759a16a97e41b32871caf01d531
5
5
  SHA512:
6
- metadata.gz: a33cc9ba73a76ebca97b8293677d8498761a07c2a6680e5182a65b2d8f7cb6237196506aedee63ed4f798168beb4161072ee5e62cbcee9506c4040e4584a508f
7
- data.tar.gz: 2fb1af553ee13ca638023120306f6284b4d04ae567171616cee658ee5277f1bb33a589d769d7625ad0d6b445d06664a068dc49db479e8ac91934d36aef3553d6
6
+ metadata.gz: bb0869546bfe5bd2c29586cffc2261f58680bb114a7f5dd01c0d4325df6736d49e24e743200285eb5cf199b87123e22bfe85cb8dce0eb2546d469e71fd98afd9
7
+ data.tar.gz: 2ef8b880ef7e027b3a49a08638235a342ad8e8f1c7a35485f01f3c3cbbbb09b8cd4b75ec21b7522a2439e685833b05ed9488d3a75c916df8391453ea618f7aa8
data/.codespellignore ADDED
File without changes
data/.rubocop.yml CHANGED
@@ -31,3 +31,6 @@ Metrics/BlockLength:
31
31
 
32
32
  Style/Documentation:
33
33
  Enabled: false
34
+
35
+ Style/MultilineBlockChain:
36
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,6 +1,17 @@
1
+ ## [0.1.4] - 2023-10-22
2
+
3
+ - Patch files other than controllers [218566d](https://github.com/makicamel/bulletmark_repairer/commit/218566d1531751f204941c3dcff7f095a056d39f)
4
+ - Patch unassigned queries [159573a](https://github.com/makicamel/bulletmark_repairer/commit/159573ada036ee3ee39428b1e59066934b676c02)
5
+ - Apply patches starting from the top of the method [f8d0058](https://github.com/makicamel/bulletmark_repairer/commit/f8d00582a5b3b084c0a35a54726396a2a063f8dd)
6
+ - Log also when the target file is in the skip list [a23a3bc](https://github.com/makicamel/bulletmark_repairer/commit/a23a3bc0edf1e94d3aa6ea95449c9570b9322d65)
7
+
8
+ ## [0.1.3] - 2023-10-18
9
+
10
+ - Fix a redundant auto-correct for multiple tests with n+1 queries when running RSpec [#6](https://github.com/makicamel/bulletmark_repairer/pull/6) ([@ydah])
11
+
1
12
  ## [0.1.2] - 2023-10-16
2
13
 
3
- - Reduce dependencies [#1](https://github.com/makicamel/bulletmark_repairer/pull/1) [@tricknotes]()
14
+ - Reduce dependencies [#1](https://github.com/makicamel/bulletmark_repairer/pull/1) ([@tricknotes])
4
15
  - Stop using class instance variables for thread safe [024f6c5](https://github.com/makicamel/bulletmark_repairer/commit/024f6c53f82b182a998c1e43de48d8c6c9ce5bf3)
5
16
 
6
17
  ## [0.1.1] - 2023-10-11
@@ -10,3 +21,6 @@
10
21
  ## [0.1.0] - 2023-10-10
11
22
 
12
23
  - Initial release
24
+
25
+ [@tricknotes]: https://github.com/tricknotes
26
+ [@ydah]: https://github.com/ydah
data/README.md CHANGED
@@ -47,14 +47,12 @@ For example, the following cases are not supported as known cases currently:
47
47
 
48
48
  ```ruby
49
49
  def index
50
- # N+1 is caused but not assigned
51
- Play.all_actors_name
52
- end
53
-
54
- def index
55
- # N+1 occurs when assigning a local variable
56
- plays = Play.all.as_json
57
- @play = plays.last
50
+ # Nested associations require `includes` though child associations are already included
51
+ @plays = Play.includes(:actors)
52
+ # expected correct
53
+ @plays = Play.includes(actors: [:company])
54
+ # actual correct
55
+ @plays = Play.includes(:actors).includes([:company])
58
56
  end
59
57
  ```
60
58
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BulletmarkRepairer
4
- class Configration
4
+ class Configuration
5
5
  attr_accessor :skip_file_list, :logger
6
6
  attr_writer :debug
7
7
 
@@ -22,7 +22,7 @@ module BulletmarkRepairer
22
22
  end
23
23
 
24
24
  def config
25
- @config ||= Configration.new
25
+ @config ||= Configuration.new
26
26
  end
27
27
  end
28
28
  end
@@ -46,14 +46,15 @@ class ControllerCorrector < Parser::TreeRewriter
46
46
  return unless node.respond_to?(:to_sexp_array)
47
47
 
48
48
  type, identifier = node.to_sexp_array.take(2)
49
-
50
49
  if type == :ivasgn && identifier == instance_variable_name
51
- insert_after node.children.last.location.expression, ".includes(#{associations})"
52
- @patched = true
50
+ inserted = ".includes(#{associations})"
51
+ unless node.location.expression.source.include?(inserted)
52
+ insert_after node.children.last.location.expression, inserted
53
+ @patched = true
54
+ end
53
55
  else
54
56
  node
55
57
  .children
56
- .reverse
57
58
  .each do |child_node|
58
59
  child_type, _, child_identifier = child_node.try(:to_sexp_array)
59
60
  if child_type == :send && target_nodes.key?(child_identifier)
@@ -16,17 +16,30 @@ module BulletmarkRepairer
16
16
  end
17
17
 
18
18
  def execute
19
- corrector_name = '/controller_corrector.rb'
20
- File.open("#{@dir}#{corrector_name}", 'w') do |f|
21
- corrector = Pathname.new(__FILE__).sub('/corrector_builder.rb', corrector_name)
22
- src = File.read(corrector)
23
- src
24
- .sub!(ASSOCIATIONS, @associations[:base].to_s)
25
- .sub!(ACTION, @action)
26
- .sub!(INSTANCE_VARIABLE_NAME, @instance_variable_name)
27
- f.puts src
28
- f
29
- end.path
19
+ if @marker.retry
20
+ corrector_name = '/retry_corrector.rb'
21
+ File.open("#{@dir}#{corrector_name}", 'w') do |f|
22
+ corrector = Pathname.new(__FILE__).sub('/corrector_builder.rb', corrector_name)
23
+ src = File.read(corrector)
24
+ src
25
+ .sub!(ASSOCIATIONS, @associations[:base].to_s)
26
+ .sub!(LINE_NO, @marker.line_no)
27
+ f.puts src
28
+ f
29
+ end.path
30
+ else
31
+ corrector_name = '/controller_corrector.rb'
32
+ File.open("#{@dir}#{corrector_name}", 'w') do |f|
33
+ corrector = Pathname.new(__FILE__).sub('/corrector_builder.rb', corrector_name)
34
+ src = File.read(corrector)
35
+ src
36
+ .sub!(ASSOCIATIONS, @associations[:base].to_s)
37
+ .sub!(ACTION, @action)
38
+ .sub!(INSTANCE_VARIABLE_NAME, @instance_variable_name)
39
+ f.puts src
40
+ f
41
+ end.path
42
+ end
30
43
  end
31
44
  end
32
45
  end
@@ -28,7 +28,7 @@ module BulletmarkRepairer
28
28
  end
29
29
 
30
30
  class Marker
31
- attr_reader :base_class, :associations, :action, :file_name, :instance_variable_name, :index
31
+ attr_reader :base_class, :associations, :action, :file_name, :instance_variable_name, :index, :retry, :line_no
32
32
 
33
33
  def initialize(notification, controller:, action:)
34
34
  @base_class = notification.instance_variable_get(:@base_class)
@@ -36,6 +36,8 @@ module BulletmarkRepairer
36
36
  @associations = notification.instance_variable_get(:@associations)
37
37
  @controller = controller
38
38
  @action = action
39
+ @retry = false
40
+ @line_no = nil
39
41
  set_up
40
42
  end
41
43
 
@@ -56,6 +58,7 @@ module BulletmarkRepairer
56
58
 
57
59
  def log_patchable_files_not_be_found
58
60
  return if index
61
+ return if BulletmarkRepairer.config.skip_file_list.exclude?(file_name.remove("#{Rails.root}/"))
59
62
 
60
63
  BulletmarkRepairer.config.logger.info <<~LOG
61
64
  Repairer couldn't patch
@@ -93,7 +96,6 @@ module BulletmarkRepairer
93
96
  @index = @instance_variable_name ? "#{view_file}:#{view_yield_index}" : nil
94
97
  else
95
98
  # TODO: Ignore controllers list
96
- # TODO: Allow directories list
97
99
  controller_file_index = @stacktraces.index { |stacktrace| stacktrace.match?(%r{\A(#{Rails.root}/app/controllers[./\w]+):(\d+):in `[()\w\s]+'\z}) }
98
100
  @file_name, controller_yield_index = @stacktraces[controller_file_index].scan(%r{\A(#{Rails.root}/app/controllers[./\w]+):(\d+):in `[()\w\s]+'\z}).flatten
99
101
  controller_yield_index = controller_yield_index.to_i
@@ -104,13 +106,25 @@ module BulletmarkRepairer
104
106
 
105
107
  controller_yield_index -= 1
106
108
  line = lines[controller_yield_index]
107
- # TODO: patch to local variables
108
109
  @instance_variable_name = line&.scan(/\b?(@[\w]+)\b?/)&.flatten&.last
109
110
  break if line.match?(/^\s+def [()\w\s=]+$/)
110
111
  end
111
112
  end
112
113
  @index = @instance_variable_name ? "#{@file_name}:#{controller_yield_index}" : nil
113
114
  end
115
+
116
+ return if @index
117
+
118
+ # TODO: Ignore files list
119
+ # TODO: Allow model files list
120
+ @retry = @stacktraces.any? do |stacktrace|
121
+ !stacktrace.match?(%r{\A(#{Rails.root}/app/models[./\w]+):(\d+):in `[()\w\s=!?]+'\z}) &&
122
+ stacktrace =~ %r{\A(#{Rails.root}/app[./\w]+):(\d+):in `[()\w\s=!?]+'\z}
123
+ end.tap do
124
+ @file_name = Regexp.last_match(1)
125
+ @line_no = Regexp.last_match(2)
126
+ end
127
+ @index = @retry ? "#{@file_name}:#{@line_no}" : nil
114
128
  end
115
129
  end
116
130
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RetryCorrector < Parser::TreeRewriter
4
+ def on_def(node)
5
+ return if patched?
6
+
7
+ node.children.each { |child_node| insert_includes(node: child_node) }
8
+ end
9
+
10
+ private
11
+
12
+ def patched?
13
+ @patched ||= false
14
+ end
15
+
16
+ def insert_includes(node:)
17
+ return if patched?
18
+ return if !node.respond_to?(:children) || node.children.empty?
19
+ return unless node.location.expression.line <= line_no && line_no <= node.location.expression.last_line
20
+
21
+ if node.type == :begin
22
+ node.children.each { |child_node| insert_includes(node: child_node) }
23
+ else
24
+ inserted = ".includes(#{associations})"
25
+ return if node.location.expression.source.include?(inserted)
26
+
27
+ insert_after node.location.expression, ".includes(#{associations})"
28
+ @patched = true
29
+ end
30
+ end
31
+
32
+ def line_no
33
+ __EMBEDDED_LINE_NO__
34
+ end
35
+
36
+ def associations
37
+ '__EMBEDDED_ASSOCIATIONS__'
38
+ end
39
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BulletmarkRepairer
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.4'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bulletmark_repairer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - makicamel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-16 00:00:00.000000000 Z
11
+ date: 2023-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -73,6 +73,7 @@ executables: []
73
73
  extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
+ - ".codespellignore"
76
77
  - ".rspec"
77
78
  - ".rubocop.yml"
78
79
  - CHANGELOG.md
@@ -86,12 +87,12 @@ files:
86
87
  - lib/bulletmark_repairer/associations_builder.rb
87
88
  - lib/bulletmark_repairer/configuration.rb
88
89
  - lib/bulletmark_repairer/controller_corrector.rb
89
- - lib/bulletmark_repairer/corrector.rb
90
90
  - lib/bulletmark_repairer/corrector_builder.rb
91
91
  - lib/bulletmark_repairer/markers.rb
92
92
  - lib/bulletmark_repairer/patcher.rb
93
93
  - lib/bulletmark_repairer/rack.rb
94
94
  - lib/bulletmark_repairer/railtie.rb
95
+ - lib/bulletmark_repairer/retry_corrector.rb
95
96
  - lib/bulletmark_repairer/version.rb
96
97
  - sig/bulletmark_repairer.rbs
97
98
  homepage: https://github.com/makicamel/bulletmark_repairer
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Corrector < Parser::TreeRewriter
4
- def on_def(node)
5
- return if patched?
6
-
7
- node.children.each { |child_node| insert_includes(node: child_node) }
8
- return if patched?
9
-
10
- node.children.each { |child_node| insert_includes_for_vasgn(node: child_node, type: :ivasgn) }
11
- return if patched?
12
-
13
- node.children.each { |child_node| insert_includes_for_vasgn(node: child_node, type: :lvasgn) }
14
- end
15
-
16
- private
17
-
18
- def patched?
19
- @patched ||= false
20
- end
21
-
22
- def insert_includes(node:)
23
- return if patched?
24
- return if !node.respond_to?(:children) || node.children.empty?
25
- return unless node.location.expression.line <= line_no && line_no <= node.location.expression.last_line
26
-
27
- # TODO: Patch Enumerable methods other than each and map
28
- if node.children.last.in?(%i[each map])
29
- insert_after node.children[0].location.expression, ".includes(#{associations})"
30
- @patched = true
31
- else
32
- node.children.each { |child_node| insert_includes(node: child_node) }
33
- end
34
- end
35
-
36
- def insert_includes_for_vasgn(node:, type:)
37
- return if patched?
38
- return if !node.respond_to?(:children) || node.children.empty?
39
- return unless node.location.expression.line <= line_no && line_no <= node.location.expression.last_line
40
-
41
- if node.type == type
42
- insert_after node.children.last.location.expression, ".includes(#{associations})"
43
- @patched = true
44
- else
45
- node.children.each { |child_node| insert_includes_for_vasgn(node: child_node, type: type) }
46
- end
47
- end
48
-
49
- def line_no
50
- __EMBEDDED_LINE_NO__
51
- end
52
-
53
- def associations
54
- '__EMBEDDED_ASSOCIATIONS__'
55
- end
56
- end