seeing_is_believing 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ script: rake
3
+ rvm:
4
+ - 1.9.3
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- seeing_is_believing (0.0.6)
4
+ seeing_is_believing (0.0.8)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
data/Readme.md CHANGED
@@ -1,13 +1,15 @@
1
+ [![Build Status](https://secure.travis-ci.org/JoshCheek/seeing_is_believing.png?branch=master)](http://travis-ci.org/JoshCheek/seeing_is_believing)
2
+
1
3
  Seeing Is Believing
2
4
  ===================
3
5
 
4
6
  Evaluates a file, recording the results of each line of code.
5
7
  You can then use this to display output values like Bret Victor does with JavaScript in his talk [Inventing on Principle][inventing_on_principle].
6
- Except, obviously, his is like a million better.
8
+ Except, obviously, his is like a million times better.
7
9
 
8
10
  Also comes with a binary to show how it might be used.
9
11
 
10
- For whatever reason, I can't embed videos, but here's a ~1 minute [video][video] showing it off.
12
+ For whatever reason, I can't embed videos, but **here's a ~1 minute [video][video]** showing it off.
11
13
 
12
14
 
13
15
  Use The Binary
@@ -29,17 +31,12 @@ meth "34" # => "34"
29
31
  ```
30
32
 
31
33
  ```ruby
32
- # $ bin/seeing_is_believing proving_grounds/raises_exception.rb 2>/dev/null
34
+ # $ bin/seeing_is_believing proving_grounds/raises_exception.rb
33
35
  1 + 1 # => 2
34
36
  raise "ZOMG!" # ~> RuntimeError: ZOMG!
35
37
  1 + 1
36
38
  ```
37
39
 
38
- ```bash
39
- # $ bin/seeing_is_believing proving_grounds/raises_exception.rb 1>/dev/null
40
- ZOMG!
41
- ```
42
-
43
40
  Use The Lib
44
41
  ===========
45
42
 
@@ -64,7 +61,6 @@ result[2] # => ['"A"', '"B"', '"C"']
64
61
  Install
65
62
  =======
66
63
 
67
- When Rubygems gets back up:
68
64
 
69
65
  $ gem install seeing_is_believing
70
66
 
@@ -81,8 +77,8 @@ Rubygems is allowing pushes again, but if it goes back down, you can install lik
81
77
  $ cd ..
82
78
  $ rm -rf "./seeing_is_believing"
83
79
 
84
- Hook it into TextMate
85
- =====================
80
+ TextMate Integration
81
+ ====================
86
82
 
87
83
  Go to the bundle editor, create this new command in the Ruby bundle:
88
84
 
@@ -94,6 +90,25 @@ It should look like this:
94
90
 
95
91
  ![textmate-integration][textmate-integration]
96
92
 
93
+ Emacs Integration
94
+ =================
95
+
96
+ Add this function to your Emacs configuration:
97
+
98
+ ~~~~ scheme
99
+ (defun seeing-is-believing ()
100
+ "Replace the current region (or the whole buffer, if none) with the output
101
+ of seeing_is_believing."
102
+ (interactive)
103
+ (let ((beg (if (region-active-p) (region-beginning) (point-min)))
104
+ (end (if (region-active-p) (region-end) (point-max))))
105
+ (shell-command-on-region beg end "seeing_is_believing" nil 'replace)))
106
+ ~~~~
107
+
108
+ You can now call `seeing-is-believing` to replace the current region
109
+ or current buffer contents with the output of running it through
110
+ `seeing_is_believing`.
111
+
97
112
  Known Issues
98
113
  ============
99
114
 
@@ -15,7 +15,7 @@ Feature: Running the binary unsuccessfully
15
15
  1 + 1
16
16
  """
17
17
  When I run "seeing_is_believing requires_exception_raising_code.rb"
18
- Then stderr is "ZOMG!"
18
+ Then stderr is empty
19
19
  And the exit status is 1
20
20
  And stdout is:
21
21
  """
@@ -0,0 +1,62 @@
1
+ Feature: Using flags
2
+
3
+ Sometimes you want more control over what comes out, for that we give you flags.
4
+
5
+ Scenario: --start-line
6
+ Given the file "start_line.rb":
7
+ """
8
+ 1 + 1
9
+ 2
10
+ 3
11
+ """
12
+ When I run "seeing_is_believing --start-line 2 start_line.rb"
13
+ Then stderr is empty
14
+ And the exit status is 0
15
+ And stdout is:
16
+ """
17
+ 1 + 1
18
+ 2 # => 2
19
+ 3 # => 3
20
+ """
21
+
22
+ Scenario: --end-line
23
+ Given the file "end_line.rb":
24
+ """
25
+ 1
26
+ 2
27
+ 3 + 3
28
+ """
29
+ When I run "seeing_is_believing --end-line 2 end_line.rb"
30
+ Then stderr is empty
31
+ And the exit status is 0
32
+ And stdout is:
33
+ """
34
+ 1 # => 1
35
+ 2 # => 2
36
+ 3 + 3
37
+ """
38
+
39
+ Scenario: --start-line and --end-line
40
+ Given the file "start_and_end_line.rb":
41
+ """
42
+ 1 + 1
43
+ 2
44
+ 3
45
+ 4 + 4
46
+ """
47
+ When I run "seeing_is_believing --start-line 2 --end-line 3 start_and_end_line.rb"
48
+ Then stderr is empty
49
+ And the exit status is 0
50
+ And stdout is:
51
+ """
52
+ 1 + 1
53
+ 2 # => 2
54
+ 3 # => 3
55
+ 4 + 4
56
+ """
57
+
58
+ Scenario: --help
59
+ When I run "seeing_is_believing --help"
60
+ Then stderr is empty
61
+ And the exit status is 0
62
+ And stdout includes "Usage"
@@ -25,3 +25,7 @@ end
25
25
  Then /^(stderr|stdout) is empty$/ do |stream_name|
26
26
  @last_executed.send(stream_name).should == ''
27
27
  end
28
+
29
+ Then /^(stderr|stdout) includes "([^"]*)"$/ do |stream_name, content|
30
+ @last_executed.send(stream_name).should include content
31
+ end
@@ -1,6 +1,7 @@
1
1
  require 'stringio'
2
2
  require 'tmpdir'
3
3
 
4
+ require 'seeing_is_believing/queue'
4
5
  require 'seeing_is_believing/result'
5
6
  require 'seeing_is_believing/expression_list'
6
7
  require 'seeing_is_believing/evaluate_by_moving_files'
@@ -20,7 +21,7 @@ class SeeingIsBelieving
20
21
  def call
21
22
  @memoized_result ||= begin
22
23
  program = ''
23
- program << expression_list.call until peek_next_line.nil? || data_segment?
24
+ program << expression_list.call until next_line_queue.peek.nil? || data_segment?
24
25
  program = record_exceptions_in program
25
26
  program << "\n" << the_rest_of_the_stream if data_segment?
26
27
  result_for program, min_line_number, max_line_number
@@ -32,8 +33,8 @@ class SeeingIsBelieving
32
33
  attr_reader :stream
33
34
 
34
35
  def expression_list
35
- @expression_list ||= ExpressionList.new get_next_line: lambda { get_next_line },
36
- peek_next_line: lambda { peek_next_line },
36
+ @expression_list ||= ExpressionList.new get_next_line: lambda { next_line_queue.dequeue },
37
+ peek_next_line: lambda { next_line_queue.peek },
37
38
  on_complete: lambda { |line, children, completions, line_number|
38
39
  track_line_number line_number
39
40
  expression = [line, *children, *completions].map(&:chomp).join("\n")
@@ -75,32 +76,22 @@ class SeeingIsBelieving
75
76
  end
76
77
 
77
78
  def eof?
78
- peek_next_line.nil?
79
+ next_line_queue.peek.nil?
79
80
  end
80
81
 
81
82
  def data_segment?
82
- peek_next_line == '__END__'
83
+ next_line_queue.peek == '__END__'
83
84
  end
84
85
 
85
- def peek_next_line
86
- @next_line ||= begin
86
+ def next_line_queue
87
+ @next_line_queue ||= Queue.new do
87
88
  line = stream.gets
88
89
  line && line.chomp
89
90
  end
90
91
  end
91
92
 
92
- def get_next_line
93
- if @next_line
94
- line = peek_next_line
95
- @next_line = nil
96
- line
97
- else
98
- peek_next_line && get_next_line
99
- end
100
- end
101
-
102
93
  def the_rest_of_the_stream
103
- get_next_line << "\n" << stream.read
94
+ next_line_queue.dequeue << "\n" << stream.read
104
95
  end
105
96
 
106
97
  def do_not_record?(code)
@@ -0,0 +1,94 @@
1
+ class SeeingIsBelieving
2
+ class ArgParser
3
+ def self.parse(args)
4
+ new(args).call
5
+ end
6
+
7
+ attr_accessor :args
8
+
9
+ def initialize(args)
10
+ self.args = args
11
+ self.filenames = []
12
+ end
13
+
14
+ def call
15
+ @result ||= begin
16
+ until args.empty?
17
+ case (arg = args.shift)
18
+
19
+ # help screen
20
+ when '-h', '--help'
21
+ options[:help] = self.class.help_screen
22
+
23
+ # start line
24
+ when '-l', '--start-line'
25
+ start_line = args.shift
26
+ i_start_line = start_line.to_i
27
+ if i_start_line.to_s == start_line && !i_start_line.zero?
28
+ options[:start_line] = start_line.to_i
29
+ else
30
+ options[:errors] << "#{arg} expects a positive integer argument"
31
+ end
32
+
33
+ # end line
34
+ when '-L', '--end-line'
35
+ end_line = args.shift
36
+ if end_line.to_i.to_s == end_line
37
+ options[:end_line] = end_line.to_i
38
+ else
39
+ options[:errors] << "#{arg} expect an integer argument"
40
+ end
41
+
42
+ # unknown flags
43
+ when /^-/
44
+ options[:errors] << "Unknown option: #{arg.inspect}"
45
+
46
+ # filenames
47
+ else
48
+ filenames << arg
49
+ options[:filename] = arg
50
+ end
51
+ end
52
+ normalize_and_validate
53
+ options
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ attr_accessor :filenames
60
+
61
+ def normalize_and_validate
62
+ if 1 < filenames.size
63
+ options[:errors] << "Can only have one filename, but had: #{filenames.map(&:inspect).join ', '}"
64
+ end
65
+
66
+ if options[:end_line] < options[:start_line]
67
+ options[:start_line], options[:end_line] = options[:end_line], options[:start_line]
68
+ end
69
+ end
70
+
71
+ def options
72
+ @options ||= {
73
+ filename: nil,
74
+ errors: [],
75
+ start_line: 1,
76
+ end_line: Float::INFINITY,
77
+ }
78
+ end
79
+ end
80
+
81
+ def ArgParser.help_screen
82
+ <<HELP_SCREEN
83
+ Usage: #{$0} [options] [filename]
84
+
85
+ #{$0} is a program and library that will evaluate a Ruby file and capture/display the results.
86
+
87
+ If no filename is provided, the binary will read the program from standard input.
88
+
89
+ -l, --start-line # line number to begin showing results on
90
+ -L, --end-line # line number to stop showing results on
91
+ -h, --help # this help screen
92
+ HELP_SCREEN
93
+ end
94
+ end
@@ -1,3 +1,4 @@
1
+ require 'seeing_is_believing/arg_parser'
1
2
  require 'seeing_is_believing/print_results_next_to_lines'
2
3
 
3
4
  class SeeingIsBelieving
@@ -12,68 +13,89 @@ class SeeingIsBelieving
12
13
  end
13
14
 
14
15
  def call
15
- return if @already_called
16
- @already_called = true
17
-
18
- file_exists_or_is_on_stdin &&
19
- syntax_is_valid &&
20
- print_program &&
21
- display_exceptions
16
+ @exitstatus ||= if flags_have_errors? then print_errors ; 1
17
+ elsif should_print_help? then print_help ; 0
18
+ elsif has_filename? && file_dne? then print_file_dne ; 1
19
+ elsif invalid_syntax? then print_syntax_error ; 1
20
+ else print_program ; (printer.has_exception? ? 1 : 0)
21
+ end
22
22
  end
23
23
 
24
- def exitstatus
25
- call
26
- @exitstatus
27
- end
24
+ alias exitstatus call
28
25
 
29
26
  private
30
27
 
31
- def on_stdin?
32
- argv.empty?
33
- end
34
-
35
28
  def filename
36
- argv.first
29
+ flags[:filename]
37
30
  end
31
+ alias has_filename? filename
38
32
 
39
- def believer
40
- @believer ||= begin
41
- if on_stdin?
42
- PrintResultsNextToLines.new stdin.read, ''
33
+ # le sigh
34
+ def printer
35
+ @printer ||= begin
36
+ if file_is_on_stdin?
37
+ body = stdin.read
38
+ stdin = ''
43
39
  else
44
- PrintResultsNextToLines.new File.read(filename), stdin, filename
40
+ body = File.read(filename)
41
+ stdin = self.stdin
45
42
  end
43
+ PrintResultsNextToLines.new body,
44
+ stdin,
45
+ filename: filename,
46
+ start_line: flags[:start_line],
47
+ end_line: flags[:end_line]
46
48
  end
47
49
  end
48
50
 
49
- def file_exists_or_is_on_stdin
50
- return true if on_stdin? || File.exist?(filename)
51
- @exitstatus = 1
51
+ def flags
52
+ @flags ||= ArgParser.parse argv
53
+ end
54
+
55
+ def flags_have_errors?
56
+ flags[:errors].any?
57
+ end
58
+
59
+ def print_errors
60
+ stderr.puts flags[:errors].join("\n")
61
+ end
62
+
63
+ def should_print_help?
64
+ flags[:help]
65
+ end
66
+
67
+ def print_help
68
+ stdout.puts flags[:help]
69
+ end
70
+
71
+ def file_is_on_stdin?
72
+ filename.nil?
73
+ end
74
+
75
+ def file_dne?
76
+ !File.exist?(filename)
77
+ end
78
+
79
+ def print_file_dne
52
80
  stderr.puts "#{filename} does not exist!"
53
- false
54
81
  end
55
82
 
56
- def syntax_is_valid
57
- return true if on_stdin? # <-- should probably check stdin too
83
+ def print_program
84
+ stdout.puts printer.call
85
+ end
86
+
87
+ def syntax_error_notice
88
+ return if file_is_on_stdin? # <-- should probably check stdin too
58
89
  out, err, syntax_status = Open3.capture3('ruby', '-c', filename)
59
- return true if syntax_status.success?
60
- @exitstatus = 1
61
- stderr.puts err
62
- false
90
+ return err unless syntax_status.success?
63
91
  end
64
92
 
65
- def print_program
66
- stdout.puts believer.call
67
- true
93
+ def invalid_syntax?
94
+ !!syntax_error_notice
68
95
  end
69
96
 
70
- def display_exceptions
71
- if believer.has_exception?
72
- stderr.puts believer.exception.message
73
- @exitstatus = 1
74
- else
75
- @exitstatus = 0
76
- end
97
+ def print_syntax_error
98
+ stderr.puts syntax_error_notice
77
99
  end
78
100
  end
79
101
  end
@@ -1,4 +1,5 @@
1
1
  require 'seeing_is_believing'
2
+ require 'seeing_is_believing/queue'
2
3
  require 'seeing_is_believing/has_exception'
3
4
 
4
5
  class SeeingIsBelieving
@@ -10,10 +11,12 @@ class SeeingIsBelieving
10
11
  EXCEPTION_PREFIX = '# ~>'
11
12
  RESULT_PREFIX = '# =>'
12
13
 
13
- def initialize(body, stdin, filename=nil)
14
- self.body = remove_previous_output_from body
15
- self.filename = filename
16
- self.stdin = stdin
14
+ def initialize(body, stdin, options={})
15
+ self.body = remove_previous_output_from body
16
+ self.stdin = stdin
17
+ self.filename = options.fetch :filename, nil
18
+ self.start_line = options.fetch :start_line
19
+ self.end_line = options.fetch :end_line
17
20
  end
18
21
 
19
22
  def new_body
@@ -23,16 +26,18 @@ class SeeingIsBelieving
23
26
  def call
24
27
  evaluate_program
25
28
  inherit_exception
26
- add_each_line_until_data_segment
29
+ add_each_line_until_start_or_data_segment
30
+ add_lines_with_results_until_end_or_data_segment
31
+ add_lines_until_data_segment
27
32
  add_stdout
28
33
  add_stderr
29
- add_data_segment
34
+ add_remaining_lines
30
35
  return new_body
31
36
  end
32
37
 
33
38
  private
34
39
 
35
- attr_accessor :body, :filename, :file_result, :stdin
40
+ attr_accessor :body, :filename, :file_result, :stdin, :start_line, :end_line
36
41
 
37
42
  def evaluate_program
38
43
  self.file_result = SeeingIsBelieving.new(body, filename: filename, stdin: stdin).call
@@ -42,27 +47,38 @@ class SeeingIsBelieving
42
47
  self.exception = file_result.exception
43
48
  end
44
49
 
45
- def add_each_line_until_data_segment
46
- body.each_line.with_index 1 do |line, index|
47
- break if start_of_data_segment? line
48
- new_body << format_line(line.chomp, file_result[index])
49
- end
50
+ def add_each_line_until_start_or_data_segment
51
+ line_queue.until { |line, line_number| line_number == start_line || start_of_data_segment?(line) }
52
+ .each { |line, line_number| new_body << line }
53
+ end
54
+
55
+ def add_lines_with_results_until_end_or_data_segment
56
+ line_queue.until { |line, line_number| end_line < line_number || start_of_data_segment?(line) }
57
+ .each { |line, line_number| new_body << format_line(line.chomp, file_result[line_number]) }
58
+ end
59
+
60
+ def add_lines_until_data_segment
61
+ line_queue.until { |line, line_number| start_of_data_segment?(line) }
62
+ .each { |line, line_number| new_body << line }
63
+ end
64
+
65
+ def add_remaining_lines
66
+ line_queue.each { |line, line_number| new_body << line }
50
67
  end
51
68
 
52
- def add_data_segment
53
- body.each_line
54
- .drop_while { |line| not start_of_data_segment? line }
55
- .each { |line| new_body << line }
69
+ def line_queue
70
+ @line_queue ||= Queue.new &body.each_line.with_index(1).to_a.method(:shift)
56
71
  end
57
72
 
58
73
  def start_of_data_segment?(line)
59
74
  line.chomp == '__END__'
60
75
  end
61
76
 
62
- # max line length of the body (exempting coments) + 2 spaces for padding
77
+ # max line length of the lines to output (exempting coments) + 2 spaces for padding
63
78
  def line_length
64
79
  @line_length ||= 2 + body.each_line
65
80
  .map(&:chomp)
81
+ .select.with_index(1) { |line, index| start_line <= index && index <= end_line }
66
82
  .take_while { |line| not start_of_data_segment? line }
67
83
  .select { |line| not (line == "=begin") .. (line == "=end") }
68
84
  .reject { |line| SyntaxAnalyzer.ends_in_comment? line }
@@ -0,0 +1,55 @@
1
+ class SeeingIsBelieving
2
+ class Queue
3
+ class While
4
+ attr_accessor :queue, :conditional
5
+
6
+ def initialize(queue, &conditional)
7
+ self.queue, self.conditional = queue, conditional
8
+ end
9
+
10
+ def each(&block)
11
+ block.call queue.dequeue while !queue.empty? && conditional.call(queue.peek)
12
+ end
13
+ end
14
+ end
15
+
16
+ class Queue
17
+ attr_accessor :value_generator
18
+
19
+ def initialize(&value_generator)
20
+ self.value_generator = value_generator
21
+ end
22
+
23
+ def dequeue
24
+ return if permanently_empty?
25
+ peek.tap { @next_value = nil }
26
+ end
27
+
28
+ def peek
29
+ return if permanently_empty?
30
+ @next_value ||= value_generator.call.tap { |value| @permanently_empty = value.nil? }
31
+ end
32
+
33
+ def empty?
34
+ permanently_empty? || peek.nil?
35
+ end
36
+
37
+ def each(&block)
38
+ block.call dequeue until empty?
39
+ end
40
+
41
+ def until(&block)
42
+ While.new(self) { |*args| !block.call(*args) }
43
+ end
44
+
45
+ def while(&block)
46
+ While.new self, &block
47
+ end
48
+
49
+ private
50
+
51
+ def permanently_empty?
52
+ @permanently_empty
53
+ end
54
+ end
55
+ end
@@ -1,3 +1,3 @@
1
1
  class SeeingIsBelieving
2
- VERSION = '0.0.8'
2
+ VERSION = '0.0.9'
3
3
  end
@@ -0,0 +1,122 @@
1
+ require 'seeing_is_believing/arg_parser'
2
+
3
+ describe SeeingIsBelieving::ArgParser do
4
+ RSpec::Matchers.define :have_error do |error_assertion|
5
+ match do |options|
6
+ options[:errors].find do |error|
7
+ case error_assertion
8
+ when Regexp
9
+ error_assertion =~ error
10
+ else
11
+ error_assertion == error
12
+ end
13
+ end
14
+ end
15
+
16
+ failure_message_for_should do |options|
17
+ "#{error_assertion.inspect} should have matched one of the errors: #{options[:errors].inspect}"
18
+ end
19
+
20
+ failure_message_for_should_not do |options|
21
+ "#{error_assertion.inspect} should NOT have matched any of the errors: #{options[:errors].inspect}"
22
+ end
23
+ end
24
+
25
+ def parse(args)
26
+ described_class.parse args
27
+ end
28
+
29
+ specify 'unknown options set an error' do
30
+ parse(['--abc']).should have_error 'Unknown option: "--abc"'
31
+ parse(['-a']).should have_error 'Unknown option: "-a"'
32
+ end
33
+
34
+ example 'example: all the args' do
35
+ options = parse(%w[filename -l 12 -L 20 -h])
36
+ options[:filename].should == 'filename'
37
+ options[:start_line].should == 12
38
+ options[:end_line].should == 20
39
+ options[:help].should be_a_kind_of String
40
+ options[:errors].should be_empty
41
+ end
42
+
43
+ describe ':filename' do
44
+ it 'defaults to nil' do
45
+ parse([])[:filename].should be_nil
46
+ end
47
+
48
+ it 'is the first non-flag' do
49
+ parse(['a'])[:filename].should == 'a'
50
+ parse(['-x', 'a'])[:filename].should == 'a'
51
+ parse(['a', '-x'])[:filename].should == 'a'
52
+ end
53
+
54
+ it 'sets an error if given multiple filenames' do
55
+ parse([]).should_not have_error /name/
56
+ parse(['a']).should_not have_error /Can only have one filename/
57
+ parse(['a', 'b']).should have_error 'Can only have one filename, but had: "a", "b"'
58
+ end
59
+ end
60
+
61
+ describe ':start_line' do
62
+ it 'defaults to 1' do
63
+ parse([])[:start_line].should equal 1
64
+ end
65
+
66
+ it 'is set with -l and --start-line' do
67
+ parse(['-l', '1'])[:start_line].should == 1
68
+ parse(['--start-line', '12'])[:start_line].should == 12
69
+ end
70
+
71
+ it 'sets an error if it cannot be turned into a positive integer' do
72
+ line_error_assertions = lambda do |flag|
73
+ parse([flag, '1']).should_not have_error /#{flag}/
74
+ parse([flag, '0']).should have_error /#{flag}/
75
+ parse([flag, 'a']).should have_error /#{flag}/
76
+ parse([flag, '']).should have_error /#{flag}/
77
+ parse([flag, '1.0']).should have_error /#{flag}/
78
+ parse([flag]).should have_error /#{flag}/
79
+ end
80
+ line_error_assertions['-l']
81
+ line_error_assertions['--start-line']
82
+ end
83
+ end
84
+
85
+ describe ':end_line' do
86
+ it 'defaults to infinity' do
87
+ parse([])[:end_line].should equal Float::INFINITY
88
+ end
89
+
90
+ it 'is set with -L and --end-line' do
91
+ parse(['-L', '1'])[:end_line].should == 1
92
+ parse(['--end-line', '12'])[:end_line].should == 12
93
+ end
94
+
95
+ it 'sets an error if it cannot be turned into an integer' do
96
+ line_error_assertions = lambda do |flag|
97
+ parse([flag, '1']).should_not have_error /#{flag}/
98
+ parse([flag, 'a']).should have_error /#{flag}/
99
+ parse([flag, '']).should have_error /#{flag}/
100
+ parse([flag]).should have_error /#{flag}/
101
+ end
102
+ line_error_assertions['-L']
103
+ line_error_assertions['--end-line']
104
+ end
105
+ end
106
+
107
+ it 'swaps start and end line around if they are out of order' do
108
+ parse(%w[-l 2 -L 1])[:start_line].should == 1
109
+ parse(%w[-l 2 -L 1])[:end_line].should == 2
110
+ end
111
+
112
+ describe ':help' do
113
+ it 'defaults to nil' do
114
+ parse([])[:help].should be_nil
115
+ end
116
+
117
+ it 'is set to the help screen with -h and --help and -help' do
118
+ parse(['-h'])[:help].should == described_class.help_screen
119
+ parse(['--help'])[:help].should == described_class.help_screen
120
+ end
121
+ end
122
+ end
@@ -1,9 +1,12 @@
1
1
  require 'seeing_is_believing/evaluate_by_moving_files'
2
+ require 'fileutils'
2
3
 
3
4
  describe SeeingIsBelieving::EvaluateByMovingFiles do
4
5
  let(:filedir) { File.expand_path '../../proving_grounds', __FILE__ }
5
6
  let(:filename) { File.join filedir, 'some_filename' }
6
7
 
8
+ before { FileUtils.mkdir_p filedir }
9
+
7
10
  def invoke(program, options={})
8
11
  evaluator = described_class.new(program, filename, options)
9
12
  FileUtils.rm_f evaluator.temp_filename
@@ -0,0 +1,80 @@
1
+ require 'seeing_is_believing/queue'
2
+
3
+ describe SeeingIsBelieving::Queue do
4
+ def queue_for(*values)
5
+ described_class.new { values.shift }
6
+ end
7
+
8
+ it 'generates values from the block it is initialized with' do
9
+ queue = queue_for 1, 2
10
+ queue.dequeue.should == 1
11
+ queue.dequeue.should == 2
12
+ queue.dequeue.should == nil
13
+ end
14
+
15
+ it 'can peek ahead' do
16
+ queue = queue_for 1, 2
17
+ queue.peek.should == 1
18
+ queue.peek.should == 1
19
+ queue.dequeue.should == 1
20
+ queue.dequeue.should == 2
21
+ end
22
+
23
+ it 'considers a nil value to mean it is empty' do
24
+ queue = queue_for 1, 2
25
+ queue.should_not be_empty
26
+ queue.peek.should == 1
27
+ queue.should_not be_empty
28
+ queue.dequeue.should == 1
29
+ queue.should_not be_empty
30
+ queue.peek.should == 2
31
+ queue.should_not be_empty
32
+ queue.dequeue.should == 2
33
+ queue.should be_empty
34
+ queue.peek.should == nil
35
+ end
36
+
37
+ it 'yields nil infinitely after the first time it is seen' do
38
+ queue = queue_for nil, 1
39
+ queue.should be_empty
40
+ queue.peek.should == nil
41
+ queue.dequeue.should == nil
42
+ queue.should be_empty
43
+ queue.peek.should == nil
44
+ queue.dequeue.should == nil
45
+ end
46
+
47
+ it 'can (destructively) iterate over its items until it is empty' do
48
+ queue = queue_for *1..5
49
+ seen = []
50
+ queue.each { |i| seen << i }
51
+ seen.should == [*1..5]
52
+ queue.should be_empty
53
+ end
54
+
55
+ describe 'conditional iteration' do
56
+ it 'will iterate while a condition is met' do
57
+ queue = queue_for *1..5
58
+ seen = []
59
+ queue.while { |arg| arg < 4 }.each { |arg| seen << arg }
60
+ seen.should == [1, 2, 3]
61
+ queue.peek.should == 4
62
+ end
63
+
64
+ it 'will iterate until a condition is met' do
65
+ queue = queue_for *1..5
66
+ seen = []
67
+ queue.until { |arg| arg == 4 }.each { |arg| seen << arg }
68
+ seen.should == [1, 2, 3]
69
+ queue.peek.should == 4
70
+ end
71
+
72
+ it 'stops iterating when it hits the end of the queue' do
73
+ queue = queue_for *1..5
74
+ seen = []
75
+ queue.while { true }.each { |arg| seen << arg }
76
+ seen.should == [*1..5]
77
+ queue.should be_empty
78
+ end
79
+ end
80
+ end
@@ -227,7 +227,7 @@ describe SeeingIsBelieving do
227
227
  invoke('$stdin.read')[1].should == ['""']
228
228
  end
229
229
 
230
- it 'can deal with methods that are invoked entirely on the next line', wip:true do
230
+ it 'can deal with methods that are invoked entirely on the next line' do
231
231
  values_for("1\n.even?").should == [[], ['false']]
232
232
  values_for("1\n.even?\n__END__").should == [[], ['false']]
233
233
  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.8
4
+ version: 0.0.9
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-02-02 00:00:00.000000000 Z
12
+ date: 2013-02-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- requirement: &70138255056540 !ruby/object:Gem::Requirement
16
+ requirement: &70151257454580 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 10.0.3
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70138255056540
24
+ version_requirements: *70151257454580
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &70138255055760 !ruby/object:Gem::Requirement
27
+ requirement: &70151257453880 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 2.12.0
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70138255055760
35
+ version_requirements: *70151257453880
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: cucumber
38
- requirement: &70138255055080 !ruby/object:Gem::Requirement
38
+ requirement: &70151257449440 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.2.1
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70138255055080
46
+ version_requirements: *70151257449440
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: ichannel
49
- requirement: &70138255054620 !ruby/object:Gem::Requirement
49
+ requirement: &70151257448960 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: 5.1.1
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70138255054620
57
+ version_requirements: *70151257448960
58
58
  description: Records the results of every line of code in your file (intended to be
59
59
  like xmpfilter), inspired by Bret Victor's JavaScript example in his talk "Inventing
60
60
  on Principle"
@@ -66,16 +66,19 @@ extensions: []
66
66
  extra_rdoc_files: []
67
67
  files:
68
68
  - .gitignore
69
+ - .travis.yml
69
70
  - Gemfile
70
71
  - Gemfile.lock
71
72
  - Rakefile
72
73
  - Readme.md
73
74
  - bin/seeing_is_believing
74
- - features/binary_errors.feature
75
- - features/binary_examples.feature
75
+ - features/errors.feature
76
+ - features/examples.feature
77
+ - features/flags.feature
76
78
  - features/step_definitions/steps.rb
77
79
  - features/support/env.rb
78
80
  - lib/seeing_is_believing.rb
81
+ - lib/seeing_is_believing/arg_parser.rb
79
82
  - lib/seeing_is_believing/binary.rb
80
83
  - lib/seeing_is_believing/error.rb
81
84
  - lib/seeing_is_believing/evaluate_by_moving_files.rb
@@ -83,15 +86,18 @@ files:
83
86
  - lib/seeing_is_believing/hard_core_ensure.rb
84
87
  - lib/seeing_is_believing/has_exception.rb
85
88
  - lib/seeing_is_believing/print_results_next_to_lines.rb
89
+ - lib/seeing_is_believing/queue.rb
86
90
  - lib/seeing_is_believing/result.rb
87
91
  - lib/seeing_is_believing/syntax_analyzer.rb
88
92
  - lib/seeing_is_believing/the_matrix.rb
89
93
  - lib/seeing_is_believing/tracks_line_numbers_seen.rb
90
94
  - lib/seeing_is_believing/version.rb
91
95
  - seeing_is_believing.gemspec
96
+ - spec/arg_parser_spec.rb
92
97
  - spec/evaluate_by_moving_files_spec.rb
93
98
  - spec/expression_list_spec.rb
94
99
  - spec/hard_core_ensure_spec.rb
100
+ - spec/queue_spec.rb
95
101
  - spec/seeing_is_believing_spec.rb
96
102
  - spec/syntax_analyzer_spec.rb
97
103
  - textmate-integration.png
@@ -120,12 +126,15 @@ signing_key:
120
126
  specification_version: 3
121
127
  summary: Records results of every line of code in your file
122
128
  test_files:
123
- - features/binary_errors.feature
124
- - features/binary_examples.feature
129
+ - features/errors.feature
130
+ - features/examples.feature
131
+ - features/flags.feature
125
132
  - features/step_definitions/steps.rb
126
133
  - features/support/env.rb
134
+ - spec/arg_parser_spec.rb
127
135
  - spec/evaluate_by_moving_files_spec.rb
128
136
  - spec/expression_list_spec.rb
129
137
  - spec/hard_core_ensure_spec.rb
138
+ - spec/queue_spec.rb
130
139
  - spec/seeing_is_believing_spec.rb
131
140
  - spec/syntax_analyzer_spec.rb