seeing_is_believing 0.0.24 → 0.0.26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Readme.md +7 -1
- data/bin/seeing_is_believing +1 -1
- data/features/flags.feature +17 -5
- data/features/regression.feature +40 -0
- data/lib/seeing_is_believing/binary/arg_parser.rb +34 -31
- data/lib/seeing_is_believing/binary/print_results_next_to_lines.rb +66 -35
- data/lib/seeing_is_believing/binary.rb +38 -37
- data/lib/seeing_is_believing/expression_list.rb +8 -4
- data/lib/seeing_is_believing/remove_inline_comments.rb +22 -0
- data/lib/seeing_is_believing/syntax_analyzer.rb +6 -1
- data/lib/seeing_is_believing/version.rb +1 -1
- data/lib/seeing_is_believing.rb +6 -1
- data/seeing_is_believing.gemspec +1 -1
- data/spec/seeing_is_believing_spec.rb +28 -7
- data/spec/syntax_analyzer_spec.rb +12 -0
- metadata +28 -41
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dda86a6b926231e08234e6a6a7c7fde07d650888
|
4
|
+
data.tar.gz: 39ab6eff76179f074c4382d5ffef3d49683bc624
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c4ad0cc0e416f1c1e01b9650a6e5a2143dbeccb4c668478b179e2a3898b0b9655c5b920b334f69e7bce7d748b4204930ab9a5d376b51dc49b727399b40e6c875
|
7
|
+
data.tar.gz: c27f2c5220c0a9e6991384de68dc4c9e3de44f7de954356311fae9989b45d531240f40be3cb6ffca5536820967efd2123aa7353ec2f1cc474566120b634bf311
|
data/Readme.md
CHANGED
@@ -146,8 +146,14 @@ Known Issues
|
|
146
146
|
Todo
|
147
147
|
====
|
148
148
|
|
149
|
+
* Make a Lines class which is a collection of lines, responsible for managing the trailing newlines in Binary::PrintResultsNextToLines and SeeingIsBelieving/ExpressionList
|
150
|
+
* Add examples of invocations to the help screen
|
151
|
+
* Add xmpfilter option to sublime text
|
152
|
+
* Update TextMate examples to use same keys as sublime, add xmpfilter option on cmd+opt+N
|
149
153
|
* Move as much of the SyntaxAnalyzer as possible over to Parser and ditch Ripper altogether
|
150
|
-
*
|
154
|
+
* print exceptions at the end of the file, too
|
155
|
+
|
156
|
+
|
151
157
|
|
152
158
|
License
|
153
159
|
=======
|
data/bin/seeing_is_believing
CHANGED
data/features/flags.feature
CHANGED
@@ -420,20 +420,32 @@ Feature: Using flags
|
|
420
420
|
When I run "seeing_is_believing --inherit-exit-status exit_status_in_at_exit_block.rb"
|
421
421
|
Then the exit status is 10
|
422
422
|
|
423
|
-
|
423
|
+
# after making this use the parser instead of regexes, add a test showing that the line `"1 # =>"` does not get updated
|
424
424
|
Scenario: --xmpfilter-style
|
425
425
|
Given the file "magic_comments.rb":
|
426
426
|
"""
|
427
|
-
1# =>
|
428
|
-
|
427
|
+
1+1# =>
|
428
|
+
2+2 # => 10
|
429
|
+
"a
|
430
|
+
b" # =>
|
429
431
|
1
|
432
|
+
"omg"
|
433
|
+
# =>
|
434
|
+
"omg2"
|
435
|
+
# => "not omg2"
|
430
436
|
"""
|
431
437
|
When I run "seeing_is_believing --xmpfilter-style magic_comments.rb"
|
432
438
|
Then stderr is empty
|
433
439
|
And the exit status is 0
|
434
440
|
And stdout is:
|
435
441
|
"""
|
436
|
-
1# =>
|
437
|
-
|
442
|
+
1+1# => 2
|
443
|
+
2+2 # => 4
|
444
|
+
"a
|
445
|
+
b" # => "a\n b"
|
438
446
|
1
|
447
|
+
"omg"
|
448
|
+
# => "omg"
|
449
|
+
"omg2"
|
450
|
+
# => "omg2"
|
439
451
|
"""
|
data/features/regression.feature
CHANGED
@@ -60,3 +60,43 @@ Feature:
|
|
60
60
|
m # => 1
|
61
61
|
"""
|
62
62
|
|
63
|
+
Scenario: comments aren't updated with values
|
64
|
+
Given the file "comments_arent_updated_with_values.rb":
|
65
|
+
"""
|
66
|
+
1 # some comment
|
67
|
+
2 # some other comment
|
68
|
+
"""
|
69
|
+
When I run "seeing_is_believing comments_arent_updated_with_values.rb"
|
70
|
+
Then stdout is:
|
71
|
+
"""
|
72
|
+
1 # some comment
|
73
|
+
2 # some other comment
|
74
|
+
"""
|
75
|
+
|
76
|
+
# NOTE: Don't change the body of this file, it's nondeterministic
|
77
|
+
# I have no idea why this particular string fucks Parser up, but other similar ones don't
|
78
|
+
# We can probably remove this once parser reaches 2.0.0, they've fixed this bug now.
|
79
|
+
Scenario: Parser correctly identify comments
|
80
|
+
Given the file "parser_bug.rb" "Class # whatever"
|
81
|
+
When I run "seeing_is_believing parser_bug.rb"
|
82
|
+
Then stdout is "Class # whatever"
|
83
|
+
Then stderr is empty
|
84
|
+
And the exit status is 0
|
85
|
+
|
86
|
+
|
87
|
+
Scenario: Modifying output doesn't fuck it up when passing it back again as input
|
88
|
+
Given the file "modified_result.rb":
|
89
|
+
"""
|
90
|
+
1
|
91
|
+
# >> stdout
|
92
|
+
2
|
93
|
+
# !> stderr
|
94
|
+
__END__
|
95
|
+
"""
|
96
|
+
When I run "seeing_is_believing modified_result.rb"
|
97
|
+
Then stdout is:
|
98
|
+
"""
|
99
|
+
1 # => 1
|
100
|
+
2 # => 2
|
101
|
+
__END__
|
102
|
+
"""
|
@@ -67,19 +67,21 @@ class SeeingIsBelieving
|
|
67
67
|
|
68
68
|
def options
|
69
69
|
@options ||= {
|
70
|
-
version:
|
71
|
-
clean:
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
70
|
+
version: false,
|
71
|
+
clean: false,
|
72
|
+
xmpfilter_style: false,
|
73
|
+
inherit_exit_status: false,
|
74
|
+
program: nil,
|
75
|
+
filename: nil,
|
76
|
+
start_line: 1,
|
77
|
+
line_length: Float::INFINITY,
|
78
|
+
end_line: Float::INFINITY,
|
79
|
+
result_length: Float::INFINITY,
|
80
|
+
timeout: 0, # timeout lib treats this as infinity
|
81
|
+
errors: [],
|
82
|
+
require: [],
|
83
|
+
load_path: [],
|
84
|
+
alignment_strategy: AlignChunk,
|
83
85
|
}
|
84
86
|
end
|
85
87
|
|
@@ -132,24 +134,25 @@ Usage: seeing_is_believing [options] [filename]
|
|
132
134
|
|
133
135
|
If no filename is provided, the binary will read the program from standard input.
|
134
136
|
|
135
|
-
-l, --start-line n
|
136
|
-
-L, --end-line n
|
137
|
-
-d, --line-length n
|
138
|
-
-D, --result-length n
|
139
|
-
-s, --alignment-strategy
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
-t, --timeout n
|
144
|
-
-I, --load-path dir
|
145
|
-
-r, --require file
|
146
|
-
-e, --program program
|
147
|
-
-K, --encoding encoding
|
148
|
-
-a, --as filename
|
149
|
-
-c, --clean
|
150
|
-
-
|
151
|
-
-
|
152
|
-
-
|
137
|
+
-l, --start-line n # line number to begin showing results on
|
138
|
+
-L, --end-line n # line number to stop showing results on
|
139
|
+
-d, --line-length n # max length of the entire line (only truncates results, not source lines)
|
140
|
+
-D, --result-length n # max length of the portion after the "# => "
|
141
|
+
-s, --alignment-strategy name # select the alignment strategy:
|
142
|
+
chunk (DEFAULT) => each chunk of code is at the same alignment
|
143
|
+
file => the entire file is at the same alignment
|
144
|
+
line => each line is at its own alignment
|
145
|
+
-t, --timeout n # timeout limit in seconds when evaluating source file (ex. -t 0.3 or -t 3)
|
146
|
+
-I, --load-path dir # a dir that should be added to the $LOAD_PATH
|
147
|
+
-r, --require file # additional files to be required before running the program
|
148
|
+
-e, --program program # Pass the program to execute as an argument
|
149
|
+
-K, --encoding encoding # sets file encoding, equivalent to Ruby's -Kx (see `man ruby` for valid values)
|
150
|
+
-a, --as filename # run the program as if it was the specified filename
|
151
|
+
-c, --clean # remove annotations from previous runs of seeing_is_believing
|
152
|
+
-x, --xmpfilter-style # annotate marked lines instead of every line
|
153
|
+
-i, --inherit-exit-status # exit with the exit status of the program being eval
|
154
|
+
-v, --version # print the version (#{VERSION})
|
155
|
+
-h, --help # this help screen
|
153
156
|
HELP_SCREEN
|
154
157
|
end
|
155
158
|
end
|
@@ -2,6 +2,17 @@ require 'seeing_is_believing/queue'
|
|
2
2
|
require 'seeing_is_believing/has_exception'
|
3
3
|
require 'seeing_is_believing/binary/line_formatter'
|
4
4
|
|
5
|
+
# I think there is a bug where with xmpfilter_style set,
|
6
|
+
# the exceptions won't be shown. But it's not totally clear
|
7
|
+
# how to show them with this option set, anyway.
|
8
|
+
# probably do what xmpfilter does and print them at the bottom
|
9
|
+
# of the file (probably do this regardless of whether xmpfilter_style
|
10
|
+
# is set)
|
11
|
+
#
|
12
|
+
# Would also be nice to support
|
13
|
+
# 1 + 1
|
14
|
+
# # => 2
|
15
|
+
# style updates like xmpfilter does
|
5
16
|
|
6
17
|
class SeeingIsBelieving
|
7
18
|
class Binary
|
@@ -15,8 +26,8 @@ class SeeingIsBelieving
|
|
15
26
|
|
16
27
|
def self.remove_previous_output_from(string)
|
17
28
|
string.gsub(/\s+(#{EXCEPTION_PREFIX}|#{RESULT_PREFIX}).*?$/, '')
|
18
|
-
.gsub(
|
19
|
-
.gsub(
|
29
|
+
.gsub(/(^\n)?(^#{STDOUT_PREFIX}[^\n]*\r?\n?)+/m, '')
|
30
|
+
.gsub(/(^\n)?(^#{STDERR_PREFIX}[^\n]*\r?\n?)+/m, '')
|
20
31
|
end
|
21
32
|
|
22
33
|
|
@@ -27,14 +38,23 @@ class SeeingIsBelieving
|
|
27
38
|
method_from_options :filename, nil
|
28
39
|
method_from_options :start_line
|
29
40
|
method_from_options :end_line
|
30
|
-
method_from_options :line_length,
|
31
|
-
method_from_options :result_length,
|
41
|
+
method_from_options :line_length, Float::INFINITY
|
42
|
+
method_from_options :result_length, Float::INFINITY
|
43
|
+
method_from_options :xmpfilter_style
|
32
44
|
|
33
|
-
|
34
|
-
|
45
|
+
attr_accessor :file_result
|
46
|
+
def initialize(body, options={})
|
47
|
+
cleaned_body = self.class.remove_previous_output_from body
|
35
48
|
self.options = options
|
36
|
-
self.
|
37
|
-
self.
|
49
|
+
self.body = (xmpfilter_style ? body : cleaned_body)
|
50
|
+
self.file_result = SeeingIsBelieving.call body(),
|
51
|
+
filename: (options[:as] || options[:filename]),
|
52
|
+
require: options[:require],
|
53
|
+
load_path: options[:load_path],
|
54
|
+
encoding: options[:encoding],
|
55
|
+
stdin: options[:stdin],
|
56
|
+
timeout: options[:timeout]
|
57
|
+
self.alignment_strategy = options[:alignment_strategy].new cleaned_body, start_line, end_line
|
38
58
|
end
|
39
59
|
|
40
60
|
def new_body
|
@@ -42,44 +62,51 @@ class SeeingIsBelieving
|
|
42
62
|
end
|
43
63
|
|
44
64
|
def call
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
65
|
+
@printed_program ||= begin
|
66
|
+
# can we put the call to chomp into the line_queue initialization code?
|
67
|
+
line_queue.until { |line, line_number| SyntaxAnalyzer.begins_data_segment?(line.chomp) }
|
68
|
+
.each { |line, line_number| add_line line, line_number }
|
69
|
+
add_stdout
|
70
|
+
add_stderr
|
71
|
+
add_remaining_lines
|
72
|
+
new_body
|
73
|
+
end
|
52
74
|
end
|
53
75
|
|
54
76
|
private
|
55
77
|
|
56
|
-
attr_accessor :body, :
|
57
|
-
|
58
|
-
def add_each_line_until_start_or_data_segment
|
59
|
-
line_queue.until { |line, line_number| line_number == start_line || start_of_data_segment?(line) }
|
60
|
-
.each { |line, line_number| new_body << line }
|
61
|
-
end
|
62
|
-
|
63
|
-
def add_lines_with_results_until_end_or_data_segment
|
64
|
-
line_queue.until { |line, line_number| end_line < line_number || start_of_data_segment?(line) }
|
65
|
-
.each { |line, line_number| new_body << format_line(line.chomp, line_number, file_result[line_number]) }
|
66
|
-
end
|
78
|
+
attr_accessor :body, :options, :alignment_strategy
|
67
79
|
|
68
|
-
def
|
69
|
-
line_queue
|
70
|
-
.each { |line, line_number| new_body << line }
|
80
|
+
def line_queue
|
81
|
+
@line_queue ||= Queue.new &body.each_line.with_index(1).to_a.method(:shift)
|
71
82
|
end
|
72
83
|
|
73
|
-
|
74
|
-
|
84
|
+
# if we want to pull this into a strategy
|
85
|
+
# we need to make available:
|
86
|
+
# file_result, start_line, end_line, alignment_strategy, line_length, result_length
|
87
|
+
def add_line(line, line_number)
|
88
|
+
should_record = should_record? line, line_number
|
89
|
+
if should_record && xmpfilter_style && line.strip =~ /^# =>/
|
90
|
+
new_body << xmpfilter_update(line, file_result[line_number - 1])
|
91
|
+
elsif should_record && xmpfilter_style
|
92
|
+
new_body << xmpfilter_update(line, file_result[line_number])
|
93
|
+
elsif should_record
|
94
|
+
new_body << format_line(line.chomp, line_number, file_result[line_number])
|
95
|
+
else
|
96
|
+
new_body << line
|
97
|
+
end
|
75
98
|
end
|
76
99
|
|
77
|
-
def
|
78
|
-
|
100
|
+
def should_record?(line, line_number)
|
101
|
+
(start_line <= line_number) &&
|
102
|
+
(line_number <= end_line) &&
|
103
|
+
(xmpfilter_style ? line =~ /# =>/ : # technically you could fuck this up with a line like "# =>", should later delegate to syntax analyzer
|
104
|
+
!SyntaxAnalyzer.ends_in_comment?(line))
|
79
105
|
end
|
80
106
|
|
81
|
-
|
82
|
-
|
107
|
+
# again, this is too naive, should actually parse the comments and update them
|
108
|
+
def xmpfilter_update(line, line_results)
|
109
|
+
line.gsub /# =>.*?$/, "# => #{line_results.join ', '}"
|
83
110
|
end
|
84
111
|
|
85
112
|
def add_stdout
|
@@ -98,6 +125,10 @@ class SeeingIsBelieving
|
|
98
125
|
end
|
99
126
|
end
|
100
127
|
|
128
|
+
def add_remaining_lines
|
129
|
+
line_queue.each { |line, line_number| new_body << line }
|
130
|
+
end
|
131
|
+
|
101
132
|
def format_line(line, line_number, line_results)
|
102
133
|
options = options().merge pad_to: alignment_strategy.line_length_for(line_number)
|
103
134
|
formatted_line = if line_results.has_exception?
|
@@ -20,23 +20,26 @@ class SeeingIsBelieving
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def call
|
23
|
-
@exitstatus ||=
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
23
|
+
@exitstatus ||= begin
|
24
|
+
parse_flags
|
25
|
+
|
26
|
+
if flags_have_errors? then print_errors ; NONDISPLAYABLE_ERROR_STATUS
|
27
|
+
elsif should_print_help? then print_help ; SUCCESS_STATUS
|
28
|
+
elsif should_print_version? then print_version ; SUCCESS_STATUS
|
29
|
+
elsif has_filename? && file_dne? then print_file_dne ; NONDISPLAYABLE_ERROR_STATUS
|
30
|
+
elsif should_clean? then print_cleaned_program ; SUCCESS_STATUS
|
31
|
+
elsif invalid_syntax? then print_syntax_error ; NONDISPLAYABLE_ERROR_STATUS
|
32
|
+
elsif (evaluate_program; program_timedout?) then print_timeout_error ; NONDISPLAYABLE_ERROR_STATUS
|
33
|
+
elsif something_blew_up? then print_unexpected_error ; NONDISPLAYABLE_ERROR_STATUS
|
34
|
+
else print_program ; program_exit_status
|
35
|
+
end
|
36
|
+
end
|
33
37
|
end
|
34
38
|
|
35
|
-
# uhm, this is dumb
|
36
|
-
alias exitstatus call
|
37
|
-
|
38
39
|
private
|
39
40
|
|
41
|
+
attr_accessor :flags, :interpolated_program
|
42
|
+
|
40
43
|
def program_exit_status
|
41
44
|
if flags[:inherit_exit_status]
|
42
45
|
results.exitstatus
|
@@ -47,12 +50,25 @@ class SeeingIsBelieving
|
|
47
50
|
end
|
48
51
|
end
|
49
52
|
|
53
|
+
def parse_flags
|
54
|
+
self.flags = ArgParser.parse argv
|
55
|
+
end
|
56
|
+
|
50
57
|
def has_filename?
|
51
58
|
flags[:filename]
|
52
59
|
end
|
53
60
|
|
61
|
+
def evaluate_program
|
62
|
+
self.interpolated_program = printer.call
|
63
|
+
rescue Timeout::Error
|
64
|
+
self.timeout_error = true
|
65
|
+
rescue Exception
|
66
|
+
self.unexpected_exception = $!
|
67
|
+
end
|
68
|
+
|
69
|
+
# could we make this more obvious? I'd like to to be clear from #call
|
70
|
+
# that this is when the program gets evaluated
|
54
71
|
def program_timedout?
|
55
|
-
results
|
56
72
|
timeout_error
|
57
73
|
end
|
58
74
|
|
@@ -60,23 +76,8 @@ class SeeingIsBelieving
|
|
60
76
|
stderr.puts "Timeout Error after #{@flags[:timeout]} seconds!"
|
61
77
|
end
|
62
78
|
|
63
|
-
def
|
64
|
-
@body ||=
|
65
|
-
flags[:program] || (file_is_on_stdin? && stdin.read) || File.read(flags[:filename])
|
66
|
-
end
|
67
|
-
|
68
|
-
def results
|
69
|
-
@results ||= SeeingIsBelieving.call cleaned_body,
|
70
|
-
filename: (flags[:as] || flags[:filename]),
|
71
|
-
require: flags[:require],
|
72
|
-
load_path: flags[:load_path],
|
73
|
-
encoding: flags[:encoding],
|
74
|
-
stdin: (file_is_on_stdin? ? '' : stdin),
|
75
|
-
timeout: flags[:timeout]
|
76
|
-
rescue Timeout::Error
|
77
|
-
self.timeout_error = true
|
78
|
-
rescue Exception
|
79
|
-
self.unexpected_exception = $!
|
79
|
+
def body
|
80
|
+
@body ||= (flags[:program] || (file_is_on_stdin? && stdin.read) || File.read(flags[:filename]))
|
80
81
|
end
|
81
82
|
|
82
83
|
def something_blew_up?
|
@@ -88,11 +89,11 @@ class SeeingIsBelieving
|
|
88
89
|
end
|
89
90
|
|
90
91
|
def printer
|
91
|
-
@printer ||= PrintResultsNextToLines.new
|
92
|
+
@printer ||= PrintResultsNextToLines.new body, flags.merge(stdin: (file_is_on_stdin? ? '' : stdin))
|
92
93
|
end
|
93
94
|
|
94
|
-
def
|
95
|
-
|
95
|
+
def results
|
96
|
+
printer.file_result
|
96
97
|
end
|
97
98
|
|
98
99
|
def flags_have_errors?
|
@@ -132,11 +133,11 @@ class SeeingIsBelieving
|
|
132
133
|
end
|
133
134
|
|
134
135
|
def print_program
|
135
|
-
stdout.puts
|
136
|
+
stdout.puts interpolated_program
|
136
137
|
end
|
137
138
|
|
138
139
|
def syntax_error_notice
|
139
|
-
out, err, syntax_status = Open3.capture3 'ruby', '-c', stdin_data:
|
140
|
+
out, err, syntax_status = Open3.capture3 'ruby', '-c', stdin_data: body
|
140
141
|
return err unless syntax_status.success?
|
141
142
|
end
|
142
143
|
|
@@ -153,7 +154,7 @@ class SeeingIsBelieving
|
|
153
154
|
end
|
154
155
|
|
155
156
|
def print_cleaned_program
|
156
|
-
stdout.print
|
157
|
+
stdout.print PrintResultsNextToLines.remove_previous_output_from body
|
157
158
|
end
|
158
159
|
end
|
159
160
|
end
|
@@ -26,9 +26,8 @@ class SeeingIsBelieving
|
|
26
26
|
def call
|
27
27
|
offset, expressions, expression = 0, [], nil
|
28
28
|
begin
|
29
|
-
pending_expression = generate
|
29
|
+
pending_expression = generate(expressions)
|
30
30
|
debug { "GENERATED: #{pending_expression.expression.inspect}, ADDING IT TO #{inspected_expressions expressions}" }
|
31
|
-
expressions << pending_expression
|
32
31
|
|
33
32
|
expression = reduce expressions, offset unless next_line_modifies_current?
|
34
33
|
|
@@ -41,10 +40,15 @@ class SeeingIsBelieving
|
|
41
40
|
|
42
41
|
attr_accessor :debug_stream, :should_debug, :get_next_line, :peek_next_line, :on_complete, :expressions
|
43
42
|
|
44
|
-
def generate
|
43
|
+
def generate(expressions)
|
45
44
|
expression = get_next_line.call
|
46
45
|
raise SyntaxError unless expression
|
47
|
-
|
46
|
+
if expressions.last && SyntaxAnalyzer.unfinished_here_doc?(expressions.last.expression)
|
47
|
+
expressions.last.expression << "\n" << expression # more stupid \n -.-
|
48
|
+
else
|
49
|
+
expressions << PendingExpression.new(expression, [])
|
50
|
+
end
|
51
|
+
expressions.last
|
48
52
|
end
|
49
53
|
|
50
54
|
def next_line_modifies_current?
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'parser/current'
|
2
|
+
|
3
|
+
class SeeingIsBelieving
|
4
|
+
module RemoveInlineComments
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def self.call(code)
|
8
|
+
remove_inline_comments code
|
9
|
+
end
|
10
|
+
|
11
|
+
def remove_inline_comments(code)
|
12
|
+
buffer = Parser::Source::Buffer.new "strip_comments"
|
13
|
+
buffer.source = code
|
14
|
+
parser = Parser::CurrentRuby.new
|
15
|
+
rewriter = Parser::Source::Rewriter.new(buffer)
|
16
|
+
ast, comments = parser.parse_with_comments(buffer)
|
17
|
+
comments.select { |comment| comment.type == :inline }
|
18
|
+
.each { |comment| rewriter.remove comment.location }
|
19
|
+
rewriter.process
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -162,7 +162,7 @@ class SeeingIsBelieving
|
|
162
162
|
ast = Parser::CurrentRuby.parse(code_or_ast) if code_or_ast.kind_of? String
|
163
163
|
|
164
164
|
case ast && ast.type
|
165
|
-
when :begin, :resbody
|
165
|
+
when :begin, :kwbegin, :resbody # begin and kwbegin should be the same thing, but it changed in parser 1.4.1 to 2.0.0, so just adding them both for safety
|
166
166
|
void_value_expression?(ast.children[-1])
|
167
167
|
when :rescue, :ensure
|
168
168
|
ast.children.any? { |child| void_value_expression? child }
|
@@ -182,6 +182,11 @@ class SeeingIsBelieving
|
|
182
182
|
instance.has_heredoc? && code.scan("\n").size.next <= instance.here_doc_last_line_number
|
183
183
|
end
|
184
184
|
|
185
|
+
def self.unfinished_here_doc?(code)
|
186
|
+
instance = parsed code
|
187
|
+
instance.heredocs.any? { |heredoc| heredoc.size == 1 }
|
188
|
+
end
|
189
|
+
|
185
190
|
def heredocs
|
186
191
|
@heredocs ||= []
|
187
192
|
end
|
data/lib/seeing_is_believing.rb
CHANGED
@@ -6,6 +6,7 @@ require 'seeing_is_believing/queue'
|
|
6
6
|
require 'seeing_is_believing/result'
|
7
7
|
require 'seeing_is_believing/version'
|
8
8
|
require 'seeing_is_believing/expression_list'
|
9
|
+
require 'seeing_is_believing/remove_inline_comments'
|
9
10
|
require 'seeing_is_believing/evaluate_by_moving_files'
|
10
11
|
|
11
12
|
# might not work on windows b/c of assumptions about line ends
|
@@ -37,6 +38,7 @@ class SeeingIsBelieving
|
|
37
38
|
@memoized_result ||= begin
|
38
39
|
leading_comments = ''
|
39
40
|
|
41
|
+
|
40
42
|
# extract leading comments (e.g. encoding) so they don't get wrapped in begin/rescue/end
|
41
43
|
while SyntaxAnalyzer.line_is_comment?(next_line_queue.peek)
|
42
44
|
leading_comments << next_line_queue.dequeue << "\n"
|
@@ -83,7 +85,9 @@ class SeeingIsBelieving
|
|
83
85
|
@expression_list ||= ExpressionList.new get_next_line: lambda { next_line_queue.dequeue },
|
84
86
|
peek_next_line: lambda { next_line_queue.peek },
|
85
87
|
on_complete: lambda { |line, children, completions, offset|
|
86
|
-
expression =
|
88
|
+
expression = RemoveInlineComments.call \
|
89
|
+
[line, *children, *completions].map(&:chomp).join("\n")
|
90
|
+
|
87
91
|
if do_not_record? expression
|
88
92
|
expression + "\n"
|
89
93
|
else
|
@@ -141,6 +145,7 @@ class SeeingIsBelieving
|
|
141
145
|
@next_line_queue ||= Queue.new { (line = stream.gets) && line.chomp }
|
142
146
|
end
|
143
147
|
|
148
|
+
# eh? -.^ (can't we pull the rest of this out of the queue instead of breaking encapsulation?)
|
144
149
|
def the_rest_of_the_stream
|
145
150
|
next_line_queue.dequeue << "\n" << stream.read
|
146
151
|
end
|
data/seeing_is_believing.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
|
-
s.add_dependency "parser", "~>
|
22
|
+
s.add_dependency "parser", "~> 2.0.0.beta9"
|
23
23
|
|
24
24
|
s.add_development_dependency "haiti", "~> 0.0.3"
|
25
25
|
s.add_development_dependency "rake", "~> 10.0.3"
|
@@ -107,12 +107,6 @@ describe SeeingIsBelieving do
|
|
107
107
|
# values_for("<<-HEREDOC\n1\nHEREDOC").should == [[], [], ['"\n1\n"']]
|
108
108
|
end
|
109
109
|
|
110
|
-
it 'does not record expressions that end in a comment' do
|
111
|
-
values_for("1
|
112
|
-
2 # on internal expression
|
113
|
-
3 # at end of program").should == [['1'], [], []]
|
114
|
-
end
|
115
|
-
|
116
110
|
it "does not record expressions that are here docs (only really b/c it's not smart enough)" do
|
117
111
|
values_for("<<A\n1\nA").should be_all &:empty?
|
118
112
|
values_for(" <<A\n1\nA").should be_all &:empty?
|
@@ -122,6 +116,27 @@ describe SeeingIsBelieving do
|
|
122
116
|
values_for("def meth\n<<-A\n1\nA\nend").should == [[], [], [], [], ['nil']]
|
123
117
|
end
|
124
118
|
|
119
|
+
it 'does not insert code into the middle of heredocs', t:true do
|
120
|
+
invoked = invoke(<<-HEREDOC.gsub(/^ /, ''))
|
121
|
+
puts <<DOC1
|
122
|
+
doc1
|
123
|
+
DOC1
|
124
|
+
puts <<-DOC2
|
125
|
+
doc2
|
126
|
+
DOC2
|
127
|
+
puts <<-DOC3
|
128
|
+
doc3
|
129
|
+
DOC3
|
130
|
+
puts <<DOC4, <<-DOC5
|
131
|
+
doc4
|
132
|
+
DOC4
|
133
|
+
doc5
|
134
|
+
DOC5
|
135
|
+
HEREDOC
|
136
|
+
|
137
|
+
invoked.stdout.should == "doc1\ndoc2\ndoc3\ndoc4\ndoc5\n"
|
138
|
+
end
|
139
|
+
|
125
140
|
it 'has no output for empty lines' do
|
126
141
|
values_for('').should == [[]]
|
127
142
|
values_for(' ').should == [[]]
|
@@ -189,7 +204,7 @@ describe SeeingIsBelieving do
|
|
189
204
|
DOC
|
190
205
|
end
|
191
206
|
|
192
|
-
it 'does not try to record the keyword retry'
|
207
|
+
it 'does not try to record the keyword retry' do
|
193
208
|
values_for(<<-DOC).should == [[], [], [], ['nil']]
|
194
209
|
def meth
|
195
210
|
rescue
|
@@ -290,6 +305,12 @@ describe SeeingIsBelieving do
|
|
290
305
|
invoke('at_exit { exit 121 }').exitstatus.should == 121
|
291
306
|
end
|
292
307
|
|
308
|
+
it 'records lines that have comments on them' do
|
309
|
+
values_for('1+1 # comment uno
|
310
|
+
#comment dos
|
311
|
+
3#comment tres').should == [['2'], [], ['3']]
|
312
|
+
end
|
313
|
+
|
293
314
|
it 'can record the middle of a chain of calls', not_implemented: true do
|
294
315
|
values_for("[*1..5]
|
295
316
|
.select(&:even?)
|
@@ -35,6 +35,18 @@ describe SeeingIsBelieving::SyntaxAnalyzer do
|
|
35
35
|
is_here_doc["a<<b\nb"].should be_false
|
36
36
|
end
|
37
37
|
|
38
|
+
it 'knows if the expression is an unfinished heredoc' do
|
39
|
+
is_unfinished_heredoc = lambda { |code| described_class.unfinished_here_doc? code }
|
40
|
+
is_unfinished_heredoc["<<A"].should be_true
|
41
|
+
is_unfinished_heredoc["puts <<A, <<B\na\nA"].should be_true
|
42
|
+
is_unfinished_heredoc["<<-A\n"].should be_true
|
43
|
+
|
44
|
+
is_unfinished_heredoc["puts <<A\na\nA"].should be_false
|
45
|
+
is_unfinished_heredoc["puts <<-A\na\nA"].should be_false
|
46
|
+
is_unfinished_heredoc["puts <<-A\na\n A"].should be_false
|
47
|
+
is_unfinished_heredoc["puts <<A, <<B\na\nA\nB"].should be_false
|
48
|
+
end
|
49
|
+
|
38
50
|
it 'knows if the last line is a comment' do
|
39
51
|
is_comment = lambda { |code| described_class.ends_in_comment? code }
|
40
52
|
|
metadata
CHANGED
@@ -1,112 +1,99 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: seeing_is_believing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.0.24
|
4
|
+
version: 0.0.26
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Josh Cheek
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-06-
|
11
|
+
date: 2013-06-29 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
|
14
|
+
name: parser
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
20
|
-
none: false
|
21
|
-
name: parser
|
19
|
+
version: 2.0.0.beta9
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
|
-
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
23
|
requirements:
|
26
24
|
- - ~>
|
27
25
|
- !ruby/object:Gem::Version
|
28
|
-
version:
|
29
|
-
none: false
|
26
|
+
version: 2.0.0.beta9
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
|
-
|
28
|
+
name: haiti
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
32
30
|
requirements:
|
33
31
|
- - ~>
|
34
32
|
- !ruby/object:Gem::Version
|
35
33
|
version: 0.0.3
|
36
|
-
none: false
|
37
|
-
name: haiti
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
|
-
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
37
|
requirements:
|
42
38
|
- - ~>
|
43
39
|
- !ruby/object:Gem::Version
|
44
40
|
version: 0.0.3
|
45
|
-
none: false
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
|
-
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
48
44
|
requirements:
|
49
45
|
- - ~>
|
50
46
|
- !ruby/object:Gem::Version
|
51
47
|
version: 10.0.3
|
52
|
-
none: false
|
53
|
-
name: rake
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
|
-
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
51
|
requirements:
|
58
52
|
- - ~>
|
59
53
|
- !ruby/object:Gem::Version
|
60
54
|
version: 10.0.3
|
61
|
-
none: false
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
|
-
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
64
58
|
requirements:
|
65
59
|
- - ~>
|
66
60
|
- !ruby/object:Gem::Version
|
67
61
|
version: 2.12.0
|
68
|
-
none: false
|
69
|
-
name: rspec
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
|
-
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
65
|
requirements:
|
74
66
|
- - ~>
|
75
67
|
- !ruby/object:Gem::Version
|
76
68
|
version: 2.12.0
|
77
|
-
none: false
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
|
-
|
70
|
+
name: cucumber
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
80
72
|
requirements:
|
81
73
|
- - ~>
|
82
74
|
- !ruby/object:Gem::Version
|
83
75
|
version: 1.2.1
|
84
|
-
none: false
|
85
|
-
name: cucumber
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
|
-
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
79
|
requirements:
|
90
80
|
- - ~>
|
91
81
|
- !ruby/object:Gem::Version
|
92
82
|
version: 1.2.1
|
93
|
-
none: false
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
|
-
|
84
|
+
name: ichannel
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
96
86
|
requirements:
|
97
87
|
- - ~>
|
98
88
|
- !ruby/object:Gem::Version
|
99
89
|
version: 5.1.1
|
100
|
-
none: false
|
101
|
-
name: ichannel
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
|
-
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
93
|
requirements:
|
106
94
|
- - ~>
|
107
95
|
- !ruby/object:Gem::Version
|
108
96
|
version: 5.1.1
|
109
|
-
none: false
|
110
97
|
description: Records the results of every line of code in your file (intended to be
|
111
98
|
like xmpfilter), inspired by Bret Victor's JavaScript example in his talk "Inventing
|
112
99
|
on Principle"
|
@@ -143,6 +130,7 @@ files:
|
|
143
130
|
- lib/seeing_is_believing/has_exception.rb
|
144
131
|
- lib/seeing_is_believing/line.rb
|
145
132
|
- lib/seeing_is_believing/queue.rb
|
133
|
+
- lib/seeing_is_believing/remove_inline_comments.rb
|
146
134
|
- lib/seeing_is_believing/result.rb
|
147
135
|
- lib/seeing_is_believing/syntax_analyzer.rb
|
148
136
|
- lib/seeing_is_believing/the_matrix.rb
|
@@ -162,27 +150,26 @@ files:
|
|
162
150
|
homepage: https://github.com/JoshCheek/seeing_is_believing
|
163
151
|
licenses:
|
164
152
|
- WTFPL
|
153
|
+
metadata: {}
|
165
154
|
post_install_message:
|
166
155
|
rdoc_options: []
|
167
156
|
require_paths:
|
168
157
|
- lib
|
169
158
|
required_ruby_version: !ruby/object:Gem::Requirement
|
170
159
|
requirements:
|
171
|
-
- -
|
160
|
+
- - '>='
|
172
161
|
- !ruby/object:Gem::Version
|
173
162
|
version: '0'
|
174
|
-
none: false
|
175
163
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
176
164
|
requirements:
|
177
|
-
- -
|
165
|
+
- - '>='
|
178
166
|
- !ruby/object:Gem::Version
|
179
167
|
version: '0'
|
180
|
-
none: false
|
181
168
|
requirements: []
|
182
169
|
rubyforge_project: seeing_is_believing
|
183
|
-
rubygems_version:
|
170
|
+
rubygems_version: 2.0.0
|
184
171
|
signing_key:
|
185
|
-
specification_version:
|
172
|
+
specification_version: 4
|
186
173
|
summary: Records results of every line of code in your file
|
187
174
|
test_files:
|
188
175
|
- features/errors.feature
|