seeing_is_believing 2.0.0.beta3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a95d8680853f82d8aee58a8ba40d16a113662f20
4
- data.tar.gz: 6e9fecb99be2adf05d75bb42d2c8a37de1ff1c7b
3
+ metadata.gz: ae86d44e9afffb2928ac761a5bf8f6810ec1c996
4
+ data.tar.gz: 4c37f23d51da74cde81e85f2c48b1928daeedce9
5
5
  SHA512:
6
- metadata.gz: 291941c2ca6975b233ecfe9f8428f40638331839ec29591d955333d49a3bf975ed0478ca67059e41a7583ddd8b18e9140a9f632b8242665d8fdfed939e8bf319
7
- data.tar.gz: 138ae24e20da808a5ea5eb31bcc9ab4eede0163054a130478f79f1e00842b5c56b073f104c98c952f77e0b5698ca6e626691e4818137db136811eaa4e64fff30
6
+ metadata.gz: 08e8e66324e9360ee680327765f7d633a0862ab22237148ddd49d0bfc78ebfaa89f9466a4390dc5404126aa791256cbb437aa346ebbfc22c904a231fab042c35
7
+ data.tar.gz: bd56f998a57e28b06bcfc04782feb64ccb1e7466503cec372b08f9f77102a70df4c05dd7e9079f45b441ed2c72ded198d02aedc653c8be2c43d69448e48a286f
data/Readme.md CHANGED
@@ -4,12 +4,12 @@ Seeing Is Believing
4
4
  ===================
5
5
 
6
6
  Evaluates a file, recording the results of each line of code.
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].
7
+ You can then use this to display output values like Bret Victor does with JavaScript in his talk [Inventing on Principle](http://vimeo.com/36579366).
8
8
  Except, obviously, his is like a million times better.
9
9
 
10
10
  Also comes with a binary to show how it might be used.
11
11
 
12
- 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](http://vimeo.com/58766950)** showing it off.
13
13
 
14
14
  Works in Ruby 1.9 and 2.0
15
15
 
@@ -17,25 +17,16 @@ Use The Binary
17
17
  ==============
18
18
 
19
19
  ```ruby
20
- # $ seeing_is_believing proving_grounds/basic_functionality.rb
20
+ $ cat simple_example.rb
21
21
  5.times do |i|
22
- i * 2 # => 0, 2, 4, 6, 8
23
- end # => 5
24
-
25
- def meth(n)
26
- n # => "12", "34"
27
- end # => nil
22
+ i * 2
23
+ end
28
24
 
29
- # some invocations
30
- meth "12" # => "12"
31
- meth "34" # => "34"
32
- ```
33
25
 
34
- ```ruby
35
- # $ bin/seeing_is_believing proving_grounds/raises_exception.rb
36
- 1 + 1 # => 2
37
- raise "ZOMG!" # ~> RuntimeError: ZOMG!
38
- 1 + 1
26
+ $ seeing_is_believing simple_example.rb
27
+ 5.times do |i| # => 5
28
+ i * 2 # => 0, 2, 4, 6, 8
29
+ end # => 5
39
30
  ```
40
31
 
41
32
  Use The Lib
@@ -43,113 +34,38 @@ Use The Lib
43
34
 
44
35
  ```ruby
45
36
  require 'seeing_is_believing'
46
-
47
- believer = SeeingIsBelieving.new("%w[a b c].each do |i|
37
+ believer = SeeingIsBelieving.new("[:a, :b, :c].each do |i|
48
38
  i.upcase
49
39
  end")
50
40
 
51
- result = believer.call
52
- result # => #<SeeingIsBelieving::Result:0x007f832298e340 @max_line_number=3, @min_line_number=1, @results={2=>#<SeeingIsBelieving::Result::Line:0x007f832298df30 @array=["\"A\"", "\"B\"", "\"C\""]>, 3=>#<SeeingIsBelieving::Result::Line:0x007f832298db98 @array=["[\"a\", \"b\", \"c\"]"]>}, @stdout="", @stderr="">
53
-
54
- result.to_a # => [#<SeeingIsBelieving::Result::Line:0x007f832299adc0 @array=[]>,
55
- # #<SeeingIsBelieving::Result::Line:0x007f832298df30 @array=['"A"', '"B"', '"C"']>,
56
- # #<SeeingIsBelieving::Result::Line:0x007f832298db98 @array=['["a", "b", "c"]']>]
41
+ result = believer.call # => #<SIB::Result @results={1=>#<SIB:Line["[:a, :b, :c]"] no exception>, 2=>#<SIB:Line[":A", ":B", ":C"] no exception>, 3=>#<SIB:Line["[:a, :b, :c]"] no exception>}\n @stdout=""\n @stderr=""\n @exitstatus=0\n @bug_in_sib=nil>
57
42
 
58
- result[2] # => #<SeeingIsBelieving::Result::Line:0x007f832298df30 @array=['"A"', '"B"', '"C"']>
43
+ result[2] # => #<SIB:Line[":A", ":B", ":C"] no exception>
44
+ result[2][0] # => ":A"
45
+ result[2][1] # => ":B"
46
+ result[2][2] # => ":C"
47
+ result[2].join(", ") # => ":A, :B, :C"
59
48
 
60
- # this result object is a thin wrapper around its array
61
- result[2][0] # => '"A"'
62
- result[2][1] # => '"B"'
63
- result[2][2] # => '"C"'
64
- result[2].join(", ") # => '"A", "B", "C"'
49
+ result.stdout # => ""
50
+ result.stderr # => ""
51
+ result.exception # => nil
65
52
  ```
66
53
 
67
54
  Install
68
55
  =======
69
56
 
57
+ Currently requires Ruby 1.9 or 2.0 I don't have specific plans to make it available on 1.8,
58
+ but it could happen.
70
59
 
71
60
  $ gem install seeing_is_believing
72
61
 
73
- Or if you haven't fixed your gem home, and you aren't using any version managers:
74
-
75
- $ sudo gem install seeing_is_believing
76
-
77
- Rubygems is allowing pushes again, but if it goes back down, you can install like this:
78
-
79
- $ git clone https://github.com/JoshCheek/seeing_is_believing/
80
- $ cd seeing_is_believing
81
- $ gem build seeing_is_believing.gemspec
82
- $ gem install seeing_is_believing-0.0.8.gem
83
- $ cd ..
84
- $ rm -rf "./seeing_is_believing"
85
-
86
- Sublime Text 2 Integration
87
- ==========================
88
-
89
- See [sublime-text-2-seeing-is-believing](https://github.com/JoshCheek/sublime-text-2-seeing-is-believing).
90
-
91
62
 
92
- TextMate Integration
93
- ====================
63
+ Editor Integration
64
+ ==================
94
65
 
95
- Note: This assumes you've already set up Ruby to work with TextMate.
96
- If not, you'll need to start there. [Here](https://rvm.io/integration/textmate/)
97
- are instructions for RVM (I recommend the wrapper approach).
98
- [Here](http://uberfork.com/post/12280974742/integrate-rbenv-with-textmate)
99
- are instructions for rbenv.
100
-
101
- Go to the bundle editor, create a new command (I put it in the Ruby bundle)
102
- You can name it what you want, I went with "seeing is believing annotate all lines"
103
-
104
- ```shell
105
- #!/bin/bash
106
-
107
- # set result length because TextMate has difficulty displaying long lines
108
- default_options=""
109
- default_options="$default_options -Ku"
110
- default_options="$default_options --result-length 200"
111
- default_options="$default_options --alignment-strategy chunk"
112
- default_options="$default_options --timeout 12"
113
-
114
- if [ -z "$TM_FILEPATH" ]; then
115
- "${TM_RUBY}" -S seeing_is_believing $default_options
116
- else
117
- "${TM_RUBY}" -S seeing_is_believing $default_options --as "$TM_FILEPATH"
118
- fi
119
- ```
120
-
121
- You can also make one for annotating only the lines you have marked.
122
- I named it "seeing is believing annotate marked lines"
123
-
124
- ```shell
125
- #!/bin/bash
126
-
127
- # set result length because TextMate has difficulty displaying long lines
128
- default_options=""
129
- default_options="$default_options --xmpfilter-style"
130
- default_options="$default_options -Ku"
131
- default_options="$default_options --result-length 200"
132
- default_options="$default_options --alignment-strategy chunk"
133
- default_options="$default_options --timeout 12"
134
-
135
- if [ -z "$TM_FILEPATH" ]; then
136
- "${TM_RUBY}" -S seeing_is_believing $default_options
137
- else
138
- "${TM_RUBY}" -S seeing_is_believing $default_options --as "$TM_FILEPATH"
139
- fi
140
- ```
141
-
142
- And you'll probably want one to clean out the outpt
143
-
144
- ```shell
145
- #!/bin/bash
146
- "${TM_RUBY}" -S seeing_is_believing -Ku --clean
147
- ```
148
-
149
- You can bind them to whatever keys you want, but I'll recomend (for consistency with what I chose for the Sublime bundle)
150
- * annotate all lines -> Command Option b
151
- * annotate marked lines -> Command Option n
152
- * remove annotations -> Command Option v
66
+ * [sublime-text-2-seeing-is-believing](https://github.com/JoshCheek/sublime-text-2-seeing-is-believing)
67
+ * [TextMate 1](https://github.com/JoshCheek/text_mate_1-seeing-is_believing)
68
+ * [TextMate 2](https://github.com/JoshCheek/text_mate_2-seeing-is_believing)
153
69
 
154
70
  Emacs Integration
155
71
  =================
@@ -173,20 +89,15 @@ or current buffer contents with the output of running it through
173
89
  Known Issues
174
90
  ============
175
91
 
176
- * `BEGIN/END` breaks things and I probably won't take the time to fix it, becuase it's nontrivial and its really meant for command-line scripts, but there is currently a cuke for it
92
+ * `BEGIN/END` breaks things and I probably won't ever fix it, becuase it's annoying and its really meant for command-line scripts... but there is currently a spec for it
177
93
  * `exit!` ignores callbacks that `SeeingIsBelieving` uses to communicate the results back to the main app. If you call it, `SeeingIsBelieving` will blow up. We could "fix" this by overriding it, but I feel like that would violate the meaning of `exit!`, so basically, just don't call that method.
94
+ * The code to find the data segment is naive, and could wind up interpolating results into a string or something
178
95
 
179
96
  Todo
180
97
  ====
181
98
 
182
99
  * Sublime: Merge xmpfilter option into main after 2.0 release
183
- * Make TextMate 1 and 2 bundles
184
- * Go through each cuke and spec, implementing however many not-implemented ones that we can
185
- * Make sure the examples in this readme all still make sense (mountain berry fields?)
186
- * Go through Peter's email about how to make the use of Parser better
187
100
  * Make a new video
188
- * Add versions to the debugging output
189
- * Shorten the debugging output
190
101
 
191
102
  Shit that will probably never get done (or if it does, won't be until after 2.0)
192
103
  ================================================================================
@@ -215,7 +126,3 @@ License
215
126
  0. You just DO WHAT THE FUCK YOU WANT TO.
216
127
 
217
128
 
218
-
219
- [inventing_on_principle]: http://vimeo.com/36579366
220
- [textmate-integration]: https://raw.github.com/JoshCheek/seeing_is_believing/master/textmate-integration.png
221
- [video]: http://vimeo.com/58766950
@@ -93,7 +93,7 @@ Feature: Running the binary unsuccessfully
93
93
  """
94
94
 
95
95
  Scenario: Total Fucking Failure
96
- Given the file "sib_will_utterly_die.rb" "BEGIN {}"
96
+ Given the file "sib_will_utterly_die.rb" "__TOTAL_FUCKING_FAILURE__"
97
97
  When I run "seeing_is_believing sib_will_utterly_die.rb"
98
98
  Then stderr is not empty
99
99
  And the exit status is 2
@@ -196,47 +196,6 @@ Feature: Running the binary successfully
196
196
  2
197
197
  """
198
198
 
199
- @not-implemented
200
- Scenario: Doesn't record BEGIN/END since that's apparently a syntax error
201
- Given the file "BEGIN_and_END.rb":
202
- """
203
- puts 1
204
- BEGIN {
205
- puts "begin code"
206
- some_var = 2
207
- }
208
- puts 3
209
- END {
210
- puts "end code"
211
- puts some_var
212
- }
213
- puts 4
214
- """
215
- When I run "seeing_is_believing BEGIN_and_END.rb"
216
- Then stderr is empty
217
- And the exit status is 0
218
- And stdout is:
219
- """
220
- puts 1 # => nil
221
- BEGIN {
222
- puts "begin code" # => nil
223
- some_var = 2 # => 2
224
- }
225
- puts 3 # => nil
226
- END {
227
- puts "end code" # => nil
228
- puts some_var # => nil
229
- }
230
- puts 4 # => nil
231
-
232
- # >> begin code
233
- # >> 1
234
- # >> 3
235
- # >> 4
236
- # >> end code
237
- # >> 2
238
- """
239
-
240
199
  Scenario: Reading from stdin
241
200
  Given the stdin content "hi!"
242
201
  And the file "reads_from_stdin.rb":
@@ -184,6 +184,19 @@ Feature: Using flags
184
184
  When I run "seeing_is_believing --line-length 14 line_lengths2.rb"
185
185
  Then stdout is "12345"
186
186
 
187
+ Scenario: --xmpfilter-style respects the line formatting (but not currently alignment strategies, it just preserves submitted alignment)
188
+ Given the file "line_lengths3.rb":
189
+ """
190
+ '1' * 30 # =>
191
+ # =>
192
+ """
193
+ When I run "seeing_is_believing --xmpfilter-style --line-length 19 line_lengths3.rb"
194
+ Then stdout is:
195
+ """
196
+ '1' * 30 # => "1...
197
+ # => "1111111111...
198
+ """
199
+
187
200
 
188
201
  Scenario: --require
189
202
  Given the file "print_1.rb" "puts 1"
@@ -292,7 +305,6 @@ Feature: Using flags
292
305
  """
293
306
 
294
307
 
295
- @not-implemented
296
308
  Scenario: --clean on an invalid file will clean
297
309
  When I run 'seeing_is_believing --clean -e "1+ # => lkj"'
298
310
  Then stderr is empty
@@ -105,7 +105,7 @@ Feature:
105
105
  __END__
106
106
  """
107
107
  When I run "seeing_is_believing modified_result.rb"
108
- Then stdout is:
108
+ Then stdout is exactly:
109
109
  """
110
110
  1 # => 1
111
111
  2 # => 2
@@ -6,3 +6,7 @@ Haiti.configure do |config|
6
6
  config.bin_dir = File.expand_path '../../../bin', __FILE__
7
7
  end
8
8
 
9
+
10
+ Then 'stdout is exactly:' do |code|
11
+ @last_executed.stdout.should == eval_curlies(code)
12
+ end
@@ -11,6 +11,18 @@ class SeeingIsBelieving
11
11
  DISPLAYABLE_ERROR_STATUS = 1 # e.g. there was an error, but the output is legit (we can display exceptions)
12
12
  NONDISPLAYABLE_ERROR_STATUS = 2 # e.g. an error like incorrect invocation or syntax that can't be displayed in the input program
13
13
 
14
+ VALUE_MARKER = "# => "
15
+ EXCEPTION_MARKER = "# ~> "
16
+ STDOUT_MARKER = "# >> "
17
+ STDERR_MARKER = "# !> "
18
+
19
+ VALUE_REGEX = /\A#\s*=>/
20
+ EXCEPTION_REGEX = /\A#\s*~>/
21
+ STDOUT_REGEX = /\A#\s*>>/
22
+ STDERR_REGEX = /\A#\s*!>/
23
+
24
+
25
+
14
26
  attr_accessor :argv, :stdin, :stdout, :stderr, :timeout_error, :unexpected_exception
15
27
 
16
28
  def initialize(argv, stdin, stdout, stderr)
@@ -138,7 +150,7 @@ class SeeingIsBelieving
138
150
  end
139
151
 
140
152
  def print_program
141
- stdout.puts interpolated_program
153
+ stdout.print interpolated_program
142
154
  end
143
155
 
144
156
  def syntax_error_notice
@@ -2,6 +2,7 @@ require 'stringio'
2
2
  require 'seeing_is_believing/has_exception'
3
3
  require 'seeing_is_believing/binary/comment_formatter'
4
4
 
5
+ require 'seeing_is_believing/binary'
5
6
  require 'seeing_is_believing/binary/clean_body'
6
7
  require 'seeing_is_believing/binary/rewrite_comments'
7
8
  require 'seeing_is_believing/binary/comment_lines'
@@ -22,7 +23,7 @@ class SeeingIsBelieving
22
23
  method_from_options :debugger
23
24
 
24
25
  attr_accessor :results, :body
25
- def initialize(uncleaned_body, options={})
26
+ def initialize(uncleaned_body, options={}, &annotater)
26
27
  self.options = options
27
28
  self.body = CleanBody.call uncleaned_body, !xmpfilter_style
28
29
  self.results = SeeingIsBelieving.call body,
@@ -38,49 +39,13 @@ class SeeingIsBelieving
38
39
 
39
40
  def call
40
41
  @new_body ||= begin
41
- # uhm, these basically look like strategies for commenting.
42
42
  new_body = if xmpfilter_style
43
- RewriteComments.call body do |line_number, line, whitespace, comment|
44
- # FIXME: can we centralize these regexes?
45
- if !comment[/\A#\s*=>/]
46
- [whitespace, comment]
47
- elsif line.empty?
48
- # should go through comment formatter
49
- [whitespace, "# => #{results[line_number-1].map { |result| result.gsub "\n", '\n' }.join(', ')}"] # FIXME: NEED TO CONSIDER THE LINE LENGTH
50
- else
51
- # should go through comment formatter
52
- [whitespace, "# => #{results[line_number].map { |result| result.gsub "\n", '\n' }.join(', ')}"] # FIXME: NEED TO CONSIDER THE LINE LENGTH
53
- end
54
- end
55
- else
56
- alignment_strategy = options[:alignment_strategy].new body, start_line, end_line
57
- CommentLines.call body do |line, line_number|
58
- options = options().merge pad_to: alignment_strategy.line_length_for(line_number)
59
- if line_number < start_line || end_line < line_number
60
- ''
61
- elsif results[line_number].has_exception?
62
- exception = results[line_number].exception
63
- result = sprintf "%s: %s", exception.class_name, exception.message.gsub("\n", '\n')
64
- CommentFormatter.new(line.size, "# ~> ", result, options).call
65
- elsif results[line_number].any?
66
- result = results[line_number].map { |result| result.gsub "\n", '\n' }.join(', ')
67
- CommentFormatter.call(line.size, "# => ", result, options)
68
- else
69
- ''
70
- end
71
- end
72
- end
73
-
74
- output = stdout_ouptut_for(results) <<
75
- stderr_ouptut_for(results) <<
76
- exception_output_for(results)
43
+ body_with_updated_annotations
44
+ else
45
+ body_with_everything_annotated
46
+ end
77
47
 
78
- if new_body["\n__END__\n"]
79
- new_body.sub! "\n__END__\n", "\n#{output}__END__\n"
80
- else
81
- new_body << "\n" unless new_body.end_with? "\n"
82
- new_body << output
83
- end
48
+ add_stdout_stderr_and_exceptions_to new_body
84
49
 
85
50
  debugger.context "OUTPUT"
86
51
  new_body
@@ -91,11 +56,60 @@ class SeeingIsBelieving
91
56
 
92
57
  attr_accessor :body, :options, :alignment_strategy
93
58
 
59
+ # doesn't currently realign output markers, do we want to do that?
60
+ def body_with_updated_annotations
61
+ RewriteComments.call body do |line_number, line_to_whitespace, whitespace, comment|
62
+ if !comment[VALUE_REGEX]
63
+ [whitespace, comment]
64
+ elsif line_to_whitespace.empty?
65
+ result = results[line_number-1].map { |result| result.gsub "\n", '\n' }.join(', ')
66
+ [whitespace, CommentFormatter.call(whitespace.size, VALUE_MARKER, result, options)]
67
+ else
68
+ result = results[line_number].map { |result| result.gsub "\n", '\n' }.join(', ')
69
+ [whitespace, CommentFormatter.call(line_to_whitespace.size + whitespace.size, VALUE_MARKER, result, options)]
70
+ end
71
+ end
72
+ end
73
+
74
+ def body_with_everything_annotated
75
+ alignment_strategy = options[:alignment_strategy].new body, start_line, end_line
76
+ CommentLines.call body do |line, line_number|
77
+ options = options().merge pad_to: alignment_strategy.line_length_for(line_number)
78
+ if line_number < start_line || end_line < line_number
79
+ ''
80
+ elsif results[line_number].has_exception?
81
+ exception = results[line_number].exception
82
+ result = sprintf "%s: %s", exception.class_name, exception.message.gsub("\n", '\n')
83
+ CommentFormatter.call(line.size, EXCEPTION_MARKER, result, options)
84
+ elsif results[line_number].any?
85
+ result = results[line_number].map { |result| result.gsub "\n", '\n' }.join(', ')
86
+ CommentFormatter.call(line.size, VALUE_MARKER, result, options)
87
+ else
88
+ ''
89
+ end
90
+ end
91
+ end
92
+
93
+ def add_stdout_stderr_and_exceptions_to(new_body)
94
+ output = stdout_ouptut_for(results) <<
95
+ stderr_ouptut_for(results) <<
96
+ exception_output_for(results)
97
+
98
+ # this technically could find an __END__ in a string or whatever
99
+ # going to just ignore that, though
100
+ if new_body[/^__END__$/]
101
+ new_body.sub! "\n__END__", "\n#{output}__END__"
102
+ else
103
+ new_body << "\n" unless new_body.end_with? "\n"
104
+ new_body << output
105
+ end
106
+ end
107
+
94
108
  def stdout_ouptut_for(results)
95
109
  return '' unless results.has_stdout?
96
110
  output = "\n"
97
111
  results.stdout.each_line do |line|
98
- output << CommentFormatter.call(0, "# >> ", line.chomp, options()) << "\n"
112
+ output << CommentFormatter.call(0, STDOUT_MARKER, line.chomp, options()) << "\n"
99
113
  end
100
114
  output
101
115
  end
@@ -104,7 +118,7 @@ class SeeingIsBelieving
104
118
  return '' unless results.has_stderr?
105
119
  output = "\n"
106
120
  results.stderr.each_line do |line|
107
- output << CommentFormatter.call(0, "# !> ", line.chomp, options()) << "\n"
121
+ output << CommentFormatter.call(0, STDERR_MARKER, line.chomp, options()) << "\n"
108
122
  end
109
123
  output
110
124
  end
@@ -113,13 +127,13 @@ class SeeingIsBelieving
113
127
  return '' unless results.has_exception?
114
128
  exception = results.exception
115
129
  output = "\n"
116
- output << CommentFormatter.new(0, "# ~> ", exception.class_name, options).call << "\n"
130
+ output << CommentFormatter.new(0, EXCEPTION_MARKER, exception.class_name, options).call << "\n"
117
131
  exception.message.each_line do |line|
118
- output << CommentFormatter.new(0, "# ~> ", line.chomp, options).call << "\n"
132
+ output << CommentFormatter.new(0, EXCEPTION_MARKER, line.chomp, options).call << "\n"
119
133
  end
120
- output << "# ~>\n"
134
+ output << EXCEPTION_MARKER.sub(/\s+$/, '') << "\n"
121
135
  exception.backtrace.each do |line|
122
- output << CommentFormatter.new(0, "# ~> ", line.chomp, options).call << "\n"
136
+ output << CommentFormatter.new(0, EXCEPTION_MARKER, line.chomp, options).call << "\n"
123
137
  end
124
138
  output
125
139
  end
@@ -18,7 +18,9 @@ class SeeingIsBelieving
18
18
  end
19
19
 
20
20
  def call
21
- buffer, parser, rewriter, ast, comments = ParserHelpers.initialize_parser code, 'strip_comments'
21
+ buffer, parser, rewriter = ParserHelpers.initialize_parser code, 'strip_comments'
22
+ comments = ParserHelpers.comments_from parser, buffer
23
+
22
24
  removed_comments = { result: [], exception: [], stdout: [], stderr: [] }
23
25
 
24
26
  comments.each do |comment|
@@ -76,7 +78,7 @@ class SeeingIsBelieving
76
78
  current_chunk = 0
77
79
  last_line_seen = -100
78
80
  chunks_to_comment = comments.chunk do |comment|
79
- line, col = buffer.decompose_position comment.location.begin_pos
81
+ line = comment.location.begin_pos.line
80
82
  if last_line_seen.next == line
81
83
  last_line_seen = line
82
84
  current_chunk
@@ -2,6 +2,8 @@ require 'seeing_is_believing/parser_helpers'
2
2
 
3
3
  class SeeingIsBelieving
4
4
  class Binary
5
+
6
+ # could possibly be sped up by just reflecting on the tokens instead of the whole ast
5
7
  class CommentableLines
6
8
 
7
9
  include ParserHelpers
@@ -12,8 +14,8 @@ class SeeingIsBelieving
12
14
 
13
15
  def initialize(code)
14
16
  self.code = code
15
- self.buffer, self.parser, self.rewriter, self.root, self.comments =
16
- initialize_parser(code, 'strip_comments')
17
+ self.buffer, self.parser, self.rewriter = initialize_parser(code, 'finding_commentable_lines')
18
+ self.root, self.comments = parser.parse_with_comments(buffer)
17
19
  end
18
20
 
19
21
  def call
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'stringio'
4
4
  require 'seeing_is_believing/version'
5
+ require 'seeing_is_believing/binary'
5
6
  require 'seeing_is_believing/debugger'
6
7
  require 'seeing_is_believing/binary/align_file'
7
8
  require 'seeing_is_believing/binary/align_line'
@@ -145,7 +146,7 @@ Usage: seeing_is_believing [options] [filename]
145
146
  -l, --start-line n # line number to begin showing results on
146
147
  -L, --end-line n # line number to stop showing results on
147
148
  -d, --line-length n # max length of the entire line (only truncates results, not source lines)
148
- -D, --result-length n # max length of the portion after the "# => "
149
+ -D, --result-length n # max length of the portion after the "#{VALUE_MARKER}"
149
150
  -s, --alignment-strategy name # select the alignment strategy:
150
151
  chunk (DEFAULT) => each chunk of code is at the same alignment
151
152
  file => the entire file is at the same alignment
@@ -168,53 +169,53 @@ Examples: A few examples, for a more comprehensive set of examples, check out fe
168
169
 
169
170
  Run the file f.rb
170
171
  $ echo __FILE__ > f.rb; seeing_is_believing f.rb
171
- __FILE__ # => "f.rb"
172
+ __FILE__ #{VALUE_MARKER}"f.rb"
172
173
 
173
174
  Aligning comments
174
175
  $ ruby -e 'puts "123\\n4\\n\\n567890"' > f.rb
175
176
 
176
177
 
177
178
  $ seeing_is_believing f.rb -s line
178
- 123 # => 123
179
- 4 # => 4
179
+ 123 #{VALUE_MARKER}123
180
+ 4 #{VALUE_MARKER}4
180
181
 
181
- 567890 # => 567890
182
+ 567890 #{VALUE_MARKER}567890
182
183
 
183
184
 
184
185
  $ seeing_is_believing f.rb -s chunk
185
- 123 # => 123
186
- 4 # => 4
186
+ 123 #{VALUE_MARKER}123
187
+ 4 #{VALUE_MARKER}4
187
188
 
188
- 567890 # => 567890
189
+ 567890 #{VALUE_MARKER}567890
189
190
 
190
191
 
191
192
  $ seeing_is_believing f.rb -s file
192
- 123 # => 123
193
- 4 # => 4
193
+ 123 #{VALUE_MARKER}123
194
+ 4 #{VALUE_MARKER}4
194
195
 
195
- 567890 # => 567890
196
+ 567890 #{VALUE_MARKER}567890
196
197
 
197
198
  Run against standard input
198
199
  $ echo '3.times { |i| puts i }' | seeing_is_believing
199
- 2.times { |i| puts i } # => 2
200
+ 2.times { |i| puts i } #{VALUE_MARKER}2
200
201
 
201
- # >> 0
202
- # >> 1
202
+ #{STDOUT_MARKER}0
203
+ #{STDOUT_MARKER}1
203
204
 
204
205
  Run against a library you're working on by fixing the load path
205
206
  $ seeing_is_believing -I lib f.rb
206
207
 
207
208
  Load up some library (can be used in tandem with -I)
208
209
  $ seeing_is_believing -r pp -e 'pp [[*1..15],[*15..30]]; nil'
209
- pp [[*1..15],[*15..30]]; nil # => nil
210
+ pp [[*1..15],[*15..30]]; nil #{VALUE_MARKER}nil
210
211
 
211
- # >> [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
212
- # >> [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]]
212
+ #{STDOUT_MARKER}[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
213
+ #{STDOUT_MARKER} [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]]
213
214
 
214
215
  Only update the lines you've marked
215
216
  $ ruby -e 'puts "1\\n2 # =>\\n3"' | seeing_is_believing -x
216
217
  1
217
- 2 # => 2
218
+ 2 #{VALUE_MARKER}2
218
219
  3
219
220
 
220
221
  Set a timeout (especially useful if running via an editor)
@@ -223,11 +224,11 @@ Examples: A few examples, for a more comprehensive set of examples, check out fe
223
224
 
224
225
  Set the encoding to utf-8
225
226
  $ seeing_is_believing -Ku -e '"⛄ "'
226
- "⛄ " # => "⛄ "
227
+ "⛄ " #{VALUE_MARKER}"⛄ "
227
228
 
228
229
  The exit status will be 1 if the error is displayable inline
229
230
  $ seeing_is_believing -e 'raise "omg"'; echo $?
230
- raise "omg" # ~> RuntimeError: omg
231
+ raise "omg" #{EXCEPTION_MARKER}RuntimeError: omg
231
232
  1
232
233
 
233
234
  The exit status will be 2 if the error is not displayable
@@ -236,15 +237,15 @@ Examples: A few examples, for a more comprehensive set of examples, check out fe
236
237
  2
237
238
 
238
239
  Run with previous output
239
- $ echo "1+1 # => old-value" | seeing_is_believing
240
- 1+1 # => 2
240
+ $ echo "1+1 #{VALUE_MARKER}old-value" | seeing_is_believing
241
+ 1+1 #{VALUE_MARKER}2
241
242
 
242
- $ echo "1+1 # => old-value" | seeing_is_believing --clean
243
+ $ echo "1+1 #{VALUE_MARKER}old-value" | seeing_is_believing --clean
243
244
  1+1
244
245
 
245
246
  If your Ruby binary is named something else (e.g. ruby2.0)
246
247
  $ ruby2.0 -S seeing_is_believing --shebang ruby2.0 -e '123'
247
- 123 # => 123
248
+ 123 #{VALUE_MARKER}123
248
249
 
249
250
  HELP_SCREEN
250
251
  end
@@ -4,7 +4,8 @@ class SeeingIsBelieving
4
4
  class Binary
5
5
  module RewriteComments
6
6
  def self.call(code, &mapping)
7
- buffer, parser, rewriter, ast, comments = ParserHelpers.initialize_parser code, 'strip_comments'
7
+ buffer, parser, rewriter = ParserHelpers.initialize_parser code, 'rewrite_comments'
8
+ ast, comments = parser.parse_with_comments buffer
8
9
 
9
10
  comments.each do |comment|
10
11
  next unless comment.type == :inline
@@ -1,15 +1,36 @@
1
1
  require 'parser/current'
2
2
  class SeeingIsBelieving
3
3
  module ParserHelpers
4
+
5
+ # override #process so it does not raise an error on
6
+ # fatal parsings (we want to keep going if possible,
7
+ # this allows us to find comments in syntactically invalid files
8
+ class NullDiagnostics < Parser::Diagnostic::Engine
9
+ def process(*)
10
+ # no op
11
+ end
12
+ end
13
+
4
14
  extend self
5
15
 
6
16
  def initialize_parser(code, name)
7
- buffer = Parser::Source::Buffer.new(name)
8
- buffer.source = code
9
- parser = Parser::CurrentRuby.new
10
- root, comments = parser.parse_with_comments buffer
11
- rewriter = Parser::Source::Rewriter.new buffer
12
- [buffer, parser, rewriter, root, comments]
17
+ buffer = Parser::Source::Buffer.new(name)
18
+ buffer.source = code
19
+
20
+ builder = Parser::Builders::Default.new
21
+ builder.emit_file_line_as_literals = false
22
+
23
+ parser = Parser::CurrentRuby.new builder
24
+ rewriter = Parser::Source::Rewriter.new buffer
25
+
26
+ [buffer, parser, rewriter]
27
+ end
28
+
29
+ # useful b/c it can find comments even in syntactically invalid code
30
+ def comments_from(parser, buffer)
31
+ parser.instance_variable_set(:@diagnostics, NullDiagnostics.new) # seems really fucking risky
32
+ success, comments, tokens, * = parser.tokenize buffer # experimentally, seems to be what these things return
33
+ comments
13
34
  end
14
35
 
15
36
  # this is the scardest fucking method I think I've ever written.
@@ -21,7 +42,6 @@ class SeeingIsBelieving
21
42
  ast.kind_of?(Parser::AST::Node) &&
22
43
  (ast.type == :dstr || ast.type == :str) &&
23
44
  (location = ast.location) &&
24
- (location.respond_to?(:begin)) &&
25
45
  (the_begin = location.begin) &&
26
46
  (the_begin.source =~ /^\<\<-?/)
27
47
  end
@@ -1,3 +1,3 @@
1
1
  class SeeingIsBelieving
2
- VERSION = '2.0.0.beta3'
2
+ VERSION = '2.0.0'
3
3
  end
@@ -45,7 +45,8 @@ class SeeingIsBelieving
45
45
  self.after_all = wrappings.fetch :after_all, ''.freeze
46
46
  self.before_each = wrappings.fetch :before_each, -> * { '' }
47
47
  self.after_each = wrappings.fetch :after_each, -> * { '' }
48
- self.buffer, _, self.rewriter, self.root, _ = initialize_parser(program, 'program-without-annotations')
48
+ self.buffer, parser, self.rewriter = initialize_parser(program, 'program-without-annotations')
49
+ self.root = parser.parse buffer
49
50
  self.wrappings = {}
50
51
  rescue Parser::SyntaxError => e
51
52
  raise ::SyntaxError, e.message
@@ -58,8 +59,15 @@ class SeeingIsBelieving
58
59
  if root # file may be empty
59
60
  rewriter.insert_before root.location.expression, before_all
60
61
 
61
- wrappings.each do |line_num, (range, last_col)|
62
+
63
+ wrappings.each do |line_num, (range, last_col, meta)|
62
64
  rewriter.insert_before range, before_each.call(line_num)
65
+ if meta == :wrap_in_braces
66
+ rewriter.insert_before range, '{'
67
+ rewriter.insert_after range, '}'
68
+ elsif meta == :total_fucking_failure
69
+ rewriter.replace range, '.....TOTAL FUCKING FAILURE!.....'
70
+ end
63
71
  rewriter.insert_after range, after_each.call(line_num)
64
72
  end
65
73
 
@@ -78,12 +86,12 @@ class SeeingIsBelieving
78
86
 
79
87
  attr_accessor :program, :before_all, :after_all, :before_each, :after_each, :buffer, :root, :rewriter, :wrappings
80
88
 
81
- def add_to_wrappings(range_or_ast)
89
+ def add_to_wrappings(range_or_ast, meta=nil)
82
90
  range = range_or_ast
83
91
  range = range_or_ast.location.expression if range.kind_of? ::AST::Node
84
92
  line, col = buffer.decompose_position range.end_pos
85
- _, prev_col = wrappings[line]
86
- wrappings[line] = (!wrappings[line] || prev_col < col ? [range, col] : wrappings[line] )
93
+ _, prev_col, _ = wrappings[line]
94
+ wrappings[line] = (!wrappings[line] || prev_col < col ? [range, col, meta] : wrappings[line] )
87
95
  end
88
96
 
89
97
  def add_children(ast, omit_first = false)
@@ -228,7 +236,10 @@ class SeeingIsBelieving
228
236
 
229
237
  begin_pos = ast.location.expression.begin_pos
230
238
  range = Parser::Source::Range.new(buffer, begin_pos, end_pos)
231
- add_to_wrappings range
239
+
240
+ meta = nil
241
+ meta = :total_fucking_failure if message == :__TOTAL_FUCKING_FAILURE__
242
+ add_to_wrappings range, meta
232
243
  add_children ast
233
244
  when :begin
234
245
  last_child = ast.children.last
@@ -242,6 +253,13 @@ class SeeingIsBelieving
242
253
  add_children ast
243
254
  when :str, :dstr, :xstr, :regexp
244
255
  add_to_wrappings heredoc_hack ast
256
+
257
+ when :hash
258
+ meta = :wrap_in_braces
259
+ meta = nil if ast.location.begin
260
+ add_to_wrappings ast, meta
261
+ add_children ast
262
+
245
263
  else
246
264
  add_to_wrappings ast
247
265
  add_children ast
@@ -125,17 +125,17 @@ describe SeeingIsBelieving do
125
125
  values_for("-> { \n return 1 \n }.call" ).should == [[], ['1'], ['1']]
126
126
  values_for("-> { return 1 }.call" ).should == [['1']]
127
127
 
128
- pending "we'd like this to record 1 and nil, but currently we dont' differentiate between inline and multiline if statements" do
128
+ pending "would be really cool if this would record 1 and nil, but it probably won't ever happen." do
129
+ # Currently we dont' differentiate between inline and multiline if statements,
130
+ # also, we can't wrap the whole statement since it's void value, which means we'd have to introduce
131
+ # the idea of multiple wrappings for the same line, which I just don't care enough about to consider
129
132
  values_for("def meth \n return 1 if true \n end \n meth").should == [[], ['1'], [], ['1']] # records true instead of 1
130
133
  values_for("def meth \n return 1 if false \n end \n meth").should == [[], ['nil'], [], ['nil']] # records false instead of nil
131
134
  end
132
135
  end
133
136
 
134
137
  it 'does not try to record the keyword next' do
135
- # tbh, I don't even really know what I want in this case. Maybe record nothing since there is no arg to next?
136
- pending 'broken because of misordering in the rewriter' do
137
- values_for("(1..2).each do |i|\nnext if i == 1\ni\nend").should == [['1..2'], [], ['true', 'false'], ['1..2']]
138
- end
138
+ values_for("(1..2).each do |i|\nnext if i == 1\ni\nend").should == [['1..2'], ['true', 'false'], ['2'], ['1..2']]
139
139
  end
140
140
 
141
141
  it 'does not try to record the keyword redo' do
@@ -152,25 +152,28 @@ describe SeeingIsBelieving do
152
152
  end
153
153
 
154
154
  it 'does not try to record the keyword retry' do
155
- pending 'uhhh, what do I want here?' do
156
- values_for(<<-DOC).should == [[], [], [], ['nil']]
157
- def meth
158
- rescue
159
- retry
160
- end
161
- DOC
162
- end
155
+ values_for(<<-DOC).should == [[], [], [], [], ['nil']]
156
+ def meth
157
+ rescue
158
+ retry
159
+ end
160
+ meth
161
+ DOC
163
162
  end
164
163
 
165
164
  it 'does not try to record the keyword retry' do
166
- pending 'uhhh, what do I want here?' do
167
- values_for(<<-DOC).should == [[], ['0'], [], ['nil']]
168
- (0..2).each do |n|
169
- n
170
- break
171
- end
172
- DOC
173
- end
165
+ values_for(<<-DOC).should == [['0..2'], ['0'], [], ['nil']]
166
+ (0..2).each do |n|
167
+ n
168
+ break
169
+ end
170
+ DOC
171
+ values_for(<<-DOC).should == [['0..2'], ['0'], ['10'], ['10']]
172
+ (0..2).each do |n|
173
+ n
174
+ break 10
175
+ end
176
+ DOC
174
177
  end
175
178
 
176
179
  it 'does not affect its environment' do
@@ -319,6 +322,22 @@ describe SeeingIsBelieving do
319
322
  end
320
323
  end
321
324
 
325
+ it 'does not record BEGIN and END', not_implemented: true do
326
+ expect { invoke <<-CODE }.to_not raise_error
327
+ puts 1
328
+ BEGIN {
329
+ puts "begin code"
330
+ some_var = 2
331
+ }
332
+ puts 3
333
+ END {
334
+ puts "end code"
335
+ puts some_var
336
+ }
337
+ puts 4
338
+ CODE
339
+ end
340
+
322
341
  context 'when given a debugger' do
323
342
  let(:stream) { StringIO.new }
324
343
  let(:debugger) { SeeingIsBelieving::Debugger.new stream: stream }
@@ -1,9 +1,5 @@
1
1
  require 'seeing_is_believing/wrap_expressions'
2
2
 
3
- # eventually make this not wrap BEGIN and END
4
- # but for now, leave it b/c it's convenient to be able to make it blow up
5
- # Probably replace this with some macro like __INVALID_SYNTAX__ that blows it up :)
6
-
7
3
  describe SeeingIsBelieving::WrapExpressions do
8
4
  def wrap(code)
9
5
  described_class.call code,
@@ -15,6 +11,10 @@ describe SeeingIsBelieving::WrapExpressions do
15
11
  expect { wrap '+' }.to raise_error SyntaxError
16
12
  end
17
13
 
14
+ it 'can inject syntax errors with __TOTAL_FUCKING_FAILURE__' do
15
+ wrap('__TOTAL_FUCKING_FAILURE__').should == '<.....TOTAL FUCKING FAILURE!.....>'
16
+ end
17
+
18
18
  describe 'wrapping the body' do
19
19
  let(:options) { { before_all: "[",
20
20
  after_all: "]",
@@ -514,6 +514,10 @@ describe SeeingIsBelieving::WrapExpressions do
514
514
  wrap("{\n1 => 2}").should == "<{\n1 => 2}>"
515
515
  wrap("{\n1 => 2,\n:abc => 3,\ndef: 4\n}").should == "<{\n1 => <2>,\n:abc => <3>,\ndef: <4>\n}>"
516
516
  end
517
+
518
+ it 'wraps explicit braces around recorded in method invocations' do
519
+ wrap("a(\nb: 1, c: 2\n)").should == "<a(\n<{b: 1, c: 2}>\n)>"
520
+ end
517
521
  end
518
522
 
519
523
  describe 'array literals' do
@@ -761,4 +765,32 @@ describe SeeingIsBelieving::WrapExpressions do
761
765
  end
762
766
  end
763
767
  end
768
+
769
+ describe 'BEGIN/END' do
770
+ # not implemented b/c we cannot wrap around these either.
771
+ # So what does it mean to wrap around?
772
+ # mabe this?
773
+ # 1
774
+ # BEGIN {}
775
+ # 2
776
+ # END {}
777
+ # 3
778
+ #
779
+ # becomes
780
+ # BEGIN {}
781
+ # END {}
782
+ # [<1>
783
+ # <2>
784
+ # <3>]
785
+ #
786
+ # idk, but then we also need to deal with the fact that we're changing result of __LINE__
787
+ # which we could do with some meta, just replacing it with the literal when we parse it
788
+ # but still, moving this out of here will be really annoying, and no one is going to use it, so fuck it
789
+ it 'does not record them', not_implemented: true do
790
+ wrap("BEGIN {}").should == "BEGIN {}"
791
+ wrap("END {}").should == "END {}"
792
+ wrap("BEGIN {\n123\n}").should == "BEGIN {\n<123>\n}"
793
+ wrap("END {\n123\n}").should == "END {\n<123>\n}"
794
+ end
795
+ end
764
796
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: seeing_is_believing
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta3
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Cheek
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-14 00:00:00.000000000 Z
11
+ date: 2013-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -166,9 +166,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
166
166
  version: '0'
167
167
  required_rubygems_version: !ruby/object:Gem::Requirement
168
168
  requirements:
169
- - - '>'
169
+ - - '>='
170
170
  - !ruby/object:Gem::Version
171
- version: 1.3.1
171
+ version: '0'
172
172
  requirements: []
173
173
  rubyforge_project: seeing_is_believing
174
174
  rubygems_version: 2.0.5
@@ -192,4 +192,3 @@ test_files:
192
192
  - spec/line_spec.rb
193
193
  - spec/seeing_is_believing_spec.rb
194
194
  - spec/wrap_expressions_spec.rb
195
- has_rdoc: