Edit 2014/12/30: I ended up rewriting demonstrate in several different languages, but the implementation that I like the best is in python.

So, in the course of trying to prepare a presentation for this Thursday (today!), I ended up creating a program called demonstrate.sh. Basically, it lets you write a script, meant for an interpreter (like bash, python, irb, coffee etc.) and then execute it on demand.

What do I mean by "on demand"? Well, basically it invokes the interpreter and then reads the script file one line at a time. Then it prints out a fake prompt based on the interpreter you specified, and then it prints out the line of input it's processing. When you hit enter, the script sends that line of input to the interpreter and it then prints its output to the screen. Oh, there's one little caveat. When demonstrate.sh prints the line of output, it prints it character by character with a small randomized delay. So it looks a bit like you're actually typing out the command.

That's it! It's a simple script, but it allows you to create and then run in a repeatable way a sequence of commands that you want to demonstrate.

There are some improvements I'd like to add. The ability to recursively run demonstrate scripts inside of a demonstrate script would be awesome. Currently because I'm doing everything in the simplest possible way, and the script is run in the background running demonstrate inside of a demonstrate script doesn't work very well. I'm actually not entirely sure why it doesn't work, but the results are demonstrably not what I want.

It would also be nice to make it so that you can insert arbitrary commands to the interpreter, instead of only being able to run the commands in the script. This is a particularly key feature since if you just start another interpreter to run ad-hoc commands, you don't have the same environment. This isn't important if your script doesn't contain any side-effectful things, but I think that a lot of scripts will tend to.

Finally, it would be really nice if the demonstrate.sh didn't need to fake the prompts for the interpreters. In an ideal world, those prompts would be transparently printed directly to the screen. I'm sure there's a way to do it, but it probably isn't possible/easy in bash.

When I talked to Jesse about this, he asked the critical question. Why not just record the output? My answer was essentially because I wanted to eventually be able to run arbitrary commands in addition to the script commands. This is sort of a weak answer, since it depends on a feature I haven't yet implemented!

But there's another answer, that I discovered today when I was playing with the classic Unix utility script that does exactly what Jesse was talking about. The difference between recording an interaction with script and writing a demonstrate script is this. Recording with script is still live coding. This is especially true if you want to use the timing feature to play it back at the same speed that it happened at. In contrast, writing a demonstrate script is the same as writing any regular script for the interpreter you're targeting. You are totally offline, and you can write and edit the script directly, and then run it with demonstrate to make sure it does exactly what you want.

From what I've been told about the early days of programming, the difference between recording an interaction with script and writing a demonstrate script is approximately the same as the difference between writing programs on punch cards and writing programs in a text editor on a computer. If you mess up while punching the card, you have to start over from the beginning (barring awesome hacks like this).

Yup, that's it. If you're interested, check it out on Github. Pull requests welcome :)

691 Words

2014-10-30