andyw8-seeing_is_believing 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yml +60 -0
  3. data/.gitignore +19 -0
  4. data/.rspec +2 -0
  5. data/Gemfile +2 -0
  6. data/README.md +70 -0
  7. data/Rakefile +88 -0
  8. data/appveyor.yml +32 -0
  9. data/bin/seeing_is_believing +7 -0
  10. data/docs/example.gif +0 -0
  11. data/docs/frog-brown.png +0 -0
  12. data/docs/sib-streaming.gif +0 -0
  13. data/features/deprecated-flags.feature +91 -0
  14. data/features/errors.feature +155 -0
  15. data/features/examples.feature +423 -0
  16. data/features/flags.feature +852 -0
  17. data/features/regression.feature +898 -0
  18. data/features/support/env.rb +102 -0
  19. data/features/xmpfilter-style.feature +471 -0
  20. data/lib/seeing_is_believing/binary/align_chunk.rb +47 -0
  21. data/lib/seeing_is_believing/binary/align_file.rb +24 -0
  22. data/lib/seeing_is_believing/binary/align_line.rb +25 -0
  23. data/lib/seeing_is_believing/binary/annotate_end_of_file.rb +56 -0
  24. data/lib/seeing_is_believing/binary/annotate_every_line.rb +52 -0
  25. data/lib/seeing_is_believing/binary/annotate_marked_lines.rb +179 -0
  26. data/lib/seeing_is_believing/binary/comment_lines.rb +36 -0
  27. data/lib/seeing_is_believing/binary/commentable_lines.rb +126 -0
  28. data/lib/seeing_is_believing/binary/config.rb +455 -0
  29. data/lib/seeing_is_believing/binary/data_structures.rb +58 -0
  30. data/lib/seeing_is_believing/binary/engine.rb +161 -0
  31. data/lib/seeing_is_believing/binary/format_comment.rb +79 -0
  32. data/lib/seeing_is_believing/binary/interline_align.rb +57 -0
  33. data/lib/seeing_is_believing/binary/remove_annotations.rb +113 -0
  34. data/lib/seeing_is_believing/binary/rewrite_comments.rb +62 -0
  35. data/lib/seeing_is_believing/binary.rb +73 -0
  36. data/lib/seeing_is_believing/code.rb +139 -0
  37. data/lib/seeing_is_believing/compatibility.rb +28 -0
  38. data/lib/seeing_is_believing/debugger.rb +32 -0
  39. data/lib/seeing_is_believing/error.rb +17 -0
  40. data/lib/seeing_is_believing/evaluate_by_moving_files.rb +195 -0
  41. data/lib/seeing_is_believing/event_stream/consumer.rb +221 -0
  42. data/lib/seeing_is_believing/event_stream/events.rb +193 -0
  43. data/lib/seeing_is_believing/event_stream/handlers/debug.rb +61 -0
  44. data/lib/seeing_is_believing/event_stream/handlers/record_exit_events.rb +26 -0
  45. data/lib/seeing_is_believing/event_stream/handlers/stream_json_events.rb +23 -0
  46. data/lib/seeing_is_believing/event_stream/handlers/update_result.rb +41 -0
  47. data/lib/seeing_is_believing/event_stream/producer.rb +178 -0
  48. data/lib/seeing_is_believing/hard_core_ensure.rb +58 -0
  49. data/lib/seeing_is_believing/hash_struct.rb +206 -0
  50. data/lib/seeing_is_believing/result.rb +89 -0
  51. data/lib/seeing_is_believing/safe.rb +112 -0
  52. data/lib/seeing_is_believing/swap_files.rb +90 -0
  53. data/lib/seeing_is_believing/the_matrix.rb +97 -0
  54. data/lib/seeing_is_believing/version.rb +3 -0
  55. data/lib/seeing_is_believing/wrap_expressions.rb +265 -0
  56. data/lib/seeing_is_believing/wrap_expressions_with_inspect.rb +19 -0
  57. data/lib/seeing_is_believing.rb +69 -0
  58. data/seeing_is_believing.gemspec +84 -0
  59. data/spec/binary/alignment_specs.rb +27 -0
  60. data/spec/binary/comment_lines_spec.rb +852 -0
  61. data/spec/binary/config_spec.rb +831 -0
  62. data/spec/binary/engine_spec.rb +114 -0
  63. data/spec/binary/format_comment_spec.rb +210 -0
  64. data/spec/binary/marker_spec.rb +71 -0
  65. data/spec/binary/remove_annotations_spec.rb +342 -0
  66. data/spec/binary/rewrite_comments_spec.rb +106 -0
  67. data/spec/code_spec.rb +233 -0
  68. data/spec/debugger_spec.rb +45 -0
  69. data/spec/evaluate_by_moving_files_spec.rb +204 -0
  70. data/spec/event_stream_spec.rb +762 -0
  71. data/spec/hard_core_ensure_spec.rb +120 -0
  72. data/spec/hash_struct_spec.rb +514 -0
  73. data/spec/seeing_is_believing_spec.rb +1094 -0
  74. data/spec/sib_spec_helpers/version.rb +17 -0
  75. data/spec/spec_helper.rb +26 -0
  76. data/spec/spec_helper_spec.rb +16 -0
  77. data/spec/wrap_expressions_spec.rb +1013 -0
  78. metadata +340 -0
@@ -0,0 +1,90 @@
1
+ require 'seeing_is_believing/error'
2
+ require 'seeing_is_believing/hard_core_ensure'
3
+
4
+ class SeeingIsBelieving
5
+ class SwapFiles
6
+ # Might honeslty make more sense to break this out into 2 different classes.
7
+ # We've got to do some confusing state accounting since there are really 2
8
+ # algorithms here:
9
+ #
10
+ # if the file exists:
11
+ # make sure there isn't a backup (could cause the user to lose their file)
12
+ # back the file up
13
+ # write the rewritten code to the file
14
+ # if we are told to show the user program
15
+ # move the backup over the top of the rewritten file
16
+ # do nothing in the ensure block
17
+ # else
18
+ # in the ensure block: move the backup over the top of the rewritten file
19
+ # if the file DNE:
20
+ # write the rewritten code to the file
21
+ # if we are told to show the user program
22
+ # write the user program to the file
23
+ # delete the file in the ensure block
24
+ def self.call(*args, &block)
25
+ new(*args, &block).call
26
+ end
27
+
28
+ def initialize(file_path, backup_path, user_program, rewritten_program, &block)
29
+ self.file_path = file_path
30
+ self.block = block
31
+ self.backup_path = backup_path
32
+ self.user_program = user_program
33
+ self.rewritten_program = rewritten_program
34
+ end
35
+
36
+ def call
37
+ HardCoreEnsure.call \
38
+ code: -> {
39
+ File.exist? backup_path and
40
+ raise TempFileAlreadyExists.new(file_path, backup_path)
41
+
42
+ @has_file = File.exist? file_path
43
+
44
+ if @has_file
45
+ File.rename file_path, backup_path
46
+ @needs_restore = true
47
+ end
48
+
49
+ save_file rewritten_program
50
+
51
+ block.call self
52
+ },
53
+ ensure: -> {
54
+ set_back_to_initial_conditions
55
+ }
56
+ end
57
+
58
+ def show_user_program
59
+ if @needs_restore
60
+ restore
61
+ else
62
+ save_file user_program
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ attr_accessor :block, :file_path, :backup_path, :rewritten_program, :user_program
69
+
70
+ def restore
71
+ File.rename(backup_path, file_path)
72
+ @needs_restore = false
73
+ end
74
+
75
+
76
+ def save_file(program)
77
+ File.open file_path, 'w', external_encoding: "utf-8" do |f|
78
+ f.write program.to_s
79
+ end
80
+ end
81
+
82
+ def set_back_to_initial_conditions
83
+ if @needs_restore
84
+ restore
85
+ elsif !@has_file
86
+ File.delete(file_path)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,97 @@
1
+ require_relative 'safe'
2
+ require_relative 'version'
3
+ require_relative 'event_stream/producer'
4
+ require 'socket'
5
+ require 'timeout'
6
+
7
+ using SeeingIsBelieving::Safe
8
+
9
+ sib_vars = Marshal.load ENV["SIB_VARIABLES.MARSHAL.B64"].unpack('m0').first
10
+ event_stream = Timeout.timeout(1) do
11
+ begin
12
+ Socket.tcp("localhost", sib_vars.fetch(:event_stream_port))
13
+ rescue Errno::ECONNREFUSED
14
+ sleep 0.1
15
+ retry
16
+ end
17
+ end
18
+
19
+ $SiB = SeeingIsBelieving::EventStream::Producer.new(event_stream)
20
+ $SiB.record_ruby_version RUBY_VERSION
21
+ $SiB.record_sib_version SeeingIsBelieving::VERSION
22
+ $SiB.record_filename sib_vars.fetch(:filename)
23
+ $SiB.record_num_lines sib_vars.fetch(:num_lines)
24
+ $SiB.record_max_line_captures sib_vars.fetch(:max_line_captures)
25
+
26
+ STDOUT.sync = true
27
+ STDOUT.binmode
28
+ STDERR.binmode
29
+ STDIN.set_encoding "utf-8"
30
+ stdout, stderr = STDOUT, STDERR
31
+
32
+ finish = lambda do
33
+ $SiB.finish!
34
+ event_stream.close
35
+ stdout.flush unless stdout.closed?
36
+ stderr.flush unless stderr.closed?
37
+ end
38
+
39
+ real_exec = method :exec
40
+ real_fork = method :fork
41
+ real_exit_bang = method :exit!
42
+ fork_defn = lambda do |*args|
43
+ result = real_fork.call(*args)
44
+ $SiB.send :forking_occurred_and_you_are_the_child, event_stream unless result
45
+ result
46
+ end
47
+ Kernel.module_eval do
48
+ private
49
+
50
+ define_method :warn do |*args, &block|
51
+ $stderr.puts(*args)
52
+ end
53
+
54
+ alias :exec :exec # disable warning
55
+ define_method :exec do |*args, &block|
56
+ $SiB.record_exec(args)
57
+ finish.call
58
+ real_exec.call(*args, &block)
59
+ end
60
+
61
+ alias :exit! :exit! # disable warning
62
+ define_method :exit! do |status=false|
63
+ finish.call
64
+ real_exit_bang.call(status)
65
+ end
66
+
67
+ alias :fork :fork
68
+ define_method :fork, &fork_defn
69
+ end
70
+
71
+ module Process
72
+ class << self
73
+ alias :fork :fork
74
+ end
75
+ end
76
+
77
+ Kernel.define_singleton_method :fork, &fork_defn
78
+ Process.define_singleton_method :fork, &fork_defn
79
+
80
+
81
+ # Some things need to be recorded and readded as they are called from Ruby C code and it blows up in really difficult to dianose ways -.-
82
+ symbol_to_s = Symbol.instance_method(:to_s)
83
+ exception_message = Exception.instance_method(:message)
84
+ exception_backtrace = Exception.instance_method(:backtrace)
85
+
86
+ # Guarding against hostile users (e.g. me) that do ridiculous things like blowing away these constants
87
+ exception_class = Exception
88
+ symbol_class = Symbol
89
+
90
+ at_exit do
91
+ exception_class.class_eval { define_method :message, exception_message }
92
+ exception_class.class_eval { define_method :backtrace, exception_backtrace }
93
+ symbol_class.class_eval { define_method :to_s, symbol_to_s }
94
+ exitstatus = ($! ? $SiB.record_exception(nil, $!) : 0)
95
+ finish.call
96
+ real_exit_bang.call(exitstatus) # clears exceptions so they don't print to stderr and change the processes actual exit status (we recorded what it should be)
97
+ end
@@ -0,0 +1,3 @@
1
+ class SeeingIsBelieving
2
+ VERSION = '4.2.0'
3
+ end
@@ -0,0 +1,265 @@
1
+ require 'seeing_is_believing/code'
2
+
3
+ # comprehensive list of syntaxes that can come up
4
+ # https://github.com/whitequark/parser/blob/master/doc/AST_FORMAT.md
5
+ class SeeingIsBelieving
6
+ class WrapExpressions
7
+
8
+ def self.call(program, wrappings)
9
+ new(program, wrappings).call
10
+ end
11
+
12
+ def initialize(program, wrappings)
13
+ self.before_all = wrappings.fetch :before_all, -> { '' }
14
+ self.after_all = wrappings.fetch :after_all, -> { '' }
15
+ self.before_each = wrappings.fetch :before_each, -> * { '' }
16
+ self.after_each = wrappings.fetch :after_each, -> * { '' }
17
+ self.wrappings = {}
18
+ self.code = Code.new(program, 'program-without-annotations')
19
+ code.syntax.valid? || raise(::SyntaxError, code.syntax.error_message)
20
+ end
21
+
22
+ def call
23
+ @called ||= begin
24
+ wrap_recursive code.root
25
+
26
+ wrappings = wrappings().sort_by(&:first)
27
+
28
+ wrappings.each do |line_num, (range, _last_col, meta)|
29
+ case meta
30
+ when :total_fucking_failure
31
+ rewriter.replace range, '.....TOTAL FUCKING FAILURE!.....'
32
+ when :match_current_line
33
+ rewriter.insert_before range, '~' # Regexp#~
34
+ end
35
+ end
36
+
37
+ wrappings.each do |line_num, (range, _last_col, _meta)|
38
+ rewriter.insert_before range, before_each.call(line_num)
39
+ end
40
+
41
+ wrappings.each do |line_num, (range, _last_col, _meta)|
42
+ rewriter.insert_after range, after_each.call(line_num)
43
+ end
44
+
45
+ rewriter.insert_before root_range, before_all.call
46
+ rewriter.insert_after root_range, after_all_text
47
+ rewriter.process
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ attr_accessor :before_all, :after_all, :before_each, :after_each
54
+ attr_accessor :code, :wrappings
55
+
56
+ def buffer
57
+ code.buffer
58
+ end
59
+
60
+ def rewriter
61
+ code.rewriter
62
+ end
63
+
64
+ def root_range
65
+ code.root.location.expression
66
+ end
67
+
68
+ def after_all_text
69
+ after_all_text = after_all.call
70
+ data_segment_code = "__END__\n"
71
+ code_after_end_of_file = buffer.source[root_range.end_pos, data_segment_code.size]
72
+ ends_in_data_segment = code_after_end_of_file.chomp == data_segment_code.chomp
73
+ if ends_in_data_segment
74
+ "#{after_all_text}\n"
75
+ else
76
+ after_all_text
77
+ end
78
+ end
79
+
80
+ def add_to_wrappings(range_or_ast, meta=nil)
81
+ range = range_or_ast
82
+ if range.kind_of? ::AST::Node
83
+ location = range_or_ast.location
84
+ # __ENCODING__ becomes: (const (const nil :Encoding) :UTF_8)
85
+ # Where the inner const doesn't have a location because it doesn't correspond to a real token.
86
+ # There is not currently a way to turn this off, but it would be nice to have one like __LINE__ does
87
+ # https://github.com/whitequark/parser/blob/e2249d7051b1adb6979139928e14a81bc62f566e/lib/parser/builders/default.rb#L333-343
88
+ return unless location.respond_to? :expression
89
+ range = location.expression
90
+ end
91
+ line, col = buffer.decompose_position range.end_pos
92
+ _, prev_col, _ = wrappings[line]
93
+ wrappings[line] = (!wrappings[line] || prev_col < col ? [range, col, meta] : wrappings[line] )
94
+ end
95
+
96
+ def add_children(ast, omit_first = false)
97
+ (omit_first ? ast.children.drop(1) : ast.children)
98
+ .each { |child| wrap_recursive child }
99
+ end
100
+
101
+ def add_interpolations_in(ast)
102
+ ast.children
103
+ .select { |child| child.type == :begin }
104
+ .each { |child| add_children child }
105
+ end
106
+
107
+ def wrap_recursive(ast)
108
+ return wrappings unless ast.kind_of? ::AST::Node
109
+ case ast.type
110
+ when :args, :redo, :retry, :alias, :undef, :null_node, :iflipflop, :eflipflop
111
+ # no op
112
+ when :defs, :module
113
+ add_to_wrappings ast
114
+ add_children ast, true
115
+ when :ensure, :return, :break, :next, :splat, :kwsplat
116
+ add_children ast
117
+ when :rescue
118
+ add_to_wrappings ast if inline_rescue? ast
119
+ add_children ast
120
+ when :class
121
+ name, * = ast.children
122
+ namespace, * = name.children
123
+ add_to_wrappings ast
124
+ wrap_recursive namespace
125
+ add_children ast, true
126
+ when :if
127
+ if ast.location.kind_of? Parser::Source::Map::Ternary
128
+ add_to_wrappings ast unless ast.children.any? { |child| code.void_value? child }
129
+ add_children ast
130
+ else
131
+ keyword = ast.location.keyword.source # if, elsif, unless, else, ....
132
+ if (keyword == 'if' || keyword == 'unless') && ast.children.none? { |child| code.void_value? child }
133
+ add_to_wrappings ast
134
+ end
135
+ add_children ast
136
+ end
137
+ when :when, :pair # pair is 1=>2
138
+ wrap_recursive ast.children.last
139
+ when :resbody
140
+ _exception_type, _variable_name, body = ast.children
141
+ wrap_recursive body
142
+ when :array
143
+ add_to_wrappings ast
144
+ the_begin = ast.location.begin
145
+ if !the_begin
146
+ # a = 1,2,3
147
+ add_children ast
148
+ elsif the_begin.source !~ /\A%/
149
+ # normal array
150
+ add_children ast
151
+ elsif the_begin.source =~ /\A%/
152
+ # array of literals
153
+
154
+ ast.children.each do |child|
155
+ t = child.type
156
+ if t == :dsym || t == :dstr
157
+ add_interpolations_in child
158
+ end
159
+ end
160
+ end
161
+ when :block
162
+ add_to_wrappings ast
163
+
164
+ # a {} comes in as
165
+ # (block
166
+ # (send nil :a)
167
+ # (args) nil)
168
+ #
169
+ # a.b {} comes in as
170
+ # (block
171
+ # (send
172
+ # (send nil :a) :b)
173
+ # (args) nil)
174
+ #
175
+ # we don't want to wrap the send itself, otherwise could come in as <a>{}
176
+ # but we do want ot wrap its first child so that we can get <<a>\n.b{}>
177
+ #
178
+ # I can't think of anything other than a :send that could be the first child
179
+ # but I'll check for it anyway.
180
+ the_send = ast.children[0]
181
+ wrap_recursive the_send.children.first if the_send.type == :send
182
+ add_children ast, true
183
+ when :masgn
184
+ # we must look at RHS because [1,<<A] and 1,<<A are both allowed
185
+ #
186
+ # in the first case, we must take the end_pos of the array,
187
+ # or we'll insert the after_each in the wrong location
188
+ #
189
+ # in the second, there is an implicit Array wrapped around it, with the wrong end_pos,
190
+ # so we must take the end_pos of the last arg
191
+ array = ast.children.last
192
+ if array.type != :array # e.g. `a, b = c`
193
+ add_to_wrappings ast
194
+ add_children ast, true
195
+ elsif array.location.expression.source.start_with? '['
196
+ add_to_wrappings ast
197
+ add_children ast, true
198
+ else
199
+ begin_pos = ast.location.expression.begin_pos
200
+ end_pos = array.children.last.location.expression.end_pos
201
+ range = code.range_for(begin_pos, end_pos)
202
+ add_to_wrappings range
203
+ add_children ast.children.last
204
+ end
205
+ when :lvasgn, # a = 1
206
+ :ivasgn, # @a = 1
207
+ :gvasgn, # $a = 1
208
+ :cvasgn, # @@a = 1
209
+ :casgn, # A = 1
210
+ :or_asgn, # a ||= b
211
+ :and_asgn, # a &&= b
212
+ :op_asgn # a += b, a -= b, a *= b, etc
213
+
214
+ # a=b gets wrapped <a=b>
215
+ # but we don't wrap the lvar in `for a in range`
216
+ if ast.children.last.kind_of? ::AST::Node
217
+ begin_pos = ast.location.expression.begin_pos
218
+ end_pos = ast.children.last.location.expression.end_pos
219
+ range = code.range_for(begin_pos, end_pos)
220
+ add_to_wrappings range
221
+ add_children ast, true
222
+ end
223
+ when :send
224
+ _target, message, * = ast.children
225
+ meta = (:total_fucking_failure if message == :__TOTAL_FUCKING_FAILURE__)
226
+ add_to_wrappings ast, meta
227
+ add_children ast
228
+ when :begin
229
+ if ast.location.expression.source.start_with?("(") && # e.g. `(1)` we want `<(1)>`
230
+ !code.void_value?(ast) # e.g. `(return 1)` we want `(return <1>)`
231
+ add_to_wrappings ast
232
+ end
233
+ add_children ast
234
+ when :str
235
+ add_to_wrappings ast
236
+
237
+ when :regexp, :dstr, :xstr, :dsym
238
+ add_to_wrappings ast
239
+ add_interpolations_in ast
240
+
241
+ when :hash
242
+ # method arguments might not have braces around them
243
+ # in these cases, we want to record the value, not the hash
244
+ add_to_wrappings ast, meta if ast.location.begin
245
+ add_children ast
246
+
247
+ when :block_pass, :preexe, :postexe
248
+ add_children ast # strange, I'm not too sure about this :/
249
+
250
+ when :match_current_line # ie `if /abc/; ...; end`
251
+ add_to_wrappings ast, :match_current_line
252
+
253
+ else
254
+ add_to_wrappings ast
255
+ add_children ast
256
+ end
257
+ end
258
+
259
+ def inline_rescue?(ast)
260
+ primary_code, rescue_body, _else_body = ast.children
261
+ return false unless primary_code
262
+ primary_code.loc.expression.last_line == rescue_body.loc.expression.first_line
263
+ end
264
+ end
265
+ end
@@ -0,0 +1,19 @@
1
+ require 'seeing_is_believing/wrap_expressions'
2
+ class SeeingIsBelieving
3
+ module WrapExpressionsWithInspect
4
+ def self.call(program)
5
+ # NOTE: if it received the AST, it could figure out if it needs
6
+ # to always wrap the expression in parentheses
7
+ WrapExpressions.call program,
8
+ before_all: -> {
9
+ "BEGIN { $SiB.file_loaded };"
10
+ },
11
+ before_each: -> line_number {
12
+ "$SiB.record_result(:inspect, #{line_number}, ("
13
+ },
14
+ after_each: -> line_number {
15
+ ")) { |v| v.inspect }"
16
+ }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,69 @@
1
+ require 'tmpdir'
2
+
3
+ require 'seeing_is_believing/result'
4
+ require 'seeing_is_believing/version'
5
+ require 'seeing_is_believing/debugger'
6
+ require 'seeing_is_believing/wrap_expressions_with_inspect'
7
+ require 'seeing_is_believing/hash_struct'
8
+ require 'seeing_is_believing/evaluate_by_moving_files'
9
+ require 'seeing_is_believing/event_stream/handlers/debug'
10
+ require 'seeing_is_believing/event_stream/handlers/update_result'
11
+
12
+ class SeeingIsBelieving
13
+ class Options < HashStruct
14
+ predicate(:event_handler) { EventStream::Handlers::UpdateResult.new Result.new }
15
+ predicate(:local_cwd) { false }
16
+ attribute(:filename) { nil }
17
+ attribute(:encoding) { nil }
18
+ attribute(:stdin) { "" }
19
+ attribute(:require_files) { ['seeing_is_believing/the_matrix'] }
20
+ attribute(:load_path_dirs) { [File.realpath(__dir__)] }
21
+ attribute(:timeout_seconds) { 0 }
22
+ attribute(:debugger) { Debugger::Null }
23
+ attribute(:max_line_captures) { Float::INFINITY }
24
+ attribute(:rewrite_code) { WrapExpressionsWithInspect }
25
+ end
26
+
27
+ def self.call(*args)
28
+ new(*args).call
29
+ end
30
+
31
+ attr_reader :options
32
+ def initialize(program, options={})
33
+ @program = program
34
+ @program += "\n" unless @program.end_with? "\n"
35
+ @options = Options.new options
36
+ end
37
+
38
+ def call
39
+ @memoized_result ||= Dir.mktmpdir("seeing_is_believing_temp_dir") { |dir|
40
+ filename = options.filename || File.join(dir, 'program.rb')
41
+ new_program = options.rewrite_code.call @program
42
+
43
+ options.debugger.context("REWRITTEN PROGRAM") { new_program }
44
+
45
+ EvaluateByMovingFiles.call \
46
+ filename,
47
+ @program,
48
+ new_program,
49
+ event_handler: event_handler(options.debugger, options.event_handler),
50
+ provided_input: options.stdin,
51
+ require_files: options.require_files,
52
+ load_path_dirs: options.load_path_dirs,
53
+ encoding: options.encoding,
54
+ timeout_seconds: options.timeout_seconds,
55
+ max_line_captures: options.max_line_captures,
56
+ local_cwd: options.local_cwd?
57
+
58
+ options.event_handler
59
+ }
60
+ end
61
+
62
+ private
63
+
64
+ # If we need debugging, wrap a debugging handler around the current handler
65
+ def event_handler(debugger, current_handler)
66
+ return current_handler unless debugger.enabled?
67
+ EventStream::Handlers::Debug.new debugger, current_handler
68
+ end
69
+ end
@@ -0,0 +1,84 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.realpath("lib", __dir__)
3
+ require "seeing_is_believing/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "andyw8-seeing_is_believing"
7
+ s.version = SeeingIsBelieving::VERSION
8
+ s.authors = ["Josh Cheek"]
9
+ s.email = ["josh.cheek@gmail.com"]
10
+ s.homepage = "https://github.com/JoshCheek/seeing_is_believing"
11
+ s.summary = %q{Records results of every line of code in your file}
12
+ s.description = %q{Records the results of every line of code in your file (intended to be like xmpfilter), inspired by Bret Victor's JavaScript example in his talk "Inventing on Principle"}
13
+ s.license = "WTFPL"
14
+
15
+ s.files = `git ls-files`.split("\n") - ['docs/seeing is believing.psd'] # remove psd b/c it boosts the gem size from 50kb to 20mb O.o
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency "parser", ">= 2.7", "< 4"
21
+ s.add_dependency "childprocess","~> 4.1"
22
+ s.add_dependency "ffi", "~> 1.15"
23
+
24
+ s.add_development_dependency "pry"
25
+ s.add_development_dependency "haiti", ">= 0.1", "< 0.3"
26
+ s.add_development_dependency "rake", "~> 13.0"
27
+ s.add_development_dependency "rspec", "~> 3.6"
28
+ s.add_development_dependency "bundler", "~> 2.0"
29
+ s.add_development_dependency "cucumber", "~> 2.4"
30
+ s.add_development_dependency "ripper-tags", "~> 0.3"
31
+
32
+ s.post_install_message = <<'Omg, frogs <3'.gsub(/(gg+)/) { |capture| "\e[32m#{capture.gsub 'g', '.'}\e[0m" }.gsub("brown", "\e[33m").gsub("off", "\e[0m")
33
+ .7
34
+ . .M
35
+ . . .N
36
+ M. ..O
37
+ =. .. .M
38
+ N . . .N
39
+ O.. . . O
40
+ MN:. . M
41
+ OM...N
42
+ N .OM brown.NM8MMMMMMoff
43
+ O ..N brown...MM=:Z7?Z7??MMMMIMMOM8Noff
44
+ M...O brown,MMMMMMMMMM$$:=ZZ$~:$?7ZMMMMM8?Moff
45
+ .N . M brownMMI$7:==?:77MMMM7$O~+~ZO~~I=7ZMMMMoff
46
+ O$...N brownM=$ZZI=MMM7ZZI=?MMZ+:$I?8Z~?ZO~=ZIMMoff
47
+ .MN ...O brownM~?Z==ZZZ=MM$$=$ZZMMO=~~?$=$Z~~OO+=MMoff
48
+ OM ...,M DAAAAAAAAAAAAAAAAAAAAAAAMbrown=Z=+OOI=+ZO$O+MMoff
49
+ NOM.. . N DAAAAAAAAAAAAM?:DAAAAAAAAAAAAMbrown$ZZ?$+IZ7+8?M8off
50
+ NOM.....O DAAAAAAAAM:ggggDAAAAAAAAAAAAAAMbrown78OI+D=78=$MMoff
51
+ NO.. ...MN DAAAAAAAMgggggggDAAAAAAAAAAAAAM,MMbrownMO7?I8Z7OMoff
52
+ MN.... ..O DAAAAAMgggggggggDAAAAAAAAAAAAMgg~MMbrown?NMM7O8MMoff
53
+ NOM.. ..MN DAAMggggggggggggDAAAAAAAAAAMgggggggMMbrown7.MMMoff
54
+ NOM.. .. .OM MggggggggggggggggDAAAAAAAMgggggggggggMM:M
55
+ NOM. .. ..NO Mggggggggggggggggggg~DAAMggggggggggggggI,,M
56
+ NOM.. .. .MN MMgggbrownZMMMMMMoffggggggggggggggggggggggggggggg=MM
57
+ NOM. . ... O MggbrownMMMNMMMMMMMMZoffgggggggggggggggggggggggggg$MI
58
+ NOM8.. .. .MM MZbrownMMMMMMMMMMMMMMMoffgggggggggM~gggggggggggggggMM
59
+ NOM .. . . NOM Mgggggggggggggggggggggggg8M$ggggggggggggggggMM
60
+ NOMO. . . . . M.MMMMMMMMMMMMNMMMMNMMMMMMggggggggggggggggggMM,
61
+ NOMM8. . M:MM MMggggggggggggggggggggggggggggggggggggggMM
62
+ . .MMMM brownMMMMgggggggggggggbrown7ZMMggggggggggggggggggMM
63
+ .MNOM brownMMMMMMMMMMMMMMMMMMMggggggggggggggggggggOMM
64
+ H brownMMMMMMMMMMMMMMMMMggggggg,ggggggggggggggMM
65
+ brownMMMMMMMMMMMM=gggggggggMMggggggggggggggMMN
66
+ brown:MMMMggggggggggggggggMgggggggMggggggMMM
67
+ MMMggggggggggggggMNggggg:7gggggggMMM .MMMMMM
68
+ Seeing MMMMgggggggggMgggMgggggMgggggggggMMMMggggggMM
69
+ MggMMMgggggggMgggMgggg=IggggggggMMgggggggggM
70
+ is MggMMMMgggggMggggMggggMgggggMMM:ggggggggggMM
71
+ MMggM MMMgggMgggMMgggMggggMMMgggggggggggggM,
72
+ Believing .MggMM MMMMMMgggMggggMgggggggggggggggggggMM
73
+ ggMMMMMMMMggM MggMMMgggMMgggOMggggggggggggggMNggMM
74
+ MgggggggggggggM MMMggMMgggMMMMMMMgggggggggggggMgg+MM
75
+ :MM7ggggMggIMM D ggM?MgggMM MgggggggggggMMggMM,
76
+ .MggMgg ggg gM+gggM NMggggggggMMMggMM
77
+ .MM+gZMMgggggM MMMMMMMMMMggggM
78
+ MIgg8MM,ggggMM .MMMggMggM
79
+ MMMgggMMMMggMI ggOMMMggOMMggMM
80
+ MgggMDggggM M MgggggNMMggMMggM
81
+ MMMMgggggM ggM .M:gggMggggMggggM
82
+ MM MMMMggggggMMMI
83
+ Omg, frogs <3
84
+ end
@@ -0,0 +1,27 @@
1
+ # This is mostly tested in the cukes, but some are hard to hit
2
+
3
+ require 'seeing_is_believing/binary/align_chunk'
4
+
5
+ RSpec.describe '1-off alignment specs' do
6
+ def chunk(code)
7
+ code << "\n"
8
+ SeeingIsBelieving::Binary::AlignChunk.new code
9
+ end
10
+
11
+ describe 'AlignChunk' do
12
+ it 'considers entirely whitespace lines to be a chunk separator' do
13
+ empty_line = chunk "aaaaa\n\n1"
14
+ whitespace_line = chunk "aaaaa\n \t \n1"
15
+ expect(whitespace_line.line_length_for 1).to eq empty_line.line_length_for(1)
16
+ expect(whitespace_line.line_length_for 3).to eq empty_line.line_length_for(3)
17
+ end
18
+
19
+ it 'is not fooled by whitespace on the first/last line' do
20
+ expect(chunk(" \na\n ").line_length_for(2)).to eq 3
21
+ end
22
+
23
+ it 'is not fooled by trailing whitespace in general' do
24
+ expect(chunk("a ").line_length_for(1)).to eq 3
25
+ end
26
+ end
27
+ end