no_comments 0.1.5 → 0.1.6

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: 71ade70ce6b697e2f4f4244766a9b7914c04b628eb9c87ba4f4273b8c4cbb846
4
+ data.tar.gz: 9ed3453c9e8c9fe097e6b5506ada7917adcd54e10ec7bfd0e2297508612eff12
5
5
  SHA512:
6
- metadata.gz: 4d8805b6f04b9a1ac48c8992b274f29c5f5ca0574ebebe2ed28fa9b2abf92e2bc87063100ade5365b73fd8d0b185142b521683e3b84a48c863897a7d656c7b27
7
- data.tar.gz: 9c1af8324d295c9bc1fc1174d4789004e001758ac3e198d8c1735c27ef64e317367158b0097301331a4bb591810567f4c8e33687b45dc6a956c52e99fff2d706
6
+ metadata.gz: 6768a1bafedf5cf9abb143c5a08cca1bd534122d888fde625ebb124fb1591b6f6fce9c8585463ab2f27692a322c85c1f119d454b4f4847c03428545174a8b0a9
7
+ data.tar.gz: c3f05e89997be0923516daf3599a080b222d19c1cbca23e5b52553e282fcdfe7246e7cbbc1e2b4fa543181765b23dc36f35ee307337c2d29fd9ca39b72e3a55f
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,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/no_comments/comment_detector.rb
4
+
5
+ module NoComments
6
+ module CommentDetector
7
+ MAGIC_COMMENT_REGEX = /\A#.*\b(?:frozen_string_literal|encoding|coding|warn_indent|fileencoding)\b.*\z/
8
+ TOOL_COMMENT_REGEX = /\A#\s*(?:rubocop|reek|simplecov|coveralls|pry|byebug|noinspection|sorbet|type)\b/
9
+
10
+ def magic_comment?(stripped_line)
11
+ stripped_line.match?(MAGIC_COMMENT_REGEX)
12
+ end
13
+
14
+ def tool_comment?(stripped_line)
15
+ stripped_line.match?(TOOL_COMMENT_REGEX)
16
+ end
17
+ end
18
+ end
@@ -1,9 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # lib/no_comments/content_processor.rb
4
+
3
5
  require "no_comments/version"
6
+ require "no_comments/comment_detector"
7
+ require "no_comments/line_parser"
4
8
 
5
9
  module NoComments
6
10
  class ContentProcessor
11
+ include CommentDetector
12
+ include LineParser
13
+
7
14
  def initialize
8
15
  @comments = []
9
16
  @result_lines = []
@@ -11,10 +18,13 @@ module NoComments
11
18
  @in_heredoc = false
12
19
  @heredoc_delimiter = nil
13
20
  @line_number = 0
21
+ @code_started = false
14
22
  end
15
23
 
16
24
  def process(content)
17
- content.each_line do |line|
25
+ lines = content.lines
26
+
27
+ lines.each do |line|
18
28
  @line_number += 1
19
29
  stripped_line = line.strip
20
30
  process_line(line, stripped_line)
@@ -30,11 +40,32 @@ module NoComments
30
40
  handle_multiline_comment(stripped_line)
31
41
  elsif @in_heredoc
32
42
  handle_heredoc(line, stripped_line)
43
+ elsif !@code_started
44
+ handle_initial_lines(line, stripped_line)
33
45
  else
34
46
  handle_regular_line(line, stripped_line)
35
47
  end
36
48
  end
37
49
 
50
+ def handle_initial_lines(line, stripped_line)
51
+ if stripped_line.empty? || stripped_line.start_with?("#!") || magic_comment?(stripped_line)
52
+ # Preserve blank lines, shebang lines, and magic comments
53
+ @result_lines << line.rstrip
54
+ elsif stripped_line.start_with?("#")
55
+ if tool_comment?(stripped_line)
56
+ # Preserve tool-specific comments
57
+ @result_lines << line.rstrip
58
+ else
59
+ # Regular comment at the top, remove it
60
+ @comments << [@line_number, stripped_line]
61
+ end
62
+ else
63
+ # First code line encountered
64
+ @code_started = true
65
+ handle_regular_line(line, stripped_line)
66
+ end
67
+ end
68
+
38
69
  def handle_multiline_comment(stripped_line)
39
70
  @comments << [@line_number, stripped_line]
40
71
  @in_multiline_comment = false if stripped_line == "=end"
@@ -42,7 +73,7 @@ module NoComments
42
73
 
43
74
  def handle_heredoc(line, stripped_line)
44
75
  @result_lines << line.rstrip
45
- @in_heredoc, @heredoc_delimiter = self.class.update_heredoc_state(
76
+ @in_heredoc, @heredoc_delimiter = update_heredoc_state(
46
77
  stripped_line, @heredoc_delimiter
47
78
  )
48
79
  end
@@ -50,8 +81,11 @@ module NoComments
50
81
  def handle_regular_line(line, stripped_line)
51
82
  if stripped_line == "=begin"
52
83
  start_multiline_comment(stripped_line)
53
- elsif (heredoc_start = self.class.detect_heredoc_start(line))
84
+ elsif (heredoc_start = detect_heredoc_start(line))
54
85
  start_heredoc(line, heredoc_start)
86
+ elsif stripped_line.start_with?("#") && tool_comment?(stripped_line)
87
+ # Preserve tool-specific comments anywhere in the code
88
+ @result_lines << line.rstrip
55
89
  else
56
90
  process_code_line(line)
57
91
  end
@@ -69,89 +103,16 @@ module NoComments
69
103
  end
70
104
 
71
105
  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]
106
+ code_part, comment_part = split_line(line)
107
+ if comment_part && tool_comment?(comment_part.strip)
108
+ # Preserve tool-specific inline comments
109
+ @result_lines << ("#{code_part.rstrip} #{comment_part.strip}")
139
110
  else
140
- [true, heredoc_delimiter]
141
- end
142
- end
111
+ @comments << [@line_number, comment_part.strip] if comment_part
112
+ return if code_part.strip.empty?
143
113
 
144
- def self.detect_heredoc_start(line)
145
- if (match = line.match(/<<[-~]?(["'`]?)(\w+)\1/))
146
- match[2]
114
+ @result_lines << code_part.rstrip
147
115
  end
148
116
  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
117
  end
157
118
  end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/no_comments/line_parser.rb
4
+
5
+ module NoComments
6
+ module LineParser
7
+ # rubocop:disable Metrics/MethodLength
8
+ # rubocop:disable Metrics/AbcSize
9
+ # rubocop:disable Metrics/CyclomaticComplexity
10
+ # rubocop:disable Metrics/PerceivedComplexity
11
+ # rubocop:disable Metrics/BlockNesting
12
+ #
13
+ def split_line(line)
14
+ in_single_quote = false
15
+ in_double_quote = false
16
+ in_regex = false
17
+ escape = false
18
+ index = 0
19
+
20
+ while index < line.length
21
+ char = line[index]
22
+
23
+ if escape
24
+ escape = false
25
+ else
26
+ case char
27
+ when "\\"
28
+ escape = true
29
+ when "'"
30
+ in_single_quote = !in_single_quote unless in_double_quote || in_regex
31
+ when '"'
32
+ in_double_quote = !in_double_quote unless in_single_quote || in_regex
33
+ when "/"
34
+ if in_regex
35
+ in_regex = false
36
+ elsif !in_single_quote && !in_double_quote &&
37
+ preceding_char_is_operator?(line, index)
38
+ in_regex = true
39
+ end
40
+ when "#"
41
+ result = handle_comment_character(line, index, in_single_quote, in_double_quote, in_regex)
42
+ return result if result
43
+ end
44
+ end
45
+ index += 1
46
+ end
47
+ [line, nil]
48
+ end
49
+ # rubocop:enable Metrics/MethodLength
50
+ # rubocop:enable Metrics/AbcSize
51
+ # rubocop:enable Metrics/CyclomaticComplexity
52
+ # rubocop:enable Metrics/PerceivedComplexity
53
+ # rubocop:enable Metrics/BlockNesting
54
+
55
+ def handle_comment_character(line, index, in_single_quote, in_double_quote, in_regex)
56
+ unless in_single_quote || in_double_quote || in_regex
57
+ code_part = line[0...index]
58
+ comment_part = line[index..]
59
+ return [code_part, comment_part]
60
+ end
61
+ nil
62
+ end
63
+
64
+ def update_heredoc_state(stripped_line, heredoc_delimiter)
65
+ if stripped_line == heredoc_delimiter
66
+ [false, nil]
67
+ else
68
+ [true, heredoc_delimiter]
69
+ end
70
+ end
71
+
72
+ def detect_heredoc_start(line)
73
+ if (match = line.match(/<<[-~]?(["'`]?)(\w+)\1/))
74
+ match[2]
75
+ end
76
+ end
77
+
78
+ def preceding_char_is_operator?(line, index)
79
+ idx = index - 1
80
+ idx -= 1 while idx >= 0 && line[idx] =~ /\s/
81
+
82
+ return true if idx.negative? # Beginning of line or after whitespace
83
+
84
+ # Handle special case where preceding character is part of a multi-character operator
85
+ return true if line[idx - 1..idx] == "::"
86
+
87
+ prev_char = line[idx]
88
+
89
+ # List of operator characters
90
+ operator_chars = %w[\[ = + - * / % | & ! < > ^ ~ ( , ? : ; {]
91
+
92
+ # Return true if preceding character is an operator
93
+ operator_chars.include?(prev_char)
94
+ end
95
+ end
96
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # lib/no_comments/remover.rb
4
+
3
5
  require "no_comments/version"
4
6
  require "no_comments/content_processor"
5
7
 
@@ -19,7 +21,8 @@ module NoComments
19
21
  validate_file_extension(file_path)
20
22
  content = File.read(file_path)
21
23
 
22
- cleaned_content, comments = process_content(content)
24
+ processor = ContentProcessor.new
25
+ cleaned_content, comments = processor.process(content)
23
26
 
24
27
  if audit
25
28
  print_audit(file_path, comments)
@@ -32,11 +35,6 @@ module NoComments
32
35
  raise "Only Ruby files are supported" unless file_path.end_with?(".rb")
33
36
  end
34
37
 
35
- def self.process_content(content)
36
- processor = NoComments::ContentProcessor.new
37
- processor.process(content)
38
- end
39
-
40
38
  def self.print_audit(file_path, comments)
41
39
  return if comments.empty?
42
40
 
@@ -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.6"
5
5
  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.6
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,7 +25,9 @@ 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