seeing_is_believing 2.2.0 → 3.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Changelog.md +33 -0
- data/bin/seeing_is_believing +1 -1
- data/features/errors.feature +3 -3
- data/features/examples.feature +6 -6
- data/features/flags.feature +51 -196
- data/features/regression.feature +12 -3
- data/features/safe.feature +33 -0
- data/features/support/env.rb +20 -0
- data/features/xmpfilter-style.feature +156 -0
- data/lib/seeing_is_believing.rb +17 -35
- data/lib/seeing_is_believing/binary.rb +81 -176
- data/lib/seeing_is_believing/binary/align_chunk.rb +5 -7
- data/lib/seeing_is_believing/binary/align_file.rb +4 -5
- data/lib/seeing_is_believing/binary/align_line.rb +4 -4
- data/lib/seeing_is_believing/binary/annotate_end_of_file.rb +60 -0
- data/lib/seeing_is_believing/binary/annotate_every_line.rb +64 -0
- data/lib/seeing_is_believing/binary/annotate_xmpfilter_style.rb +133 -0
- data/lib/seeing_is_believing/binary/comment_formatter.rb +19 -5
- data/lib/seeing_is_believing/binary/comment_lines.rb +1 -1
- data/lib/seeing_is_believing/binary/commentable_lines.rb +1 -1
- data/lib/seeing_is_believing/binary/interpret_flags.rb +149 -0
- data/lib/seeing_is_believing/binary/parse_args.rb +96 -104
- data/lib/seeing_is_believing/binary/remove_annotations.rb +95 -0
- data/lib/seeing_is_believing/binary/rewrite_comments.rb +8 -30
- data/lib/seeing_is_believing/code.rb +99 -0
- data/lib/seeing_is_believing/evaluate_by_moving_files.rb +27 -19
- data/lib/seeing_is_believing/evaluate_with_eval_in.rb +27 -0
- data/lib/seeing_is_believing/event_stream/consumer.rb +111 -0
- data/lib/seeing_is_believing/event_stream/events.rb +16 -0
- data/lib/seeing_is_believing/event_stream/producer.rb +106 -0
- data/lib/seeing_is_believing/event_stream/update_result.rb +21 -0
- data/lib/seeing_is_believing/inspect_expressions.rb +24 -0
- data/lib/seeing_is_believing/parser_helpers.rb +1 -11
- data/lib/seeing_is_believing/result.rb +14 -56
- data/lib/seeing_is_believing/the_matrix.rb +14 -14
- data/lib/seeing_is_believing/version.rb +1 -1
- data/lib/seeing_is_believing/wrap_expressions.rb +32 -9
- data/seeing_is_believing.gemspec +7 -7
- data/spec/binary/comment_formatter_spec.rb +169 -18
- data/spec/binary/comment_lines_spec.rb +1 -1
- data/spec/binary/interpret_flags_spec.rb +307 -0
- data/spec/binary/parse_args_spec.rb +93 -91
- data/spec/binary/{clean_body_spec.rb → remove_annotations_spec.rb} +29 -22
- data/spec/binary/rewrite_comments_spec.rb +13 -13
- data/spec/code_spec.rb +49 -0
- data/spec/debugger_spec.rb +1 -1
- data/spec/evaluate_by_moving_files_spec.rb +7 -3
- data/spec/event_stream_spec.rb +390 -0
- data/spec/hard_core_ensure_spec.rb +1 -1
- data/spec/seeing_is_believing_spec.rb +137 -40
- data/spec/spec_helper.rb +3 -3
- data/spec/wrap_expressions_spec.rb +48 -35
- metadata +58 -35
- data/lib/seeing_is_believing/binary/add_annotations.rb +0 -144
- data/lib/seeing_is_believing/binary/clean_body.rb +0 -95
- data/lib/seeing_is_believing/has_exception.rb +0 -27
- data/lib/seeing_is_believing/line.rb +0 -90
- data/spec/line_spec.rb +0 -86
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'seeing_is_believing/binary/commentable_lines'
|
2
2
|
|
3
3
|
class SeeingIsBelieving
|
4
|
-
|
4
|
+
module Binary
|
5
5
|
class AlignChunk
|
6
|
-
def initialize(body
|
7
|
-
self.body
|
6
|
+
def initialize(body)
|
7
|
+
self.body = body
|
8
8
|
end
|
9
9
|
|
10
10
|
# max line length of the the chunk (newline separated sections of code exempting comments) + 2 spaces for padding
|
@@ -14,7 +14,7 @@ class SeeingIsBelieving
|
|
14
14
|
|
15
15
|
private
|
16
16
|
|
17
|
-
attr_accessor :body
|
17
|
+
attr_accessor :body
|
18
18
|
|
19
19
|
def line_lengths
|
20
20
|
@line_lengths ||= begin
|
@@ -24,9 +24,7 @@ class SeeingIsBelieving
|
|
24
24
|
.sort
|
25
25
|
.slice_before { |line_number| line_num_to_indexes[line_number].last.zero? }
|
26
26
|
.map { |slice|
|
27
|
-
max_chunk_length = 2 + slice.
|
28
|
-
.map { |line_num| line_num_to_indexes[line_num].last }
|
29
|
-
.max
|
27
|
+
max_chunk_length = 2 + slice.map { |line_num| line_num_to_indexes[line_num].last }.max
|
30
28
|
slice.map { |line_number| [line_number, max_chunk_length] }
|
31
29
|
}
|
32
30
|
.flatten(1)
|
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'seeing_is_believing/binary/commentable_lines'
|
2
2
|
|
3
3
|
class SeeingIsBelieving
|
4
|
-
|
4
|
+
module Binary
|
5
5
|
class AlignFile
|
6
|
-
attr_accessor :body
|
6
|
+
attr_accessor :body
|
7
7
|
|
8
|
-
def initialize(body
|
9
|
-
self.body
|
8
|
+
def initialize(body)
|
9
|
+
self.body = body
|
10
10
|
end
|
11
11
|
|
12
12
|
# max line length of the lines to output (exempting comments) + 2 spaces for padding
|
@@ -14,7 +14,6 @@ class SeeingIsBelieving
|
|
14
14
|
@max_source_line_length ||= 2 + begin
|
15
15
|
line_num_to_indexes = CommentableLines.new(body).call # {line_number => [index_in_file, index_in_col]}
|
16
16
|
max_value = line_num_to_indexes
|
17
|
-
.select { |line_num, _| start_line <= line_num && line_num <= end_line }
|
18
17
|
.values
|
19
18
|
.map { |index, col| col }.max
|
20
19
|
max_value || 0
|
@@ -1,10 +1,10 @@
|
|
1
1
|
class SeeingIsBelieving
|
2
|
-
|
2
|
+
module Binary
|
3
3
|
class AlignLine
|
4
|
-
attr_accessor :body
|
4
|
+
attr_accessor :body
|
5
5
|
|
6
|
-
def initialize(body
|
7
|
-
self.body
|
6
|
+
def initialize(body)
|
7
|
+
self.body = body
|
8
8
|
end
|
9
9
|
|
10
10
|
# length of the line + 2 spaces for padding
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'seeing_is_believing/binary' # defines the markers
|
2
|
+
require 'seeing_is_believing/binary/comment_formatter'
|
3
|
+
|
4
|
+
class SeeingIsBelieving
|
5
|
+
module Binary
|
6
|
+
module AnnotateEndOfFile
|
7
|
+
extend self
|
8
|
+
|
9
|
+
# TODO: Switch options to markers
|
10
|
+
def add_stdout_stderr_and_exceptions_to(new_body, results, options)
|
11
|
+
output = stdout_ouptut_for(results, options) <<
|
12
|
+
stderr_ouptut_for(results, options) <<
|
13
|
+
exception_output_for(results, options)
|
14
|
+
|
15
|
+
# this technically could find an __END__ in a string or whatever
|
16
|
+
# going to just ignore that, though
|
17
|
+
if new_body[/^__END__$/]
|
18
|
+
new_body.sub! "\n__END__", "\n#{output}__END__"
|
19
|
+
else
|
20
|
+
new_body << "\n" unless new_body.end_with? "\n"
|
21
|
+
new_body << output
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def stdout_ouptut_for(results, options)
|
26
|
+
return '' unless results.has_stdout?
|
27
|
+
output = "\n"
|
28
|
+
results.stdout.each_line do |line|
|
29
|
+
output << CommentFormatter.call(0, options[:markers][:stdout], line.chomp, options) << "\n"
|
30
|
+
end
|
31
|
+
output
|
32
|
+
end
|
33
|
+
|
34
|
+
def stderr_ouptut_for(results, options)
|
35
|
+
return '' unless results.has_stderr?
|
36
|
+
output = "\n"
|
37
|
+
results.stderr.each_line do |line|
|
38
|
+
output << CommentFormatter.call(0, options[:markers][:stderr], line.chomp, options) << "\n"
|
39
|
+
end
|
40
|
+
output
|
41
|
+
end
|
42
|
+
|
43
|
+
def exception_output_for(results, options)
|
44
|
+
return '' unless results.has_exception?
|
45
|
+
exception_marker = options[:markers][:exception]
|
46
|
+
exception = results.exception
|
47
|
+
output = "\n"
|
48
|
+
output << CommentFormatter.new(0, exception_marker, exception.class_name, options).call << "\n"
|
49
|
+
exception.message.each_line do |line|
|
50
|
+
output << CommentFormatter.new(0, exception_marker, line.chomp, options).call << "\n"
|
51
|
+
end
|
52
|
+
output << exception_marker.sub(/\s+$/, '') << "\n"
|
53
|
+
exception.backtrace.each do |line|
|
54
|
+
output << CommentFormatter.new(0, exception_marker, line.chomp, options).call << "\n"
|
55
|
+
end
|
56
|
+
output
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class SeeingIsBelieving
|
2
|
+
module Binary
|
3
|
+
class AnnotateEveryLine
|
4
|
+
def self.prepare_body(uncleaned_body, markers)
|
5
|
+
require 'seeing_is_believing/binary/remove_annotations'
|
6
|
+
RemoveAnnotations.call uncleaned_body, true, markers
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.expression_wrapper(markers)
|
10
|
+
require 'seeing_is_believing/inspect_expressions'
|
11
|
+
InspectExpressions
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.call(body, results, options)
|
15
|
+
new(body, results, options).call
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(body, results, options={})
|
19
|
+
@options = options
|
20
|
+
@body = body
|
21
|
+
@results = results
|
22
|
+
end
|
23
|
+
|
24
|
+
def call
|
25
|
+
@new_body ||= begin
|
26
|
+
require 'seeing_is_believing/binary/comment_lines'
|
27
|
+
require 'seeing_is_believing/binary/comment_formatter'
|
28
|
+
|
29
|
+
alignment_strategy = @options[:alignment_strategy].new(@body)
|
30
|
+
exception_lineno = @results.has_exception? ? @results.exception.line_number : -1
|
31
|
+
new_body = CommentLines.call @body do |line, line_number|
|
32
|
+
options = @options.merge pad_to: alignment_strategy.line_length_for(line_number)
|
33
|
+
if exception_lineno == line_number
|
34
|
+
result = sprintf "%s: %s", @results.exception.class_name, @results.exception.message.gsub("\n", '\n')
|
35
|
+
CommentFormatter.call(line.size, exception_marker, result, options)
|
36
|
+
elsif @results[line_number].any?
|
37
|
+
result = @results[line_number].map { |result| result.gsub "\n", '\n' }.join(', ')
|
38
|
+
CommentFormatter.call(line.size, value_marker, result, options)
|
39
|
+
else
|
40
|
+
''
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
require 'seeing_is_believing/binary/annotate_end_of_file'
|
45
|
+
AnnotateEndOfFile.add_stdout_stderr_and_exceptions_to new_body, @results, @options
|
46
|
+
|
47
|
+
# What's w/ this debugger? maybe this should move higher?
|
48
|
+
@options[:debugger].context "OUTPUT"
|
49
|
+
new_body
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def value_marker
|
56
|
+
@value_marker ||= @options[:markers][:value]
|
57
|
+
end
|
58
|
+
|
59
|
+
def exception_marker
|
60
|
+
@exception_marker ||= @options[:markers][:exception]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'seeing_is_believing/code'
|
2
|
+
|
3
|
+
class SeeingIsBelieving
|
4
|
+
module Binary
|
5
|
+
class AnnotateXmpfilterStyle
|
6
|
+
def self.prepare_body(uncleaned_body, markers)
|
7
|
+
# TODO: There's definitely a lot of overlap in responsibilities with invoking of parser
|
8
|
+
# and this is a conspicuous hack, since this functionality should really be provided by RemoveAnnotations
|
9
|
+
code = Code.new(uncleaned_body)
|
10
|
+
code.inline_comments
|
11
|
+
.select { |c| c.whitespace_col == 0 } # TODO: Would be nice to support indentation here
|
12
|
+
.slice_before { |c| c.text.start_with? markers[:value] }
|
13
|
+
.flat_map { |cs|
|
14
|
+
consecutives = cs.each_cons(2).take_while { |c1, c2| c1.line_number.next == c2.line_number }
|
15
|
+
cs[1, consecutives.size]
|
16
|
+
}
|
17
|
+
.select { |c| c.text.start_with? markers[:nextline] }
|
18
|
+
.each { |c|
|
19
|
+
range_with_preceding_newline = code.range_for(c.comment_range.begin_pos.pred, c.comment_range.end_pos)
|
20
|
+
code.rewriter.remove range_with_preceding_newline
|
21
|
+
}
|
22
|
+
partially_cleaned_body = code.rewriter.process
|
23
|
+
|
24
|
+
require 'seeing_is_believing/binary/remove_annotations'
|
25
|
+
RemoveAnnotations.call partially_cleaned_body, false, markers
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.expression_wrapper(markers)
|
29
|
+
-> program, number_of_captures {
|
30
|
+
inspect_linenos = []
|
31
|
+
pp_linenos = []
|
32
|
+
Code.new(program).inline_comments.each do |c|
|
33
|
+
next unless c.text.start_with? markers[:value].sub(/\s+$/, '')
|
34
|
+
c.whitespace_col == 0 ? pp_linenos << c.line_number - 1
|
35
|
+
: inspect_linenos << c.line_number
|
36
|
+
end
|
37
|
+
|
38
|
+
InspectExpressions.call program,
|
39
|
+
number_of_captures,
|
40
|
+
before_all: -> {
|
41
|
+
# TODO: this is duplicated with the InspectExpressions class
|
42
|
+
number_of_captures_as_str = number_of_captures.inspect
|
43
|
+
number_of_captures_as_str = 'Float::INFINITY' if number_of_captures == Float::INFINITY
|
44
|
+
"begin; require 'pp'; $SiB.max_line_captures = #{number_of_captures_as_str}; $SiB.num_lines = #{program.lines.count}; "
|
45
|
+
},
|
46
|
+
after_each: -> line_number {
|
47
|
+
should_inspect = inspect_linenos.include?(line_number)
|
48
|
+
should_pp = pp_linenos.include?(line_number)
|
49
|
+
inspect = "$SiB.record_result(:inspect, #{line_number}, v)"
|
50
|
+
pp = "$SiB.record_result(:pp, #{line_number}, v) { PP.pp v, '', 74 }" # TODO: Is 74 the right value? Prob not, I think it's 80(default width) - 1(comment width) - 5(" => {"), but if I allow indented `# => `, then that would need to be less than 74 (idk if I actually do this or not, though :P)
|
51
|
+
|
52
|
+
if should_inspect && should_pp then ").tap { |v| #{inspect}; #{pp} }"
|
53
|
+
elsif should_inspect then ").tap { |v| #{inspect} }"
|
54
|
+
elsif should_pp then ").tap { |v| #{pp} }"
|
55
|
+
else ")"
|
56
|
+
end
|
57
|
+
}
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.call(body, results, options)
|
62
|
+
new(body, results, options).call
|
63
|
+
end
|
64
|
+
|
65
|
+
def initialize(body, results, options={})
|
66
|
+
@options = options
|
67
|
+
@body = body
|
68
|
+
@results = results
|
69
|
+
end
|
70
|
+
|
71
|
+
# TODO: I think that this should respect the alignment strategy
|
72
|
+
# and we should just add a new alignment strategy for default xmpfilter style
|
73
|
+
def call
|
74
|
+
@new_body ||= begin
|
75
|
+
# TODO: doesn't currently realign output markers, do we want to do that?
|
76
|
+
require 'seeing_is_believing/binary' # defines the markers
|
77
|
+
require 'seeing_is_believing/binary/rewrite_comments'
|
78
|
+
require 'seeing_is_believing/binary/comment_formatter'
|
79
|
+
exception_lineno = @results.has_exception? ? @results.exception.line_number : -1
|
80
|
+
new_body = RewriteComments.call @body do |comment|
|
81
|
+
if !comment.text[value_regex]
|
82
|
+
[comment.whitespace, comment.text]
|
83
|
+
elsif comment.whitespace_col == 0
|
84
|
+
# TODO: check that having multiple mult-line output values here looks good (e.g. avdi's example in a loop)
|
85
|
+
result = @results[comment.line_number-1, :pp].map { |result| result.chomp }.join(', ')
|
86
|
+
comment_lines = result.each_line.map.with_index do |comment_line, result_offest|
|
87
|
+
if result_offest == 0
|
88
|
+
CommentFormatter.call(comment.whitespace_col, value_marker, comment_line.chomp, @options)
|
89
|
+
else
|
90
|
+
CommentFormatter.call(comment.whitespace_col, nextline_marker, comment_line.chomp, @options)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
[comment.whitespace, comment_lines.join("\n")]
|
94
|
+
else
|
95
|
+
result = @results[comment.line_number].map { |result| result.gsub "\n", '\n' }.join(', ')
|
96
|
+
[comment.whitespace, CommentFormatter.call(comment.text_col, value_marker, result, @options)]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# if exception_lineno == line_number
|
101
|
+
# if comment.text[value_regex] # has exception and comment
|
102
|
+
# # '# => # ~> exception...'
|
103
|
+
# [comment.whitespace, comment.text]
|
104
|
+
# else # exception, no comment
|
105
|
+
# # NORMAL EXCEPTION
|
106
|
+
# # result = @results[line_number].map { |result| result.gsub "\n", '\n' }.join(', ')
|
107
|
+
# # CommentFormatter.call(line.size, value_marker, result, options)
|
108
|
+
# # [comment.whitespace, comment.text]
|
109
|
+
# end
|
110
|
+
|
111
|
+
require 'seeing_is_believing/binary/annotate_end_of_file'
|
112
|
+
AnnotateEndOfFile.add_stdout_stderr_and_exceptions_to new_body, @results, @options
|
113
|
+
|
114
|
+
# What's w/ this debugger? maybe this should move higher?
|
115
|
+
@options[:debugger].context "OUTPUT"
|
116
|
+
new_body
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def value_marker
|
121
|
+
@value_marker ||= @options[:markers][:value]
|
122
|
+
end
|
123
|
+
|
124
|
+
def nextline_marker
|
125
|
+
@xnextline_marker ||= @options[:markers][:nextline]
|
126
|
+
end
|
127
|
+
|
128
|
+
def value_regex
|
129
|
+
@value_regex ||= /\A#{value_marker.sub(/\s+$/, '')}/
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class SeeingIsBelieving
|
2
|
-
|
3
|
-
# not sure I like this name, it formats comments that
|
4
|
-
#
|
2
|
+
module Binary
|
3
|
+
# not sure I like this name, it formats comments that show results
|
4
|
+
# e.g. "# => [1, 2, 3]"
|
5
5
|
#
|
6
6
|
# line_length is the length of the line this comment is being appended to
|
7
7
|
#
|
@@ -15,13 +15,14 @@ class SeeingIsBelieving
|
|
15
15
|
def initialize(line_length, separator, result, options)
|
16
16
|
self.line_length = line_length
|
17
17
|
self.separator = separator
|
18
|
-
self.result = result
|
18
|
+
self.result = result
|
19
19
|
self.options = options
|
20
20
|
end
|
21
21
|
|
22
22
|
def call
|
23
23
|
@formatted ||= begin
|
24
|
-
formatted =
|
24
|
+
formatted = escape_non_printable result, chars_not_to_escape
|
25
|
+
formatted = truncate "#{separator}#{formatted}", max_result_length
|
25
26
|
formatted = "#{' '*padding_length}#{formatted}"
|
26
27
|
formatted = truncate formatted, max_line_length
|
27
28
|
formatted = '' unless formatted.sub(/^ */, '').start_with? separator
|
@@ -57,6 +58,19 @@ class SeeingIsBelieving
|
|
57
58
|
def ellipsify(string)
|
58
59
|
string.sub(/.{0,3}$/) { |last_chars| '.' * last_chars.size }
|
59
60
|
end
|
61
|
+
|
62
|
+
def chars_not_to_escape
|
63
|
+
options.fetch :dont_escape, []
|
64
|
+
end
|
65
|
+
|
66
|
+
def escape_non_printable(str, omissions)
|
67
|
+
str.each_char
|
68
|
+
.map { |char|
|
69
|
+
next char if 0x20 <= char.ord # above this has a printable representation
|
70
|
+
next char if omissions.include? char
|
71
|
+
char.inspect[1...-1]
|
72
|
+
}.join('')
|
73
|
+
end
|
60
74
|
end
|
61
75
|
end
|
62
76
|
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# Debugger initialization happens here
|
2
|
+
require 'seeing_is_believing/debugger'
|
3
|
+
|
4
|
+
# Alignment decision happens here
|
5
|
+
require 'seeing_is_believing/binary/align_file'
|
6
|
+
require 'seeing_is_believing/binary/align_line'
|
7
|
+
require 'seeing_is_believing/binary/align_chunk'
|
8
|
+
|
9
|
+
# Evaluator decision happens here
|
10
|
+
require 'seeing_is_believing/evaluate_by_moving_files'
|
11
|
+
require 'seeing_is_believing/evaluate_with_eval_in'
|
12
|
+
|
13
|
+
# Annotator decision happens here
|
14
|
+
require 'seeing_is_believing/binary/annotate_every_line'
|
15
|
+
require 'seeing_is_believing/binary/annotate_xmpfilter_style'
|
16
|
+
|
17
|
+
class SeeingIsBelieving
|
18
|
+
module Binary
|
19
|
+
class InterpretFlags
|
20
|
+
def self.attr_predicate(name)
|
21
|
+
define_method("#{name}?") { predicates.fetch name }
|
22
|
+
end
|
23
|
+
attr_predicate :print_version
|
24
|
+
attr_predicate :inherit_exit_status
|
25
|
+
attr_predicate :result_as_json
|
26
|
+
attr_predicate :print_help
|
27
|
+
attr_predicate :print_cleaned
|
28
|
+
attr_predicate :provided_filename_dne
|
29
|
+
attr_predicate :file_is_on_stdin
|
30
|
+
|
31
|
+
def self.attr_attribute(name)
|
32
|
+
define_method(name) { attributes.fetch name }
|
33
|
+
end
|
34
|
+
attr_attribute :annotator
|
35
|
+
attr_attribute :help_screen
|
36
|
+
attr_attribute :debugger
|
37
|
+
attr_attribute :markers
|
38
|
+
attr_attribute :timeout
|
39
|
+
attr_attribute :shebang
|
40
|
+
attr_attribute :filename
|
41
|
+
attr_attribute :body
|
42
|
+
attr_attribute :annotator_options
|
43
|
+
attr_attribute :prepared_body
|
44
|
+
attr_attribute :lib_options
|
45
|
+
attr_attribute :errors
|
46
|
+
|
47
|
+
def initialize(flags, stdin, stdout)
|
48
|
+
# Some simple attributes
|
49
|
+
self.attributes = {}
|
50
|
+
attributes[:errors] = flags.fetch(:errors)
|
51
|
+
attributes[:markers] = flags.fetch(:markers) # TODO: Should probably object-ify these
|
52
|
+
attributes[:timeout] = flags.fetch(:timeout) # b/c binary prints this out in the error message TODO: rename seconds_until_timeout
|
53
|
+
attributes[:shebang] = flags.fetch(:shebang) # b/c binary uses this to validate syntax atm
|
54
|
+
attributes[:filename] = flags.fetch(:filename)
|
55
|
+
|
56
|
+
# All predicates
|
57
|
+
self.predicates = {}
|
58
|
+
predicates[:print_version] = flags.fetch(:version) # TODO: rename rhs to print_version ?
|
59
|
+
predicates[:inherit_exit_status] = flags.fetch(:inherit_exit_status)
|
60
|
+
predicates[:result_as_json] = flags.fetch(:result_as_json)
|
61
|
+
predicates[:print_help] = !!flags.fetch(:help)
|
62
|
+
predicates[:print_cleaned] = flags.fetch(:clean) # TODO: Better name on rhs
|
63
|
+
predicates[:provided_filename_dne] = !!(filename && !File.exist?(filename)) # TODO: Should this just be an error in errors table?
|
64
|
+
predicates[:file_is_on_stdin] = (!filename && !flags.fetch(:program_from_args))
|
65
|
+
|
66
|
+
# Polymorphism, y'all!
|
67
|
+
attributes[:annotator] = (flags.fetch(:xmpfilter_style) ? AnnotateXmpfilterStyle : AnnotateEveryLine)
|
68
|
+
attributes[:help_screen] = flags.fetch(:help) == 'help' ? flags.fetch(:short_help_screen) : flags.fetch(:long_help_screen)
|
69
|
+
attributes[:debugger] = flags.fetch(:debug) ? Debugger.new(stream: stdout, colour: true) : Debugger.new(stream: nil)
|
70
|
+
attributes[:body] = ((print_version? || print_help?) && String.new) ||
|
71
|
+
flags.fetch(:program_from_args) ||
|
72
|
+
(file_is_on_stdin? && stdin.read) ||
|
73
|
+
(File.read filename unless provided_filename_dne?) ||
|
74
|
+
String.new
|
75
|
+
|
76
|
+
# Attributes that depend on predicates
|
77
|
+
attributes[:prepared_body] = body && annotator.prepare_body(body, markers)
|
78
|
+
|
79
|
+
# The lib's options (passed to SeeingIsBelieving.new)
|
80
|
+
attributes[:lib_options] = {
|
81
|
+
evaluate_with: (flags.fetch(:safe) ? EvaluateWithEvalIn : EvaluateByMovingFiles),
|
82
|
+
filename: (flags.fetch(:as) || filename),
|
83
|
+
ruby_executable: shebang,
|
84
|
+
stdin: (file_is_on_stdin? ? '' : stdin),
|
85
|
+
require: (['seeing_is_believing/the_matrix'] + flags.fetch(:require)), # TODO: rename requires: files_to_require, or :requires or maybe :to_require
|
86
|
+
load_path: ([File.expand_path('../../..', __FILE__)] + flags.fetch(:load_path)),
|
87
|
+
encoding: flags.fetch(:encoding),
|
88
|
+
timeout: timeout,
|
89
|
+
debugger: debugger,
|
90
|
+
number_of_captures: flags.fetch(:number_of_captures), # TODO: Rename to max_number_of_captures
|
91
|
+
record_expressions: annotator.expression_wrapper(markers), # TODO: rename to wrap_expressions
|
92
|
+
}
|
93
|
+
|
94
|
+
# The annotator's options (passed to annotator.call)
|
95
|
+
attributes[:annotator_options] = {
|
96
|
+
alignment_strategy: extract_alignment_strategy(flags.fetch(:alignment_strategy), errors),
|
97
|
+
debugger: debugger,
|
98
|
+
markers: markers,
|
99
|
+
max_line_length: flags.fetch(:max_line_length),
|
100
|
+
max_result_length: flags.fetch(:max_result_length),
|
101
|
+
}
|
102
|
+
|
103
|
+
# Some error checking
|
104
|
+
if 1 < flags.fetch(:filenames).size
|
105
|
+
errors << "Can only have one filename, but had: #{flags.fetch(:filenames).map(&:inspect).join ', '}"
|
106
|
+
elsif filename && flags.fetch(:program_from_args)
|
107
|
+
errors << "You passed the program in an argument, but have also specified the filename #{filename.inspect}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def inspect
|
112
|
+
inspected = "#<#{self.class.name.inspect}\n"
|
113
|
+
inspected << " --PREDICATES--\n"
|
114
|
+
predicates.each do |predicate, value|
|
115
|
+
inspected << inspect_line(sprintf " %-25s %p", predicate.to_s+"?", value)
|
116
|
+
end
|
117
|
+
inspected << " --ATTRIBUTES--\n"
|
118
|
+
attributes.each do |predicate, value|
|
119
|
+
inspected << inspect_line(sprintf " %-20s %p", predicate.to_s, value)
|
120
|
+
end
|
121
|
+
inspected << ">"
|
122
|
+
inspected
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
attr_accessor :predicates, :attributes
|
128
|
+
|
129
|
+
def extract_alignment_strategy(strategy_name, errors)
|
130
|
+
strategies = {'file' => AlignFile, 'chunk' => AlignChunk, 'line' => AlignLine}
|
131
|
+
if strategies[strategy_name]
|
132
|
+
strategies[strategy_name]
|
133
|
+
elsif strategy_name
|
134
|
+
errors << "alignment-strategy does not know #{strategy_name}, only knows: #{strategies.keys.join(', ')}"
|
135
|
+
else
|
136
|
+
errors << "alignment-strategy expected an alignment strategy as the following argument but did not see one"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def inspect_line(line)
|
141
|
+
if line.size < 78
|
142
|
+
line << "\n"
|
143
|
+
else
|
144
|
+
line[0, 75] << "...\n"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|