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
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'parser/current'
|
2
|
+
|
3
|
+
class SeeingIsBelieving
|
4
|
+
class Binary
|
5
|
+
module RewriteComments
|
6
|
+
def self.call(code, &mapping)
|
7
|
+
buffer = Parser::Source::Buffer.new "strip_comments"
|
8
|
+
buffer.source = code
|
9
|
+
parser = Parser::CurrentRuby.new
|
10
|
+
rewriter = Parser::Source::Rewriter.new(buffer)
|
11
|
+
ast, comments = parser.parse_with_comments(buffer)
|
12
|
+
|
13
|
+
comments.each do |comment|
|
14
|
+
next unless comment.type == :inline
|
15
|
+
# find whitespace
|
16
|
+
last_char = comment.location.expression.begin_pos
|
17
|
+
first_char = last_char
|
18
|
+
first_char -= 1 while first_char > 0 && buffer.source[first_char-1] =~ /[ \t]/
|
19
|
+
preceeding_whitespace = buffer.source[first_char...last_char]
|
20
|
+
preceeding_whitespace_range = Parser::Source::Range.new buffer, first_char, last_char
|
21
|
+
|
22
|
+
# find line
|
23
|
+
last_char = first_char
|
24
|
+
first_char -= 1 while first_char > 0 && buffer.source[first_char-1] !~ /[\r\n]/
|
25
|
+
line = buffer.source[first_char...last_char]
|
26
|
+
|
27
|
+
# get results
|
28
|
+
new_whitespace, new_comment = mapping.call(comment.location.line,
|
29
|
+
line,
|
30
|
+
preceeding_whitespace,
|
31
|
+
comment.text)
|
32
|
+
|
33
|
+
# update code
|
34
|
+
rewriter.replace preceeding_whitespace_range, new_whitespace
|
35
|
+
rewriter.replace comment.location.expression, new_comment
|
36
|
+
end
|
37
|
+
|
38
|
+
rewriter.process
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,11 +1,9 @@
|
|
1
1
|
require 'seeing_is_believing/line'
|
2
2
|
require 'seeing_is_believing/has_exception'
|
3
|
-
require 'seeing_is_believing/tracks_line_numbers_seen'
|
4
3
|
|
5
4
|
class SeeingIsBelieving
|
6
5
|
class Result
|
7
6
|
include HasException
|
8
|
-
include TracksLineNumbersSeen
|
9
7
|
include Enumerable
|
10
8
|
|
11
9
|
attr_accessor :stdout, :stderr, :exitstatus, :bug_in_sib
|
@@ -20,12 +18,7 @@ class SeeingIsBelieving
|
|
20
18
|
stderr && !stderr.empty?
|
21
19
|
end
|
22
20
|
|
23
|
-
def initialize
|
24
|
-
@min_line_number = @max_line_number = 1
|
25
|
-
end
|
26
|
-
|
27
21
|
def record_result(line_number, value)
|
28
|
-
track_line_number line_number
|
29
22
|
results_for(line_number) << value.inspect
|
30
23
|
value
|
31
24
|
end
|
@@ -35,7 +28,6 @@ class SeeingIsBelieving
|
|
35
28
|
exception.message,
|
36
29
|
exception.backtrace
|
37
30
|
self.exception = recorded_exception
|
38
|
-
track_line_number line_number
|
39
31
|
results_for(line_number).exception = recorded_exception
|
40
32
|
end
|
41
33
|
|
@@ -44,7 +36,8 @@ class SeeingIsBelieving
|
|
44
36
|
end
|
45
37
|
|
46
38
|
def each(&block)
|
47
|
-
|
39
|
+
max = results.keys.max || 1
|
40
|
+
(1..max).each { |line_number| block.call self[line_number] }
|
48
41
|
end
|
49
42
|
|
50
43
|
def inspect
|
@@ -9,16 +9,16 @@ STDOUT = $stdout = fake_stdout = StringIO.new
|
|
9
9
|
STDERR = $stderr = fake_stderr = StringIO.new
|
10
10
|
|
11
11
|
require 'seeing_is_believing/result'
|
12
|
-
$
|
12
|
+
$SiB = SeeingIsBelieving::Result.new
|
13
13
|
|
14
14
|
at_exit do
|
15
|
-
$
|
16
|
-
$
|
15
|
+
$SiB.stdout = fake_stdout.string
|
16
|
+
$SiB.stderr = fake_stderr.string
|
17
17
|
|
18
|
-
$
|
19
|
-
$
|
20
|
-
$
|
21
|
-
$
|
18
|
+
$SiB.exitstatus ||= 0
|
19
|
+
$SiB.exitstatus = 1 if $!
|
20
|
+
$SiB.exitstatus = $!.status if $!.kind_of? SystemExit
|
21
|
+
$SiB.bug_in_sib = $! && ! $!.kind_of?(SystemExit)
|
22
22
|
|
23
|
-
real_stdout.write YAML.dump $
|
23
|
+
real_stdout.write YAML.dump $SiB
|
24
24
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'parser/current'
|
2
2
|
|
3
3
|
# hack rewriter to apply insertions in stable order
|
4
|
-
# until https://github.com/whitequark/parser/pull/102 gets
|
4
|
+
# until https://github.com/whitequark/parser/pull/102 gets released
|
5
5
|
module Parser
|
6
6
|
module Source
|
7
7
|
class Rewriter
|
@@ -30,7 +30,7 @@ end
|
|
30
30
|
# comprehensive list of syntaxes that can come up
|
31
31
|
# https://github.com/whitequark/parser/blob/master/doc/AST_FORMAT.md
|
32
32
|
class SeeingIsBelieving
|
33
|
-
class
|
33
|
+
class WrapExpressions
|
34
34
|
def self.call(program, wrappings)
|
35
35
|
new(program, wrappings).call
|
36
36
|
end
|
@@ -62,7 +62,11 @@ class SeeingIsBelieving
|
|
62
62
|
rewriter.insert_after range, after_each.call(line_num)
|
63
63
|
end
|
64
64
|
|
65
|
-
|
65
|
+
# another stupid hack to get around a heredoc at the end of the document
|
66
|
+
# hopefully we can remove this after next version of Parser is released
|
67
|
+
last_index, (range, col) = wrappings.max_by(&:first)
|
68
|
+
range ||= root.location.expression
|
69
|
+
rewriter.insert_after range, after_all
|
66
70
|
end
|
67
71
|
|
68
72
|
rewriter.process
|
@@ -110,6 +114,10 @@ class SeeingIsBelieving
|
|
110
114
|
when :resbody
|
111
115
|
exception_type, variable_name, body = ast.children
|
112
116
|
find_wrappings body
|
117
|
+
when :array
|
118
|
+
add_to_wrappings ast
|
119
|
+
the_begin = ast.location.begin
|
120
|
+
add_children ast if the_begin && the_begin.source !~ /\A%/
|
113
121
|
when :block
|
114
122
|
add_to_wrappings ast
|
115
123
|
|
@@ -140,32 +148,24 @@ class SeeingIsBelieving
|
|
140
148
|
# in the second, there is an implicit Array wrapped around it, with the wrong end_pos,
|
141
149
|
# so we must take the end_pos of the last arg
|
142
150
|
array = ast.children.last
|
143
|
-
if array.
|
151
|
+
if array.type != :array # e.g. `a, g = c`
|
152
|
+
add_to_wrappings ast
|
153
|
+
add_to_wrappings ast.children.last
|
154
|
+
elsif array.location.expression.source.start_with? '['
|
144
155
|
add_to_wrappings ast
|
145
156
|
find_wrappings array
|
146
157
|
else
|
147
158
|
begin_pos = ast.location.expression.begin_pos
|
148
|
-
end_pos = heredoc_hack(
|
159
|
+
end_pos = heredoc_hack(array.children.last).location.expression.end_pos
|
149
160
|
range = Parser::Source::Range.new buffer, begin_pos, end_pos
|
150
161
|
add_to_wrappings range
|
151
162
|
add_children ast.children.last
|
152
163
|
end
|
153
|
-
when :lvasgn
|
164
|
+
when :lvasgn, :ivasgn, :gvasgn, :cvasgn, :casgn # local variable, instance variable, global variable, class variable, constant
|
154
165
|
# because the RHS can be a heredoc, and parser currently handles heredocs locations incorrectly
|
155
166
|
# we must hack around this
|
156
167
|
|
157
|
-
|
158
|
-
# in a=1 (has children :a, and 1)
|
159
|
-
# in a,b=1,2 it comes out like:
|
160
|
-
# (masgn
|
161
|
-
# (mlhs
|
162
|
-
# (lvasgn :a) <-- one child
|
163
|
-
#
|
164
|
-
# (lvasgn :b))
|
165
|
-
# (array
|
166
|
-
# (int 1)
|
167
|
-
# (int 2)))
|
168
|
-
if ast.children.size == 2
|
168
|
+
if ast.children.last.kind_of? ::AST::Node
|
169
169
|
begin_pos = ast.location.expression.begin_pos
|
170
170
|
end_pos = heredoc_hack(ast.children.last).location.expression.end_pos
|
171
171
|
range = Parser::Source::Range.new buffer, begin_pos, end_pos
|
@@ -190,15 +190,20 @@ class SeeingIsBelieving
|
|
190
190
|
end_pos += 1
|
191
191
|
end
|
192
192
|
|
193
|
-
|
193
|
+
elsif heredoc?(target) && last_arg
|
194
|
+
end_pos = last_arg.location.expression.end_pos
|
195
|
+
|
196
|
+
# neither the target, nor the last arg are heredocs, the range of the expression can be trusted
|
194
197
|
elsif last_arg
|
195
198
|
end_pos = ast.location.expression.end_pos
|
196
199
|
|
200
|
+
# in lambda{}.() the send has no selector, so use the expression
|
201
|
+
# I'm going to ignore the fact that you could define call on a heredoc and do <<HERE.(),
|
202
|
+
elsif !ast.location.selector
|
203
|
+
end_pos = ast.location.expression.end_pos
|
204
|
+
|
197
205
|
# there is no last arg, but there are parens, find the closing paren
|
198
206
|
# we can't trust the expression range because the *target* could be a heredoc
|
199
|
-
# FIXME: This blows up on 2.0 with ->{}.() because it has no selector, so in this case
|
200
|
-
# we would want to use the expression, but I'm ignoring that for now, because
|
201
|
-
# we would have to check the target to see whether to use the selector or the expression
|
202
207
|
elsif buffer.source[ast.location.selector.end_pos] == '('
|
203
208
|
closing_paren_index = ast.location.selector.end_pos + 1
|
204
209
|
closing_paren_index += 1 until buffer.source[closing_paren_index] == ')'
|
@@ -239,6 +244,7 @@ class SeeingIsBelieving
|
|
239
244
|
puts $!
|
240
245
|
require "pry"
|
241
246
|
binding.pry
|
247
|
+
raise
|
242
248
|
end
|
243
249
|
|
244
250
|
def heredoc_hack(ast)
|
@@ -250,6 +256,8 @@ class SeeingIsBelieving
|
|
250
256
|
|
251
257
|
# this is the scardest fucking method I think I've ever written.
|
252
258
|
# *anything* can go wrong!
|
259
|
+
#
|
260
|
+
# !!NOTE!! This method is copy/pasted into Binary::CommentLines
|
253
261
|
def heredoc?(ast)
|
254
262
|
# some strings are fucking weird.
|
255
263
|
# e.g. the "1" in `%w[1]` returns nil for ast.location.begin
|
@@ -122,25 +122,25 @@ describe SeeingIsBelieving::Binary::ArgParser do
|
|
122
122
|
|
123
123
|
describe ':result_length' do
|
124
124
|
it 'defaults to infinity' do
|
125
|
-
parse([])[:
|
125
|
+
parse([])[:max_result_length].should == Float::INFINITY
|
126
126
|
end
|
127
127
|
|
128
128
|
it 'is set with -D and --result-length' do
|
129
|
-
parse(['-D', '10'])[:
|
130
|
-
parse(['--result-length', '10'])[:
|
129
|
+
parse(['-D', '10'])[:max_result_length].should == 10
|
130
|
+
parse(['--result-length', '10'])[:max_result_length].should == 10
|
131
131
|
end
|
132
132
|
|
133
133
|
it_behaves_like 'it requires a positive int argument', ['-D', '--result-length']
|
134
134
|
end
|
135
135
|
|
136
|
-
describe ':
|
136
|
+
describe ':max_line_length' do
|
137
137
|
it 'defaults to infinity' do
|
138
|
-
parse([])[:
|
138
|
+
parse([])[:max_line_length].should == Float::INFINITY
|
139
139
|
end
|
140
140
|
|
141
141
|
it 'is set with -d and --line-length' do
|
142
|
-
parse(['-d', '10'])[:
|
143
|
-
parse(['--line-length', '10'])[:
|
142
|
+
parse(['-d', '10'])[:max_line_length].should == 10
|
143
|
+
parse(['--line-length', '10'])[:max_line_length].should == 10
|
144
144
|
end
|
145
145
|
|
146
146
|
it_behaves_like 'it requires a positive int argument', ['-d', '--line-length']
|
@@ -0,0 +1,217 @@
|
|
1
|
+
require 'seeing_is_believing/binary/clean_body'
|
2
|
+
|
3
|
+
describe SeeingIsBelieving::Binary::CleanBody do
|
4
|
+
def call(code, should_clean_values=true)
|
5
|
+
indentation = code[/\A */]
|
6
|
+
code = code.gsub /^#{indentation}/, ''
|
7
|
+
described_class.call(code, should_clean_values).chomp
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'when told to clean out value annotations' do
|
11
|
+
example { call("1#=>1", true).should == "1" }
|
12
|
+
example { call("1 #=>1", true).should == "1" }
|
13
|
+
example { call("1 #=>1", true).should == "1" }
|
14
|
+
example { call("1 #=> 1", true).should == "1" }
|
15
|
+
example { call("1 #=> 1", true).should == "1" }
|
16
|
+
example { call("1 #=> 1", true).should == "1" }
|
17
|
+
example { call("\n1 # => 1", true).should == "\n1" }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when told not to clean out value annotations' do
|
21
|
+
example { call("1#=>1", false).should == "1#=>1" }
|
22
|
+
example { call("1 #=>1", false).should == "1 #=>1" }
|
23
|
+
example { call("1 #=>1", false).should == "1 #=>1" }
|
24
|
+
example { call("1 #=> 1", false).should == "1 #=> 1" }
|
25
|
+
example { call("1 #=> 1", false).should == "1 #=> 1" }
|
26
|
+
example { call("1 #=> 1", false).should == "1 #=> 1" }
|
27
|
+
example { call("\n1 # => 1", false).should == "\n1 # => 1" }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'cleaning inline exception annotations' do
|
31
|
+
example { call("1#~>1").should == "1" }
|
32
|
+
example { call("1 #~>1").should == "1" }
|
33
|
+
example { call("1 #~>1").should == "1" }
|
34
|
+
example { call("1 #~> 1").should == "1" }
|
35
|
+
example { call("1 #~> 1").should == "1" }
|
36
|
+
example { call("1 #~> 1").should == "1" }
|
37
|
+
example { call("\n1 # ~> 1").should == "\n1" }
|
38
|
+
|
39
|
+
example { call("# >> 1").should == "" }
|
40
|
+
example { call("# !> 1").should == "" }
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'cleaning stdout annotations' do
|
44
|
+
example { call(<<-CODE).should == "1" }
|
45
|
+
1
|
46
|
+
# >> 2
|
47
|
+
CODE
|
48
|
+
|
49
|
+
example { call(<<-CODE).should == "1" }
|
50
|
+
1
|
51
|
+
|
52
|
+
# >> 2
|
53
|
+
CODE
|
54
|
+
|
55
|
+
example { call(<<-CODE).should == "1\n" }
|
56
|
+
1
|
57
|
+
|
58
|
+
|
59
|
+
# >> 2
|
60
|
+
CODE
|
61
|
+
|
62
|
+
example { call(<<-CODE).should == "1\n" }
|
63
|
+
1
|
64
|
+
|
65
|
+
|
66
|
+
# >> 2
|
67
|
+
# >> 2
|
68
|
+
# >> 2
|
69
|
+
CODE
|
70
|
+
|
71
|
+
|
72
|
+
example { call(<<-CODE).should == "1\n" }
|
73
|
+
1
|
74
|
+
|
75
|
+
|
76
|
+
# >> 2
|
77
|
+
# >> 3
|
78
|
+
CODE
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'cleaning stderr annotations' do
|
82
|
+
example { call(<<-CODE).should == "1" }
|
83
|
+
1
|
84
|
+
# !> 2
|
85
|
+
CODE
|
86
|
+
|
87
|
+
example { call(<<-CODE).should == "1" }
|
88
|
+
1
|
89
|
+
|
90
|
+
# !> 2
|
91
|
+
CODE
|
92
|
+
|
93
|
+
example { call(<<-CODE).should == "1" }
|
94
|
+
1
|
95
|
+
|
96
|
+
# !> 2
|
97
|
+
# !> 3
|
98
|
+
CODE
|
99
|
+
|
100
|
+
example { call(<<-CODE).should == "1\n" }
|
101
|
+
1
|
102
|
+
|
103
|
+
|
104
|
+
# !> 2
|
105
|
+
# !> 2
|
106
|
+
# !> 2
|
107
|
+
CODE
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
context 'cleaning end of file exception annotations' do
|
112
|
+
example { call(<<-CODE).should == "1" }
|
113
|
+
1
|
114
|
+
# ~>2
|
115
|
+
CODE
|
116
|
+
|
117
|
+
example { call(<<-CODE).should == "1" }
|
118
|
+
1
|
119
|
+
|
120
|
+
# ~> 2
|
121
|
+
CODE
|
122
|
+
|
123
|
+
example { call(<<-CODE).should == "1" }
|
124
|
+
1
|
125
|
+
|
126
|
+
# ~> 2
|
127
|
+
# ~> 3
|
128
|
+
CODE
|
129
|
+
|
130
|
+
example { call(<<-CODE).should == "1\n" }
|
131
|
+
1
|
132
|
+
|
133
|
+
|
134
|
+
# ~> 2
|
135
|
+
# ~> 2
|
136
|
+
# ~> 2
|
137
|
+
CODE
|
138
|
+
|
139
|
+
example { call(<<-CODE).should == "1\n" }
|
140
|
+
1 # ~> error
|
141
|
+
|
142
|
+
|
143
|
+
# ~> error again
|
144
|
+
CODE
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'putting it all together' do
|
148
|
+
example { call(<<-CODE).should == "1" }
|
149
|
+
1
|
150
|
+
|
151
|
+
# >> 1
|
152
|
+
# >> 2
|
153
|
+
|
154
|
+
# !> 3
|
155
|
+
# !> 4
|
156
|
+
|
157
|
+
# ~> 5
|
158
|
+
# ~> 6
|
159
|
+
CODE
|
160
|
+
|
161
|
+
example { call(<<-CODE).should == "1" }
|
162
|
+
1
|
163
|
+
|
164
|
+
# >> 1
|
165
|
+
|
166
|
+
# >> 2
|
167
|
+
|
168
|
+
# !> 3
|
169
|
+
|
170
|
+
# !> 4
|
171
|
+
|
172
|
+
# ~> 5
|
173
|
+
|
174
|
+
# ~> 6
|
175
|
+
CODE
|
176
|
+
|
177
|
+
example { call(<<-CODE).should == "1" }
|
178
|
+
1
|
179
|
+
|
180
|
+
# >> 1
|
181
|
+
# >> 2
|
182
|
+
# !> 3
|
183
|
+
# !> 4
|
184
|
+
# ~> 5
|
185
|
+
# ~> 6
|
186
|
+
CODE
|
187
|
+
|
188
|
+
example { call(<<-CODE).should == "1\n3" }
|
189
|
+
1
|
190
|
+
# >> 1
|
191
|
+
# >> 2
|
192
|
+
3
|
193
|
+
# !> 4
|
194
|
+
# !> 5
|
195
|
+
CODE
|
196
|
+
|
197
|
+
example { call(<<-CODE).should == "1\n3\n6" }
|
198
|
+
1
|
199
|
+
# >> 1
|
200
|
+
# >> 2
|
201
|
+
3
|
202
|
+
# !> 4
|
203
|
+
# !> 5
|
204
|
+
6
|
205
|
+
# ~> 7
|
206
|
+
# ~> 8
|
207
|
+
CODE
|
208
|
+
|
209
|
+
example { call(<<-CODE).should == "1\n\nputs \"omg\"" }
|
210
|
+
1 # => 1
|
211
|
+
|
212
|
+
puts "omg" # ~> RuntimeError: omg
|
213
|
+
|
214
|
+
# ~> RuntimeError
|
215
|
+
CODE
|
216
|
+
end
|
217
|
+
end
|