seeing_is_believing 2.0.0.beta1 → 2.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|