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
@@ -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
|