rubomop 0.1.0 → 1.0.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: 3e23279657fd3a3f2172cbbcdd14d3f7c6067c8721a1e18b50eaf45ed7602149
4
- data.tar.gz: 85f85b5809d827705ee7c0e77978c6efb24be669f3d50c013394373b82f7fe45
3
+ metadata.gz: 216a8fe4da9335c5a7c12ee8e5660003658aab305804acf99bb69c8493b357d1
4
+ data.tar.gz: 86644a5f0e10bf9d744fa9e7c516b5749cc303ced54991fd6062f25c3ba87e1b
5
5
  SHA512:
6
- metadata.gz: 64d68023ebb7185bd24096b7377ec04f2968047c2dcee244873f56bcaa3cd569c917979d32db8a4cd95ce32ca342652f2569a9feac2f10b1dde2f1617f75b5f4
7
- data.tar.gz: 5c1c1bb6adfe50f915dc1d2607ea2039bf0b6f8070ce89885dcdba72900f723b78b869c5b9221638ccc5b8c53e937c67c9ed0b84736fee9f14def7ae964780ed
6
+ metadata.gz: 3480c30528e1bf9439bb8b8c7c1de4dc7ce5f77e38c234640eacad02fbdd9365cc739b2b205f741635fbff4145ae3a2725db611d83af0365ade53efedbe8d0da
7
+ data.tar.gz: ff974af44e598fd848c50f5be23f96515c446a5e674344b2b972b026c99bf25899fb88fee67d416b3b45ae0c4ca8927934ae9f43e0372f36b306ae9bfbdbe8d7
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.1.2
1
+ 3.2.8
data/.standard.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  # For available configuration options, see:
2
2
  # https://github.com/testdouble/standard
3
- ruby_version: 2.7
3
+ ruby_version: 3.2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
- ## [Unreleased]
1
+ ## [1.0.0] - 7/31/2025
2
2
 
3
- ## [0.1.0] - 2022-07-19
3
+ - Allow for a second run type that removes a specific cop from the todo
4
+ - Allow for running the cleanup on a different directory
5
+ - Allow for the difference between safe and unsafe autocorrect
6
+ - Drop support for Ruby 3.1 and lower
7
+ - Handles the case where Rubocop puts criteria and not exclusions in the to-do
8
+
9
+ ## [0.3.0] - 2022-08-12
10
+
11
+ - More accurately update offense count in todo file after running rubocop
12
+
13
+ ## [0.2.0] - 2022-07-22
14
+
15
+ - Adds for a .rubomop.yml file with configuration options
16
+ - Command line switch to override config file name
17
+ - Allows for only/except for specific cops by name or pattern
18
+ - Allows for excluding specific file patterns from being changed
19
+ - Only runs rubocop on selected files, not on the whole repo
20
+
21
+ ## [0.1.0] - 2022-07-20
4
22
 
5
23
  - Initial release
data/Gemfile CHANGED
@@ -8,5 +8,5 @@ gemspec
8
8
  gem "awesome_print"
9
9
  gem "rake", "~> 13.0"
10
10
  gem "rspec", "~> 3.0"
11
- gem "standard", "~> 1.3"
12
11
  gem "rspec-collection_matchers"
12
+ gem "standard", "~> 1.3"
data/Gemfile.lock CHANGED
@@ -1,72 +1,115 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubomop (0.1.0)
5
- activesupport (> 5.0)
6
- date_by_example (> 0.1)
4
+ rubomop (1.0.0)
5
+ activesupport (>= 7.0)
6
+ date_by_example (~> 0.1)
7
+ literal
8
+ zeitwerk (~> 2.7.0)
7
9
 
8
10
  GEM
9
11
  remote: https://rubygems.org/
10
12
  specs:
11
- activesupport (7.0.3.1)
12
- concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ activesupport (8.0.2)
14
+ base64
15
+ benchmark (>= 0.3)
16
+ bigdecimal
17
+ concurrent-ruby (~> 1.0, >= 1.3.1)
18
+ connection_pool (>= 2.2.5)
19
+ drb
13
20
  i18n (>= 1.6, < 2)
21
+ logger (>= 1.4.2)
14
22
  minitest (>= 5.1)
15
- tzinfo (~> 2.0)
16
- ast (2.4.2)
23
+ securerandom (>= 0.3)
24
+ tzinfo (~> 2.0, >= 2.0.5)
25
+ uri (>= 0.13.1)
26
+ ast (2.4.3)
17
27
  awesome_print (1.9.2)
18
- concurrent-ruby (1.1.10)
28
+ base64 (0.3.0)
29
+ benchmark (0.4.1)
30
+ bigdecimal (3.2.2)
31
+ concurrent-ruby (1.3.5)
32
+ connection_pool (2.5.3)
19
33
  date_by_example (0.1.1)
20
- diff-lcs (1.5.0)
21
- i18n (1.12.0)
34
+ diff-lcs (1.6.2)
35
+ drb (2.2.3)
36
+ i18n (1.14.7)
22
37
  concurrent-ruby (~> 1.0)
23
- minitest (5.16.2)
24
- parallel (1.22.1)
25
- parser (3.1.2.0)
38
+ json (2.13.2)
39
+ language_server-protocol (3.17.0.5)
40
+ lint_roller (1.1.0)
41
+ literal (1.8.1)
42
+ zeitwerk
43
+ logger (1.7.0)
44
+ minitest (5.25.5)
45
+ parallel (1.27.0)
46
+ parser (3.3.9.0)
26
47
  ast (~> 2.4.1)
48
+ racc
49
+ prism (1.4.0)
50
+ racc (1.8.1)
27
51
  rainbow (3.1.1)
28
- rake (13.0.6)
29
- regexp_parser (2.5.0)
30
- rexml (3.2.5)
31
- rspec (3.11.0)
32
- rspec-core (~> 3.11.0)
33
- rspec-expectations (~> 3.11.0)
34
- rspec-mocks (~> 3.11.0)
35
- rspec-collection_matchers (1.2.0)
52
+ rake (13.3.0)
53
+ regexp_parser (2.10.0)
54
+ rspec (3.13.1)
55
+ rspec-core (~> 3.13.0)
56
+ rspec-expectations (~> 3.13.0)
57
+ rspec-mocks (~> 3.13.0)
58
+ rspec-collection_matchers (1.2.1)
36
59
  rspec-expectations (>= 2.99.0.beta1)
37
- rspec-core (3.11.0)
38
- rspec-support (~> 3.11.0)
39
- rspec-expectations (3.11.0)
60
+ rspec-core (3.13.5)
61
+ rspec-support (~> 3.13.0)
62
+ rspec-expectations (3.13.5)
40
63
  diff-lcs (>= 1.2.0, < 2.0)
41
- rspec-support (~> 3.11.0)
42
- rspec-mocks (3.11.1)
64
+ rspec-support (~> 3.13.0)
65
+ rspec-mocks (3.13.5)
43
66
  diff-lcs (>= 1.2.0, < 2.0)
44
- rspec-support (~> 3.11.0)
45
- rspec-support (3.11.0)
46
- rubocop (1.29.1)
67
+ rspec-support (~> 3.13.0)
68
+ rspec-support (3.13.4)
69
+ rubocop (1.75.8)
70
+ json (~> 2.3)
71
+ language_server-protocol (~> 3.17.0.2)
72
+ lint_roller (~> 1.1.0)
47
73
  parallel (~> 1.10)
48
- parser (>= 3.1.0.0)
74
+ parser (>= 3.3.0.2)
49
75
  rainbow (>= 2.2.2, < 4.0)
50
- regexp_parser (>= 1.8, < 3.0)
51
- rexml (>= 3.2.5, < 4.0)
52
- rubocop-ast (>= 1.17.0, < 2.0)
76
+ regexp_parser (>= 2.9.3, < 3.0)
77
+ rubocop-ast (>= 1.44.0, < 2.0)
53
78
  ruby-progressbar (~> 1.7)
54
- unicode-display_width (>= 1.4.0, < 3.0)
55
- rubocop-ast (1.19.1)
56
- parser (>= 3.1.1.0)
57
- rubocop-performance (1.13.3)
58
- rubocop (>= 1.7.0, < 2.0)
59
- rubocop-ast (>= 0.4.0)
60
- ruby-progressbar (1.11.0)
61
- standard (1.12.1)
62
- rubocop (= 1.29.1)
63
- rubocop-performance (= 1.13.3)
64
- tzinfo (2.0.4)
79
+ unicode-display_width (>= 2.4.0, < 4.0)
80
+ rubocop-ast (1.46.0)
81
+ parser (>= 3.3.7.2)
82
+ prism (~> 1.4)
83
+ rubocop-performance (1.25.0)
84
+ lint_roller (~> 1.1)
85
+ rubocop (>= 1.75.0, < 2.0)
86
+ rubocop-ast (>= 1.38.0, < 2.0)
87
+ ruby-progressbar (1.13.0)
88
+ securerandom (0.4.1)
89
+ standard (1.50.0)
90
+ language_server-protocol (~> 3.17.0.2)
91
+ lint_roller (~> 1.0)
92
+ rubocop (~> 1.75.5)
93
+ standard-custom (~> 1.0.0)
94
+ standard-performance (~> 1.8)
95
+ standard-custom (1.0.2)
96
+ lint_roller (~> 1.0)
97
+ rubocop (~> 1.50)
98
+ standard-performance (1.8.0)
99
+ lint_roller (~> 1.1)
100
+ rubocop-performance (~> 1.25.0)
101
+ tzinfo (2.0.6)
65
102
  concurrent-ruby (~> 1.0)
66
- unicode-display_width (2.2.0)
103
+ unicode-display_width (3.1.4)
104
+ unicode-emoji (~> 4.0, >= 4.0.4)
105
+ unicode-emoji (4.0.4)
106
+ uri (1.0.3)
107
+ zeitwerk (2.7.3)
67
108
 
68
109
  PLATFORMS
69
110
  arm64-darwin-21
111
+ arm64-darwin-24
112
+ arm64-darwin-25
70
113
  x86_64-darwin-21
71
114
  x86_64-linux
72
115
 
data/README.md CHANGED
@@ -19,6 +19,10 @@ Options include
19
19
  * The number of items to delete (default: 10)
20
20
  * Whether to limit to autocorrectable cops (default: true)
21
21
  * Whether to automatically run `rubocop -a` after deletion
22
+ * A configuration file at `.rubomop.yml`
23
+ * A list of cops to only include for deletion
24
+ * A list of cops to exempt from deletion
25
+ * A list of files to exempt from change
22
26
 
23
27
  ## Installation
24
28
 
@@ -28,13 +32,6 @@ Add this line to your application's Gemfile:
28
32
  gem "rubomop"
29
33
  ```
30
34
 
31
- (Well, until I actually submit it, it's)
32
-
33
- ```
34
- gem "rubocop", github: "noelrappin/rubomop"
35
- ```
36
-
37
-
38
35
  And then execute:
39
36
 
40
37
  $ bundle install
@@ -49,15 +46,50 @@ Or install it yourself as:
49
46
  $ rubomop --help
50
47
  Usage: rubomop [options]
51
48
  -n, --number NUMBER Number of cleanups to perform (default: 10)
52
- -a, --autocorrect_only Only clean autocorrectable cops (default)
53
- --no_autocorrect_only Clean all cops (not default)
54
- -r, --run_rubocop Run rubocop -aD after (default)
55
- -f, --filename FILENAME Name of todo file (default: ./.rubocop_todo.yml)
56
- --no_run_rubocop Don't run rubocop -aD after (not default)
49
+ -a, --autocorrect-only Only clean autocorrectable cops (default)
50
+ --no_autocorrect-only Clean all cops (not default)
51
+ -r, --run-rubocop Run rubocop -aD after (default)
52
+ -f, --filename=FILENAME Name of todo file (default: ./.rubocop_todo.yml)
53
+ --no-run-rubocop Don't run rubocop -aD after (not default)
54
+ -c, --config=CONFIG_FILE Name of optional config file (default: .rubomop.yml)
55
+ --only=ONLY String or regex of cops to limit removal do, can have multiple
56
+ --except=EXCEPT String or regex of cops to limit removal do, can have multiple
57
+ --block=BLOCK String or regex of files to not touch, can have multiple
57
58
  -h, --help Prints this help
59
+
60
+ ```
61
+
62
+ The `--only` option allows you to limit cops to be selected from to only
63
+ those listed, the option can be a string and will match on substrings, and you
64
+ can have more than one.
65
+
66
+ The `--except` option allows you to specify a cop that should not be
67
+ selected, again, the option can be a string and will match on substrings, and you
68
+ can have more than one. If a cop is in both the `--except` and `--include`
69
+ lists for some reasone, the except list wins and it's excluded.
70
+
71
+ The `--block` option allows you to specify files that should not be selected
72
+ for any cops. The option can be a string and will match on substrings and you can
73
+ have more than one. If a cop/file combination is in both the `--include`
74
+ cops list and the file `--block` list, the block wins and the file is not
75
+ included.
76
+
77
+ You can also put options in a `rubomop.yml` file, or you can put it in a
78
+ different location with the `-c` option from the command line.
79
+
80
+ ```yaml
81
+ number: 10
82
+ autocorrect-only: true
83
+ only:
84
+ - Lint
85
+ block:
86
+ - oops
58
87
  ```
59
88
 
60
- ## Development
89
+ If an option is set via the config file and the command line, the command
90
+ line option wins. This is true even for the list options where you can have
91
+ more than one, the command line completly blocks the config file from being
92
+ used.
61
93
 
62
94
 
63
95
  ## Contributing
data/exe/rubomop CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "rubomop"
3
+ require_relative "../lib/rubomop"
4
4
 
5
5
  Rubomop::Runner.new.execute(ARGV)
data/lib/rubomop/cop.rb CHANGED
@@ -1,38 +1,41 @@
1
1
  module Rubomop
2
- class Cop
3
- attr_accessor :offense_count, :name, :files, :autocorrect, :comments
4
- attr_reader :raw_lines
2
+ class Cop < Literal::Object
3
+ prop :raw_lines, _Array(String), reader: :public, default: -> { [] }
4
+ prop :files, _Array(String), reader: :public, writer: :public, default: -> { [] }
5
+ prop :comments, _Array(String), reader: :public, writer: :public, default: -> { [] }
6
+ prop :config_params, _Array(String), reader: :public, writer: :public, default: -> { [] }
7
+ prop :autocorrect, _Nilable(Symbol), reader: :public, writer: :public, default: :none
8
+ prop :offense_count, Integer, reader: :public, writer: :public, default: 0
9
+ prop :name, String, reader: :public, writer: :public, default: -> { "" }
10
+ prop :active, _Boolean, reader: :public, writer: :public, default: true
5
11
 
6
12
  def self.create_and_parse(raw_lines)
7
- result = new(raw_lines)
13
+ result = new(raw_lines:)
8
14
  result.parse
9
15
  result
10
16
  end
11
17
 
12
- def initialize(raw_lines)
13
- @raw_lines = raw_lines
14
- @files = []
15
- @autocorrect = false
16
- @comments = []
17
- end
18
-
19
18
  def parse
20
19
  raw_lines.each { parse_one_line(_1) }
21
20
  end
22
21
 
23
22
  OFFENSE_COUNT_REGEX = /\A# Offense count: (\d*)/
24
- COP_NAME_REGEX = /\A(.*):/
23
+ COP_NAME_REGEX = /\A(\S.*):/
25
24
  FILE_NAME_REGEX = /- '(.*)'/
26
- AUTOCORRECT_REGEX = /\A# Cop supports --auto-correct./
25
+ SAFE_AUTOCORRECT_REGEX = /\A# This cop supports safe autocorrection/
26
+ UNSAFE_AUTOCORRECT_REGEX = /\A# This cop supports unsafe autocorrection/
27
27
  GENERAL_COMMENT_REGEX = /\A#/
28
28
  EXCLUDE_REGEX = /Exclude:/
29
+ CONFIG_PARAM_REGEX = /\A\s\s(.*)/
29
30
 
30
31
  def parse_one_line(line)
31
32
  case line
32
33
  when OFFENSE_COUNT_REGEX
33
34
  self.offense_count = line.match(OFFENSE_COUNT_REGEX)[1].to_i
34
- when AUTOCORRECT_REGEX
35
- self.autocorrect = true
35
+ when SAFE_AUTOCORRECT_REGEX
36
+ self.autocorrect = :safe
37
+ when UNSAFE_AUTOCORRECT_REGEX
38
+ self.autocorrect = :unsafe
36
39
  when GENERAL_COMMENT_REGEX
37
40
  comments << line.chomp
38
41
  when EXCLUDE_REGEX
@@ -41,6 +44,8 @@ module Rubomop
41
44
  self.name = line.match(COP_NAME_REGEX)[1]
42
45
  when FILE_NAME_REGEX
43
46
  files << line.match(FILE_NAME_REGEX)[1]
47
+ when CONFIG_PARAM_REGEX
48
+ config_params << line.match(CONFIG_PARAM_REGEX)[1]
44
49
  end
45
50
  end
46
51
 
@@ -50,20 +55,62 @@ module Rubomop
50
55
 
51
56
  def output_lines
52
57
  result = ["# Offense count: #{offense_count}"]
53
- result << "# Cop supports --auto-correct." if autocorrect
58
+ result << "# This cop supports safe autocorrection (--autocorrect)." if autocorrect == :safe
59
+ result << "# This cop supports unsafe autocorrection (--autocorrect-all)." if autocorrect == :unsafe
54
60
  result += comments
55
61
  result << "#{name}:"
56
- result << " Exclude:"
57
- result + files.map { " - '#{_1}'"}
62
+ result += config_params.map { " #{_1}" }
63
+ unless files.empty?
64
+ result << " Exclude:"
65
+ result += files.map { " - '#{_1}'" }
66
+ end
67
+ result
68
+ end
69
+
70
+ def any_autocorrect?
71
+ autocorrect != :none
72
+ end
73
+
74
+ def autocorrect_inquiry
75
+ autocorrect.to_s.inquiry
76
+ end
77
+
78
+ def autocorrect_verbiage
79
+ case autocorrect
80
+ when :safe then "safe autocorrect"
81
+ when :unsafe then "unsafe autocorrect"
82
+ else
83
+ "no autocorrect"
84
+ end
58
85
  end
59
86
 
60
- def delete_options
61
- files.map { {cop: self, file: _1} }
87
+ def autocorrect_option
88
+ case autocorrect
89
+ when :safe then "a"
90
+ when :unsafe then "A"
91
+ else
92
+ ""
93
+ end
62
94
  end
63
95
 
64
96
  def delete!(filename)
65
97
  files.delete(filename)
66
- self.offense_count -= 1
98
+ end
99
+
100
+ def subtract!(offense_count)
101
+ self.offense_count -= offense_count
102
+ end
103
+
104
+ def activate
105
+ self.active = true
106
+ end
107
+
108
+ def deactivate
109
+ self.active = false
110
+ end
111
+
112
+ def active?
113
+ active
67
114
  end
68
115
  end
69
116
  end
@@ -0,0 +1,12 @@
1
+ module Rubomop
2
+ class NamedMop < Literal::Object
3
+ prop :todo_file, TodoFile, reader: :public, writer: :public
4
+ prop :name, String, reader: :public, writer: :public
5
+ prop :verbose, _Boolean, reader: :public, writer: :public
6
+ prop :run_rubocop, _Boolean, reader: :public, writer: :public
7
+
8
+ def mop!
9
+ todo_file.cop_for(name).deactivate
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,97 @@
1
+ module Rubomop
2
+ class RandomMop < Literal::Object
3
+ prop :todo_file, TodoFile, reader: :public, writer: :public
4
+ prop :number, Integer, reader: :public, writer: :public
5
+ prop :autocorrect_only, _Boolean, reader: :public, writer: :public
6
+ prop :verbose, _Boolean, reader: :public, writer: :public
7
+ prop :run_rubocop, _Boolean, reader: :public, writer: :public
8
+ prop :only, _Array(String), reader: :public, writer: :public
9
+ prop :except, _Array(String), reader: :public, writer: :public
10
+ prop :blocklist, _Array(String), reader: :public, writer: :public
11
+
12
+ def cops
13
+ todo_file.cops
14
+ end
15
+
16
+ def accept?(delete_option)
17
+ return false if autocorrect_only && !delete_option.cop.any_autocorrect?
18
+ unless except.empty?
19
+ return except.none? { delete_option.cop.name.include?(_1) }
20
+ end
21
+ unless blocklist.empty?
22
+ return blocklist.none? { delete_option.file.include?(_1) }
23
+ end
24
+ unless only.empty?
25
+ return only.any? { delete_option.cop.name.include?(_1) }
26
+ end
27
+ true
28
+ # return true unless autocorrect_only
29
+ # cop.autocorrect
30
+ end
31
+
32
+ def delete_options
33
+ cops.flat_map { delete_options_for(_1) }
34
+ .select { accept?(_1) }
35
+ end
36
+
37
+ def delete_options_for(cop)
38
+ cop.files.map { DeleteOption.new(cop, _1, verbose, run_rubocop) }
39
+ end
40
+
41
+ def log(message)
42
+ return unless verbose
43
+ print message
44
+ end
45
+
46
+ def mop!
47
+ number.times do |i|
48
+ options = delete_options
49
+ next if options.empty?
50
+ log("#{i + 1}:")
51
+ mop_once!(options.sample)
52
+ log("\n")
53
+ end
54
+ end
55
+
56
+ def mop_once!(delete_option)
57
+ delete_option.print_message if verbose
58
+ delete_option.delete!
59
+ return unless run_rubocop
60
+ todo_file.save!
61
+ offense_count = delete_option.rubocop_runner || 0
62
+ delete_option.subtract!(offense_count)
63
+ end
64
+
65
+ DeleteOption = Struct.new(:cop, :file, :verbose, :run_rubocop) do
66
+ def print_message
67
+ return unless verbose
68
+ print "Deleting #{file} from #{cop.name}" if verbose
69
+ end
70
+
71
+ def delete!
72
+ cop.delete!(file)
73
+ end
74
+
75
+ def subtract!(offense_count)
76
+ cop.subtract!(offense_count)
77
+ end
78
+
79
+ def rubocop_runner
80
+ return unless run_rubocop
81
+ print "\nbundle exec rubocop #{file} -aD\n"
82
+ IO.popen("bundle exec rubocop #{file} -aD") do |io|
83
+ result_string = io.read
84
+ puts result_string.split("\n").last
85
+ puts "\n"
86
+ parse_io(result_string)
87
+ end
88
+ end
89
+
90
+ def parse_io(string)
91
+ match_data = string.match(/(\d*) offense(s?) corrected/)
92
+ return 0 if match_data.nil?
93
+ match_data[1].to_i
94
+ end
95
+ end
96
+ end
97
+ end
@@ -1,46 +1,113 @@
1
1
  module Rubomop
2
2
  class Runner
3
- attr_accessor :number, :autocorrect_only, :run_rubocop, :filename, :todo
3
+ attr_accessor :number, :autocorrect_only, :run_rubocop, :filename, :todo_file, :verbose, :config,
4
+ :options_from_command_line, :only, :except, :blocklist, :name, :directory
5
+
4
6
  NUM_STRING = "Number of cleanups to perform (default: 10)"
5
- AUTOCORRECT_STRING = "Only clean autocorrectable cops (default)"
7
+ NAME_STRING = "Name of cop to clean up. Choosing a name overrides choosing a number"
8
+ AUTOCORRECT_STRING = "Only clean auto-correctable cops (default)"
6
9
  NO_AUTOCORRECT_STRING = "Clean all cops (not default)"
7
10
  RUBOCOP_STRING = "Run rubocop -aD after (default)"
8
11
  NO_RUBOCOP_STRING = "Don't run rubocop -aD after (not default)"
9
12
  FILENAME_STRING = "Name of todo file (default: ./.rubocop_todo.yml)"
13
+ CONFIG_STRING = "Name of optional config file (default: .rubomop.yml)"
14
+ ONLY_STRING = "String or regex of cops to limit removal do, can have multiple"
15
+ EXCEPT_STRING = "String or regex of cops to not remove from, can have multiple"
16
+ BLOCK_STRING = "String or regex of files to not touch, can have multiple"
17
+ DIRECTORY_STRING = "Directory to work in (default: current directory)"
10
18
 
11
19
  def initialize
12
20
  @number = 10
13
21
  @autocorrect_only = true
14
22
  @run_rubocop = true
15
23
  @filename = ".rubocop_todo.yml"
16
- @todo = nil
24
+ @config = ".rubomop.yml"
25
+ @directory = "."
26
+ @todo_file = TodoFile.new(filename: full_path(@filename))
27
+ @verbose = true
28
+ @options_from_command_line = []
29
+ @only = []
30
+ @except = []
31
+ @blocklist = []
32
+ @name = nil
17
33
  end
18
34
 
19
35
  def execute(args)
20
- parse(args)
36
+ load_options(args)
21
37
  run
22
38
  end
23
39
 
40
+ def load_options(args)
41
+ parse(args)
42
+ load_from_file
43
+ # Recreate todo_file with the correct directory after options are loaded
44
+ @todo_file = TodoFile.new(filename: full_path(@filename))
45
+ end
46
+
47
+ def load_from_file
48
+ config_path = full_path(config)
49
+ return unless File.exist?(config_path)
50
+
51
+ file_options = YAML.safe_load_file(config_path)
52
+ file_options.each do |key, value|
53
+ next if options_from_command_line.include?(key)
54
+
55
+ send("#{key.underscore}=", value) if respond_to?("#{key.underscore}=")
56
+ end
57
+ rescue Psych::Exception
58
+ nil
59
+ end
60
+
24
61
  def parse(args)
25
62
  option_parser = OptionParser.new do |opts|
26
63
  opts.banner = "Usage: rubomop [options]"
27
64
  opts.on("-nNUMBER", "--number NUMBER", Integer, NUM_STRING) do |value|
28
65
  self.number = value
66
+ @options_from_command_line << "number"
29
67
  end
30
68
  opts.on("-a", "--autocorrect-only", AUTOCORRECT_STRING) do
31
69
  self.autocorrect_only = true
70
+ @options_from_command_line << "autocorrect-only"
32
71
  end
33
72
  opts.on("--no_autocorrect-only", NO_AUTOCORRECT_STRING) do
34
73
  self.autocorrect_only = false
74
+ @options_from_command_line << "autocorrect-only"
35
75
  end
36
76
  opts.on("-r", "--run-rubocop", RUBOCOP_STRING) do
37
77
  self.run_rubocop = true
78
+ @options_from_command_line << "run-rubocop"
38
79
  end
39
- opts.on("-fFILENAME", "--filename FILENAME", FILENAME_STRING) do |value|
80
+ opts.on("-fFILENAME", "--filename=FILENAME", FILENAME_STRING) do |value|
40
81
  self.filename = value
82
+ @options_from_command_line << "filename"
41
83
  end
42
84
  opts.on("--no-run-rubocop", NO_RUBOCOP_STRING) do
43
85
  self.run_rubocop = false
86
+ @options_from_command_line << "run-rubocop"
87
+ end
88
+ opts.on("-cCONFIG_FILE", "--config=CONFIG_FILE", CONFIG_STRING) do |value|
89
+ self.config = value
90
+ @options_from_command_line << "config"
91
+ end
92
+ opts.on("-dDIRECTORY", "--directory=DIRECTORY", "--dir=DIRECTORY", DIRECTORY_STRING) do |value|
93
+ self.directory = value
94
+ @options_from_command_line << "directory"
95
+ end
96
+ opts.on("--only=ONLY", ONLY_STRING) do |value|
97
+ only << value
98
+ @options_from_command_line << "only"
99
+ end
100
+ opts.on("--except=EXCEPT", ONLY_STRING) do |value|
101
+ except << value
102
+ @options_from_command_line << "except"
103
+ end
104
+ opts.on("--block=BLOCK", BLOCK_STRING) do |value|
105
+ blocklist << value
106
+ @options_from_command_line << "block"
107
+ end
108
+ opts.on("--name=NAME", NAME_STRING) do |value|
109
+ self.name = value
110
+ @options_from_command_line << "name"
44
111
  end
45
112
  opts.on("-h", "--help", "Prints this help") do
46
113
  puts opts
@@ -50,34 +117,48 @@ module Rubomop
50
117
  option_parser.parse(args)
51
118
  end
52
119
 
53
- def run
54
- self.todo = TodoFile.new(filename: filename)&.parse
55
- return if todo.nil?
56
- number.times do |i|
57
- delete_options = todo&.delete_options(autocorrect_only: autocorrect_only)
58
- next if delete_options.empty?
59
- object_to_delete = delete_options.sample
60
- print "#{i + 1}: Deleting #{object_to_delete[:file]} from #{object_to_delete[:cop].name}\n"
61
- todo&.delete!(object_to_delete)
120
+ def mop
121
+ if name
122
+ NamedMop.new(
123
+ todo_file:,
124
+ name:,
125
+ verbose:,
126
+ run_rubocop:
127
+ )
128
+ else
129
+ RandomMop.new(
130
+ todo_file:,
131
+ number:,
132
+ autocorrect_only:,
133
+ verbose:,
134
+ run_rubocop:,
135
+ only:,
136
+ except:,
137
+ blocklist:
138
+ )
62
139
  end
140
+ end
141
+
142
+ def run
143
+ self.todo_file = TodoFile.new(filename: full_path(filename))&.parse
144
+ return if todo_file.nil?
145
+
63
146
  backup_existing_file
64
- save_new_file
65
- rubocop_runner
147
+ mop.mop!
148
+ todo_file&.save!
66
149
  end
67
150
 
68
151
  def backup_existing_file
69
- FileUtils.rm("#{filename}.bak") if File.exist?("#{filename}.bak")
70
- FileUtils.mv(filename, "#{filename}.bak")
152
+ filename_path = full_path(filename)
153
+ backup_path = "#{filename_path}.bak"
154
+ FileUtils.rm(backup_path) if File.exist?(backup_path)
155
+ FileUtils.mv(filename_path, backup_path)
71
156
  end
72
157
 
73
- def save_new_file
74
- File.write(filename, todo&.output || "")
75
- end
158
+ private
76
159
 
77
- def rubocop_runner
78
- return unless run_rubocop
79
- print "Running bundle exec rubocop -aD"
80
- system("bundle exec rubocop -aD")
160
+ def full_path(file_path)
161
+ File.join(directory, file_path)
81
162
  end
82
163
  end
83
164
  end
@@ -14,10 +14,18 @@ module Rubomop
14
14
  self
15
15
  end
16
16
 
17
+ def cop_for(name)
18
+ cops.select { _1.name == name }.first
19
+ end
20
+
21
+ def active_cops
22
+ cops.select { _1.active? }
23
+ end
24
+
17
25
  def output_lines
18
26
  result = header.map(&:chomp)
19
27
  result << ""
20
- cops.each do |cop|
28
+ active_cops.each do |cop|
21
29
  result += cop.output_lines
22
30
  result << ""
23
31
  end
@@ -28,14 +36,9 @@ module Rubomop
28
36
  output_lines.join("\n") + "\n"
29
37
  end
30
38
 
31
- def delete_options(autocorrect_only: true)
32
- result = cops.flat_map(&:delete_options)
33
- result = result.select { _1[:cop].autocorrect } if autocorrect_only
34
- result
35
- end
36
-
37
- def delete!(delete_option)
38
- delete_option[:cop].delete!(delete_option[:file])
39
+ def save!
40
+ FileUtils.rm_f(filename)
41
+ File.write(filename, output || "")
39
42
  end
40
43
  end
41
44
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubomop
4
- VERSION = "0.1.0"
4
+ VERSION = "1.0.0"
5
5
  end
data/lib/rubomop.rb CHANGED
@@ -1,13 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/array"
4
+ require "active_support/core_ext/string/inflections"
5
+ require "active_support/core_ext/string/inquiry"
6
+ require "awesome_print"
3
7
  require "fileutils"
8
+ require "literal"
4
9
  require "optparse"
5
- require "awesome_print"
6
- require "active_support/core_ext/array"
7
- require_relative "rubomop/cop"
8
- require_relative "rubomop/runner"
9
- require_relative "rubomop/todo_file"
10
- require_relative "rubomop/version"
10
+ require "yaml"
11
+ require "zeitwerk"
12
+ loader = Zeitwerk::Loader.for_gem
13
+ loader.setup
11
14
 
12
15
  module Rubomop
13
16
  class Error < StandardError; end
metadata CHANGED
@@ -1,43 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubomop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Noel Rappin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-21 00:00:00.000000000 Z
11
+ date: 2025-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '7.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '7.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: date_by_example
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
- - - ">"
31
+ - - "~>"
18
32
  - !ruby/object:Gem::Version
19
33
  version: '0.1'
20
34
  type: :runtime
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
- - - ">"
38
+ - - "~>"
25
39
  - !ruby/object:Gem::Version
26
40
  version: '0.1'
27
41
  - !ruby/object:Gem::Dependency
28
- name: activesupport
42
+ name: literal
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: zeitwerk
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
- - - ">"
59
+ - - "~>"
32
60
  - !ruby/object:Gem::Version
33
- version: '5.0'
61
+ version: 2.7.0
34
62
  type: :runtime
35
63
  prerelease: false
36
64
  version_requirements: !ruby/object:Gem::Requirement
37
65
  requirements:
38
- - - ">"
66
+ - - "~>"
39
67
  - !ruby/object:Gem::Version
40
- version: '5.0'
68
+ version: 2.7.0
41
69
  description: Rubomop cleans up after your Rubocop
42
70
  email:
43
71
  - noel.rappin@chime.com
@@ -59,6 +87,8 @@ files:
59
87
  - exe/rubomop
60
88
  - lib/rubomop.rb
61
89
  - lib/rubomop/cop.rb
90
+ - lib/rubomop/named_mop.rb
91
+ - lib/rubomop/random_mop.rb
62
92
  - lib/rubomop/runner.rb
63
93
  - lib/rubomop/todo_file.rb
64
94
  - lib/rubomop/version.rb
@@ -79,14 +109,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
109
  requirements:
80
110
  - - ">="
81
111
  - !ruby/object:Gem::Version
82
- version: 2.7.0
112
+ version: 3.2.0
83
113
  required_rubygems_version: !ruby/object:Gem::Requirement
84
114
  requirements:
85
115
  - - ">="
86
116
  - !ruby/object:Gem::Version
87
117
  version: '0'
88
118
  requirements: []
89
- rubygems_version: 3.3.7
119
+ rubygems_version: 3.4.19
90
120
  signing_key:
91
121
  specification_version: 4
92
122
  summary: Rubomop cleans up after your Rubocop