seeing_is_believing 0.0.1
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.
- data/.gitignore +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +34 -0
- data/bin/seeing_is_believing +8 -0
- data/features/binary.feature +35 -0
- data/features/step_definitions/steps.rb +19 -0
- data/features/support/env.rb +54 -0
- data/lib/seeing_is_believing.rb +58 -0
- data/lib/seeing_is_believing/example_use.rb +40 -0
- data/lib/seeing_is_believing/expression_list.rb +74 -0
- data/lib/seeing_is_believing/result.rb +48 -0
- data/lib/seeing_is_believing/version.rb +3 -0
- data/seeing_is_believing.gemspec +23 -0
- data/spec/expression_list_spec.rb +107 -0
- data/spec/seeing_is_believing_spec.rb +116 -0
- metadata +90 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
seeing_is_believing (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
builder (3.1.4)
|
10
|
+
cucumber (1.2.1)
|
11
|
+
builder (>= 2.1.2)
|
12
|
+
diff-lcs (>= 1.1.3)
|
13
|
+
gherkin (~> 2.11.0)
|
14
|
+
json (>= 1.4.6)
|
15
|
+
diff-lcs (1.1.3)
|
16
|
+
gherkin (2.11.5)
|
17
|
+
json (>= 1.4.6)
|
18
|
+
json (1.7.6)
|
19
|
+
rspec (2.12.0)
|
20
|
+
rspec-core (~> 2.12.0)
|
21
|
+
rspec-expectations (~> 2.12.0)
|
22
|
+
rspec-mocks (~> 2.12.0)
|
23
|
+
rspec-core (2.12.2)
|
24
|
+
rspec-expectations (2.12.1)
|
25
|
+
diff-lcs (~> 1.1.3)
|
26
|
+
rspec-mocks (2.12.1)
|
27
|
+
|
28
|
+
PLATFORMS
|
29
|
+
ruby
|
30
|
+
|
31
|
+
DEPENDENCIES
|
32
|
+
cucumber (~> 1.2.1)
|
33
|
+
rspec (~> 2.12.0)
|
34
|
+
seeing_is_believing!
|
@@ -0,0 +1,35 @@
|
|
1
|
+
Feature: Running the binary
|
2
|
+
They say seeing is believing. So to believe that this works
|
3
|
+
I want to see that it works by making a binary to use the lib.
|
4
|
+
|
5
|
+
It should be approximately like xmpfilter, except that it should
|
6
|
+
run against every line.
|
7
|
+
|
8
|
+
Scenario: Some basic functionality
|
9
|
+
Given the file "f.rb":
|
10
|
+
"""
|
11
|
+
a = '12'
|
12
|
+
a + a
|
13
|
+
|
14
|
+
5.times do |i|
|
15
|
+
i * 2
|
16
|
+
end
|
17
|
+
"""
|
18
|
+
When I run "seeing_is_believing f.rb"
|
19
|
+
And stderr is empty
|
20
|
+
Then the exit status is 0
|
21
|
+
And stdout is:
|
22
|
+
"""
|
23
|
+
a = '12' # => "12"
|
24
|
+
a + a # => "1212"
|
25
|
+
|
26
|
+
5.times do |i|
|
27
|
+
i * 2 # => 0, 2, 4, 6, 8
|
28
|
+
end # => 5
|
29
|
+
|
30
|
+
"""
|
31
|
+
|
32
|
+
Scenario: Printing within the file
|
33
|
+
Scenario: Raising exceptions
|
34
|
+
Scenario: Requiring other files
|
35
|
+
Scenario: Syntactically invalid file
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Given 'the file "$filename":' do |filename, body|
|
2
|
+
CommandLineHelpers.write_file filename, body
|
3
|
+
end
|
4
|
+
|
5
|
+
When 'I run "$command"' do |command|
|
6
|
+
@last_executed = CommandLineHelpers.execute command
|
7
|
+
end
|
8
|
+
|
9
|
+
Then /^(stderr|stdout) is:$/ do |stream_name, output|
|
10
|
+
@last_executed.send(stream_name).should == output
|
11
|
+
end
|
12
|
+
|
13
|
+
Then 'the exit status is $status' do |status|
|
14
|
+
@last_executed.exitstatus.to_s.should == status
|
15
|
+
end
|
16
|
+
|
17
|
+
Then /^(stderr|stdout) is empty$/ do |stream_name|
|
18
|
+
@last_executed.send(stream_name).should == ''
|
19
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'open3'
|
3
|
+
|
4
|
+
|
5
|
+
module CommandLineHelpers
|
6
|
+
Invocation = Struct.new :stdout, :stderr, :status do
|
7
|
+
def exitstatus
|
8
|
+
status.exitstatus
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
extend self
|
13
|
+
|
14
|
+
def write_file(filename, body)
|
15
|
+
in_proving_grounds do
|
16
|
+
File.open(filename, 'w') { |file| file.write body }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute(command)
|
21
|
+
in_proving_grounds do
|
22
|
+
command = "PATH=#{bin_dir}:$PATH #{command}"
|
23
|
+
Invocation.new *Open3.capture3(command)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def in_proving_grounds(&block)
|
28
|
+
Dir.chdir proving_grounds_dir, &block
|
29
|
+
end
|
30
|
+
|
31
|
+
def proving_grounds_dir
|
32
|
+
File.join root_dir, 'proving_grounds'
|
33
|
+
end
|
34
|
+
|
35
|
+
def root_dir
|
36
|
+
@root_dir ||= begin
|
37
|
+
dir = Dir.pwd
|
38
|
+
until Dir.glob("#{dir}/*").map(&File.method(:basename)).include?("features")
|
39
|
+
dir = File.expand_path File.dirname dir
|
40
|
+
end
|
41
|
+
dir
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def make_proving_grounds
|
46
|
+
FileUtils.mkdir_p proving_grounds_dir
|
47
|
+
end
|
48
|
+
|
49
|
+
def bin_dir
|
50
|
+
File.join root_dir, "bin"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
CommandLineHelpers.make_proving_grounds
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
require 'seeing_is_believing/result'
|
4
|
+
require 'seeing_is_believing/expression_list'
|
5
|
+
|
6
|
+
# might not work on windows b/c of assumptions about line ends
|
7
|
+
class SeeingIsBelieving
|
8
|
+
def initialize(string_or_stream)
|
9
|
+
@stream = to_stream string_or_stream
|
10
|
+
@result = Result.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
@memoized_result ||= begin
|
15
|
+
program = ''
|
16
|
+
program << expression_list.call until stream.eof?
|
17
|
+
$seeing_is_believing_current_result = @result # can we make this a threadlocal var on the class?
|
18
|
+
TOPLEVEL_BINDING.eval record_exceptions_in(program), 'program.rb', 1
|
19
|
+
@result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :stream
|
26
|
+
|
27
|
+
def expression_list
|
28
|
+
@expression_list ||= ExpressionList.new generator: lambda { stream.gets.chomp },
|
29
|
+
on_complete: lambda { |line, children, completions, line_number|
|
30
|
+
@result.contains_line_number line_number
|
31
|
+
expression = [line, *children, *completions].join("\n")
|
32
|
+
if expression == ''
|
33
|
+
expression
|
34
|
+
else
|
35
|
+
record_yahself expression, line_number
|
36
|
+
end
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_stream(string_or_stream)
|
41
|
+
return string_or_stream if string_or_stream.respond_to? :gets
|
42
|
+
StringIO.new string_or_stream
|
43
|
+
end
|
44
|
+
|
45
|
+
def record_yahself(line, line_number)
|
46
|
+
"($seeing_is_believing_current_result.record_result(#{line_number}, (#{line})))\n"
|
47
|
+
end
|
48
|
+
|
49
|
+
def record_exceptions_in(code)
|
50
|
+
require 'pp'
|
51
|
+
"begin;"\
|
52
|
+
"#{code};"\
|
53
|
+
"rescue Exception;"\
|
54
|
+
"line_number = $!.backtrace.first[/:\\d+:/][1..-2].to_i;"\
|
55
|
+
"$seeing_is_believing_current_result.record_exception line_number, $!;"\
|
56
|
+
"end"
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'seeing_is_believing'
|
2
|
+
|
3
|
+
class SeeingIsBelieving
|
4
|
+
class ExampleUse
|
5
|
+
def initialize(body)
|
6
|
+
self.body = body
|
7
|
+
end
|
8
|
+
|
9
|
+
def call
|
10
|
+
body.each_line.with_index 1 do |line, index|
|
11
|
+
write_line line.chomp, results[index], line_length
|
12
|
+
end
|
13
|
+
output
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_accessor :body
|
19
|
+
|
20
|
+
def results
|
21
|
+
@results ||= SeeingIsBelieving.new(body).call
|
22
|
+
end
|
23
|
+
|
24
|
+
def output
|
25
|
+
@result ||= ''
|
26
|
+
end
|
27
|
+
|
28
|
+
def write_line(line, results, line_length)
|
29
|
+
if results.any?
|
30
|
+
output << sprintf("%-#{line_length}s# => %s\n", line, results.join(', '))
|
31
|
+
else
|
32
|
+
output << line << "\n"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def line_length
|
37
|
+
@line_length ||= body.each_line.map(&:chomp).map(&:length).max + 2
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
class SeeingIsBelieving
|
4
|
+
class ExpressionList
|
5
|
+
PendingExpression = Struct.new :expression, :children do
|
6
|
+
def inspect(debug=false)
|
7
|
+
colour1 = colour2 = lambda { |s| s }
|
8
|
+
colour1 = lambda { |s| "\e[30;46m#{s}\e[0m" } if debug
|
9
|
+
colour2 = lambda { |s| "\e[37;46m#{s}\e[0m" } if debug
|
10
|
+
"#{colour1['PE(']}#{colour2[expression.inspect]}#{colour1[',' ]}#{colour2[children.inspect]}#{colour1[')']}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(options)
|
15
|
+
self.debug_stream = options.fetch :debug_stream, $stdout
|
16
|
+
self.should_debug = options.fetch :debug, false
|
17
|
+
self.generator = options.fetch :generator
|
18
|
+
self.on_complete = options.fetch :on_complete
|
19
|
+
self.line_number = 0
|
20
|
+
self.list = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def call
|
24
|
+
expression = nil
|
25
|
+
begin
|
26
|
+
generate
|
27
|
+
expression = reduce_expressions
|
28
|
+
end until list.empty?
|
29
|
+
expression
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_accessor :debug_stream, :should_debug, :generator, :on_complete, :line_number, :list
|
35
|
+
|
36
|
+
def generate
|
37
|
+
@line_number += 1
|
38
|
+
expression = generator.call
|
39
|
+
debug? && debug("GENERATED: #{expression.inspect}, ADDING IT TO #{inspected_list}")
|
40
|
+
@list << PendingExpression.new(expression, [])
|
41
|
+
end
|
42
|
+
|
43
|
+
def inspected_list
|
44
|
+
"[#{@list.map { |pe| pe.inspect debug? }.join(', ')}]"
|
45
|
+
end
|
46
|
+
|
47
|
+
def debug?
|
48
|
+
@should_debug
|
49
|
+
end
|
50
|
+
|
51
|
+
def debug(message)
|
52
|
+
@debug_stream.puts message
|
53
|
+
end
|
54
|
+
|
55
|
+
def reduce_expressions
|
56
|
+
@list.size.times do |i|
|
57
|
+
expression = @list[i..-1].map(&:expression).join("\n") # must use newline otherwise can get expressions like `a\\+b` that should be `a\\\n+b`, former is invalid
|
58
|
+
next unless valid_ruby? expression
|
59
|
+
result = on_complete.call(@list[i].expression,
|
60
|
+
@list[i].children,
|
61
|
+
@list[i+1..-1].map { |pe| [pe.expression, pe.children] }.flatten, # hmmm, not sure this is really correct, but it allows it to work for my use cases
|
62
|
+
@line_number)
|
63
|
+
@list = @list[0, i]
|
64
|
+
@list[i-1].children << result unless @list.empty?
|
65
|
+
debug? && debug("RESULT: #{result.inspect}, LIST: [#{@list.map { |e| e.inspect debug? }.join(', ')}]")
|
66
|
+
return result
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def valid_ruby?(expression)
|
71
|
+
Open3.capture3('ruby -c', stdin_data: expression).last.success?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class SeeingIsBelieving
|
2
|
+
class Result
|
3
|
+
attr_reader :min_line_number, :max_line_number
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@min_line_number = @max_line_number = 1
|
7
|
+
end
|
8
|
+
|
9
|
+
def record_result(line_number, value)
|
10
|
+
contains_line_number line_number
|
11
|
+
results[line_number] << value.inspect
|
12
|
+
value
|
13
|
+
end
|
14
|
+
|
15
|
+
def record_exception(line_number, exception)
|
16
|
+
contains_line_number line_number
|
17
|
+
@exception_line_number = line_number
|
18
|
+
@exception = exception
|
19
|
+
end
|
20
|
+
|
21
|
+
def [](line_number)
|
22
|
+
results[line_number]
|
23
|
+
end
|
24
|
+
|
25
|
+
# uhm, maybe switch to #each and including Enumerable?
|
26
|
+
def to_a
|
27
|
+
(min_line_number..max_line_number).map do |line_number|
|
28
|
+
[line_number, [*self[line_number], *Array(exception_at line_number)]]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def contains_line_number(line_number)
|
33
|
+
@min_line_number = line_number if line_number < @min_line_number
|
34
|
+
@max_line_number = line_number if line_number > @max_line_number
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def exception_at(line_number)
|
40
|
+
return unless @exception_line_number == line_number
|
41
|
+
@exception
|
42
|
+
end
|
43
|
+
|
44
|
+
def results
|
45
|
+
@results ||= Hash.new { |hash, line_number| hash[line_number] = [] }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "seeing_is_believing/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "seeing_is_believing"
|
7
|
+
s.version = SeeingIsBelieving::VERSION
|
8
|
+
s.authors = ["Josh Cheek"]
|
9
|
+
s.email = ["josh.cheek@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/JoshCheek/seeing_is_believing"
|
11
|
+
s.summary = %q{Records results of every line of code in your file}
|
12
|
+
s.description = %q{Records the results of every line of code in your file (intended to be like xmpfilter), inspired by Brett Victor's JavaScript example in his talk "Inventing on Principle"}
|
13
|
+
|
14
|
+
s.rubyforge_project = "seeing_is_believing"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "rspec", "~> 2.12.0"
|
22
|
+
s.add_development_dependency "cucumber", "~> 1.2.1"
|
23
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'seeing_is_believing/expression_list'
|
2
|
+
|
3
|
+
describe SeeingIsBelieving::ExpressionList do
|
4
|
+
|
5
|
+
def call(generations, options={}, &block)
|
6
|
+
options = { on_complete: block, generator: -> { generations.shift || raise("EMPTY!") } }.merge(options)
|
7
|
+
described_class.new(options).call
|
8
|
+
end
|
9
|
+
|
10
|
+
example 'example: multiple children' do
|
11
|
+
block_invocations = 0
|
12
|
+
result = call %w[a( b+ c x\\ + y )] do |line, children, completions, line_number|
|
13
|
+
case line_number
|
14
|
+
when 3
|
15
|
+
line.should == 'b+'
|
16
|
+
children.should == []
|
17
|
+
completions.should == ['c']
|
18
|
+
block_invocations += 1
|
19
|
+
'b+c'
|
20
|
+
when 6
|
21
|
+
line.should == 'x\\'
|
22
|
+
children.should == []
|
23
|
+
completions.should == ['+', 'y']
|
24
|
+
block_invocations += 10
|
25
|
+
'x\\+y'
|
26
|
+
when 7
|
27
|
+
line.should == 'a('
|
28
|
+
children.should == ['b+c', 'x\\+y']
|
29
|
+
completions.should == [')']
|
30
|
+
block_invocations += 100
|
31
|
+
'ALL DONE!'
|
32
|
+
else
|
33
|
+
raise "line_number: #{line_number.inspect}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
result.should == 'ALL DONE!'
|
37
|
+
block_invocations.should == 111
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
example 'example: nested children' do
|
42
|
+
block_invocations = 0
|
43
|
+
expressions = [ '[1].map do |n1|',
|
44
|
+
' [2].map do |n2|',
|
45
|
+
' n1 + n2',
|
46
|
+
' end',
|
47
|
+
'end',
|
48
|
+
]
|
49
|
+
result = call expressions do |line, children, completions, line_number|
|
50
|
+
case line_number
|
51
|
+
when 3
|
52
|
+
[line, children, completions].should == [' n1 + n2', [], []]
|
53
|
+
block_invocations += 1
|
54
|
+
when 4
|
55
|
+
[line, children, completions].should == [' [2].map do |n2|', [' n1 + n2'], [' end']]
|
56
|
+
block_invocations += 10
|
57
|
+
when 5
|
58
|
+
[line, children, completions].should == ['[1].map do |n1|',
|
59
|
+
[" [2].map do |n2|\n n1 + n2\n end"],
|
60
|
+
['end']]
|
61
|
+
block_invocations += 100
|
62
|
+
else
|
63
|
+
raise "line_number: #{line_number.inspect}"
|
64
|
+
end
|
65
|
+
[line, *children, *completions].join("\n")
|
66
|
+
end
|
67
|
+
block_invocations.should == 111
|
68
|
+
result.should == "[1].map do |n1|\n"\
|
69
|
+
" [2].map do |n2|\n"\
|
70
|
+
" n1 + n2\n"\
|
71
|
+
" end\n"\
|
72
|
+
"end"
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
example 'example: completions that have children' do
|
77
|
+
block_invocations = 0
|
78
|
+
expressions = [ "[1].map do |n1|",
|
79
|
+
"[2].map do |n2|",
|
80
|
+
"n1 + n2",
|
81
|
+
"end end",
|
82
|
+
]
|
83
|
+
result = call expressions do |line, children, completions, line_number|
|
84
|
+
case line_number
|
85
|
+
when 3
|
86
|
+
[line, children, completions].should == ["n1 + n2", [], []]
|
87
|
+
block_invocations += 1
|
88
|
+
when 4
|
89
|
+
# not really sure what this *should* be like, but if this is the result,
|
90
|
+
# then it will work for the use cases I need it for
|
91
|
+
[line, *children, *completions].should == ["[1].map do |n1|",
|
92
|
+
"[2].map do |n2|",
|
93
|
+
"n1 + n2",
|
94
|
+
'end end']
|
95
|
+
block_invocations += 10
|
96
|
+
else
|
97
|
+
raise "line_number: #{line_number.inspect}"
|
98
|
+
end
|
99
|
+
[line, *children, *completions].join("\n")
|
100
|
+
end
|
101
|
+
block_invocations.should == 11
|
102
|
+
result.should == "[1].map do |n1|\n"\
|
103
|
+
"[2].map do |n2|\n"\
|
104
|
+
"n1 + n2\n"\
|
105
|
+
"end end"\
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'seeing_is_believing'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
describe SeeingIsBelieving do
|
5
|
+
def invoke(input)
|
6
|
+
described_class.new(input).call
|
7
|
+
end
|
8
|
+
|
9
|
+
def values_for(input)
|
10
|
+
invoke(input).to_a.map(&:last)
|
11
|
+
end
|
12
|
+
|
13
|
+
def stream(string)
|
14
|
+
StringIO.new string
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'takes a string or stream and returns a result of the line numbers (counting from 1) and each inspected result from that line' do
|
18
|
+
input = "1+1\n'2'+'2'"
|
19
|
+
output = [[1, ["2"]], [2, ['"22"']]]
|
20
|
+
invoke(input).to_a.should == output
|
21
|
+
invoke(stream input).to_a.should == output
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'remembers context of previous lines' do
|
25
|
+
values_for("a=12\na*2").should == [['12'], ['24']]
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'can be invoked multiple times, returning the same result' do
|
29
|
+
believer = described_class.new("$xyz||=1\n$xyz+=1")
|
30
|
+
believer.call.to_a.should == [[1, ['1']], [2, ['2']]]
|
31
|
+
believer.call.to_a.should == [[1, ['1']], [2, ['2']]]
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'is evaluated at the toplevel' do
|
35
|
+
values_for('self').should == [['main']]
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'records the value immediately, so that it is correct even if the result is mutated' do
|
39
|
+
values_for("a = 'a'\na << 'b'").should == [['"a"'], ['"ab"']]
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'records each value when a line is evaluated multiple times' do
|
43
|
+
values_for("(1..2).each do |i|\ni\nend").should == [[], ['1', '2'], ['1..2']]
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'evalutes to an empty array for lines that it cannot understand' do
|
47
|
+
values_for("[3].map do |n|\n n*2\n end").should == [[], ['6'], ['[6]']]
|
48
|
+
values_for("[1].map do |n1|
|
49
|
+
[2].map do |n2|
|
50
|
+
n1 + n2
|
51
|
+
end
|
52
|
+
end").should == [[], [], ['3'], ['[3]'], ['[[3]]']]
|
53
|
+
|
54
|
+
values_for("[1].map do |n1|
|
55
|
+
[2].map do |n2| n1 + n2
|
56
|
+
end
|
57
|
+
end").should == [[], [], ['[3]'], ['[[3]]']]
|
58
|
+
|
59
|
+
values_for("[1].map do |n1|
|
60
|
+
[2].map do |n2|
|
61
|
+
n1 + n2 end
|
62
|
+
end").should == [[], [], ['[3]'], ['[[3]]']]
|
63
|
+
|
64
|
+
values_for("[1].map do |n1|
|
65
|
+
[2].map do |n2|
|
66
|
+
n1 + n2 end end").should == [[], [], ['[[3]]']]
|
67
|
+
|
68
|
+
values_for("[1].map do |n1|
|
69
|
+
[2].map do |n2| n1 + n2 end end").should == [[], ['[[3]]']]
|
70
|
+
|
71
|
+
values_for("[1].map do |n1| [2].map do |n2| n1 + n2 end end").should == [['[[3]]']]
|
72
|
+
|
73
|
+
values_for("[1].map do |n1|
|
74
|
+
[2].map do |n2|
|
75
|
+
n1 + n2
|
76
|
+
end end").should == [[], [], ['3'], ['[[3]]']]
|
77
|
+
|
78
|
+
values_for("[1].map do |n1| [2].map do |n2|
|
79
|
+
n1 + n2
|
80
|
+
end end").should == [[], ['3'], ['[[3]]']]
|
81
|
+
|
82
|
+
values_for("[1].map do |n1| [2].map do |n2|
|
83
|
+
n1 + n2 end end").should == [[], ['[[3]]']]
|
84
|
+
|
85
|
+
values_for("[1].map do |n1| [2].map do |n2|
|
86
|
+
n1 + n2 end
|
87
|
+
end").should == [[], [], ['[[3]]']]
|
88
|
+
|
89
|
+
values_for("1 +
|
90
|
+
2").should == [[], ['3']]
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'has no output for empty lines' do
|
94
|
+
values_for('').should == [[]]
|
95
|
+
values_for("1\n\n2").should == [['1'],[],['2']]
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'stops executing on errors and reports them' do
|
99
|
+
result = values_for("12\nraise Exception, 'omg!'\n12")
|
100
|
+
result[0].should == ['12']
|
101
|
+
|
102
|
+
result[1].size.should == 1
|
103
|
+
exception = result[1].first
|
104
|
+
exception.class.should == Exception
|
105
|
+
exception.message.should == 'omg!'
|
106
|
+
|
107
|
+
result[2].should == []
|
108
|
+
result.size.should == 3
|
109
|
+
end
|
110
|
+
|
111
|
+
# something about printing to stdout
|
112
|
+
# something about printing to stderr
|
113
|
+
# something about when the whole input is invalid
|
114
|
+
# something about multi-line strings
|
115
|
+
# does not fuck up __LINE__ macro
|
116
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: seeing_is_believing
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Josh Cheek
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &70170924125400 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.12.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70170924125400
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: cucumber
|
27
|
+
requirement: &70170924124580 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.2.1
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70170924124580
|
36
|
+
description: Records the results of every line of code in your file (intended to be
|
37
|
+
like xmpfilter), inspired by Brett Victor's JavaScript example in his talk "Inventing
|
38
|
+
on Principle"
|
39
|
+
email:
|
40
|
+
- josh.cheek@gmail.com
|
41
|
+
executables:
|
42
|
+
- seeing_is_believing
|
43
|
+
extensions: []
|
44
|
+
extra_rdoc_files: []
|
45
|
+
files:
|
46
|
+
- .gitignore
|
47
|
+
- Gemfile
|
48
|
+
- Gemfile.lock
|
49
|
+
- bin/seeing_is_believing
|
50
|
+
- features/binary.feature
|
51
|
+
- features/step_definitions/steps.rb
|
52
|
+
- features/support/env.rb
|
53
|
+
- lib/seeing_is_believing.rb
|
54
|
+
- lib/seeing_is_believing/example_use.rb
|
55
|
+
- lib/seeing_is_believing/expression_list.rb
|
56
|
+
- lib/seeing_is_believing/result.rb
|
57
|
+
- lib/seeing_is_believing/version.rb
|
58
|
+
- seeing_is_believing.gemspec
|
59
|
+
- spec/expression_list_spec.rb
|
60
|
+
- spec/seeing_is_believing_spec.rb
|
61
|
+
homepage: https://github.com/JoshCheek/seeing_is_believing
|
62
|
+
licenses: []
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options: []
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ! '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubyforge_project: seeing_is_believing
|
81
|
+
rubygems_version: 1.8.17
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: Records results of every line of code in your file
|
85
|
+
test_files:
|
86
|
+
- features/binary.feature
|
87
|
+
- features/step_definitions/steps.rb
|
88
|
+
- features/support/env.rb
|
89
|
+
- spec/expression_list_spec.rb
|
90
|
+
- spec/seeing_is_believing_spec.rb
|