seeing_is_believing 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +29 -0
- data/bin/seeing_is_believing +3 -12
- data/features/binary_errors.feature +44 -0
- data/features/{binary.feature → binary_examples.feature} +43 -20
- data/lib/seeing_is_believing/binary.rb +52 -0
- data/lib/seeing_is_believing/evaluate_by_moving_files.rb +1 -2
- data/lib/seeing_is_believing/expression_list.rb +1 -0
- data/lib/seeing_is_believing/{example_use.rb → print_results_next_to_lines.rb} +1 -1
- data/lib/seeing_is_believing/result.rb +21 -2
- data/lib/seeing_is_believing/the_matrix.rb +1 -2
- data/lib/seeing_is_believing/version.rb +1 -1
- data/lib/seeing_is_believing.rb +1 -1
- data/spec/expression_list_spec.rb +11 -0
- data/spec/seeing_is_believing_spec.rb +9 -8
- data/spec/syntax_analyzer_spec.rb +4 -2
- metadata +15 -11
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
desc 'run specs'
|
2
|
+
task :spec do
|
3
|
+
sh 'rspec -cf d --fail-fast'
|
4
|
+
end
|
5
|
+
|
6
|
+
desc 'run cukes'
|
7
|
+
task :cuke do
|
8
|
+
sh 'cucumber -t ~@not-implemented -t ~@wip'
|
9
|
+
end
|
10
|
+
|
11
|
+
namespace :cuke do
|
12
|
+
desc 'Run work in progress cukes'
|
13
|
+
task :wip do
|
14
|
+
sh 'cucumber -t @wip'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
namespace :spec do
|
19
|
+
desc 'Run work in progress specs'
|
20
|
+
task :wip do
|
21
|
+
sh 'rspec -t wip'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Run work in progress specs and cukes'
|
26
|
+
task wip: ['spec:wip', 'cuke:wip']
|
27
|
+
|
28
|
+
desc 'Run all specs and cukes'
|
29
|
+
task default: [:spec, :cuke]
|
data/bin/seeing_is_believing
CHANGED
@@ -1,17 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
$LOAD_PATH.unshift File.expand_path '../../lib', __FILE__
|
4
|
-
require 'seeing_is_believing/example_use'
|
5
4
|
|
6
|
-
|
5
|
+
require 'open3'
|
6
|
+
require 'seeing_is_believing/binary'
|
7
7
|
|
8
|
-
ARGV
|
9
|
-
believer = SeeingIsBelieving::ExampleUse.new File.read(filename), filename
|
10
|
-
$stdout.puts believer.call
|
11
|
-
if believer.has_exception?
|
12
|
-
$stderr.puts believer.exception.message
|
13
|
-
status = 1
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
exit status
|
8
|
+
exit SeeingIsBelieving::Binary.new(ARGV, $stdin, $stdout, $stderr).exitstatus
|
@@ -0,0 +1,44 @@
|
|
1
|
+
Feature: Running the binary unsuccessfully
|
2
|
+
|
3
|
+
Sometimes I mess up and use the program in a way that doesn't work.
|
4
|
+
I'd like it to be helpful in these situations so I can fix my use.
|
5
|
+
|
6
|
+
Scenario: Raising exceptions
|
7
|
+
Given the file "raises_exception.rb":
|
8
|
+
"""
|
9
|
+
raise "ZOMG!"
|
10
|
+
"""
|
11
|
+
And the file "requires_exception_raising_code.rb":
|
12
|
+
"""
|
13
|
+
1 + 1
|
14
|
+
require_relative 'raises_exception'
|
15
|
+
1 + 1
|
16
|
+
"""
|
17
|
+
When I run "seeing_is_believing requires_exception_raising_code.rb"
|
18
|
+
Then stderr is "ZOMG!"
|
19
|
+
And the exit status is 1
|
20
|
+
And stdout is:
|
21
|
+
"""
|
22
|
+
1 + 1 # => 2
|
23
|
+
require_relative 'raises_exception' # ~> RuntimeError: ZOMG!
|
24
|
+
1 + 1
|
25
|
+
"""
|
26
|
+
|
27
|
+
Scenario: Syntactically invalid file
|
28
|
+
Given the file "invalid_syntax.rb":
|
29
|
+
"""
|
30
|
+
'abc
|
31
|
+
"""
|
32
|
+
When I run "seeing_is_believing invalid_syntax.rb"
|
33
|
+
Then stderr is:
|
34
|
+
"""
|
35
|
+
invalid_syntax.rb:1: unterminated string meets end of file
|
36
|
+
"""
|
37
|
+
And the exit status is 1
|
38
|
+
And stdout is empty
|
39
|
+
|
40
|
+
Scenario: Passing a nonexistent file
|
41
|
+
When I run "seeing_is_believing this_file_does_not_exist.rb"
|
42
|
+
Then stderr is "this_file_does_not_exist.rb does not exist!"
|
43
|
+
And the exit status is 1
|
44
|
+
And stdout is empty
|
@@ -1,4 +1,5 @@
|
|
1
|
-
Feature: Running the binary
|
1
|
+
Feature: Running the binary successfully
|
2
|
+
|
2
3
|
They say seeing is believing. So to believe that this works
|
3
4
|
I want to see that it works by making a binary to use the lib.
|
4
5
|
|
@@ -48,23 +49,6 @@ Feature: Running the binary
|
|
48
49
|
c" # => "a\n b\n c"
|
49
50
|
"""
|
50
51
|
|
51
|
-
Scenario: Raising exceptions
|
52
|
-
Given the file "raises_exception.rb":
|
53
|
-
"""
|
54
|
-
1 + 1
|
55
|
-
raise "ZOMG!"
|
56
|
-
1 + 1
|
57
|
-
"""
|
58
|
-
When I run "seeing_is_believing raises_exception.rb"
|
59
|
-
Then stderr is "ZOMG!"
|
60
|
-
And the exit status is 1
|
61
|
-
And stdout is:
|
62
|
-
"""
|
63
|
-
1 + 1 # => 2
|
64
|
-
raise "ZOMG!" # ~> RuntimeError: ZOMG!
|
65
|
-
1 + 1
|
66
|
-
"""
|
67
|
-
|
68
52
|
Scenario: Passing previous output back into input
|
69
53
|
Given the file "previous_output.rb":
|
70
54
|
"""
|
@@ -145,8 +129,47 @@ Feature: Running the binary
|
|
145
129
|
2
|
146
130
|
"""
|
147
131
|
|
132
|
+
@not-implemented
|
133
|
+
Scenario: Doesn't record BEGIN/END since that's apparently a syntax error
|
134
|
+
Given the file "BEGIN_and_END.rb":
|
135
|
+
"""
|
136
|
+
puts 1
|
137
|
+
BEGIN {
|
138
|
+
puts "begin code"
|
139
|
+
some_var = 2
|
140
|
+
}
|
141
|
+
puts 3
|
142
|
+
END {
|
143
|
+
puts "end code"
|
144
|
+
puts some_var
|
145
|
+
}
|
146
|
+
puts 4
|
147
|
+
"""
|
148
|
+
When I run "seeing_is_believing BEGIN_and_END.rb"
|
149
|
+
Then stderr is empty
|
150
|
+
And the exit status is 0
|
151
|
+
And stdout is:
|
152
|
+
"""
|
153
|
+
puts 1 # => nil
|
154
|
+
BEGIN {
|
155
|
+
puts "begin code" # => nil
|
156
|
+
some_var = 2 # => 2
|
157
|
+
}
|
158
|
+
puts 3 # => nil
|
159
|
+
END {
|
160
|
+
puts "end code" # => nil
|
161
|
+
puts some_var # => nil
|
162
|
+
}
|
163
|
+
puts 4 # => nil
|
164
|
+
|
165
|
+
# >> begin code
|
166
|
+
# >> 1
|
167
|
+
# >> 3
|
168
|
+
# >> 4
|
169
|
+
# >> end code
|
170
|
+
# >> 2
|
171
|
+
"""
|
172
|
+
|
148
173
|
Scenario: Requiring other files
|
149
|
-
Scenario: Syntactically invalid file
|
150
|
-
Scenario: Passing a nonexistent file
|
151
174
|
Scenario: Evaluating a file that requires other files, from a different directory
|
152
175
|
Scenario: Passing the file on stdin
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'seeing_is_believing/print_results_next_to_lines'
|
2
|
+
|
3
|
+
class SeeingIsBelieving
|
4
|
+
class Binary
|
5
|
+
attr_accessor :argv, :stdin, :stdout, :stderr
|
6
|
+
|
7
|
+
def initialize(argv, stdin, stdout, stderr)
|
8
|
+
self.argv = argv
|
9
|
+
self.stdin = stdin
|
10
|
+
self.stdout = stdout
|
11
|
+
self.stderr = stderr
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
return if @already_called
|
16
|
+
@already_called = true
|
17
|
+
|
18
|
+
unless File.exist? filename
|
19
|
+
@exitstatus = 1
|
20
|
+
stderr.puts "#{filename} does not exist!"
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
out, err, syntax_status = Open3.capture3('ruby', '-c', filename)
|
25
|
+
unless syntax_status.success?
|
26
|
+
@exitstatus = 1
|
27
|
+
stderr.puts err
|
28
|
+
return
|
29
|
+
end
|
30
|
+
|
31
|
+
believer = SeeingIsBelieving::PrintResultsNextToLines.new File.read(filename), filename
|
32
|
+
stdout.puts believer.call
|
33
|
+
if believer.has_exception?
|
34
|
+
stderr.puts believer.exception.message
|
35
|
+
@exitstatus = 1
|
36
|
+
else
|
37
|
+
@exitstatus = 0
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def exitstatus
|
42
|
+
call
|
43
|
+
@exitstatus
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def filename
|
49
|
+
argv.first
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -11,7 +11,6 @@
|
|
11
11
|
# I did look at Ripper, and it will invoke on_kw("__FILE__")
|
12
12
|
# when it sees this.
|
13
13
|
|
14
|
-
require 'yaml'
|
15
14
|
require 'open3'
|
16
15
|
require 'fileutils'
|
17
16
|
require 'seeing_is_believing/error'
|
@@ -99,7 +98,7 @@ class SeeingIsBelieving
|
|
99
98
|
end
|
100
99
|
|
101
100
|
def deserialize_result
|
102
|
-
|
101
|
+
Marshal.load stdout
|
103
102
|
end
|
104
103
|
|
105
104
|
def record_error
|
@@ -1,10 +1,29 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
require 'seeing_is_believing/has_exception'
|
2
3
|
require 'seeing_is_believing/tracks_line_numbers_seen'
|
3
4
|
|
4
5
|
class SeeingIsBelieving
|
5
6
|
class Result
|
6
7
|
|
7
|
-
Line
|
8
|
+
class Line
|
9
|
+
include HasException
|
10
|
+
|
11
|
+
extend Forwardable
|
12
|
+
def_delegators :@array, :[], :<<, :any?, :join, :to_ary, :to_a
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@array ||= []
|
16
|
+
end
|
17
|
+
|
18
|
+
def ==(ary_or_line)
|
19
|
+
if Array === ary_or_line
|
20
|
+
@array == ary_or_line
|
21
|
+
else
|
22
|
+
@array == ary_or_line &&
|
23
|
+
has_exception? == ary_or_line.has_exception?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
8
27
|
|
9
28
|
include HasException
|
10
29
|
include TracksLineNumbersSeen
|
@@ -42,7 +61,7 @@ class SeeingIsBelieving
|
|
42
61
|
# probably not really useful, just exists to satisfy the tests, which specified too simple of an interface
|
43
62
|
def to_a
|
44
63
|
(min_line_number..max_line_number).map do |line_number|
|
45
|
-
[line_number, [*self[line_number], *Array(self[line_number].exception)]]
|
64
|
+
[line_number, [*self[line_number].to_ary, *Array(self[line_number].exception)]]
|
46
65
|
end
|
47
66
|
end
|
48
67
|
|
@@ -7,7 +7,6 @@ real_stderr = STDERR
|
|
7
7
|
STDOUT = $stdout = fake_stdout = StringIO.new
|
8
8
|
STDERR = $stderr = fake_stderr = StringIO.new
|
9
9
|
|
10
|
-
require 'yaml'
|
11
10
|
require 'seeing_is_believing/result'
|
12
11
|
$seeing_is_believing_current_result = SeeingIsBelieving::Result.new
|
13
12
|
|
@@ -15,5 +14,5 @@ at_exit do
|
|
15
14
|
$seeing_is_believing_current_result.stdout = fake_stdout.string
|
16
15
|
$seeing_is_believing_current_result.stderr = fake_stderr.string
|
17
16
|
|
18
|
-
real_stdout.write
|
17
|
+
real_stdout.write Marshal.dump $seeing_is_believing_current_result
|
19
18
|
end
|
data/lib/seeing_is_believing.rb
CHANGED
@@ -57,7 +57,7 @@ class SeeingIsBelieving
|
|
57
57
|
"begin;"\
|
58
58
|
"#{code}\n"\
|
59
59
|
"rescue Exception;"\
|
60
|
-
"line_number = $!.backtrace.first[/:\\d+:/][1..-2].to_i;"\
|
60
|
+
"line_number = $!.backtrace.grep(/\#{__FILE__}/).first[/:\\d+:/][1..-2].to_i;"\
|
61
61
|
"$seeing_is_believing_current_result.record_exception line_number, $!;"\
|
62
62
|
"end"
|
63
63
|
end
|
@@ -131,4 +131,15 @@ describe SeeingIsBelieving::ExpressionList do
|
|
131
131
|
stream.string.should include "GENERATED"
|
132
132
|
stream.string.should include "REDUCED"
|
133
133
|
end
|
134
|
+
|
135
|
+
# in reality, the problem may just lie with our lib
|
136
|
+
# but it should be correct in most cases
|
137
|
+
it 'Raises a syntax error if it cannot generate the expression' do
|
138
|
+
generations = ["'"]
|
139
|
+
expect do
|
140
|
+
described_class.new(
|
141
|
+
on_complete: -> { "" }, generator: -> { generations.shift }
|
142
|
+
).call
|
143
|
+
end.to raise_error SyntaxError
|
144
|
+
end
|
134
145
|
end
|
@@ -125,10 +125,11 @@ describe SeeingIsBelieving do
|
|
125
125
|
|
126
126
|
result[3].should == []
|
127
127
|
result.to_a.size.should == 3
|
128
|
+
end
|
128
129
|
|
129
|
-
|
130
|
-
|
131
|
-
|
130
|
+
it 'records the backtrace on the errors' do
|
131
|
+
result = invoke("12\nraise Exception, 'omg!'\n12")
|
132
|
+
result.exception.backtrace.should be_a_kind_of Array
|
132
133
|
end
|
133
134
|
|
134
135
|
it 'does not fuck up __LINE__ macro' do
|
@@ -149,9 +150,8 @@ describe SeeingIsBelieving do
|
|
149
150
|
values_for("def meth \n return 1 if true \n end \n meth").should == [[], [], ['nil'], ['1']]
|
150
151
|
values_for("def meth \n return 1 if false \n end \n meth").should == [[], [], ['nil'], ['nil']]
|
151
152
|
values_for("-> { \n return 1 \n }.call" ).should == [[], [], ['1']]
|
152
|
-
|
153
|
-
|
154
|
-
end
|
153
|
+
# this doesn't work because the return detecting code is a very conservative regexp
|
154
|
+
# values_for("-> { return 1 }.call" ).should == [['1']]
|
155
155
|
end
|
156
156
|
|
157
157
|
it 'does not affect its environment' do
|
@@ -201,6 +201,7 @@ describe SeeingIsBelieving do
|
|
201
201
|
values_for("1+1\nDATA.read\n__END__\n....").should == [['2'], ['"...."']]
|
202
202
|
end
|
203
203
|
|
204
|
-
|
205
|
-
|
204
|
+
it 'raises a SyntaxError when the whole program is invalid' do
|
205
|
+
expect { invoke '"' }.to raise_error SyntaxError
|
206
|
+
end
|
206
207
|
end
|
@@ -121,10 +121,12 @@ describe SeeingIsBelieving::SyntaxAnalyzer do
|
|
121
121
|
will_return["o.return"].should be_false
|
122
122
|
will_return[":return"].should be_false
|
123
123
|
will_return["'return'"].should be_false
|
124
|
-
# will_return["'return\nreturn\nreturn'"].should be_false
|
125
124
|
will_return["def a\nreturn 1\nend"].should be_false
|
126
125
|
will_return["-> {\nreturn 1\n}"].should be_false
|
127
126
|
will_return["Proc.new {\nreturn 1\n}"].should be_false
|
128
|
-
|
127
|
+
pending "this doesn't work because the return detecting code is an insufficient regexp" do
|
128
|
+
will_return["'return\nreturn\nreturn'"].should be_false
|
129
|
+
will_return["return \\\n1"].should be_true
|
130
|
+
end
|
129
131
|
end
|
130
132
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: seeing_is_believing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70333793492220 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 2.12.0
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70333793492220
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: cucumber
|
27
|
-
requirement: &
|
27
|
+
requirement: &70333793491440 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.2.1
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70333793491440
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: ichannel
|
38
|
-
requirement: &
|
38
|
+
requirement: &70333793490760 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: 5.1.1
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70333793490760
|
47
47
|
description: Records the results of every line of code in your file (intended to be
|
48
48
|
like xmpfilter), inspired by Bret Victor's JavaScript example in his talk "Inventing
|
49
49
|
on Principle"
|
@@ -57,18 +57,21 @@ files:
|
|
57
57
|
- .gitignore
|
58
58
|
- Gemfile
|
59
59
|
- Gemfile.lock
|
60
|
+
- Rakefile
|
60
61
|
- Readme.md
|
61
62
|
- bin/seeing_is_believing
|
62
|
-
- features/
|
63
|
+
- features/binary_errors.feature
|
64
|
+
- features/binary_examples.feature
|
63
65
|
- features/step_definitions/steps.rb
|
64
66
|
- features/support/env.rb
|
65
67
|
- lib/seeing_is_believing.rb
|
68
|
+
- lib/seeing_is_believing/binary.rb
|
66
69
|
- lib/seeing_is_believing/error.rb
|
67
70
|
- lib/seeing_is_believing/evaluate_by_moving_files.rb
|
68
|
-
- lib/seeing_is_believing/example_use.rb
|
69
71
|
- lib/seeing_is_believing/expression_list.rb
|
70
72
|
- lib/seeing_is_believing/hard_core_ensure.rb
|
71
73
|
- lib/seeing_is_believing/has_exception.rb
|
74
|
+
- lib/seeing_is_believing/print_results_next_to_lines.rb
|
72
75
|
- lib/seeing_is_believing/result.rb
|
73
76
|
- lib/seeing_is_believing/syntax_analyzer.rb
|
74
77
|
- lib/seeing_is_believing/the_matrix.rb
|
@@ -105,7 +108,8 @@ signing_key:
|
|
105
108
|
specification_version: 3
|
106
109
|
summary: Records results of every line of code in your file
|
107
110
|
test_files:
|
108
|
-
- features/
|
111
|
+
- features/binary_errors.feature
|
112
|
+
- features/binary_examples.feature
|
109
113
|
- features/step_definitions/steps.rb
|
110
114
|
- features/support/env.rb
|
111
115
|
- spec/evaluate_by_moving_files_spec.rb
|