seeing_is_believing 3.0.0.beta.7 → 3.0.0
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/.travis.yml +3 -4
- data/Gemfile +1 -0
- data/Rakefile +18 -6
- data/Readme.md +79 -32
- data/features/examples.feature +4 -7
- data/lib/seeing_is_believing/binary/config.rb +13 -4
- data/lib/seeing_is_believing/evaluate_by_moving_files.rb +34 -20
- data/lib/seeing_is_believing/event_stream/producer.rb +51 -25
- data/lib/seeing_is_believing/hard_core_ensure.rb +1 -1
- data/lib/seeing_is_believing/safe.rb +43 -0
- data/lib/seeing_is_believing/the_matrix.rb +27 -2
- data/lib/seeing_is_believing/version.rb +1 -1
- data/seeing_is_believing.gemspec +5 -6
- data/spec/binary/config_spec.rb +64 -11
- data/spec/binary/marker_spec.rb +3 -3
- data/spec/evaluate_by_moving_files_spec.rb +2 -2
- data/spec/hard_core_ensure_spec.rb +2 -2
- data/spec/seeing_is_believing_spec.rb +303 -13
- metadata +16 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0318721dea2259939dac9f239eaf465f9a7d605
|
4
|
+
data.tar.gz: a9c3681770369df1da596a736c266ff51624603e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06109b5b546f05c712f17d3856fb5faf8e41579a00758dd3fe05a4bec5dd12028a532c6429529db257a15aebfe4bee5a574999f714f0ac2e22ab1986eafc267c
|
7
|
+
data.tar.gz: 12f47cae8b1613713ec81bc66a7156d89ed15a967b8c1b3a54af4bdc520cb25541bf2327cadf452eef2da14f4cf35ec4cd103c4718a3319ecbd1bdc035e076a4
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1,9 +1,14 @@
|
|
1
|
-
require 'bundler'
|
2
|
-
|
3
1
|
desc 'Have Bundler setup a standalone environment -- run tests in this, b/c its faster and safer'
|
4
2
|
task :install do
|
5
|
-
|
6
|
-
|
3
|
+
`which bundle`
|
4
|
+
unless $?.success?
|
5
|
+
sh 'gem', 'install', 'bundler'
|
6
|
+
end
|
7
|
+
|
8
|
+
unless Dir.exist? 'bundle'
|
9
|
+
# Running without rubygems # http://myronmars.to/n/dev-blog/2012/03/faster-test-boot-times-with-bundler-standalone
|
10
|
+
sh 'bundle', 'install', '--standalone', '--binstubs', 'bundle/bin'
|
11
|
+
end
|
7
12
|
end
|
8
13
|
|
9
14
|
desc 'Remove generated and irrelevant files'
|
@@ -24,12 +29,19 @@ end
|
|
24
29
|
|
25
30
|
desc 'Run specs'
|
26
31
|
task spec: :bundle do
|
27
|
-
|
32
|
+
require 'bundler'
|
33
|
+
sh 'ruby', '--disable-gem',
|
34
|
+
*Bundler.load.specs.flat_map(&:full_require_paths).flat_map { |p| ['-I', p ] },
|
35
|
+
'-S', 'bundle/bin/mrspec'
|
28
36
|
end
|
29
37
|
|
30
38
|
desc 'Run cukes'
|
31
39
|
task cuke: :bundle do
|
32
|
-
|
40
|
+
require 'bundler'
|
41
|
+
sh 'ruby', '--disable-gem',
|
42
|
+
*Bundler.load.specs.flat_map(&:full_require_paths).flat_map { |p| ['-I', p ] },
|
43
|
+
'-S', 'bundle/bin/cucumber',
|
44
|
+
'--tags', '~@not-implemented'
|
33
45
|
end
|
34
46
|
|
35
47
|
desc 'Run all specs and cukes'
|
data/Readme.md
CHANGED
@@ -6,17 +6,34 @@ Seeing Is Believing
|
|
6
6
|
|
7
7
|
Evaluates Ruby code, recording the results of each line.
|
8
8
|
Integrates with any extensible editor (I've integrated it with many already, see [the list](https://github.com/JoshCheek/seeing_is_believing#editor-integration)).
|
9
|
+
If you like Swift Playgrounds, you'll like SiB.
|
9
10
|
|
10
11
|

|
11
12
|
|
12
13
|
Watch a [longer video](http://vimeo.com/73866851).
|
13
14
|
|
14
|
-
|
15
|
+
|
16
|
+
Install
|
17
|
+
=======
|
18
|
+
|
19
|
+
Requires Ruby >= 2.1
|
20
|
+
|
21
|
+
```sh
|
22
|
+
$ gem install seeing_is_believing
|
23
|
+
```
|
24
|
+
|
25
|
+
Verify the install with
|
26
|
+
|
27
|
+
```sh
|
28
|
+
$ seeing_is_believing -e '1 + 1'
|
29
|
+
1 + 1 # => 2
|
30
|
+
```
|
31
|
+
|
15
32
|
|
16
33
|
Use The Binary
|
17
34
|
==============
|
18
35
|
|
19
|
-
`
|
36
|
+
Given the file `simple_example.rb`
|
20
37
|
|
21
38
|
```ruby
|
22
39
|
5.times do |i|
|
@@ -24,25 +41,29 @@ Use The Binary
|
|
24
41
|
end
|
25
42
|
```
|
26
43
|
|
27
|
-
|
44
|
+
`$ seeing_is_believing simple_example.rb` will print:
|
45
|
+
|
28
46
|
```ruby
|
47
|
+
|
29
48
|
5.times do |i| # => 5
|
30
49
|
i * 2 # => 0, 2, 4, 6, 8
|
31
50
|
end # => 5
|
32
51
|
```
|
33
52
|
|
53
|
+
|
34
54
|
Use The Lib
|
35
55
|
===========
|
36
56
|
|
37
57
|
```ruby
|
38
58
|
require 'seeing_is_believing'
|
39
|
-
|
59
|
+
|
60
|
+
# There are a lot of options you can pass here, including a custom handler
|
61
|
+
handler = SeeingIsBelieving.call("[:a, :b, :c].each do |i|
|
40
62
|
i.upcase
|
41
63
|
end")
|
64
|
+
result = handler.result
|
42
65
|
|
43
|
-
result
|
44
|
-
|
45
|
-
result[2] # => #<SIB:Line[":A", ":B", ":C"] no exception>
|
66
|
+
result[2] # => [":A", ":B", ":C"]
|
46
67
|
result[2][0] # => ":A"
|
47
68
|
result[2][1] # => ":B"
|
48
69
|
result[2][2] # => ":C"
|
@@ -53,12 +74,6 @@ result.stderr # => ""
|
|
53
74
|
result.exception # => nil
|
54
75
|
```
|
55
76
|
|
56
|
-
Install
|
57
|
-
=======
|
58
|
-
|
59
|
-
Currently requires Ruby 1.9 or 2.x
|
60
|
-
|
61
|
-
$ gem install seeing_is_believing
|
62
77
|
|
63
78
|
|
64
79
|
Editor Integration
|
@@ -69,20 +84,44 @@ Editor Integration
|
|
69
84
|
* [TextMate 1](https://github.com/JoshCheek/text_mate_1-seeing-is_believing)
|
70
85
|
* [TextMate 2](https://github.com/JoshCheek/text_mate_2-seeing-is_believing) (TM2 is actually looking really nice these days -- Josh Cheek, 18 Feb 2015)
|
71
86
|
|
87
|
+
|
72
88
|
Vim
|
73
|
-
|
89
|
+
---
|
74
90
|
|
75
|
-
|
91
|
+
These packages support SiB:
|
76
92
|
|
77
|
-
* [vim-ruby-xmpfilter](https://github.com/t9md/vim-ruby-xmpfilter)
|
78
93
|
* [vim-seeing-is-believing](https://github.com/hwartig/vim-seeing-is-believing)
|
94
|
+
* [vim-ruby-xmpfilter](https://github.com/t9md/vim-ruby-xmpfilter)
|
95
|
+
|
96
|
+
Personally, I had difficulty with them, but this configuration has gotten me pretty far:
|
97
|
+
|
98
|
+
```viml
|
99
|
+
" ===== Seeing Is Believing =====
|
100
|
+
" Assumes you have a Ruby with SiB available in the PATH
|
101
|
+
" If it doesn't work, you may need to `gem install seeing_is_believing -v 3.0.0.beta.6`
|
102
|
+
" ...yeah, current release is a beta, which won't auto-install
|
103
|
+
|
104
|
+
" Annotate every line
|
105
|
+
nmap <leader>b :%!seeing_is_believing --timeout 12 --line-length 500 --number-of-captures 300 --alignment-strategy chunk<CR>;
|
106
|
+
" Annotate marked lines
|
107
|
+
nmap <leader>n :%.!seeing_is_believing --timeout 12 --line-length 500 --number-of-captures 300 --alignment-strategy chunk --xmpfilter-style<CR>;
|
108
|
+
" Remove annotations
|
109
|
+
nmap <leader>c :%.!seeing_is_believing --clean<CR>;
|
110
|
+
" Mark the current line for annotation
|
111
|
+
nmap <leader>m A # => <Esc>
|
112
|
+
" Mark the highlighted lines for annotation
|
113
|
+
vmap <leader>m :norm A # => <Esc>
|
114
|
+
```
|
115
|
+
|
79
116
|
|
80
117
|
Emacs Integration
|
81
|
-
|
118
|
+
-----------------
|
82
119
|
|
83
120
|
You can use my friend's configuration [file](https://github.com/jcinnamond/seeing-is-believing).
|
121
|
+
You can see him use it in [this](http://brightonruby.com/2016/the-point-of-objects-john-cinnamond/?utm_source=rubyweekly&utm_medium=email)
|
122
|
+
presentation at 10 minutes.
|
84
123
|
|
85
|
-
|
124
|
+
Alternatively, adding this function to your Emacs configuration will get you pretty far:
|
86
125
|
|
87
126
|
```scheme
|
88
127
|
(defun seeing-is-believing ()
|
@@ -100,6 +139,13 @@ You can now call `seeing-is-believing` to replace the current region
|
|
100
139
|
or current buffer contents with the output of running it through
|
101
140
|
`seeing_is_believing`.
|
102
141
|
|
142
|
+
|
143
|
+
Features
|
144
|
+
========
|
145
|
+
|
146
|
+
Check the [features](features) directory.
|
147
|
+
|
148
|
+
|
103
149
|
Known Issues
|
104
150
|
============
|
105
151
|
|
@@ -108,15 +154,22 @@ Known Issues
|
|
108
154
|
This code will be wrapped. But using the value is **syntactically** invalid in Ruby, because it constitutes a "void value expression" (aka a pointless timesink and the cause of many bugs in SiB).
|
109
155
|
Unfortunately, I can't easily check it to seee if it's void since it's not in the parsed AST. But it's so edge that I don't think it's worth worrying about.
|
110
156
|
|
111
|
-
|
112
|
-
|
157
|
+
Setting up Development
|
158
|
+
======================
|
113
159
|
|
114
|
-
|
160
|
+
* Make sure you have Ruby (I use [chruby](https://github.com/postmodern/chruby) and [ruby-install](https://github.com/postmodern/ruby-install) for this).
|
161
|
+
* Make sure you have bundler and rake (`gem install bundler rake`)
|
162
|
+
* Fork the repo (there's a button on Github)
|
163
|
+
* Clone your fork (`git clone git@github.com:YOUR_GITHUB_NAME/seeing_is_believing.git`)
|
164
|
+
* Install the dependencies (`rake install`) This approach is painful, but it means the test suite is like 30s instead of 5min.
|
165
|
+
* Get a list of rake tasks (`rake -T`)
|
166
|
+
* Run the full test suite (`rake`)
|
167
|
+
* Run the rspec tests `bundle exec rspec` from here you can pass options you want, such as a tag for the tests you're interested in.
|
168
|
+
* Run the Cucumber tests `bundle exec cucumber` (these literally invoke the executable, as a user would)
|
115
169
|
|
116
|
-
Version 3
|
117
|
-
=========
|
118
170
|
|
119
|
-
|
171
|
+
Some stuff that might happen one day
|
172
|
+
====================================
|
120
173
|
|
121
174
|
* Add default to number of captures (1000), require user to explicitly set it to infinity
|
122
175
|
* Expose markers via the CLI
|
@@ -127,10 +180,6 @@ These need to be done before release:
|
|
127
180
|
rather than having to figure out all the compmlex ecosystem around installing
|
128
181
|
* Would be nice to have real integration with Emacs
|
129
182
|
* Would be nice to support Ruby Mine
|
130
|
-
|
131
|
-
Version 4
|
132
|
-
=========
|
133
|
-
|
134
183
|
* How about if begin/rescue/end was able to record the result on the rescue section
|
135
184
|
* How about if you could configure which kinds of results you were interested in
|
136
185
|
(e.g. turn on/off recording of method definitions, and other results)
|
@@ -145,6 +194,8 @@ Version 4
|
|
145
194
|
Could have fallback strategies, so e.g. `-s min=40,fallback=line`
|
146
195
|
* Package Ruby with the editor downloads so that they don't require you to know so fkn much to set it up.
|
147
196
|
* Allow user to set marker
|
197
|
+
* Maybe rename xmpfilter style, not many people know what that is, so the name doesn't help users
|
198
|
+
|
148
199
|
|
149
200
|
Inspiration
|
150
201
|
===========
|
@@ -153,10 +204,6 @@ Inspiration
|
|
153
204
|
* Bret Victor's completely inspiring talk [Inventing on Principle](https://www.youtube.com/watch?v=PUv66718DII).
|
154
205
|
* My 8th Light mentor, [Doug Bradbury](http://blog.8thlight.com/doug-bradbury/archive.html) who asked me to make it for his Kids Ruby sessions (I don't think we ever finished integrating it, though >.<)
|
155
206
|
|
156
|
-
Interestingly, [Swift playground](https://www.youtube.com/watch?v=oY6nQS3MiF8&t=25m51s)
|
157
|
-
are very similar (though better integrated since they cerce you into using xcode).
|
158
|
-
Released about a year and a half before them, but maybe I should take advantage of
|
159
|
-
their marketing anyway: Swift Playgrounds for Ruby!! :P
|
160
207
|
|
161
208
|
Shout outs
|
162
209
|
==========
|
data/features/examples.feature
CHANGED
@@ -258,8 +258,6 @@ Feature: Running the binary successfully
|
|
258
258
|
"""
|
259
259
|
And the exit status is 0
|
260
260
|
|
261
|
-
|
262
|
-
@not-implemented
|
263
261
|
Scenario: Fork records data in parent and child, parent exec does not affect it.
|
264
262
|
Given the file "fork_exec_parent.rb":
|
265
263
|
"""
|
@@ -268,7 +266,7 @@ Feature: Running the binary successfully
|
|
268
266
|
:parent
|
269
267
|
exec 'echo', 'hello'
|
270
268
|
else
|
271
|
-
sleep 1
|
269
|
+
sleep 1 #
|
272
270
|
:child
|
273
271
|
end
|
274
272
|
:child
|
@@ -283,15 +281,14 @@ Feature: Running the binary successfully
|
|
283
281
|
:parent # => :parent
|
284
282
|
exec 'echo', 'hello'
|
285
283
|
else
|
286
|
-
sleep 1
|
284
|
+
sleep 1 #
|
287
285
|
:child # => :child
|
288
|
-
end
|
286
|
+
end # => :child
|
289
287
|
:child # => :child
|
290
288
|
|
291
289
|
# >> hello
|
292
290
|
"""
|
293
291
|
|
294
|
-
@not-implemented
|
295
292
|
Scenario: Fork records data in parent and child, child exec does not affect it.
|
296
293
|
Given the file "fork_exec_child.rb":
|
297
294
|
"""
|
@@ -317,7 +314,7 @@ Feature: Running the binary successfully
|
|
317
314
|
else
|
318
315
|
:child # => :child
|
319
316
|
exec 'echo', 'hello'
|
320
|
-
end
|
317
|
+
end # => :parent
|
321
318
|
:parent # => :parent
|
322
319
|
|
323
320
|
# >> hello
|
@@ -123,7 +123,12 @@ class SeeingIsBelieving
|
|
123
123
|
self.help_screen = Binary.help_screen_extended(markers)
|
124
124
|
|
125
125
|
when '-g', '--debug'
|
126
|
-
self.debug
|
126
|
+
self.debug = true
|
127
|
+
|
128
|
+
when '--debug-to'
|
129
|
+
next_arg.call arg, "a filename" do |filename|
|
130
|
+
self.debug = filename
|
131
|
+
end
|
127
132
|
|
128
133
|
when '-d', '--line-length'
|
129
134
|
extract_positive_int_for.call arg do |n|
|
@@ -237,10 +242,14 @@ class SeeingIsBelieving
|
|
237
242
|
lib_options.event_handler = EventStream::Handlers::StreamJsonEvents.new(stdout)
|
238
243
|
end
|
239
244
|
|
240
|
-
|
241
|
-
|
242
|
-
|
245
|
+
case debug
|
246
|
+
when String
|
247
|
+
debug_file = File.open(debug, 'a').tap { |f| f.sync = true }
|
248
|
+
self.debugger = Debugger.new stream: debug_file, colour: false
|
249
|
+
when true
|
250
|
+
self.debugger = Debugger.new stream: stderr, colour: stderr.tty?
|
243
251
|
end
|
252
|
+
self.lib_options.debugger = debugger
|
244
253
|
|
245
254
|
if filename && body
|
246
255
|
add_error("Cannot give a program body and a filename to get the program body from.")
|
@@ -11,6 +11,7 @@
|
|
11
11
|
# read the wrong file... of course, since we rewrite the file,
|
12
12
|
# its body will be incorrect, anyway.
|
13
13
|
|
14
|
+
require 'rbconfig'
|
14
15
|
require 'timeout'
|
15
16
|
require 'seeing_is_believing/error'
|
16
17
|
require 'seeing_is_believing/result'
|
@@ -74,9 +75,11 @@ class SeeingIsBelieving
|
|
74
75
|
end
|
75
76
|
|
76
77
|
def set_back_to_initial_conditions
|
77
|
-
@was_backed_up
|
78
|
-
File.rename(backup_filename, filename)
|
78
|
+
if @was_backed_up
|
79
|
+
File.rename(backup_filename, filename)
|
80
|
+
else
|
79
81
|
File.delete(filename)
|
82
|
+
end
|
80
83
|
end
|
81
84
|
|
82
85
|
def write_program_to_file
|
@@ -97,32 +100,33 @@ class SeeingIsBelieving
|
|
97
100
|
# setup environment variables
|
98
101
|
env = ENV.to_hash.merge 'SIB_VARIABLES.MARSHAL.B64' =>
|
99
102
|
[Marshal.dump(
|
100
|
-
event_stream_fd:
|
103
|
+
event_stream_fd: 4,
|
101
104
|
max_line_captures: max_line_captures,
|
102
105
|
num_lines: program.lines.count,
|
103
106
|
filename: filename
|
104
107
|
)].pack('m0')
|
105
108
|
|
106
109
|
# evaluate the code in a child process
|
107
|
-
opts = {
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
110
|
+
opts = {
|
111
|
+
4 => child_eventstream,
|
112
|
+
in: child_stdin,
|
113
|
+
out: child_stdout,
|
114
|
+
err: child_stderr,
|
115
|
+
pgroup: true, # run it in its own process group so we can SIGINT the whole group
|
116
|
+
}
|
117
|
+
child_pid = Kernel.spawn(env, *popen_args, opts)
|
118
|
+
child_pgid = Process.getpgid(child_pid)
|
112
119
|
|
113
120
|
# close child streams b/c they won't emit EOF
|
114
121
|
# until both child and parent references are closed
|
115
|
-
child_eventstream
|
116
|
-
child_stdout.close
|
117
|
-
child_stderr.close
|
118
|
-
child_stdin.close
|
122
|
+
close_streams(child_eventstream, child_stdout, child_stderr, child_stdin)
|
119
123
|
stdin.sync = true
|
120
124
|
|
121
|
-
# send stdin
|
122
|
-
Thread.new
|
125
|
+
# send stdin (char at a time b/c input could come from a stream)
|
126
|
+
Thread.new do
|
123
127
|
provided_input.each_char { |char| stdin.write char }
|
124
128
|
stdin.close
|
125
|
-
|
129
|
+
end
|
126
130
|
|
127
131
|
# set up the event consumer
|
128
132
|
consumer = EventStream::Consumer.new(events: eventstream, stdout: stdout, stderr: stderr)
|
@@ -130,16 +134,17 @@ class SeeingIsBelieving
|
|
130
134
|
|
131
135
|
# wait for completion
|
132
136
|
Timeout.timeout timeout_seconds do
|
133
|
-
|
134
|
-
consumer.process_exitstatus
|
137
|
+
Process.wait child_pid
|
138
|
+
consumer.process_exitstatus($?.exitstatus)
|
135
139
|
consumer_thread.join
|
136
140
|
end
|
137
141
|
rescue Timeout::Error
|
138
|
-
Process.kill "KILL", child.pid
|
139
142
|
consumer.process_timeout timeout_seconds
|
140
|
-
consumer_thread.join # finish consuming events
|
141
143
|
ensure
|
142
|
-
|
144
|
+
allow_error(Errno::ESRCH) { Process.kill "-INT", child_pgid } # negative makes it apply to the group
|
145
|
+
allow_error(Errno::ECHILD) { Process.wait child_pid } # I can't tell if this actually works, or just creates enough of a delay for the OS to finish cleaning up the thread
|
146
|
+
consumer_thread.join
|
147
|
+
close_streams(stdin, stdout, stderr, eventstream)
|
143
148
|
end
|
144
149
|
|
145
150
|
def popen_args
|
@@ -151,5 +156,14 @@ class SeeingIsBelieving
|
|
151
156
|
*require_flags, # users can inject files to be required
|
152
157
|
filename]
|
153
158
|
end
|
159
|
+
|
160
|
+
def allow_error(error)
|
161
|
+
yield
|
162
|
+
rescue error
|
163
|
+
end
|
164
|
+
|
165
|
+
def close_streams(*streams)
|
166
|
+
streams.each { |io| io.close unless io.closed? }
|
167
|
+
end
|
154
168
|
end
|
155
169
|
end
|