seeing_is_believing 2.2.0 → 3.0.0.beta.1
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 +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
|