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