no_comments 0.1.5 → 0.1.7

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: '0778f4eb4bbe1723231e1668730a87d462f154221fb7097fa35d21d5b34e832c'
4
- data.tar.gz: f65eec62db3eab6acec0f44f4b02a2bc5983bf559aae3cec96855c4996d66a5e
3
+ metadata.gz: b0866e1f078f1e7465e0196ca4a71cac6956bb607452f7fec15f55ebf7e2f417
4
+ data.tar.gz: fbec43970d78b83199c3c5288e72fb300bb4382c82c98555c4e7089c4abddf88
5
5
  SHA512:
6
- metadata.gz: 4d8805b6f04b9a1ac48c8992b274f29c5f5ca0574ebebe2ed28fa9b2abf92e2bc87063100ade5365b73fd8d0b185142b521683e3b84a48c863897a7d656c7b27
7
- data.tar.gz: 9c1af8324d295c9bc1fc1174d4789004e001758ac3e198d8c1735c27ef64e317367158b0097301331a4bb591810567f4c8e33687b45dc6a956c52e99fff2d706
6
+ metadata.gz: 32de2f75bcaf62648b319e6bab3da0020115ce52454c63081f91e71a6670a0fa6c5f66e0da0043a1bd22fc68a547a2622c19ddb55feb95046ff06843b34c175e
7
+ data.tar.gz: 292f77329f185d695359a9d14e0b724118409a2bb44904488d761e7ff89eeaf9ef6f6286630fb6f0ff40f2b8d63089420c774d29a8b575585b72daa197994658
data/.rubocop.yml CHANGED
@@ -17,8 +17,10 @@ Metrics/BlockLength:
17
17
  - 'spec/no_comments/**/*'
18
18
 
19
19
  Metrics/ClassLength:
20
- Max: 120
20
+ Max: 150
21
21
 
22
+ Metrics/MethodLength:
23
+ Max: 20
22
24
 
23
25
  Style/Documentation:
24
26
  Enabled: false
data/README.md CHANGED
@@ -1,23 +1,52 @@
1
- # no_comments
1
+ # NoComments
2
+ NoComments is a Ruby gem designed to clean up `.rb` files by removing unnecessary comments, leaving your code clean and ready for deployment.
2
3
 
3
- `no_comments` is a simple Ruby gem that removes comments from `.rb` files. It can handle single-line, block and inline comments, leaving your code clean and readable.
4
+ ## What This Gem Does
5
+ It removes:
4
6
 
5
- ---
7
+ - Single-line comments (e.g., # This is a comment)
8
+ - Block comments (e.g., =begin ... =end)
9
+ - Inline comments (e.g., puts 'Hello' # This is a comment)
10
+
11
+ It preserves:
12
+
13
+ - Shebangs (e.g., #!/usr/bin/env ruby)
14
+ - Magic comments (e.g., # frozen_string_literal: true)
15
+ - Tool-defined comments (e.g., # rubocop:disable all)
6
16
 
7
17
  ## Table of Contents
18
+ 1. [When to Use This Gem](#When-to-Use-This-Gem)
19
+ 2. [When Not to Use This Gem](#When-Not-to-Use-This-Gem)
20
+ 3. [Installation](#Installation)
21
+ 4. [Usage](#Usage)
22
+ - [Audit Mode](#Audit-Mode)
23
+ - [CLI](#CLI)
24
+ 5. [Testing](#Testing)
25
+ 6. [Contributing](#Contributing)
26
+ 7. [License](#License)
27
+ 8. [TODO](#TODO)
8
28
 
9
- 1. [Installation](#installation)
10
- 2. [Usage](#usage)
11
- 3. [Testing](#testing)
12
- 4. [Contribution](#contribution)
13
- 5. [License](#license)
14
- 6. [TODO](#todo)
29
+ ## When to Use This Gem
15
30
 
16
- ---
31
+ NoComments is particularly useful in the following scenarios:
32
+
33
+ - **Auto-Generated or Boilerplate Code:** Helps clean up scaffolding or boilerplate comments, commonly generated in frameworks like Rails.
34
+ - **Codebases with Overused Comments:** Removes redundant comments that restate obvious code.
35
+ - **Continuous Integration/Code Review Workflows:** Automates comment cleanup during CI/CD processes.
36
+ - **Educational Projects:** Streamlines code by removing teaching-related comments after the learning phase.
37
+ - **Maintaining Open Source Projects:** Ensures consistency by removing unnecessary comments in contributions.
38
+
39
+ ## When Not to Use This Gem
40
+
41
+ While the gem is powerful, it may not be suitable in these scenarios:
42
+
43
+ - **Code with Valuable Documentation Comments:** Avoid using the gem if your code relies on comments for explaining complex logic or business rules.
44
+ - **Codebases Requiring Compliance:** In regulated industries, where specific comments are required for audits or documentation purposes.
45
+ - **Highly Dynamic Environments:** In fast-changing projects, comments might provide crucial context for recent changes or decisions.
17
46
 
18
47
  ## Installation
19
48
 
20
- To install `no_comments`, add it to your Gemfile:
49
+ To install no_comments, add it to your Gemfile:
21
50
 
22
51
  ```ruby
23
52
  gem 'no_comments'
@@ -27,94 +56,109 @@ Then execute:
27
56
  ```bash
28
57
  bundle install
29
58
  ```
30
- Or install it yourself using the following command:
59
+
60
+ Or install directly:
31
61
 
32
62
  ```bash
33
63
  gem install no_comments
34
64
  ```
35
65
 
36
-
37
66
  ## Usage
38
- To clean up comments from a .rb file or directory, use the `NoComments::Remover.clean` method. This will remove all single-line, block and inline comments from the file or directory.
67
+
68
+ ### Cleaning Files or Directories
69
+ To clean up comments from a `.rb` file or an entire directory, use the `NoComments::Remover.clean` method:
39
70
 
40
71
  ```ruby
41
72
  require 'no_comments'
42
73
 
74
+ # Clean a single file
43
75
  NoComments::Remover.clean('path/to/your_file.rb')
44
- NoComments::Remover.clean('path/to/your_directory')
45
76
 
77
+ # Clean all `.rb` files in a directory
78
+ NoComments::Remover.clean('path/to/your_directory')
46
79
  ```
47
80
  ### Audit Mode
48
-
49
- To use the audit mode, pass the `audit: true` flag to the `clean` method. This will output the file paths and lines containing comments without modifying the files.
50
-
51
- #### Example
81
+ Audit mode allows you to preview the comments that would be removed without modifying the files. Use the `audit: true` flag with the `clean` method:
52
82
 
53
83
  ```ruby
54
84
  NoComments::Remover.clean('example.rb', audit: true)
55
85
  ```
56
- #### Output
57
-
86
+ #### Example Output:
87
+ `example.rb`:
88
+ ```ruby
89
+ # This is a comment
90
+ def hello
91
+ puts 'Hello' # Another comment
92
+ end
93
+ ```
94
+ Output:
58
95
  ```bash
59
96
  File: example.rb
60
97
  Line 1: # This is a comment
61
98
  Line 3: # Another comment
62
99
  ```
63
100
 
64
- ### Command-Line Interface (CLI)
65
-
66
- You can use `no_comments` directly from the command line to clean or audit `.rb` files.
67
-
68
- #### Clean Comments
69
-
70
- To remove comments from a file, use:
101
+ ### CLI
102
+ `NoComments` provides a Command Line Interface (CLI) for easy comment cleanup. The CLI supports the following options:
71
103
 
104
+ #### Clean Comments:
72
105
  ```bash
73
106
  no_comments -p path/to/file.rb
74
107
  no_comments -p path/to/directory
75
108
  ```
76
- #### Audit mode
77
-
78
- To run `no_comments` in audit mode without modifying files, use the `--audit` flag:
79
-
109
+ #### Audit Mode:
80
110
  ```bash
81
111
  no_comments -p path/to/file.rb --audit
82
112
  no_comments -p path/to/directory --audit
83
113
  ```
84
114
 
85
115
  ## Testing
86
- `no_comments` uses RSpec for testing. To run the tests, first make sure all dependencies are installed:
87
116
 
117
+ This gem uses RSpec for testing. To run tests:
118
+
119
+ 1. Install dependencies:
88
120
  ```bash
89
121
  bundle install
90
122
  ```
91
- Then, run the tests with:
92
-
123
+ 2. Run the test suite::
93
124
  ```bash
94
125
  bundle exec rspec
95
126
  ```
96
- All tests are located in the spec directory and cover the main functionality of the gem, ensuring it properly removes comments from Ruby files.
97
127
 
98
- ## Contribution
128
+ Tests are located in the spec directory and ensure that the gem behaves as expected, removing comments appropriately while preserving essential ones.
99
129
 
100
- Bug reports and pull requests are welcome on GitHub at https://github.com/justi/no_comments.
130
+ ## Contributing
131
+ We welcome contributions! To contribute:
101
132
 
102
- To contribute:
103
-
104
- Fork the repository.
105
- Create a new branch (git checkout -b feature-branch).
106
- Make your changes.
107
- Commit your changes (git commit -m 'Add new feature').
108
- Push to the branch (git push origin feature-branch).
109
- Open a pull request.
133
+ 1. Fork the repository.
134
+ 2. Create a new branch for your feature or fix:
135
+ ```bash
136
+ git checkout -b feature-branch
137
+ ```
138
+ 3. Make your changes.
139
+ 4. Commit your changes with a descriptive message:
140
+ ```bash
141
+ git commit -m 'Add new feature'
142
+ ```
143
+ 5. Push your branch:
144
+ ```bash
145
+ git push origin feature-branch
146
+ ```
147
+ 6. Open a pull request on GitHub.
110
148
 
111
- Please ensure that your code follows the existing style and that all tests pass.
149
+ Please ensure your code follows the existing style and that all tests pass before submitting.
112
150
 
113
151
  ## License
114
- The gem is available as open source under the terms of the MIT License.
115
-
152
+ This gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
116
153
 
117
154
  ## TODO
118
- - Add support to magic comments (e.g. `# frozen_string_literal: true`) https://docs.ruby-lang.org/en/3.2/syntax/comments_rdoc.html - thanks [Chris](https://github.com/khasinski)!
119
- - Option to keep documentation comments (e.g. `# @param`) https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/Documentation
120
- - Option to clean all files in a directory except for a specified file
155
+ Planned features for future updates:
156
+ - **Option to Keep Documentation Comments:**
157
+ - Preserve comments like # @param or # @return for tools like YARD.
158
+ Reference: [RuboCop documentation cop](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/Documentation).
159
+ - **Selective Cleaning:**
160
+ - Allow users to clean all files in a directory except for specified ones.
161
+
162
+ ---
163
+ ## Why Use NoComments?
164
+ NoComments is the perfect tool for keeping your codebase clean and focused, whether you're starting fresh or maintaining an existing project. By automating comment cleanup, you can focus on what matters: writing great code.
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NoComments
4
+ module CommentDetector
5
+ MAGIC_COMMENT_REGEX = /\A#.*\b(?:frozen_string_literal|encoding|coding|warn_indent|fileencoding)\b.*\z/
6
+ TOOL_COMMENT_REGEX = /\A#\s*(?:rubocop|reek|simplecov|coveralls|pry|byebug|noinspection|sorbet|type)\b/
7
+ def magic_comment?(stripped_line)
8
+ stripped_line.match?(MAGIC_COMMENT_REGEX)
9
+ end
10
+
11
+ def tool_comment?(stripped_line)
12
+ stripped_line.match?(TOOL_COMMENT_REGEX)
13
+ end
14
+ end
15
+ end
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "no_comments/version"
4
-
4
+ require "no_comments/comment_detector"
5
+ require "no_comments/line_parser"
5
6
  module NoComments
6
7
  class ContentProcessor
8
+ include CommentDetector
9
+ include LineParser
7
10
  def initialize
8
11
  @comments = []
9
12
  @result_lines = []
@@ -11,15 +14,16 @@ module NoComments
11
14
  @in_heredoc = false
12
15
  @heredoc_delimiter = nil
13
16
  @line_number = 0
17
+ @code_started = false
14
18
  end
15
19
 
16
20
  def process(content)
17
- content.each_line do |line|
21
+ lines = content.lines
22
+ lines.each do |line|
18
23
  @line_number += 1
19
24
  stripped_line = line.strip
20
25
  process_line(line, stripped_line)
21
26
  end
22
-
23
27
  cleaned_content = @result_lines.join("\n")
24
28
  cleaned_content += "\n" unless cleaned_content.empty?
25
29
  [cleaned_content, @comments]
@@ -30,7 +34,24 @@ module NoComments
30
34
  handle_multiline_comment(stripped_line)
31
35
  elsif @in_heredoc
32
36
  handle_heredoc(line, stripped_line)
37
+ elsif !@code_started
38
+ handle_initial_lines(line, stripped_line)
39
+ else
40
+ handle_regular_line(line, stripped_line)
41
+ end
42
+ end
43
+
44
+ def handle_initial_lines(line, stripped_line)
45
+ if stripped_line.empty? || stripped_line.start_with?("#!") || magic_comment?(stripped_line)
46
+ @result_lines << line.rstrip
47
+ elsif stripped_line.start_with?("#")
48
+ if tool_comment?(stripped_line)
49
+ @result_lines << line.rstrip
50
+ else
51
+ @comments << [@line_number, stripped_line]
52
+ end
33
53
  else
54
+ @code_started = true
34
55
  handle_regular_line(line, stripped_line)
35
56
  end
36
57
  end
@@ -42,7 +63,7 @@ module NoComments
42
63
 
43
64
  def handle_heredoc(line, stripped_line)
44
65
  @result_lines << line.rstrip
45
- @in_heredoc, @heredoc_delimiter = self.class.update_heredoc_state(
66
+ @in_heredoc, @heredoc_delimiter = update_heredoc_state(
46
67
  stripped_line, @heredoc_delimiter
47
68
  )
48
69
  end
@@ -50,8 +71,10 @@ module NoComments
50
71
  def handle_regular_line(line, stripped_line)
51
72
  if stripped_line == "=begin"
52
73
  start_multiline_comment(stripped_line)
53
- elsif (heredoc_start = self.class.detect_heredoc_start(line))
74
+ elsif (heredoc_start = detect_heredoc_start(line))
54
75
  start_heredoc(line, heredoc_start)
76
+ elsif stripped_line.start_with?("#") && tool_comment?(stripped_line)
77
+ @result_lines << line.rstrip
55
78
  else
56
79
  process_code_line(line)
57
80
  end
@@ -69,89 +92,15 @@ module NoComments
69
92
  end
70
93
 
71
94
  def process_code_line(line)
72
- code_part, comment_part = self.class.split_line(line)
73
- @comments << [@line_number, comment_part.strip] if comment_part
74
- return if code_part.strip.empty?
75
-
76
- @result_lines << code_part.rstrip
77
- end
78
-
79
- # rubocop:disable Metrics/AbcSize
80
- # rubocop:disable Metrics/MethodLength
81
- # rubocop:disable Metrics/PerceivedComplexity
82
- # rubocop:disable Metrics/CyclomaticComplexity
83
- # rubocop:disable Metrics/BlockNesting
84
- def self.split_line(line)
85
- in_single_quote = false
86
- in_double_quote = false
87
- in_regex = false
88
- escape = false
89
- index = 0
90
-
91
- while index < line.length
92
- char = line[index]
93
-
94
- if escape
95
- escape = false
96
- else
97
- case char
98
- when "\\"
99
- escape = true
100
- when "'"
101
- in_single_quote = !in_single_quote unless in_double_quote || in_regex
102
- when '"'
103
- in_double_quote = !in_double_quote unless in_single_quote || in_regex
104
- when "/"
105
- if in_regex
106
- in_regex = false
107
- elsif !in_single_quote && !in_double_quote &&
108
- preceding_char_is_operator?(line, index)
109
- in_regex = true
110
- end
111
- when "#"
112
- result = handle_comment_character(line, index, in_single_quote, in_double_quote, in_regex)
113
- return result if result
114
- end
115
- end
116
- index += 1
117
- end
118
- [line, nil]
119
- end
120
-
121
- # rubocop:enable Metrics/AbcSize
122
- # rubocop:enable Metrics/MethodLength
123
- # rubocop:enable Metrics/PerceivedComplexity
124
- # rubocop:enable Metrics/CyclomaticComplexity
125
- # rubocop:enable Metrics/BlockNesting
126
-
127
- def self.handle_comment_character(line, index, in_single_quote, in_double_quote, in_regex)
128
- unless in_single_quote || in_double_quote || in_regex
129
- code_part = line[0...index]
130
- comment_part = line[index..]
131
- return [code_part, comment_part]
132
- end
133
- nil
134
- end
135
-
136
- def self.update_heredoc_state(stripped_line, heredoc_delimiter)
137
- if stripped_line == heredoc_delimiter
138
- [false, nil]
95
+ code_part, comment_part = split_line(line)
96
+ if comment_part && tool_comment?(comment_part.strip)
97
+ @result_lines << ("#{code_part.rstrip} #{comment_part.strip}")
139
98
  else
140
- [true, heredoc_delimiter]
141
- end
142
- end
99
+ @comments << [@line_number, comment_part.strip] if comment_part
100
+ return if code_part.strip.empty?
143
101
 
144
- def self.detect_heredoc_start(line)
145
- if (match = line.match(/<<[-~]?(["'`]?)(\w+)\1/))
146
- match[2]
102
+ @result_lines << code_part.rstrip
147
103
  end
148
104
  end
149
-
150
- def self.preceding_char_is_operator?(line, index)
151
- return true if index.zero?
152
-
153
- prev_char = line[index - 1]
154
- prev_char =~ %r{[\s(,=+\-*/%|&!<>?:]}
155
- end
156
105
  end
157
106
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NoComments
4
+ module LineParser
5
+ # rubocop:disable Metrics/MethodLength
6
+ # rubocop:disable Metrics/AbcSize
7
+ # rubocop:disable Metrics/CyclomaticComplexity
8
+ # rubocop:disable Metrics/PerceivedComplexity
9
+ # rubocop:disable Metrics/BlockNesting
10
+ def split_line(line)
11
+ in_single_quote = false
12
+ in_double_quote = false
13
+ in_regex = false
14
+ escape = false
15
+ index = 0
16
+ while index < line.length
17
+ char = line[index]
18
+ if escape
19
+ escape = false
20
+ else
21
+ case char
22
+ when "\\"
23
+ escape = true
24
+ when "'"
25
+ in_single_quote = !in_single_quote unless in_double_quote || in_regex
26
+ when '"'
27
+ in_double_quote = !in_double_quote unless in_single_quote || in_regex
28
+ when "/"
29
+ if in_regex
30
+ in_regex = false
31
+ elsif !in_single_quote && !in_double_quote &&
32
+ preceding_char_is_operator?(line, index)
33
+ in_regex = true
34
+ end
35
+ when "#"
36
+ result = handle_comment_character(line, index, in_single_quote, in_double_quote, in_regex)
37
+ return result if result
38
+ end
39
+ end
40
+ index += 1
41
+ end
42
+ [line, nil]
43
+ end
44
+
45
+ # rubocop:enable Metrics/MethodLength
46
+ # rubocop:enable Metrics/AbcSize
47
+ # rubocop:enable Metrics/CyclomaticComplexity
48
+ # rubocop:enable Metrics/PerceivedComplexity
49
+ # rubocop:enable Metrics/BlockNesting
50
+ def handle_comment_character(line, index, in_single_quote, in_double_quote, in_regex)
51
+ unless in_single_quote || in_double_quote || in_regex
52
+ code_part = line[0...index]
53
+ comment_part = line[index..]
54
+ return [code_part, comment_part]
55
+ end
56
+ nil
57
+ end
58
+
59
+ def update_heredoc_state(stripped_line, heredoc_delimiter)
60
+ if stripped_line == heredoc_delimiter
61
+ [false, nil]
62
+ else
63
+ [true, heredoc_delimiter]
64
+ end
65
+ end
66
+
67
+ def detect_heredoc_start(line)
68
+ if (match = line.match(/<<[-~]?(["'`]?)(\w+)\1/))
69
+ match[2]
70
+ end
71
+ end
72
+
73
+ def preceding_char_is_operator?(line, index)
74
+ idx = index - 1
75
+ idx -= 1 while idx >= 0 && line[idx] =~ /\s/
76
+ return true if idx.negative?
77
+ return true if line[idx - 1..idx] == "::"
78
+
79
+ prev_char = line[idx]
80
+ operator_chars = %w[\[ = + - * / % | & ! < > ^ ~ ( , ? : ; {]
81
+ operator_chars.include?(prev_char)
82
+ end
83
+ end
84
+ end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "no_comments/version"
4
4
  require "no_comments/content_processor"
5
-
6
5
  module NoComments
7
6
  class Remover
8
7
  def self.clean(file_path, audit: false)
@@ -18,9 +17,8 @@ module NoComments
18
17
  def self.process_file(file_path, audit: false)
19
18
  validate_file_extension(file_path)
20
19
  content = File.read(file_path)
21
-
22
- cleaned_content, comments = process_content(content)
23
-
20
+ processor = ContentProcessor.new
21
+ cleaned_content, comments = processor.process(content)
24
22
  if audit
25
23
  print_audit(file_path, comments)
26
24
  else
@@ -32,11 +30,6 @@ module NoComments
32
30
  raise "Only Ruby files are supported" unless file_path.end_with?(".rb")
33
31
  end
34
32
 
35
- def self.process_content(content)
36
- processor = NoComments::ContentProcessor.new
37
- processor.process(content)
38
- end
39
-
40
33
  def self.print_audit(file_path, comments)
41
34
  return if comments.empty?
42
35
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NoComments
4
- VERSION = "0.1.5"
4
+ VERSION = "0.1.7"
5
5
  end
data/lib/no_comments.rb CHANGED
@@ -2,6 +2,5 @@
2
2
 
3
3
  require "no_comments/content_processor"
4
4
  require "no_comments/remover"
5
-
6
5
  module NoComments
7
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: no_comments
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justyna
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-16 00:00:00.000000000 Z
11
+ date: 2024-11-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -25,11 +25,13 @@ files:
25
25
  - Rakefile
26
26
  - exe/no_comments
27
27
  - lib/no_comments.rb
28
+ - lib/no_comments/comment_detector.rb
28
29
  - lib/no_comments/content_processor.rb
30
+ - lib/no_comments/line_parser.rb
29
31
  - lib/no_comments/remover.rb
30
32
  - lib/no_comments/version.rb
31
33
  - sig/no_comments.rbs
32
- homepage:
34
+ homepage: https://github.com/justi/no_comments
33
35
  licenses:
34
36
  - MIT
35
37
  metadata:
@@ -52,5 +54,6 @@ requirements: []
52
54
  rubygems_version: 3.4.19
53
55
  signing_key:
54
56
  specification_version: 4
55
- summary: Remove comments from Ruby files
57
+ summary: NoComments is a Ruby gem designed to clean up .rb files by removing unnecessary
58
+ comments, leaving your code clean and ready for deployment.
56
59
  test_files: []