Common Dream

TConsole 1.2

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.

TConsole 1.1 Preview

TConsole 1.1 is pretty close to finished, so I wanted to show off some of the new features in a quick screencast!

Mastering Fork

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:

1
2
3
4
5
6
7
8
9
name = "Alan"
pid = fork do
  name = "Hello from the child process, #{name}"
  puts name
end

Process.wait(pid)

puts name

Here’s the output for that script:

1
2
Hello from the child process, Alan
Alan

Let’s walk through the script:

1
pid = fork do

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
puts name

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:

1
2
3
4
5
6
7
8
9
10
11
pid = fork do
  exit(rand.round)
end

pid, status = Process.wait2(pid)

if status.exitstatus == 0
  puts "Everything's OK"
else
  puts "FAIL"
end

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.

Add Features to Your Elements With Featurette

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:

1
2
3
4
5
6
<script type="text/javascript">
  function handleClick() {
    alert("Stop clicking me!");
  }
</script>
<a href="#" onclick="handleClick(); return false;">Click Me</a>

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:

1
2
3
4
5
6
7
8
9
10
<a id="click-me" href="#">Click Me</a>

<!-- this code was usually down at the bottom of the body of the document -->
<script type="text/javascript">
  function handleClick() {
    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:

page.html
1
2
3
4
5
<a id="click-me" href="#">Click Me</a>

<script type="text/javascript">
  new ClickMeThingy("click-me");
</script>
script.js
1
2
3
4
5
6
var ClickMeThingy = function(id) {
  $('#click-me').click(function(e) {
    e.preventDefault();
    alert("Stop clicking me!");
  });
};

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:

1
<a class="click-me" href="#">Click Me</a>
1
2
3
4
5
6
7
8
9
10
11
12
class ClickMeThingy
  @detect: () ->
    $('.click-me').each (index, element) ->
      new ClickMeThingy(element)

  constructor: (element) ->
    $(element).click (e) ->
      e.preventDefault()
      alert("Stop clicking me!")

$ ->
  ClickMeThingy.detect()

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.

1
<a class="featurette" data-featurette="click-me" href="#">Click Me</a>
1
2
3
4
5
6
7
class ClickMeThingy
  constructor: (element) ->
    $(element).click (e) ->
      e.preventDefault()
      alert("Stop clicking me!")

Featurette.register("click-me", ClickMeThingy)

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.

Blogging With Octopress

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.

Disabling and Re-Enabling Text Selection

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!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class TextSelection
  @returnFalse = -> false

  @disable = ->
    $('body').css
      "-moz-user-select": "none"
      "-webkit-user-select": "none"
      "-ms-user-select": "none"
    $(document).mousedown -> @returnFalse
    if $.browser.msie or $.browser.opera
      $('body').find(":not(input)").attr("unselectable", "on")

  @enable = ->
    $('body').css
      "-moz-user-select": "auto"
      "-webkit-user-select": "auto"
      "-ms-user-select": "auto"
    if $.browser.msie or $.browser.opera
      $('body').find(":not(input)").attr("unselectable", "off")

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.

So now for the disable method:

1
2
3
4
$('body').css
  "-moz-user-select": "none"
  "-webkit-user-select": "none"
  "-ms-user-select": "none"

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.

1
2
if $.browser.msie or $.browser.opera
  $('*').attr("unselectable", "on")

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.

Where the Magic Is Supposed to Happen

 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.

Jeffrey Katzenberg, Some Thoughts on our Business, from Letters of Note

Tconsole 1.0 Is Out!

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.

Interested in tconsole? Check it out on GitHub!

Figuring Out Where a File Was Required

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.