seeing_is_believing 3.0.0.beta.7 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
![example](https://s3.amazonaws.com/josh.cheek/images/scratch/sib-example1.gif)
|
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
|