seeing_is_believing 0.0.24 → 0.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|