comment_strip-ruby 0.2.0 → 0.2.1

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.
@@ -1,14 +1,15 @@
1
+ # frozen_string_literal: true
1
2
  # ######################################################################## #
2
3
  # File: comment_strip/language_families/c.rb
3
4
  #
4
5
  # Purpose: Definition of strip() function for C-family languages.
5
6
  #
6
7
  # Created: 14th September 2020
7
- # Updated: 31st March 2024
8
+ # Updated: 30th August 2026
8
9
  #
9
- # Home: http://github.com/synesissoftware/comment_strip.r
10
+ # Home: https://github.com/synesissoftware/comment_strip.r
10
11
  #
11
- # Copyright (c) 2020-2024, Matthew Wilson and Synesis Information Systems
12
+ # Copyright (c) 2020-2026, Matthew Wilson and Synesis Information Systems
12
13
  # All rights reserved.
13
14
  #
14
15
  # Redistribution and use in source and binary forms, with or without
@@ -47,6 +48,23 @@ module LanguageFamilies
47
48
 
48
49
  module C
49
50
 
51
+ def self.decimal_digit? character
52
+
53
+ character && character >= ?0 && character <= ?9
54
+ end
55
+
56
+ def self.identifier_character? character
57
+
58
+ return false unless character
59
+
60
+ case character
61
+ when ?a..?z, ?A..?Z, ?0..?9, '_'
62
+ true
63
+ else
64
+ false
65
+ end
66
+ end
67
+
50
68
  def self.strip input, lf, **options
51
69
 
52
70
  return input if input.nil?
@@ -57,29 +75,63 @@ module C
57
75
 
58
76
  # States:
59
77
  #
60
- # - :c_comment - in a C comment, i.e. from immediately after "/*"
61
- # - :c_comment_star - in a C comment when just received '*', e.g. from immediately after "/* comment *"
62
- # - :cpp_comment - in a C++ comment, i.e. from immediately after "//"
63
- # - :dq_string - within a double-quoted string
64
- # - :dq_string_escape - within a double-quoted string when just received a '"', e.g. from immediately after '"the next word is quoted \'
65
- # - :slash_start - having found a slash (not in a string)
66
- # - :sq_string_closing - waiting for final '\'' in a single-quoted string
67
- # - :sq_string_escape - within a escaped single-quoted string, i.e. from immediately after "'\"
68
- # - :sq_string_open - within a single-quoted string, i.e. from immediately after "'"
69
- # - :text - regular part of the code
78
+ # - :c_comment - in a C comment, i.e. from immediately after "/*"
79
+ # - :c_comment_star - in a C comment when just received '*', e.g. from immediately after "/* comment *"
80
+ # - :cpp_comment - in a C++ comment, i.e. from immediately after "//"
81
+ # - :dq_string - within a double-quoted string
82
+ # - :dq_string_escape - within a double-quoted string when just received a '"', e.g. from immediately after '"the next word is quoted \'
83
+ # - :raw_string - within a C++ raw string
84
+ # - :raw_string_closing - waiting for the final '"' in a C++ raw string
85
+ # - :backtick_string - within a Go raw string
86
+ # - :backtick_string_open - waiting for the opening '`' in a Go raw string
87
+ # - :lifetime - within a Rust lifetime name
88
+ # - :verbatim_string - within a C# verbatim string
89
+ # - :verbatim_string_open - waiting for the opening '"' in a C# verbatim string
90
+ # - :verbatim_string_quote - waiting to determine whether a C# quote is doubled
91
+ # - :slash_start - having found a slash (not in a string)
92
+ # - :sq_string_closing - waiting for final '\'' in a single-quoted string
93
+ # - :sq_string_escape - within a escaped single-quoted string, i.e. from immediately after "'\"
94
+ # - :sq_string_open - within a single-quoted string, i.e. from immediately after "'"
95
+ # - :text - regular part of the code
70
96
 
71
97
  state = :text
72
98
 
73
- r = ''
99
+ r = String.new
100
+ r.force_encoding input.encoding
74
101
 
75
102
  cc_lines = 0
103
+ previous_was_cr = false
104
+
105
+ i = 0
106
+ while i < input.length
107
+ c = input[i]
108
+
109
+ if ?\\ == c
110
+ next_c = input[i + 1]
111
+
112
+ if ?\n == next_c
113
+ i += 2
114
+ previous_was_cr = false
115
+ next
116
+ elsif ?\r == next_c
117
+ i += 2
118
+ previous_was_cr = false
119
+
120
+ if ?\n == input[i]
121
+ i += 1
122
+ next
123
+ end
76
124
 
77
- input.each_char do |c|
125
+ next if i >= input.length
126
+
127
+ c = input[i]
128
+ end
129
+ end
78
130
 
79
131
  case c
80
132
  when ?\r, ?\n
81
133
 
82
- line += 1
134
+ line += 1 unless ?\n == c && previous_was_cr
83
135
  column = 0
84
136
  else
85
137
 
@@ -88,13 +140,23 @@ module C
88
140
 
89
141
  skip = false
90
142
 
143
+ if :text == state && 'R' == c && '"' == input[i + 1] && '(' == input[i + 2]
144
+ state = :raw_string
145
+ elsif :text == state && '@' == c && '"' == input[i + 1]
146
+ state = :verbatim_string_open
147
+ elsif :text == state && i > 0 && '<' == input[i - 1] && input[i + 1] && input[i + 1] >= ?a && input[i + 1] <= ?z
148
+ state = :lifetime
149
+ elsif :text == state && '`' == c
150
+ state = :backtick_string_open
151
+ end
152
+
91
153
  case c
92
154
  when ?\r, ?\n
93
155
 
94
156
  case state
95
157
  when :c_comment, :c_comment_star
96
158
 
97
- cc_lines += 1
159
+ cc_lines += 1 unless ?\n == c && previous_was_cr
98
160
 
99
161
  state = :c_comment
100
162
  when :cpp_comment
@@ -121,6 +183,37 @@ module C
121
183
  # - for comment-star
122
184
 
123
185
  case state
186
+ when :backtick_string_open
187
+
188
+ state = :backtick_string if '`' == c
189
+ when :backtick_string
190
+
191
+ state = :text if '`' == c
192
+ when :lifetime
193
+
194
+ if !identifier_character?(c)
195
+ state = :text
196
+ elsif !identifier_character?(input[i + 1])
197
+ state = :text
198
+ end
199
+ when :verbatim_string_open
200
+
201
+ state = :verbatim_string if '"' == c
202
+ when :verbatim_string
203
+
204
+ if '"' == c
205
+ state = :verbatim_string_quote if '"' == input[i + 1]
206
+ state = :text unless '"' == input[i + 1]
207
+ end
208
+ when :verbatim_string_quote
209
+
210
+ state = :verbatim_string if '"' == c
211
+ when :raw_string
212
+
213
+ state = :raw_string_closing if ')' == c && '"' == input[i + 1]
214
+ when :raw_string_closing
215
+
216
+ state = :text if '"' == c
124
217
  when :sq_string_open
125
218
 
126
219
  state = (?\\ == c) ? :sq_string_escape : :sq_string_closing
@@ -195,7 +288,11 @@ module C
195
288
  case state
196
289
  when :text
197
290
 
198
- state = :sq_string_open
291
+ if i > 0 && decimal_digit?(input[i - 1]) && decimal_digit?(input[i + 1])
292
+ ;
293
+ else
294
+ state = :sq_string_open
295
+ end
199
296
  when :sq_string_closing
200
297
 
201
298
  state = :text
@@ -259,8 +356,14 @@ module C
259
356
 
260
357
  r << c unless skip
261
358
  end
359
+
360
+ previous_was_cr = ?\r == c
361
+ i += 1
262
362
  end
263
363
 
364
+ r << '/' if :slash_start == state
365
+ r << ?\n * cc_lines if [ :c_comment, :c_comment_star, ].include?(state)
366
+
264
367
  r
265
368
  end
266
369
  end # module C
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # ######################################################################## #
2
3
  # File: comment_strip/language_families/hash_line.rb
3
4
  #
@@ -5,11 +6,11 @@
5
6
  # line comments beginning at the # character.
6
7
  #
7
8
  # Created: 1st December 2023
8
- # Updated: 31st March 2024
9
+ # Updated: 30th August 2026
9
10
  #
10
- # Home: http://github.com/synesissoftware/comment_strip.r
11
+ # Home: https://github.com/synesissoftware/comment_strip.r
11
12
  #
12
- # Copyright (c) 2023-2024, Matthew Wilson and Synesis Information Systems
13
+ # Copyright (c) 2023-2026, Matthew Wilson and Synesis Information Systems
13
14
  # All rights reserved.
14
15
  #
15
16
  # Redistribution and use in source and binary forms, with or without
@@ -48,6 +49,18 @@ module LanguageFamilies
48
49
 
49
50
  module HashLine
50
51
 
52
+ def self.identifier_character? character
53
+
54
+ return false unless character
55
+
56
+ case character
57
+ when ?a..?z, ?A..?Z, ?0..?9, '_'
58
+ true
59
+ else
60
+ false
61
+ end
62
+ end
63
+
51
64
  def self.strip input, lf, **options
52
65
 
53
66
  return input if input.nil?
@@ -58,21 +71,66 @@ module HashLine
58
71
 
59
72
  # States:
60
73
  #
61
- # - :dq_string - within a double-quoted string
62
- # - :dq_string_escape - within a double-quoted string when just received a '"', e.g. from immediately after '"the next word is quoted \'
63
- # - :hash_comment - in a #-comment, i.e. from immediately after "#"
64
- # - :sq_string_closing - waiting for final '\'' in a single-quoted string
65
- # - :sq_string_escape - within a escaped single-quoted string, i.e. from immediately after "'\"
66
- # - :sq_string_open - within a single-quoted string, i.e. from immediately after "'"
67
- # - :text - regular part of the code
74
+ # - :dq_string - within a double-quoted string
75
+ # - :dq_string_escape - within a double-quoted string when just received a '"', e.g. from immediately after '"the next word is quoted \'
76
+ # - :hash_comment - in a #-comment, i.e. from immediately after "#"
77
+ # - :heredoc_body - within a Ruby heredoc body
78
+ # - :heredoc_header - within a Ruby heredoc header
79
+ # - :percent_string - within a Ruby percent string
80
+ # - :percent_string_open - waiting for the opening delimiter of a Ruby percent string
81
+ # - :sq_string_closing - waiting for final '\'' in a single-quoted string
82
+ # - :sq_string_escape - within a escaped single-quoted string, i.e. from immediately after "'\"
83
+ # - :sq_string_open - within a single-quoted string, i.e. from immediately after "'"
84
+ # - :text - regular part of the code
68
85
 
69
86
  state = :text
70
87
 
71
- r = ''
88
+ r = String.new
89
+ r.force_encoding input.encoding
90
+
91
+ percent_open = nil
92
+ percent_closing = nil
93
+ heredoc_terminator = nil
94
+ at_line_start = true
95
+
96
+ i = 0
97
+ while i < input.length
98
+ c = input[i]
99
+ percent_start = false
100
+
101
+ if :text == state && '%' == c
102
+ percent_type = input[i + 1]
103
+ percent_delimiter = input[i + 2]
104
+
105
+ if [ 'q', 'w', ].include?(percent_type) && percent_delimiter
106
+ percent_open = percent_delimiter
107
+ percent_closing = case percent_delimiter
108
+ when '{' then '}'
109
+ when '[' then ']'
110
+ when '(' then ')'
111
+ else percent_open
112
+ end
113
+ percent_start = true
114
+ end
115
+ end
72
116
 
73
- cc_lines = 0
117
+ if :text == state && '<' == c && '<' == input[i + 1]
118
+ heredoc_offset = i + 2
119
+ heredoc_offset += 1 if '~' == input[heredoc_offset]
120
+ heredoc_quote = input[heredoc_offset]
121
+ heredoc_quote = nil unless [ '\'', '"', ].include?(heredoc_quote)
122
+ heredoc_offset += 1 if [ '\'', '"', ].include?(heredoc_quote)
123
+ heredoc_start = heredoc_offset
74
124
 
75
- input.each_char do |c|
125
+ while heredoc_offset < input.length && identifier_character?(input[heredoc_offset])
126
+ heredoc_offset += 1
127
+ end
128
+
129
+ if heredoc_start < heredoc_offset && (!heredoc_quote || heredoc_quote == input[heredoc_offset])
130
+ heredoc_terminator = input[heredoc_start...heredoc_offset]
131
+ state = :heredoc_header
132
+ end
133
+ end
76
134
 
77
135
  case c
78
136
  when ?\r, ?\n
@@ -99,9 +157,9 @@ module HashLine
99
157
  when :dq_string_escape
100
158
 
101
159
  state = :dq_string
102
- when :hash_comment
160
+ when :heredoc_header
103
161
 
104
- state = :text
162
+ state = :heredoc_body
105
163
  end
106
164
  else
107
165
 
@@ -111,12 +169,39 @@ module HashLine
111
169
  # - for slash-start
112
170
 
113
171
  case state
172
+ when :heredoc_body
173
+
174
+ if at_line_start
175
+ heredoc_match = true
176
+ heredoc_index = 0
177
+
178
+ while heredoc_index < heredoc_terminator.length
179
+ heredoc_match = false unless input[i + heredoc_index] ==
180
+ heredoc_terminator[heredoc_index]
181
+ heredoc_index += 1
182
+ end
183
+
184
+ if heredoc_match && [ nil, ?\r, ?\n, ].include?(input[i + heredoc_terminator.length])
185
+ state = :text
186
+ end
187
+ end
188
+ when :percent_string_open
189
+
190
+ state = :percent_string if c == percent_open
191
+ when :percent_string
192
+
193
+ state = :text if c == percent_closing
114
194
  when :sq_string_open
115
195
 
116
- state = (?\\ == c) ? :sq_string_escape : :sq_string_closing
196
+ case c
197
+ when ?\\
198
+ state = :sq_string_escape
199
+ when ?\'
200
+ state = :text
201
+ end
117
202
  when :sq_string_escape
118
203
 
119
- state = :sq_string_closing
204
+ state = :sq_string_open
120
205
  when :dq_string_escape
121
206
 
122
207
  state = :dq_string
@@ -139,9 +224,6 @@ module HashLine
139
224
  when :text
140
225
 
141
226
  state = :sq_string_open
142
- when :sq_string_closing
143
-
144
- state = :text
145
227
  else
146
228
 
147
229
  ;
@@ -198,6 +280,10 @@ module HashLine
198
280
 
199
281
  r << c unless skip
200
282
  end
283
+
284
+ state = :percent_string_open if percent_start
285
+ at_line_start = ?\r == c || ?\n == c
286
+ i += 1
201
287
  end
202
288
 
203
289
  r
@@ -1,14 +1,15 @@
1
+ # frozen_string_literal: true
1
2
  # ######################################################################## #
2
3
  # File: comment_strip/strip.rb
3
4
  #
4
5
  # Purpose: Definition of strip() function
5
6
  #
6
7
  # Created: 14th September 2020
7
- # Updated: 30th March 2024
8
+ # Updated: 19th August 2026
8
9
  #
9
- # Home: http://github.com/synesissoftware/comment_strip.r
10
+ # Home: https://github.com/synesissoftware/comment_strip.r
10
11
  #
11
- # Copyright (c) 2020-2024, Matthew Wilson and Synesis Information Systems
12
+ # Copyright (c) 2020-2026, Matthew Wilson and Synesis Information Systems
12
13
  # All rights reserved.
13
14
  #
14
15
  # Redistribution and use in source and binary forms, with or without
@@ -57,22 +58,25 @@ module CommentStrip
57
58
  include ::Xqsr3::Quality::ParameterChecking
58
59
 
59
60
  # Strips comments from an input string, according to the rules and
60
- # conventions of a given language-family
61
+ # conventions of a given language-family.
61
62
  #
62
63
  # === Signature
63
64
  #
64
65
  # * *Parameters:*
65
- # - +input+ (+String+, +nil+) the input source code
66
- # - +lf+ (+String+) the name of the language family, which must be one of the following:
67
- # - +'C'+
68
- # - +'Hash_Line'+
69
- # - +options+ (+Hash+) options that moderate the behaviour
66
+ # - +input+ (+String+, +nil+) the input source code;
67
+ # - +lf+ (+String+) the name of the language family, which must be one of the following listed in the section below;
68
+ # - +options+ (+Hash+) options that moderate the behaviour;
70
69
  #
71
70
  # * *Options:*
72
71
  # None currently defined.
73
72
  #
74
- # === Signature
73
+ # === Return
75
74
  # (+String+) The stripped for of the input.
75
+ #
76
+ # === Supported language families
77
+ # Currently supported language families:
78
+ # - +'C'+ - including C, C++, C#, Go, Java, Rust;
79
+ # - +'Hash_Line'+ - include Ruby, Python, Ruby, shell;
76
80
  def strip input, lf, **options
77
81
 
78
82
  check_parameter input, 'input', responds_to: [ :each_char, :empty?, :nil?, ], nil: true
@@ -87,7 +91,7 @@ module CommentStrip
87
91
  LanguageFamilies::HashLine.strip input, lf, **options
88
92
  else
89
93
 
90
- raise "language family '#{lf}' unrecognised or not supported1"
94
+ raise "language family '#{lf}' unrecognised or not supported"
91
95
  end
92
96
  end
93
97
 
@@ -1,14 +1,15 @@
1
+ # frozen_string_literal: true
1
2
  # ######################################################################## #
2
3
  # File: comment_strip/version.rb
3
4
  #
4
5
  # Purpose: Version for comment_strip.r library
5
6
  #
6
7
  # Created: 14th September 2020
7
- # Updated: 30th March 2024
8
+ # Updated: 30th August 2026
8
9
  #
9
- # Home: http://github.com/synesissoftware/comment_strip.r
10
+ # Home: https://github.com/synesissoftware/comment_strip.r
10
11
  #
11
- # Copyright (c) 2020-2024, Matthew Wilson and Synesis Information Systems
12
+ # Copyright (c) 2020-2026, Matthew Wilson and Synesis Information Systems
12
13
  # All rights reserved.
13
14
  #
14
15
  # Redistribution and use in source and binary forms, with or without
@@ -43,7 +44,7 @@
43
44
  module CommentStrip
44
45
 
45
46
  # Current version of the comment_strip.r library
46
- VERSION = '0.2.0'
47
+ VERSION = '0.2.1'
47
48
 
48
49
  private
49
50
  VERSION_PARTS_ = VERSION.split(/[.]/).collect { |n| n.to_i } # :nodoc:
data/lib/comment_strip.rb CHANGED
@@ -1,14 +1,15 @@
1
+ # frozen_string_literal: true
1
2
  # ######################################################################## #
2
- # File: comment_strip.rb
3
+ # File: comment_strip.rb
3
4
  #
4
- # Purpose: Top-level include for comment_strip.r library
5
+ # Purpose: Top-level include for comment_strip.r library
5
6
  #
6
- # Created: 14th September 2020
7
- # Updated: 11th July 2022
7
+ # Created: 14th September 2020
8
+ # Updated: 19th August 2026
8
9
  #
9
- # Home: http://github.com/synesissoftware/comment_strip.r
10
+ # Home: https://github.com/synesissoftware/comment_strip.r
10
11
  #
11
- # Copyright (c) 2020-2022, Matthew Wilson and Synesis Information Systems
12
+ # Copyright (c) 2020-2026, Matthew Wilson and Synesis Information Systems
12
13
  # All rights reserved.
13
14
  #
14
15
  # Redistribution and use in source and binary forms, with or without
@@ -1,5 +1,12 @@
1
1
  #! /usr/bin/env ruby
2
2
 
3
+ # NOTE: TAB characters in this test file are intentional and occur only
4
+ # inside HEREDOC fixtures containing imported C/C++ source. They preserve
5
+ # the fixtures' original whitespace so comment stripping can be tested
6
+ # accurately. All Ruby test code and all non-fixture lines must use spaces,
7
+ # with two-space indentation; do not add TABs elsewhere.
8
+
9
+
3
10
  $:.unshift File.join(__dir__, '../..', 'lib')
4
11
 
5
12
 
@@ -865,8 +872,6 @@ EOF_main
865
872
  #include <new>
866
873
  EOF_main
867
874
 
868
- actual = strip(input, 'C')
869
-
870
875
  assert_equal expected, strip(input, 'C')
871
876
  end
872
877
 
@@ -2384,7 +2389,7 @@ EOF_main
2384
2389
  assert_equal expected, actual
2385
2390
  end
2386
2391
 
2387
- def _test_real_sample_6
2392
+ def test_real_sample_6
2388
2393
 
2389
2394
  input = <<-EOF_main
2390
2395
 
@@ -2474,8 +2479,6 @@ namespace {
2474
2479
 
2475
2480
  default:
2476
2481
  // Check for control characters and invalid utf-8
2477
- EOF_main
2478
- x1 = <<-EOF_main
2479
2482
  // Escape control characters in standard ascii
2480
2483
  // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
2481
2484
  if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {
@@ -2764,9 +2767,6 @@ namespace {
2764
2767
 
2765
2768
  default:
2766
2769
 
2767
- EOF_main
2768
- x1 = <<-EOF_main
2769
-
2770
2770
 
2771
2771
 
2772
2772
  if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {