seeing_is_believing 2.0.0.beta1 → 2.0.0.beta2
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 +7 -0
- data/Readme.md +8 -20
- data/features/examples.feature +1 -3
- data/features/flags.feature +4 -12
- data/features/regression.feature +95 -1
- data/lib/seeing_is_believing.rb +17 -21
- data/lib/seeing_is_believing/binary.rb +3 -3
- data/lib/seeing_is_believing/binary/add_annotations.rb +86 -118
- data/lib/seeing_is_believing/binary/align_chunk.rb +22 -23
- data/lib/seeing_is_believing/binary/align_file.rb +10 -13
- data/lib/seeing_is_believing/binary/align_line.rb +0 -4
- data/lib/seeing_is_believing/binary/arg_parser.rb +11 -11
- data/lib/seeing_is_believing/binary/clean_body.rb +96 -0
- data/lib/seeing_is_believing/binary/comment_formatter.rb +55 -0
- data/lib/seeing_is_believing/binary/comment_lines.rb +37 -0
- data/lib/seeing_is_believing/binary/commentable_lines.rb +158 -0
- data/lib/seeing_is_believing/binary/rewrite_comments.rb +42 -0
- data/lib/seeing_is_believing/result.rb +2 -9
- data/lib/seeing_is_believing/the_matrix.rb +8 -8
- data/lib/seeing_is_believing/version.rb +1 -1
- data/lib/seeing_is_believing/{program_rewriter.rb → wrap_expressions.rb} +30 -22
- data/spec/binary/arg_parser_spec.rb +7 -7
- data/spec/binary/clean_body_spec.rb +217 -0
- data/spec/binary/comment_formatter_spec.rb +54 -0
- data/spec/binary/comment_lines_spec.rb +847 -0
- data/spec/binary/rewrite_comments_spec.rb +54 -0
- data/spec/seeing_is_believing_spec.rb +1 -2
- data/spec/{program_rewriter_spec.rb → wrap_expressions_spec.rb} +117 -40
- metadata +41 -56
- data/lib/seeing_is_believing/binary/line_formatter.rb +0 -47
- data/lib/seeing_is_believing/binary/remove_previous_annotations.rb +0 -75
- data/lib/seeing_is_believing/queue.rb +0 -55
- data/lib/seeing_is_believing/remove_inline_comments.rb +0 -46
- data/lib/seeing_is_believing/syntax_analyzer.rb +0 -61
- data/lib/seeing_is_believing/tracks_line_numbers_seen.rb +0 -19
- data/spec/binary/line_formatter_spec.rb +0 -53
- data/spec/binary/remove_previous_annotations_spec.rb +0 -198
- data/spec/queue_spec.rb +0 -80
- data/spec/syntax_analyzer_spec.rb +0 -56
@@ -1,38 +1,37 @@
|
|
1
|
+
require 'seeing_is_believing/binary/commentable_lines'
|
2
|
+
|
1
3
|
class SeeingIsBelieving
|
2
4
|
class Binary
|
3
5
|
class AlignChunk
|
4
|
-
attr_accessor :body, :start_line, :end_line
|
5
|
-
|
6
6
|
def initialize(body, start_line, end_line)
|
7
7
|
self.body, self.start_line, self.end_line = body, start_line, end_line
|
8
8
|
end
|
9
9
|
|
10
10
|
# max line length of the the chunk (newline separated sections of code exempting comments) + 2 spaces for padding
|
11
11
|
def line_length_for(line_number)
|
12
|
-
line_lengths
|
12
|
+
line_lengths.fetch line_number, 0
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
.map(&:chomp)
|
19
|
-
.map.with_index(1) { |line, index| [line, index] }
|
20
|
-
.take_while { |line, index| not start_of_data_segment? line }
|
21
|
-
.select { |line, index| not SyntaxAnalyzer.begins_multiline_comment?(line) .. SyntaxAnalyzer.ends_multiline_comment?(line ) }
|
22
|
-
.reject { |line, index| SyntaxAnalyzer.ends_in_comment? line }
|
23
|
-
.slice_before { |line, index| line == '' }
|
24
|
-
.map { |slice|
|
25
|
-
max_chunk_length = 2 + slice.select { |line, index| start_line <= index && index <= end_line }
|
26
|
-
.map { |line, index| line.length }
|
27
|
-
.max
|
28
|
-
slice.map { |line, index| [index, max_chunk_length] }
|
29
|
-
}
|
30
|
-
.flatten(1)
|
31
|
-
]
|
32
|
-
end
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_accessor :body, :start_line, :end_line
|
33
18
|
|
34
|
-
def
|
35
|
-
|
19
|
+
def line_lengths
|
20
|
+
@line_lengths ||= begin
|
21
|
+
line_num_to_indexes = CommentableLines.new(body).call # {line_number => [index_in_file, index_in_col]}
|
22
|
+
Hash[line_num_to_indexes
|
23
|
+
.keys
|
24
|
+
.sort
|
25
|
+
.slice_before { |line_number| line_num_to_indexes[line_number].last.zero? }
|
26
|
+
.map { |slice|
|
27
|
+
max_chunk_length = 2 + slice.select { |line_num| start_line <= line_num && line_num <= end_line }
|
28
|
+
.map { |line_num| line_num_to_indexes[line_num].last }
|
29
|
+
.max
|
30
|
+
slice.map { |line_number| [line_number, max_chunk_length] }
|
31
|
+
}
|
32
|
+
.flatten(1)
|
33
|
+
]
|
34
|
+
end
|
36
35
|
end
|
37
36
|
end
|
38
37
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'seeing_is_believing/binary/commentable_lines'
|
2
|
+
|
1
3
|
class SeeingIsBelieving
|
2
4
|
class Binary
|
3
5
|
class AlignFile
|
@@ -9,19 +11,14 @@ class SeeingIsBelieving
|
|
9
11
|
|
10
12
|
# max line length of the lines to output (exempting comments) + 2 spaces for padding
|
11
13
|
def line_length_for(line_number)
|
12
|
-
@max_source_line_length ||= 2 +
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
.max
|
21
|
-
end
|
22
|
-
|
23
|
-
def start_of_data_segment?(line)
|
24
|
-
SyntaxAnalyzer.begins_data_segment?(line.chomp)
|
14
|
+
@max_source_line_length ||= 2 + begin
|
15
|
+
line_num_to_indexes = CommentableLines.new(body).call # {line_number => [index_in_file, index_in_col]}
|
16
|
+
max_value = line_num_to_indexes
|
17
|
+
.select { |line_num, _| start_line <= line_num && line_num <= end_line }
|
18
|
+
.values
|
19
|
+
.map { |index, col| col }.max
|
20
|
+
max_value || 0
|
21
|
+
end
|
25
22
|
end
|
26
23
|
end
|
27
24
|
end
|
@@ -29,15 +29,15 @@ class SeeingIsBelieving
|
|
29
29
|
when '-x', '--xmpfilter-style' then options[:xmpfilter_style] = true
|
30
30
|
when '-i', '--inherit-exit-status' then options[:inherit_exit_status] = true
|
31
31
|
when '-g', '--debug' then options[:debugger] = Debugger.new(enabled: true, colour: true)
|
32
|
-
when '-l', '--start-line' then extract_positive_int_for :start_line,
|
33
|
-
when '-L', '--end-line' then extract_positive_int_for :end_line,
|
34
|
-
when '-d', '--line-length' then extract_positive_int_for :
|
35
|
-
when '-D', '--result-length' then extract_positive_int_for :
|
36
|
-
when '-t', '--timeout' then extract_non_negative_float_for :timeout,
|
37
|
-
when '-r', '--require' then next_arg("#{arg} expected a filename as the following argument but did not see one") { |filename| options[:require]
|
38
|
-
when '-I', '--load-path' then next_arg("#{arg} expected a directory as the following argument but did not see one") { |dir| options[:load_path]
|
39
|
-
when '-e', '--program' then next_arg("#{arg} expected a program as the following argument but did not see one") { |program| options[:program]
|
40
|
-
when '-a', '--as' then next_arg("#{arg} expected a filename as the following argument but did not see one") { |filename| options[:as]
|
32
|
+
when '-l', '--start-line' then extract_positive_int_for :start_line, arg
|
33
|
+
when '-L', '--end-line' then extract_positive_int_for :end_line, arg
|
34
|
+
when '-d', '--line-length' then extract_positive_int_for :max_line_length, arg
|
35
|
+
when '-D', '--result-length' then extract_positive_int_for :max_result_length, arg
|
36
|
+
when '-t', '--timeout' then extract_non_negative_float_for :timeout, arg
|
37
|
+
when '-r', '--require' then next_arg("#{arg} expected a filename as the following argument but did not see one") { |filename| options[:require] << filename }
|
38
|
+
when '-I', '--load-path' then next_arg("#{arg} expected a directory as the following argument but did not see one") { |dir| options[:load_path] << dir }
|
39
|
+
when '-e', '--program' then next_arg("#{arg} expected a program as the following argument but did not see one") { |program| options[:program] = program }
|
40
|
+
when '-a', '--as' then next_arg("#{arg} expected a filename as the following argument but did not see one") { |filename| options[:as] = filename }
|
41
41
|
when '-s', '--alignment-strategy' then extract_alignment_strategy
|
42
42
|
when /\A-K(.+)/ then options[:encoding] = $1
|
43
43
|
when '-K', '--encoding' then next_arg("#{arg} expects an encoding, see `man ruby` for possibile values") { |encoding| options[:encoding] = encoding }
|
@@ -78,9 +78,9 @@ class SeeingIsBelieving
|
|
78
78
|
program: nil,
|
79
79
|
filename: nil,
|
80
80
|
start_line: 1,
|
81
|
-
line_length: Float::INFINITY,
|
82
81
|
end_line: Float::INFINITY,
|
83
|
-
|
82
|
+
max_line_length: Float::INFINITY,
|
83
|
+
max_result_length: Float::INFINITY,
|
84
84
|
timeout: 0, # timeout lib treats this as infinity
|
85
85
|
errors: [],
|
86
86
|
require: [],
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# CleanedBody
|
2
|
+
# takes a body
|
3
|
+
# removes annotations
|
4
|
+
# only removes "# =>" when should_clean_values is false
|
5
|
+
|
6
|
+
require 'parser/current'
|
7
|
+
|
8
|
+
class SeeingIsBelieving
|
9
|
+
class Binary
|
10
|
+
class CleanBody
|
11
|
+
def self.call(code, should_clean_values)
|
12
|
+
new(code, should_clean_values).call
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(code, should_clean_values)
|
16
|
+
self.should_clean_values = should_clean_values
|
17
|
+
self.code = code
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
buffer = Parser::Source::Buffer.new "strip_comments"
|
22
|
+
buffer.source = code
|
23
|
+
parser = Parser::CurrentRuby.new
|
24
|
+
rewriter = Parser::Source::Rewriter.new(buffer)
|
25
|
+
ast, comments = parser.parse_with_comments(buffer)
|
26
|
+
removed_comments = { result: [], exception: [], stdout: [], stderr: [] }
|
27
|
+
|
28
|
+
comments.each do |comment|
|
29
|
+
case comment.text
|
30
|
+
when /\A#\s*=>/
|
31
|
+
if should_clean_values
|
32
|
+
removed_comments[:result] << comment
|
33
|
+
rewriter.remove comment.location.expression
|
34
|
+
end
|
35
|
+
when /\A#\s*~>/
|
36
|
+
removed_comments[:exception] << comment
|
37
|
+
rewriter.remove comment.location.expression
|
38
|
+
when /\A#\s*>>/ then
|
39
|
+
removed_comments[:stdout] << comment
|
40
|
+
rewriter.remove comment.location.expression
|
41
|
+
when /\A#\s*!>/ then
|
42
|
+
removed_comments[:stderr] << comment
|
43
|
+
rewriter.remove comment.location.expression
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
remove_whitespace_preceeding_comments(buffer, rewriter, removed_comments)
|
48
|
+
rewriter.process
|
49
|
+
rescue Parser::SyntaxError => e
|
50
|
+
raise SyntaxError, e.message
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
attr_accessor :code, :should_clean_values, :buffer
|
56
|
+
|
57
|
+
def remove_whitespace_preceeding_comments(buffer, rewriter, removed_comments)
|
58
|
+
removed_comments[:result].each { |comment| remove_whitespace_before comment.location.expression.begin_pos, buffer, rewriter, false }
|
59
|
+
removed_comments[:exception].each { |comment| remove_whitespace_before comment.location.expression.begin_pos, buffer, rewriter, true }
|
60
|
+
removed_comments[:stdout].each { |comment| remove_whitespace_before comment.location.expression.begin_pos, buffer, rewriter, true }
|
61
|
+
removed_comments[:stderr].each { |comment| remove_whitespace_before comment.location.expression.begin_pos, buffer, rewriter, true }
|
62
|
+
end
|
63
|
+
|
64
|
+
# any whitespace before the index (on the same line) will be removed
|
65
|
+
# if the preceeding whitespace is at the beginning of the line, the newline will be removed
|
66
|
+
# if there is a newline before all of that, and remove_preceeding_newline is true, it will be removed as well
|
67
|
+
def remove_whitespace_before(index, buffer, rewriter, remove_preceeding_newline)
|
68
|
+
end_pos = index
|
69
|
+
begin_pos = end_pos - 1
|
70
|
+
begin_pos -= 1 while code[begin_pos] =~ /\s/ && code[begin_pos] != "\n"
|
71
|
+
begin_pos -= 1 if code[begin_pos] == "\n"
|
72
|
+
begin_pos -= 1 if code[begin_pos] == "\n" && remove_preceeding_newline
|
73
|
+
return if begin_pos.next == end_pos
|
74
|
+
rewriter.remove Parser::Source::Range.new(buffer, begin_pos.next, end_pos)
|
75
|
+
end
|
76
|
+
|
77
|
+
# returns comments in groups that are on consecutive lines
|
78
|
+
def adjacent_comments(comments, buffer)
|
79
|
+
comments = comments.sort_by { |comment| comment.location.begin_pos }
|
80
|
+
current_chunk = 0
|
81
|
+
last_line_seen = -100
|
82
|
+
chunks_to_comment = comments.chunk do |comment|
|
83
|
+
line, col = buffer.decompose_position comment.location.begin_pos
|
84
|
+
if last_line_seen.next == line
|
85
|
+
last_line_seen = line
|
86
|
+
current_chunk
|
87
|
+
else
|
88
|
+
last_line_seen = line
|
89
|
+
current_chunk += 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
chunks_to_comment.map &:last
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class SeeingIsBelieving
|
2
|
+
class Binary
|
3
|
+
class CommentFormatter
|
4
|
+
def self.call(*args)
|
5
|
+
new(*args).call
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(line_length, separator, result, options)
|
9
|
+
self.line_length = line_length
|
10
|
+
self.separator = separator
|
11
|
+
self.result = result.gsub "\n", '\n'
|
12
|
+
self.options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
@formatted ||= begin
|
17
|
+
formatted = truncate "#{separator}#{result}", max_result_length
|
18
|
+
formatted = "#{' '*padding_length}#{formatted}"
|
19
|
+
formatted = truncate formatted, max_line_length
|
20
|
+
formatted = '' unless formatted.sub(/^ */, '').start_with? separator
|
21
|
+
formatted
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_accessor :line_length, :separator, :result, :options
|
28
|
+
|
29
|
+
def max_line_length
|
30
|
+
length = options.fetch(:max_line_length, Float::INFINITY) - line_length
|
31
|
+
length = 0 if length < 0
|
32
|
+
length
|
33
|
+
end
|
34
|
+
|
35
|
+
def max_result_length
|
36
|
+
options.fetch :max_result_length, Float::INFINITY
|
37
|
+
end
|
38
|
+
|
39
|
+
def padding_length
|
40
|
+
padding_length = options.fetch(:pad_to, 0) - line_length
|
41
|
+
padding_length = 0 if padding_length < 0
|
42
|
+
padding_length
|
43
|
+
end
|
44
|
+
|
45
|
+
def truncate(string, length)
|
46
|
+
return string if string.size <= length
|
47
|
+
ellipsify string.slice(0, length)
|
48
|
+
end
|
49
|
+
|
50
|
+
def ellipsify(string)
|
51
|
+
string.sub(/.{0,3}$/) { |last_chars| last_chars.gsub /./, '.' }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'seeing_is_believing/binary/commentable_lines'
|
2
|
+
|
3
|
+
class SeeingIsBelieving
|
4
|
+
class Binary
|
5
|
+
|
6
|
+
# takes a body and a block
|
7
|
+
# passes the block the line
|
8
|
+
# the block returns the comment to add at the end of it
|
9
|
+
class CommentLines
|
10
|
+
def self.call(code, &commenter)
|
11
|
+
new(code, &commenter).call
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(code, &commenter)
|
15
|
+
self.code, self.commenter = code, commenter
|
16
|
+
end
|
17
|
+
|
18
|
+
def call
|
19
|
+
@call ||= begin
|
20
|
+
commentable_lines = CommentableLines.new code
|
21
|
+
commentable_lines.call.each do |line_number, (index_of_newline, col)|
|
22
|
+
first_index = last_index = index_of_newline
|
23
|
+
first_index -= 1 while first_index > 0 && code[first_index-1] != "\n"
|
24
|
+
comment_text = commenter.call code[first_index...last_index], line_number
|
25
|
+
range = Parser::Source::Range.new(commentable_lines.buffer, first_index, last_index)
|
26
|
+
commentable_lines.rewriter.insert_after range, comment_text
|
27
|
+
end
|
28
|
+
commentable_lines.rewriter.process
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_accessor :code, :commenter
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'parser/current'
|
2
|
+
|
3
|
+
class SeeingIsBelieving
|
4
|
+
class Binary
|
5
|
+
|
6
|
+
class CommentableLines
|
7
|
+
def self.call(code)
|
8
|
+
new(code).call
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(code)
|
12
|
+
self.code = code
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
@call ||= begin
|
17
|
+
line_num_to_indexes = line_nums_to_last_index_and_col(buffer)
|
18
|
+
remove_lines_after_data_segment line_num_to_indexes
|
19
|
+
remove_lines_whose_newline_is_escaped line_num_to_indexes
|
20
|
+
remove_lines_ending_in_comments line_num_to_indexes, comments
|
21
|
+
remove_lines_inside_of_strings_and_things line_num_to_indexes, root
|
22
|
+
line_num_to_indexes
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def buffer
|
27
|
+
@buffer ||= Parser::Source::Buffer.new("strip_comments").tap { |b| b.source = code }
|
28
|
+
end
|
29
|
+
|
30
|
+
def rewriter
|
31
|
+
@rewriter ||= Parser::Source::Rewriter.new(buffer)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_accessor :code
|
37
|
+
|
38
|
+
def parser
|
39
|
+
@parser ||= Parser::CurrentRuby.new
|
40
|
+
end
|
41
|
+
|
42
|
+
def root
|
43
|
+
parse!
|
44
|
+
@root
|
45
|
+
end
|
46
|
+
|
47
|
+
def comments
|
48
|
+
parse!
|
49
|
+
@comments
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def parse!
|
54
|
+
return if @root
|
55
|
+
@root, @comments = parser.parse_with_comments(buffer)
|
56
|
+
end
|
57
|
+
|
58
|
+
def line_nums_to_last_index_and_col(buffer)
|
59
|
+
line_num_to_indexes = code.each_char
|
60
|
+
.with_index
|
61
|
+
.select { |char, index| char == "\n" } # <-- is this okay? what about other OSes?
|
62
|
+
.each_with_object(Hash.new) do |(_, index), hash|
|
63
|
+
line, col = buffer.decompose_position index
|
64
|
+
hash[line] = [index, col]
|
65
|
+
end
|
66
|
+
if code[code.size-1] != "\n" # account for the fact that the last line wouldn't have been found above if it doesn't end in a newline
|
67
|
+
line, col = buffer.decompose_position code.size
|
68
|
+
line_num_to_indexes[line] = [code.size, col]
|
69
|
+
end
|
70
|
+
line_num_to_indexes
|
71
|
+
end
|
72
|
+
|
73
|
+
def remove_lines_whose_newline_is_escaped(line_num_to_indexes)
|
74
|
+
line_num_to_indexes.select { |line_number, (index_of_newline, col)| code[index_of_newline-1] == '\\' }
|
75
|
+
.each { |line_number, (index_of_newline, col)| line_num_to_indexes.delete line_number }
|
76
|
+
end
|
77
|
+
|
78
|
+
def remove_lines_ending_in_comments(line_num_to_indexes, comments)
|
79
|
+
comments.each do |comment|
|
80
|
+
if comment.type == :inline
|
81
|
+
line_num_to_indexes.delete comment.location.line
|
82
|
+
else
|
83
|
+
begin_pos = comment.location.expression.begin_pos
|
84
|
+
end_pos = comment.location.expression.end_pos
|
85
|
+
range = begin_pos...end_pos
|
86
|
+
line_num_to_indexes.select { |line_number, (index_of_newline, col)| range.include? index_of_newline }
|
87
|
+
.each { |line_number, (index_of_newline, col)| line_num_to_indexes.delete line_number }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def remove_lines_inside_of_strings_and_things(line_num_to_indexes, ast)
|
93
|
+
invalid_boundaries = ranges_of_atomic_expressions ast, []
|
94
|
+
invalid_boundaries.each do |invalid_boundary|
|
95
|
+
line_num_to_indexes.select { |line_number, (index_of_newline, col)| invalid_boundary.include? index_of_newline }
|
96
|
+
.each { |line_number, (index_of_newline, col)| line_num_to_indexes.delete line_number }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def ranges_of_atomic_expressions(ast, found_ranges)
|
101
|
+
return found_ranges unless ast.kind_of? ::AST::Node
|
102
|
+
if no_comment_zone?(ast) && heredoc?(ast)
|
103
|
+
begin_pos = ast.location.expression.begin.begin_pos
|
104
|
+
begin_pos += (ast.location.expression.source =~ /\n/).next
|
105
|
+
end_pos = ast.location.expression.end.end_pos.next
|
106
|
+
found_ranges << (begin_pos...end_pos)
|
107
|
+
elsif no_comment_zone? ast
|
108
|
+
begin_pos = ast.location.expression.begin.begin_pos
|
109
|
+
end_pos = ast.location.expression.end.end_pos
|
110
|
+
found_ranges << (begin_pos...end_pos)
|
111
|
+
else
|
112
|
+
ast.children.each { |child| ranges_of_atomic_expressions child, found_ranges }
|
113
|
+
end
|
114
|
+
found_ranges
|
115
|
+
end
|
116
|
+
|
117
|
+
def no_comment_zone?(ast)
|
118
|
+
case ast.type
|
119
|
+
when :dstr, :str, :xstr, :regexp
|
120
|
+
true
|
121
|
+
when :array
|
122
|
+
the_begin = ast.location.begin
|
123
|
+
the_begin && the_begin.source =~ /\A%/
|
124
|
+
else
|
125
|
+
false
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# copy/pasted from wrap_expressions
|
130
|
+
def heredoc?(ast)
|
131
|
+
# some strings are fucking weird.
|
132
|
+
# e.g. the "1" in `%w[1]` returns nil for ast.location.begin
|
133
|
+
# and `__FILE__` is a string whose location is a Parser::Source::Map instead of a Parser::Source::Map::Collection, so it has no #begin
|
134
|
+
ast.kind_of?(Parser::AST::Node) &&
|
135
|
+
(ast.type == :dstr || ast.type == :str) &&
|
136
|
+
(location = ast.location) &&
|
137
|
+
(location.respond_to?(:begin)) &&
|
138
|
+
(the_begin = location.begin) &&
|
139
|
+
(the_begin.source =~ /^\<\<-?/)
|
140
|
+
end
|
141
|
+
|
142
|
+
def remove_lines_after_data_segment(line_num_to_indexes)
|
143
|
+
data_segment_line, _ = line_num_to_indexes.find do |line_number, (end_index, col)|
|
144
|
+
if end_index == 7
|
145
|
+
code.start_with? '__END__'
|
146
|
+
elsif end_index < 7
|
147
|
+
false
|
148
|
+
else
|
149
|
+
code[(end_index-8)...end_index] == "\n__END__"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
return unless data_segment_line
|
153
|
+
max_line = line_num_to_indexes.keys.max
|
154
|
+
data_segment_line.upto(max_line) { |line_number| line_num_to_indexes.delete line_number }
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|