I just released TConsole 1.2!
There are a few new features, and also a
few improvements to TConsole’s general functionality.
Command Line Options
TConsole now supports passing the first command to run as arguments. So,
for example, running the tconsole command like:
1
tconsole all
would fire up TConsole and immediately run all tests. You can also
specify the –once option if you’d like TConsole to exit immediately
after that first command runs:
1
tconsole --once all
Proper Ctrl-D, Ctrl-C, and Ctrl-Z Handling
With TConsole 1.1 it was required that you type exit to quit the app,
because TConsole didn’t handle Ctrl-D to signal the end of input, like
irb or pry would do. Honestly, I didn’t even realize you could hit
Ctrl-D in those apps to signal the end of input. Regardless, TConsole
now handles Ctrl-D properly. TConsole also now notices when you hit
Ctrl-C as tests are running and quits your tests immediately. One
exception to that is when Rails tests are running, because Rails seems
to trap Ctrl-C itself as tests are executing, to keep users from leaving
their databases in a bad state.
TConsole also handles being backgrounded with Ctrl-Z properly now.
Cleaned Up Output
At the end of your test execution, TConsole lists the errors that
occurred during testing and outputs any stack traces that may need to be
shown. Now, test ids are included in the error report at the end of
execution, and any TConsole related paths in the stack trace are
removed. The final report also now includes skipped tests in its output.
Additionally, TConsole’s !timings command now color codes its output.
That’s All Folks!
There you have it! TConsole didn’t add any major new features, but has
become a good bit more polished in the 1.2 release. Please let me know
if you run into any problems or notice any features you’d like added
with GitHub Issues.
If you’ve been using TConsole, thanks! I’m super grateful that you’re
using it, and hope it’s making your testing workflow more efficient.
I’ve spent most of my extra time over the past couple of months playing
with the code for TConsole.
It’s been a lot of fun, and I’ve learned a ton in the process. Over the
next few posts I’m going to cover some of the key concepts behind how
TConsole works, and the technology and specific Ruby libraries that make
it all possible.
For this first post, we’re going to look at fork. Forking is, simply
put, the idea that you duplicate the currently running process, yielding
the original process and a new child process. Let’s look at some quick
example code:
123456789
name="Alan"pid=forkdoname="Hello from the child process, #{name}"putsnameendProcess.wait(pid)putsname
Here’s the output for that script:
12
Hellofromthechildprocess,AlanAlan
Let’s walk through the script:
1
pid=forkdo
Here we’re calling fork to create our new child process, and setting pid
to the result. Calls to fork return the process id of the newly created
process.
One thing that makes forking with Ruby so wonderful is that it allows
you to pass a block to the fork call. When you call fork with a block the new
process will execute the code in the block and exit when the block has
finished executing. So in our example the child process exits after
outputing its message, since it’s at the end of the block at that point.
1
Process.wait(pid)
There’s that pid variable again. The call to Process.wait is outside
of the fork block, so it’s in the parent process, and basically tells
the parent process to wait until the process with an id of pid (our
child process) exits to continue.
1
putsname
If you have the tiniest bit of Ruby experience, you’ve seen something
like this puts call before, but it’s here to demonstrate a pretty
important point about fork. The first time we see puts name in
the code we’re inside of the child
process. Since the child is a duplicate of the parent, it has copies of
the parent’s variables, so name starts out as Alan in the child, since
that was its value in the parent when fork was called.
We mess with it a bit, though, and change the value of name
in the child process to demonstrate that when the parent prints out name
with puts name, the name variable hasn’t been updated like it was in
the child. Although the child is a duplicate of the parent, they aren’t
sharing their memory, so changes to variables in child don’t happen in
parent as well.
Bonus: Communicating with Process Status
In most operating systems, any time a process exits it returns an
integer value to communicate its exit status. An exit status of 0 means
that the process exited successfully, and any other value means that
there was some sort of problem. Using the exit status, you communicate
simple bits of information back from a child process to the parent
process. Let’s look at another script:
This script uses fork, just like the last one, but inside the fork
we’re only making one call, to exit. Exit does just what you’re
probably thinking - it causes the process to exit. It takes an integer
argument representing the exit code for the process.
We’ve replaced Process.wait from the previous script with
Process.wait2. It’s got a pretty goofy name, but is really helpful
when you want to get a status code back from a process, because it
returns the pid of the process that just exited and a Process::Status
object that will let us know the exit code when we call its exitstatus
method.
Looking at the exit status can be pretty good for pass/fail situations
within the subprocess, or even if it just so happens that your subprocess
only needs to communicate a few different possible results back to the
parent, but I think you can tell that’s pretty limiting. Thankfully in
future posts we’ll look at more advanced one-way communication
from the child process to the parent process and also figure out how to
do two-way communication between the child and parent processes.
How TConsole Uses Fork
I use fork in TConsole twice - once to spawn the application environment and
again to spawn the test run environment. Fork is really useful in those sitiuations
because I can load the application environment (which is often slow to
load for large Rails applications)
at startup and avoid reloading it again unless something
changes about that environment. I can fork test processes off of
that application environment process without having to spend the time
required to reload the application environment since it’s already
loaded. When the test processes exit all of the loaded tests are removed from memory, which is a desirable side effect, because we
want to make sure we have the latest version of our tests loaded each
time they run. TConsole also includes some special code to make sure
that the Rails models and controllers are only loaded in the test
environment as well. By using fork to create subprocesses we’re able
to load and clean up our environment as we need.
Happy Forking
Hopefully now you’ve got a good feel for how to use fork and some of
the situations where it’s helpful. It’s good to keep in mind that fork
isn’t unique to Ruby - it’s a Unix system call that you can use with
many other languages and is a big part of traditional Unix systems
programming, so it’s definitely something you want to have a
solid understanding of.
In my years of working with JavaScript I’ve seen kind of a natural
progression to how I’ve scripted elements within pages. In the
beginning, I just kind of wrote some javascript, put it in a function,
and attached it with an event on the element itself. So around 2001 or
so my scripts looked a lot like this:
As time moved on the idea of unobtrusive JavaScript took hold. The idea
was that we shouldn’t use those fancy onclick attributes since they
dirtied up our markup, but should instead attach the events. I used
Prototype in those days, so my code looked something like this:
12345678910
<aid="click-me"href="#">Click Me</a><!-- this code was usually down at the bottom of the body of the document --><script type="text/javascript">functionhandleClick(){alert("Stop clicking me!");}$('click-me').observe('click',handleClick);</script>
That was probably 2006 onward for me.
In general, going unobtrusive cleaned up my document a bit, but there
was still a mess of code in the document, it was just hidden elsewhere.
Within the past year or so the way I handled that was to switch to a
series of backing objects that I included in external script files. I’d
instantiate those objects in a script tag in my document, but all the
rest of the code would be stored in scripts outside the document. At
that point, I had moved on to using jQuery. My code
started looking something like this:
This example is crazy simple, but hopefully you get the idea.
Using objects was the right direction, I
think, because they gave me a nice bundle for a feature or page’s
functionality, but something still felt wrong.
In our latest design refresh of Treehouse,
I started using CoffeeScript rather than JavaScript, and I
started bypassing the script tag in the document and instead just
detecting elements that should have features attached to them. It looked
something like this:
I liked this technique when it was for code that I really wanted to
apply to every page, but there’s a tradeoff with the technique - it
really stinks if you’re detecting a lot of different types of features
because a lot of times you’ll call the detection code and nothing
matches. That problem lead me to write
Featurette.
The idea behind Featurette is that you define new classes representing
features you want to attach to elements and register them.
Any time you want to apply a feature to an
element in your document you give it a class of featurette and add
the data-featurette attribute with the name of the feature you want to
add. Let’s look at how the ClickMeThingy example above would be
implemented with Featurette.
When the document loads up, Featurette searches for all elements with
the featurette class and instantiates registered objects based on
the data-featurette attribute. Using a class name to find elements that need features attached
ensures that performance stays super fast, thanks
to the DOM’s getElementsByClassName function. It’s a little more markup than
is ideal, but it keeps things fast and it gets rid of the script tags
that plagued my older solutions and the extra document searches that
came with my original attempt at detecting when code should be attached
to elements.
We’ve just started using Featurette with Treehouse, but so far it’s
working great. I’d love to hear what you think of it! If you find any issues,
please report them in the GitHub issue tracker,
and if you have any questions feel free to
email me or tweet at me.
I’ve been meaning to switch my blog over to
Octopress since sometime
last year, but haven’t ever taken the leap. Today, though, I figured I’d
stop putting it off and start taking advantage of the beautiful code
display and much more developer friendly workflow. I’m super glad that I
did.
If you’re interested in trying out Octopress yourself, go check out the
docs at http://octopress.org.
A few days ago I was working on a little bit of drag code for a web page, and
realized that there weren’t too many clearly defined solutions for disabling and
re-enabling text selection in browsers, so I went ahead and wrote up a solution.
Here it is!
It has been tested across all major browsers, down to IE6 and including
Opera. I’ve also tested it with iOS4 and iOS5. You can still select text
with it on Android, at least whatever version of Android my Kindle Fire
is running, but my purpose for this was primarily to disable selection
while dragging around the page, and you have to click and hold to get
selection to happen on the Kindle Fire anyway, so I don’t think it’s a
big deal.
The script does require jQuery to work, and in case the code above looks crazy to you,
it’s written in CoffeeScript. Don’t worry,
here’s a version that’s converted to JavaScript
if that’s more your thing. Let’s run through the script right quick:
1
@returnFalse = ->false
This is just defining a simple function that returns false. I realized a
couple of the techniques I was using required callbacks that just return
false, so I figured it made sense to factor out.
user-select isn’t part of any CSS spec, but it’s been added by
Firefox, Webkit, and IE, so I wouldn’t be suprised for it to make it
in there soon. It’s by far the cleanest way to disable selection in my
opinion. You’ll notice all the vendor prefix there. I decided not to
include the non-prefixed version, since there’s no spec for the behavior
anyway.
As a side note, I think embedded objects like this is one place where
CoffeeScript really shines. No commas or curly braces - it starts to
almost look line CSS inline in the script rather than code.
Adding user-select handles things for most browsers, but we do still
need to use one other technique to hit every browser. user-select is
only supported in Internet Explorer version 10, which isn’t fully
released yet. Also, Opera still doesn’t have support for user-select.
Fortunately, back in the old days both IE and Opera included an
attribute on elements to disable text selection, the aptly named
unselectable attribute. We can use jQuery to set the attribute of that value to
on for the whole page, and that’ll take care of it.
1
$('*').attr("unselectable","on")
We’re matching everything in the document and making it unselectable.
It’s really straightforward, but unfortunately * is also about one of
the worst performing selectors we could use. That’s why we go ahead and
use browser detection to try and limit usage on it to IE and Opera, the
browsers that need that technique.
That’s it! We’ve now got text selection disabled across the entire
document. You can call the disable method with TextSelection.disable(). I won’t run
through the enable method, because it’s basically just the opposite of
the disable method, and I’m pretty sure you’ve got the idea of how it
works.
It can be a pain to get things like this working across all browsers,
but it’s gotten more and more easy to do lately, since so many browsers
are becoming so similar in their implementation of features. I was
amazed that something like user-select that isn’t even part of a CSS
spec was supported across most browsers as well as it is.
So, as we begin 1991, let’s really look at those weekly box office
figures and hear what the numbers are saying… what I believe they
are telling us is to stop concentrating so much on what happens in
that little room where the tickets are sold and instead concentrate
on what happens in the big room where the lights dim and the magic is
supposed to happen.
I’ve been using a little project I spiked out called tconsole for a couple of
months now, so I figured I should mark the gem as 1.0 and get on with things.
tconsole is a command line tool that helps me and other Rails developers test
more efficiently by not requiring us to reload our environment every time we
run a test. tconsole has some helpful features like allowing us to easily test
single test files, or even specific tests.
I’ve been working on test performance a lot lately. Tonight I ran into a
strange issue and needed to figure out where a file was being required from.
That can be pretty tricky in a Rails app, since often files are being
autoloaded.
I used this code up at the top of the file in question to figure out where it
was loaded from:
ruby
puts caller.join("\n")
When the file was loaded by the Rails autoload code I got a nice looking stack
trace of where execution was at that point in time, and all I had to do was
look back to the first place where my code was referenced to figure out what
was happening.