rubycritic 4.9.2 → 4.11.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: 78f041e961ddd2844538f7fca6622192a8b2a9f64caa540cb8fc4b08f13362e0
4
- data.tar.gz: 1bb52128d47548eb1969869552d26e7ef81940c61aa22b85777652f1a53659f1
3
+ metadata.gz: dc015a0d7c129bd1da7f6a6568ddfdbd970f6fb9899632e07c1687b4d2b0e24f
4
+ data.tar.gz: a94ac6fe001ee473936352ce4684012fad2d541feab5b3a432da5391784932ab
5
5
  SHA512:
6
- metadata.gz: 202a4ba45550da029562867c284a941c65666c013fbd75dfa2be0443ce2483149f4c2c751584ff90c10242014a8f630750e6413571304b3927faecb093062b8a
7
- data.tar.gz: 9e4af57d0f10840698a488da7ce77951ef693c022fa16888bc1387fa73d9e3067eab3cd2ee7a690e4640880940426627b3b3089576c21671c408b7af77a41467
6
+ metadata.gz: 3b8712ec496070d78cb6ebbaf57a3a50e37e6971c7997fff75dd6a52bb17b3e549c66150ea8f614e2d80afe2fd4cc9ac2352a9ffeecb548c0becd0ba93a989cb
7
+ data.tar.gz: 42427d7b53a2921623a53cb9be052019b1399f0eaa729e4a17540bfe5c0a34c8153c59233f15242afcb3782cbcd2514cfccc7c9a7d25ed4e33f2c1ceea06cbf9
data/CHANGELOG.md CHANGED
@@ -1,4 +1,20 @@
1
- # main [(unreleased)](https://github.com/whitesmith/rubycritic/compare/v4.9.2...main)
1
+ # main [(unreleased)](https://github.com/whitesmith/rubycritic/compare/v4.11.0...main)
2
+
3
+ * <INSERT YOUR CHANGES HERE>
4
+
5
+ # v4.11.0 / 2025-10-15 [(commits)](https://github.com/whitesmith/rubycritic/compare/v4.10.0...v4.11.0)
6
+
7
+ * [CHANGE] Bump cucumber dependency (by [@faisal][])
8
+ * [CHANGE] Performance improvement for churn calculation: Memoize call to `git rev-parse --show-toplevel` for churn calculations (by [@mateusdeap][])
9
+ * [CHANGE] Bump minitest dependency. (by [@faisal][])
10
+
11
+ # v4.10.0 / 2025-07-30 [(commits)](https://github.com/whitesmith/rubycritic/compare/v4.9.2...v4.10.0)
12
+
13
+ * [CHANGE] Bump aruba, byebug, cucumber, fakefs, rake, reek dependencies (by [@faisal][])
14
+ * [BUGFIX] Work around issue preventing feature execution on Ruby 3.5.0dev (by [@faisal][])
15
+ * [CHANGE] Add changes or suppress warnings for issues found by newer rubocop (by [@faisal][])
16
+ * [CHANGE] Update CI checkout action to v4 (by [@faisal][])
17
+ * [CHANGE] Run RubyCritic outside of the project without losing the churn value (by [@juanvqz][])
2
18
 
3
19
  # v4.9.2 / 2025-04-08 [(commits)](https://github.com/whitesmith/rubycritic/compare/v4.9.1...v4.9.2)
4
20
 
@@ -15,6 +31,8 @@
15
31
  * [CHANGE] Fix some typos (by [@jbampton][])
16
32
  * [FEATURE] Add coverage_path configuration option (by [@exoego][])
17
33
 
34
+ * [CHANGE] Add support for wildcard entries to the paths option in rubycritic.yml (by [@rishiain][])
35
+
18
36
  # v4.9.0 / 2023-10-18 [(commits)](https://github.com/whitesmith/rubycritic/compare/v4.8.1...v4.9.0)
19
37
 
20
38
  * [CHANGE] Bump aruba, cucumber, fakefs, flog, mdl, minitest, and rubocop dependencies (by [@faisal][])
data/README.md CHANGED
@@ -154,6 +154,7 @@ minimum_score: 95 # default is 0
154
154
  paths: # Files to analyse. Churn calculation is scoped to these files when using Git SCM.
155
155
  - 'app/controllers/'
156
156
  - 'app/models/'
157
+ - 'lib/**' # Wildcard patterns are supported (excludes tmp directories automatically)
157
158
  ```
158
159
 
159
160
  ### Analyzer Configuration
@@ -8,6 +8,7 @@ module RubyCritic
8
8
  module Analyser
9
9
  class Attributes
10
10
  include Colorize
11
+
11
12
  def initialize(analysed_modules)
12
13
  @analysed_modules = analysed_modules
13
14
  end
@@ -6,6 +6,7 @@ module RubyCritic
6
6
  module Analyser
7
7
  class Churn
8
8
  include Colorize
9
+
9
10
  attr_writer :source_control_system
10
11
 
11
12
  def initialize(analysed_modules)
@@ -7,6 +7,7 @@ module RubyCritic
7
7
  module Analyser
8
8
  class Complexity
9
9
  include Colorize
10
+
10
11
  def initialize(analysed_modules)
11
12
  @flog = Flog.new
12
13
  @analysed_modules = analysed_modules
@@ -8,6 +8,7 @@ module RubyCritic
8
8
  module Analyser
9
9
  class FlaySmells
10
10
  include Colorize
11
+
11
12
  def initialize(analysed_modules)
12
13
  @analysed_modules = paths_to_analysed_modules(analysed_modules)
13
14
  @flay = Flay.new(@analysed_modules.keys)
@@ -8,6 +8,7 @@ module RubyCritic
8
8
  module Analyser
9
9
  class FlogSmells
10
10
  include Colorize
11
+
11
12
  HIGH_COMPLEXITY_SCORE_THRESHOLD = 25
12
13
  VERY_HIGH_COMPLEXITY_SCORE_THRESHOLD = 60
13
14
 
@@ -8,6 +8,7 @@ module RubyCritic
8
8
  module Analyser
9
9
  class ReekSmells
10
10
  include Colorize
11
+
11
12
  def initialize(analysed_modules)
12
13
  @analysed_modules = analysed_modules
13
14
  end
@@ -24,11 +24,11 @@ module RubyCritic
24
24
  root: root,
25
25
  coverage_path: coverage_path,
26
26
  formats: formats,
27
- deduplicate_symlinks: deduplicate_symlinks,
27
+ deduplicate_symlinks: deduplicate_symlinks?,
28
28
  paths: paths,
29
- suppress_ratings: suppress_ratings,
29
+ suppress_ratings: suppress_ratings?,
30
30
  minimum_score: minimum_score,
31
- no_browser: no_browser,
31
+ no_browser: no_browser?,
32
32
  base_branch: base_branch,
33
33
  feature_branch: feature_branch,
34
34
  threshold_score: threshold_score
@@ -68,16 +68,16 @@ module RubyCritic
68
68
  options['threshold_score']
69
69
  end
70
70
 
71
- def deduplicate_symlinks
72
- value_for(options['deduplicate_symlinks'])
71
+ def deduplicate_symlinks?
72
+ value_for?(options['deduplicate_symlinks'])
73
73
  end
74
74
 
75
- def suppress_ratings
76
- value_for(options['suppress_ratings'])
75
+ def suppress_ratings?
76
+ value_for?(options['suppress_ratings'])
77
77
  end
78
78
 
79
- def no_browser
80
- value_for(options['no_browser'])
79
+ def no_browser?
80
+ value_for?(options['no_browser'])
81
81
  end
82
82
 
83
83
  def formats
@@ -96,7 +96,7 @@ module RubyCritic
96
96
  options['paths']
97
97
  end
98
98
 
99
- def value_for(value)
99
+ def value_for?(value)
100
100
  value = value.to_s
101
101
  value == 'true' unless value.empty?
102
102
  end
@@ -26,10 +26,10 @@ module RubyCritic
26
26
  end
27
27
 
28
28
  def current_status
29
- satisfy_minimum_score_rule ? SUCCESS : SCORE_BELOW_MINIMUM
29
+ satisfy_minimum_score_rule? ? SUCCESS : SCORE_BELOW_MINIMUM
30
30
  end
31
31
 
32
- def satisfy_minimum_score_rule
32
+ def satisfy_minimum_score_rule?
33
33
  score >= @options[:minimum_score].to_f
34
34
  end
35
35
 
@@ -21,11 +21,16 @@ module RubyCritic
21
21
  self.no_browser = options[:no_browser]
22
22
  self.coverage_path = options[:coverage_path]
23
23
  self.threshold_score = options[:threshold_score].to_i
24
+ setup_paths_for_targets(options) if options[:paths]
24
25
  setup_analysis_targets(options)
25
26
  setup_version_control(options)
26
27
  setup_formats(options)
27
28
  end
28
29
 
30
+ def setup_paths_for_targets(options)
31
+ options[:paths] = find_directories(options[:paths])
32
+ end
33
+
29
34
  def setup_analysis_targets(options)
30
35
  self.paths = options[:paths] || ['.']
31
36
  self.ruby_extensions = options[:ruby_extensions] || %w[.rb .rake .thor]
@@ -51,6 +56,20 @@ module RubyCritic
51
56
  source_control_system &&
52
57
  !source_control_system.is_a?(SourceControlSystem::Double)
53
58
  end
59
+
60
+ private
61
+
62
+ def find_directories(paths)
63
+ expanded_paths = paths.flat_map do |path|
64
+ if path.include?('**')
65
+ search_pattern = File.join(path)
66
+ Dir.glob(search_pattern).select { |tmp_path| File.directory?(tmp_path) && !tmp_path.start_with?('tmp') }
67
+ else
68
+ path
69
+ end
70
+ end
71
+ expanded_paths
72
+ end
54
73
  end
55
74
 
56
75
  module Config
@@ -71,7 +71,7 @@ module RubyCritic
71
71
 
72
72
  def print_starting_up_output
73
73
  puts "\n\n!!! Running `#{name}` rake command\n"
74
- puts "!!! Inspecting #{paths} #{options.empty? ? '' : "with options #{options}"}\n\n"
74
+ puts "!!! Inspecting #{paths} #{"with options #{options}" unless options.empty?}\n\n"
75
75
  end
76
76
 
77
77
  def options_as_arguments
@@ -20,12 +20,16 @@ module RubyCritic
20
20
  end
21
21
  end
22
22
 
23
+ # :reek:TooManyInstanceVariables
24
+ # rubocop:disable Metrics/ClassLength
23
25
  class Churn
26
+ # :reek:TooManyStatements
24
27
  def initialize(churn_after: nil, paths: ['.'])
25
28
  @churn_after = churn_after
26
29
  @paths = Array(paths)
27
30
  @date = nil
28
31
  @stats = {}
32
+ @git_root = find_git_root
29
33
 
30
34
  call
31
35
  end
@@ -40,16 +44,32 @@ module RubyCritic
40
44
 
41
45
  private
42
46
 
47
+ # :reek:DuplicateMethodCall
48
+ def find_git_root
49
+ @paths.each do |path|
50
+ current_path = File.expand_path(path)
51
+ while current_path != File.dirname(current_path)
52
+ return current_path if Dir.exist?(File.join(current_path, '.git'))
53
+
54
+ current_path = File.dirname(current_path)
55
+ end
56
+ end
57
+ Dir.pwd
58
+ end
59
+
43
60
  def call
44
61
  git_log_commands.each { |log_command| exec_git_command(log_command) }
45
62
  end
46
63
 
47
64
  def exec_git_command(command)
48
- Git
49
- .git(command)
50
- .split("\n")
51
- .reject(&:empty?)
52
- .each { |line| process_line(line) }
65
+ # Run git command from the git repository root
66
+ Dir.chdir(@git_root) do
67
+ Git
68
+ .git(command)
69
+ .split("\n")
70
+ .reject(&:empty?)
71
+ .each { |line| process_line(line) }
72
+ end
53
73
  end
54
74
 
55
75
  def git_log_commands
@@ -57,7 +77,20 @@ module RubyCritic
57
77
  end
58
78
 
59
79
  def git_log_command(path)
60
- "log --all --date=iso --follow --format='format:date:%x09%ad' --name-status #{after_clause}#{path}"
80
+ # Convert absolute paths to relative paths from git root
81
+ relative_path = make_relative_to_git_root(path)
82
+ "log --all --date=iso --follow --format='format:date:%x09%ad' --name-status #{after_clause}#{relative_path}"
83
+ end
84
+
85
+ def make_relative_to_git_root(path)
86
+ absolute_path = File.expand_path(path)
87
+ if absolute_path.start_with?(@git_root)
88
+ # Convert to relative path from git root
89
+ absolute_path[(@git_root.length + 1)..] || '.'
90
+ else
91
+ # If path is not within git root, use as is
92
+ path
93
+ end
61
94
  end
62
95
 
63
96
  def after_clause
@@ -87,13 +120,22 @@ module RubyCritic
87
120
  process_file(to)
88
121
  end
89
122
 
123
+ # :reek:DuplicateMethodCall
90
124
  def filename_for_subdirectory(filename)
91
- git_path = Git.git('rev-parse --show-toplevel')
92
- cd_path = Dir.pwd
93
- if cd_path.length > git_path.length
94
- filename = filename.sub(/^#{Regexp.escape("#{File.basename(cd_path)}/")}/, '')
125
+ if @git_root == Dir.pwd
126
+ git_path = git_top_level
127
+ cd_path = Dir.pwd
128
+ if cd_path.length > git_path.length
129
+ filename = filename.sub(/^#{Regexp.escape("#{File.basename(cd_path)}/")}/, '')
130
+ end
131
+ [filename]
132
+ else
133
+ filename
95
134
  end
96
- [filename]
135
+ end
136
+
137
+ def git_top_level
138
+ @git_top_level ||= Git.git('rev-parse --show-toplevel').strip
97
139
  end
98
140
 
99
141
  def process_file(filename)
@@ -109,10 +151,32 @@ module RubyCritic
109
151
  @renames ||= Renames.new
110
152
  end
111
153
 
154
+ # :reek:TooManyStatements
155
+ # rubocop:disable Metrics/MethodLength
112
156
  def stats(path)
157
+ # Try the path as-is first
158
+ result = @stats.fetch(path, nil)
159
+ return result if result
160
+
161
+ # If not found, try converting absolute path to relative path from git root
162
+ absolute_path = File.expand_path(path)
163
+ if absolute_path.start_with?(@git_root)
164
+ relative_path = absolute_path[(@git_root.length + 1)..]
165
+ return @stats.fetch(relative_path, Stats.new(0))
166
+ end
167
+
168
+ # If still not found, try converting relative path to absolute path
169
+ unless path.start_with?('/')
170
+ absolute_path = File.expand_path(path, @git_root)
171
+ return @stats.fetch(absolute_path, Stats.new(0))
172
+ end
173
+
174
+ # Default fallback
113
175
  @stats.fetch(path, Stats.new(0))
114
176
  end
177
+ # rubocop:enable Metrics/MethodLength
115
178
  end
179
+ # rubocop:enable Metrics/ClassLength
116
180
  end
117
181
  end
118
182
  end
@@ -21,8 +21,28 @@ module RubyCritic
21
21
  self.class.git(arg)
22
22
  end
23
23
 
24
+ # :reek:DuplicateMethodCall
25
+ # :reek:NilCheck
24
26
  def self.supported?
25
- git('branch 2>&1') && $CHILD_STATUS.success?
27
+ return true if git('branch 2>&1') && $CHILD_STATUS.success?
28
+
29
+ return false if Config.paths.nil? || Config.paths.empty?
30
+
31
+ Config.paths.any? do |path|
32
+ absolute_path = File.expand_path(path)
33
+ check_git_repository?(absolute_path)
34
+ end
35
+ end
36
+
37
+ # :reek:DuplicateMethodCall
38
+ def self.check_git_repository?(path)
39
+ current_path = File.expand_path(path)
40
+ while current_path != File.dirname(current_path)
41
+ return true if Dir.exist?(File.join(current_path, '.git'))
42
+
43
+ current_path = File.dirname(current_path)
44
+ end
45
+ false
26
46
  end
27
47
 
28
48
  def self.to_s
@@ -50,7 +70,7 @@ module RubyCritic
50
70
  end
51
71
 
52
72
  def travel_to_head
53
- stash_successful = stash_changes
73
+ stash_successful = stash_changes?
54
74
  yield
55
75
  ensure
56
76
  travel_to_original_state if stash_successful
@@ -88,7 +108,7 @@ module RubyCritic
88
108
 
89
109
  private
90
110
 
91
- def stash_changes
111
+ def stash_changes?
92
112
  stashes_count_before = stashes_count
93
113
  git('stash')
94
114
  stashes_count_after = stashes_count
@@ -52,9 +52,11 @@ module RubyCritic
52
52
  Time.strptime(perforce_files[Perforce.key_file(path)].last_commit, '%s').strftime('%Y-%m-%d %H:%M:%S %z')
53
53
  end
54
54
 
55
+ # rubocop:disable Style/CollectionQuerying
55
56
  def revision?
56
57
  !perforce_files.values.count(&:opened?).zero?
57
58
  end
59
+ # rubocop:enable Style/CollectionQuerying
58
60
 
59
61
  def head_reference
60
62
  perforce_files.values.map(&:head).max_by(&:to_i)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyCritic
4
- VERSION = '4.9.2'
4
+ VERSION = '4.11.0'
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubycritic
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.9.2
4
+ version: 4.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guilherme Simoes
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-04-09 00:00:00.000000000 Z
10
+ date: 2025-10-15 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: flay
@@ -85,7 +85,7 @@ dependencies:
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: 6.4.0
88
+ version: 6.5.0
89
89
  - - "<"
90
90
  - !ruby/object:Gem::Version
91
91
  version: '7.0'
@@ -95,7 +95,7 @@ dependencies:
95
95
  requirements:
96
96
  - - "~>"
97
97
  - !ruby/object:Gem::Version
98
- version: 6.4.0
98
+ version: 6.5.0
99
99
  - - "<"
100
100
  - !ruby/object:Gem::Version
101
101
  version: '7.0'
@@ -175,14 +175,20 @@ dependencies:
175
175
  requirements:
176
176
  - - "~>"
177
177
  - !ruby/object:Gem::Version
178
- version: 2.3.0
178
+ version: 2.3.1
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: 2.3.1
179
182
  type: :development
180
183
  prerelease: false
181
184
  version_requirements: !ruby/object:Gem::Requirement
182
185
  requirements:
183
186
  - - "~>"
184
187
  - !ruby/object:Gem::Version
185
- version: 2.3.0
188
+ version: 2.3.1
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: 2.3.1
186
192
  - !ruby/object:Gem::Dependency
187
193
  name: bundler
188
194
  requirement: !ruby/object:Gem::Requirement
@@ -203,7 +209,7 @@ dependencies:
203
209
  requirements:
204
210
  - - "~>"
205
211
  - !ruby/object:Gem::Version
206
- version: '11.0'
212
+ version: '12.0'
207
213
  - - ">="
208
214
  - !ruby/object:Gem::Version
209
215
  version: '10.0'
@@ -213,7 +219,7 @@ dependencies:
213
219
  requirements:
214
220
  - - "~>"
215
221
  - !ruby/object:Gem::Version
216
- version: '11.0'
222
+ version: '12.0'
217
223
  - - ">="
218
224
  - !ruby/object:Gem::Version
219
225
  version: '10.0'
@@ -223,7 +229,7 @@ dependencies:
223
229
  requirements:
224
230
  - - "~>"
225
231
  - !ruby/object:Gem::Version
226
- version: 9.2.1
232
+ version: 10.1.0
227
233
  - - "!="
228
234
  - !ruby/object:Gem::Version
229
235
  version: 9.0.0
@@ -233,7 +239,7 @@ dependencies:
233
239
  requirements:
234
240
  - - "~>"
235
241
  - !ruby/object:Gem::Version
236
- version: 9.2.1
242
+ version: 10.1.0
237
243
  - - "!="
238
244
  - !ruby/object:Gem::Version
239
245
  version: 9.0.0
@@ -257,14 +263,14 @@ dependencies:
257
263
  requirements:
258
264
  - - "~>"
259
265
  - !ruby/object:Gem::Version
260
- version: 2.6.0
266
+ version: 3.0.0
261
267
  type: :development
262
268
  prerelease: false
263
269
  version_requirements: !ruby/object:Gem::Requirement
264
270
  requirements:
265
271
  - - "~>"
266
272
  - !ruby/object:Gem::Version
267
- version: 2.6.0
273
+ version: 3.0.0
268
274
  - !ruby/object:Gem::Dependency
269
275
  name: irb
270
276
  requirement: !ruby/object:Gem::Requirement
@@ -305,7 +311,7 @@ dependencies:
305
311
  requirements:
306
312
  - - "~>"
307
313
  - !ruby/object:Gem::Version
308
- version: 5.25.2
314
+ version: 5.26.0
309
315
  - - ">="
310
316
  - !ruby/object:Gem::Version
311
317
  version: 5.3.0
@@ -315,7 +321,7 @@ dependencies:
315
321
  requirements:
316
322
  - - "~>"
317
323
  - !ruby/object:Gem::Version
318
- version: 5.25.2
324
+ version: 5.26.0
319
325
  - - ">="
320
326
  - !ruby/object:Gem::Version
321
327
  version: 5.3.0
@@ -373,7 +379,7 @@ dependencies:
373
379
  requirements:
374
380
  - - "~>"
375
381
  - !ruby/object:Gem::Version
376
- version: 13.2.0
382
+ version: 13.3.0
377
383
  - - ">="
378
384
  - !ruby/object:Gem::Version
379
385
  version: 11.0.0
@@ -383,7 +389,7 @@ dependencies:
383
389
  requirements:
384
390
  - - "~>"
385
391
  - !ruby/object:Gem::Version
386
- version: 13.2.0
392
+ version: 13.3.0
387
393
  - - ">="
388
394
  - !ruby/object:Gem::Version
389
395
  version: 11.0.0