no_comments 0.1.4 → 0.1.5

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: 8f4d0bbabf8d2083a22cb850026add69671c3af79b1d0cb75a0a891e5187aea4
4
- data.tar.gz: a8a312eea4658d6da9ac64007d9da4ea94efc642fc0381406e4fbc82b0b84726
3
+ metadata.gz: '0778f4eb4bbe1723231e1668730a87d462f154221fb7097fa35d21d5b34e832c'
4
+ data.tar.gz: f65eec62db3eab6acec0f44f4b02a2bc5983bf559aae3cec96855c4996d66a5e
5
5
  SHA512:
6
- metadata.gz: aa15e36876ee00b72f23b2043eb661a736df5de5876b14e5e587cb04c99e7af9858d8f030520efac7af0ff8939901571a12f67f72182f87e6e94ae9abc1eb779
7
- data.tar.gz: a3aa64ab64f4c7ba06da376b7fe16e027d363b8a22626b5b23e7a5c6d99051939dd23039751ac14ed3f27258abdcf7c5869516c5fdcfc772c0f81c67e1d23478
6
+ metadata.gz: 4d8805b6f04b9a1ac48c8992b274f29c5f5ca0574ebebe2ed28fa9b2abf92e2bc87063100ade5365b73fd8d0b185142b521683e3b84a48c863897a7d656c7b27
7
+ data.tar.gz: 9c1af8324d295c9bc1fc1174d4789004e001758ac3e198d8c1735c27ef64e317367158b0097301331a4bb591810567f4c8e33687b45dc6a956c52e99fff2d706
data/.rubocop.yml CHANGED
@@ -16,6 +16,10 @@ Metrics/BlockLength:
16
16
  Exclude:
17
17
  - 'spec/no_comments/**/*'
18
18
 
19
+ Metrics/ClassLength:
20
+ Max: 120
21
+
22
+
19
23
  Style/Documentation:
20
24
  Enabled: false
21
25
 
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 comments and inline comments, leaving your code clean and readable.
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 comments and inline comments from the file or directory.
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
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "optparse"
5
- require "no_comments"
5
+ require "no_comments/remover"
6
6
 
7
7
  options = {}
8
8
  OptionParser.new do |opts|
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NoComments
4
- VERSION = "0.1.4"
4
+ VERSION = "0.1.5"
5
5
  end
data/lib/no_comments.rb CHANGED
@@ -1,76 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "no_comments/version"
4
- require "ripper"
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
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: