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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/Readme.md +8 -20
  3. data/features/examples.feature +1 -3
  4. data/features/flags.feature +4 -12
  5. data/features/regression.feature +95 -1
  6. data/lib/seeing_is_believing.rb +17 -21
  7. data/lib/seeing_is_believing/binary.rb +3 -3
  8. data/lib/seeing_is_believing/binary/add_annotations.rb +86 -118
  9. data/lib/seeing_is_believing/binary/align_chunk.rb +22 -23
  10. data/lib/seeing_is_believing/binary/align_file.rb +10 -13
  11. data/lib/seeing_is_believing/binary/align_line.rb +0 -4
  12. data/lib/seeing_is_believing/binary/arg_parser.rb +11 -11
  13. data/lib/seeing_is_believing/binary/clean_body.rb +96 -0
  14. data/lib/seeing_is_believing/binary/comment_formatter.rb +55 -0
  15. data/lib/seeing_is_believing/binary/comment_lines.rb +37 -0
  16. data/lib/seeing_is_believing/binary/commentable_lines.rb +158 -0
  17. data/lib/seeing_is_believing/binary/rewrite_comments.rb +42 -0
  18. data/lib/seeing_is_believing/result.rb +2 -9
  19. data/lib/seeing_is_believing/the_matrix.rb +8 -8
  20. data/lib/seeing_is_believing/version.rb +1 -1
  21. data/lib/seeing_is_believing/{program_rewriter.rb → wrap_expressions.rb} +30 -22
  22. data/spec/binary/arg_parser_spec.rb +7 -7
  23. data/spec/binary/clean_body_spec.rb +217 -0
  24. data/spec/binary/comment_formatter_spec.rb +54 -0
  25. data/spec/binary/comment_lines_spec.rb +847 -0
  26. data/spec/binary/rewrite_comments_spec.rb +54 -0
  27. data/spec/seeing_is_believing_spec.rb +1 -2
  28. data/spec/{program_rewriter_spec.rb → wrap_expressions_spec.rb} +117 -40
  29. metadata +41 -56
  30. data/lib/seeing_is_believing/binary/line_formatter.rb +0 -47
  31. data/lib/seeing_is_believing/binary/remove_previous_annotations.rb +0 -75
  32. data/lib/seeing_is_believing/queue.rb +0 -55
  33. data/lib/seeing_is_believing/remove_inline_comments.rb +0 -46
  34. data/lib/seeing_is_believing/syntax_analyzer.rb +0 -61
  35. data/lib/seeing_is_believing/tracks_line_numbers_seen.rb +0 -19
  36. data/spec/binary/line_formatter_spec.rb +0 -53
  37. data/spec/binary/remove_previous_annotations_spec.rb +0 -198
  38. data/spec/queue_spec.rb +0 -80
  39. 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
- (min_line_number..max_line_number).each { |line_number| block.call self[line_number] }
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
- $seeing_is_believing_current_result = SeeingIsBelieving::Result.new
12
+ $SiB = SeeingIsBelieving::Result.new
13
13
 
14
14
  at_exit do
15
- $seeing_is_believing_current_result.stdout = fake_stdout.string
16
- $seeing_is_believing_current_result.stderr = fake_stderr.string
15
+ $SiB.stdout = fake_stdout.string
16
+ $SiB.stderr = fake_stderr.string
17
17
 
18
- $seeing_is_believing_current_result.exitstatus ||= 0
19
- $seeing_is_believing_current_result.exitstatus = 1 if $!
20
- $seeing_is_believing_current_result.exitstatus = $!.status if $!.kind_of? SystemExit
21
- $seeing_is_believing_current_result.bug_in_sib = $! && ! $!.kind_of?(SystemExit)
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 $seeing_is_believing_current_result
23
+ real_stdout.write YAML.dump $SiB
24
24
  end
@@ -1,3 +1,3 @@
1
1
  class SeeingIsBelieving
2
- VERSION = '2.0.0.beta1'
2
+ VERSION = '2.0.0.beta2'
3
3
  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 merged in
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 ProgramReWriter
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
- rewriter.insert_after root.location.expression, after_all
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.location.expression.source.start_with? '['
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(ast.children.last.children.last).location.expression.end_pos
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
- # can have one or two children:
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
- # the last arg is not a heredoc, the range of the expression can be trusted
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([])[:result_length].should == Float::INFINITY
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'])[:result_length].should == 10
130
- parse(['--result-length', '10'])[:result_length].should == 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 ':line_length' do
136
+ describe ':max_line_length' do
137
137
  it 'defaults to infinity' do
138
- parse([])[:line_length].should == Float::INFINITY
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'])[:line_length].should == 10
143
- parse(['--line-length', '10'])[:line_length].should == 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