no_comments 0.1.4 → 0.1.5
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 +4 -4
- data/.rubocop.yml +4 -0
- data/README.md +2 -3
- data/exe/no_comments +1 -1
- data/lib/no_comments/content_processor.rb +157 -0
- data/lib/no_comments/remover.rb +49 -0
- data/lib/no_comments/version.rb +1 -1
- data/lib/no_comments.rb +2 -71
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0778f4eb4bbe1723231e1668730a87d462f154221fb7097fa35d21d5b34e832c'
|
4
|
+
data.tar.gz: f65eec62db3eab6acec0f44f4b02a2bc5983bf559aae3cec96855c4996d66a5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d8805b6f04b9a1ac48c8992b274f29c5f5ca0574ebebe2ed28fa9b2abf92e2bc87063100ade5365b73fd8d0b185142b521683e3b84a48c863897a7d656c7b27
|
7
|
+
data.tar.gz: 9c1af8324d295c9bc1fc1174d4789004e001758ac3e198d8c1735c27ef64e317367158b0097301331a4bb591810567f4c8e33687b45dc6a956c52e99fff2d706
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# no_comments
|
2
2
|
|
3
|
-
`no_comments` is a simple Ruby gem that removes comments from `.rb` files. It can handle single-line
|
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
4
|
|
5
5
|
---
|
6
6
|
|
@@ -35,7 +35,7 @@ gem install no_comments
|
|
35
35
|
|
36
36
|
|
37
37
|
## Usage
|
38
|
-
To clean up comments from a .rb file or directory, use the `NoComments::Remover.clean` method. This will remove all single-line
|
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.
|
39
39
|
|
40
40
|
```ruby
|
41
41
|
require 'no_comments'
|
@@ -115,7 +115,6 @@ The gem is available as open source under the terms of the MIT License.
|
|
115
115
|
|
116
116
|
|
117
117
|
## TODO
|
118
|
-
- Add support multi-line comments (`=begin`...`=end`)
|
119
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)!
|
120
119
|
- Option to keep documentation comments (e.g. `# @param`) https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/Documentation
|
121
120
|
- Option to clean all files in a directory except for a specified file
|
data/exe/no_comments
CHANGED
@@ -0,0 +1,157 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "no_comments/version"
|
4
|
+
|
5
|
+
module NoComments
|
6
|
+
class ContentProcessor
|
7
|
+
def initialize
|
8
|
+
@comments = []
|
9
|
+
@result_lines = []
|
10
|
+
@in_multiline_comment = false
|
11
|
+
@in_heredoc = false
|
12
|
+
@heredoc_delimiter = nil
|
13
|
+
@line_number = 0
|
14
|
+
end
|
15
|
+
|
16
|
+
def process(content)
|
17
|
+
content.each_line do |line|
|
18
|
+
@line_number += 1
|
19
|
+
stripped_line = line.strip
|
20
|
+
process_line(line, stripped_line)
|
21
|
+
end
|
22
|
+
|
23
|
+
cleaned_content = @result_lines.join("\n")
|
24
|
+
cleaned_content += "\n" unless cleaned_content.empty?
|
25
|
+
[cleaned_content, @comments]
|
26
|
+
end
|
27
|
+
|
28
|
+
def process_line(line, stripped_line)
|
29
|
+
if @in_multiline_comment
|
30
|
+
handle_multiline_comment(stripped_line)
|
31
|
+
elsif @in_heredoc
|
32
|
+
handle_heredoc(line, stripped_line)
|
33
|
+
else
|
34
|
+
handle_regular_line(line, stripped_line)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def handle_multiline_comment(stripped_line)
|
39
|
+
@comments << [@line_number, stripped_line]
|
40
|
+
@in_multiline_comment = false if stripped_line == "=end"
|
41
|
+
end
|
42
|
+
|
43
|
+
def handle_heredoc(line, stripped_line)
|
44
|
+
@result_lines << line.rstrip
|
45
|
+
@in_heredoc, @heredoc_delimiter = self.class.update_heredoc_state(
|
46
|
+
stripped_line, @heredoc_delimiter
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def handle_regular_line(line, stripped_line)
|
51
|
+
if stripped_line == "=begin"
|
52
|
+
start_multiline_comment(stripped_line)
|
53
|
+
elsif (heredoc_start = self.class.detect_heredoc_start(line))
|
54
|
+
start_heredoc(line, heredoc_start)
|
55
|
+
else
|
56
|
+
process_code_line(line)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def start_multiline_comment(stripped_line)
|
61
|
+
@in_multiline_comment = true
|
62
|
+
@comments << [@line_number, stripped_line]
|
63
|
+
end
|
64
|
+
|
65
|
+
def start_heredoc(line, heredoc_start)
|
66
|
+
@in_heredoc = true
|
67
|
+
@heredoc_delimiter = heredoc_start
|
68
|
+
@result_lines << line.rstrip
|
69
|
+
end
|
70
|
+
|
71
|
+
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]
|
139
|
+
else
|
140
|
+
[true, heredoc_delimiter]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.detect_heredoc_start(line)
|
145
|
+
if (match = line.match(/<<[-~]?(["'`]?)(\w+)\1/))
|
146
|
+
match[2]
|
147
|
+
end
|
148
|
+
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
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "no_comments/version"
|
4
|
+
require "no_comments/content_processor"
|
5
|
+
|
6
|
+
module NoComments
|
7
|
+
class Remover
|
8
|
+
def self.clean(file_path, audit: false)
|
9
|
+
if File.directory?(file_path)
|
10
|
+
Dir.glob("#{file_path}/**/*.rb").each do |file|
|
11
|
+
process_file(file, audit: audit)
|
12
|
+
end
|
13
|
+
else
|
14
|
+
process_file(file_path, audit: audit)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.process_file(file_path, audit: false)
|
19
|
+
validate_file_extension(file_path)
|
20
|
+
content = File.read(file_path)
|
21
|
+
|
22
|
+
cleaned_content, comments = process_content(content)
|
23
|
+
|
24
|
+
if audit
|
25
|
+
print_audit(file_path, comments)
|
26
|
+
else
|
27
|
+
File.write(file_path, cleaned_content)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.validate_file_extension(file_path)
|
32
|
+
raise "Only Ruby files are supported" unless file_path.end_with?(".rb")
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.process_content(content)
|
36
|
+
processor = NoComments::ContentProcessor.new
|
37
|
+
processor.process(content)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.print_audit(file_path, comments)
|
41
|
+
return if comments.empty?
|
42
|
+
|
43
|
+
puts "File: #{file_path}"
|
44
|
+
comments.each do |line_number, comment_text|
|
45
|
+
puts " Line #{line_number}: #{comment_text}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/no_comments/version.rb
CHANGED
data/lib/no_comments.rb
CHANGED
@@ -1,76 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "no_comments/
|
4
|
-
require "
|
3
|
+
require "no_comments/content_processor"
|
4
|
+
require "no_comments/remover"
|
5
5
|
|
6
6
|
module NoComments
|
7
|
-
class Remover
|
8
|
-
def self.clean(file_path, audit: false)
|
9
|
-
if File.directory?(file_path)
|
10
|
-
Dir.glob("#{file_path}/**/*.rb").each do |file|
|
11
|
-
process_file(file, audit: audit)
|
12
|
-
end
|
13
|
-
else
|
14
|
-
process_file(file_path, audit: audit)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.process_file(file_path, audit: false)
|
19
|
-
validate_file_extension(file_path)
|
20
|
-
file_content = File.read(file_path)
|
21
|
-
|
22
|
-
if audit
|
23
|
-
audit_comments(file_path, file_content)
|
24
|
-
else
|
25
|
-
content_cleaned = remove_comments(file_content)
|
26
|
-
File.write(file_path, content_cleaned)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.validate_file_extension(file_path)
|
31
|
-
raise "Only Ruby files are supported" unless file_path.end_with?(".rb")
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.audit_comments(file_path, content)
|
35
|
-
comments = extract_comments(content)
|
36
|
-
puts "File: #{file_path}" unless comments.empty?
|
37
|
-
|
38
|
-
comments.each do |(pos, _, tok, _)|
|
39
|
-
line, = pos
|
40
|
-
puts " Line #{line}: #{tok.strip}"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.remove_comments(content)
|
45
|
-
comments = extract_comments(content)
|
46
|
-
content = process_comments(content, comments)
|
47
|
-
remove_empty_lines(content)
|
48
|
-
end
|
49
|
-
|
50
|
-
def self.extract_comments(content)
|
51
|
-
Ripper.lex(content).select { |_pos, type, _tok, _| type == :on_comment }
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.process_comments(content, comments)
|
55
|
-
comments.sort_by { |(pos, _, _, _)| [pos[0], pos[1]] }.reverse.each do |(pos, _, _, _)|
|
56
|
-
line, col = pos
|
57
|
-
lines = content.lines
|
58
|
-
lines[line - 1] = process_comment_line(lines[line - 1], col)
|
59
|
-
content = lines.join
|
60
|
-
end
|
61
|
-
content
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.process_comment_line(line, col)
|
65
|
-
if line[col..].strip.start_with?("#")
|
66
|
-
"#{line[0...col].rstrip}\n"
|
67
|
-
else
|
68
|
-
"\n"
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def self.remove_empty_lines(content)
|
73
|
-
content.gsub(/^\s*$\n/, "")
|
74
|
-
end
|
75
|
-
end
|
76
7
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: no_comments
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justyna
|
@@ -25,6 +25,8 @@ files:
|
|
25
25
|
- Rakefile
|
26
26
|
- exe/no_comments
|
27
27
|
- lib/no_comments.rb
|
28
|
+
- lib/no_comments/content_processor.rb
|
29
|
+
- lib/no_comments/remover.rb
|
28
30
|
- lib/no_comments/version.rb
|
29
31
|
- sig/no_comments.rbs
|
30
32
|
homepage:
|