Seven ways Tux is awesome

One of the most awesome tools I’ve learned to use while working with Penny’s Ruby/Sinatra stack is Tux. Tux is a Ruby REPL that augments the standard irb with a bunch of incredibly helpful plugins to help you with your Ruby development. In fact, it’s probably our most important development tool—possibly even more important than Slack. In this listicle, I’ll lay out some of the ways Tux has won our hearts and saved our fingers.

1. History, Tab-Completion, And More

Tux includes irbtools, which offers some basic improvements over irb, such as history preservation between sessions and tab-completion for methods. It can even detect when you call the wrong method:

>> 'asdf'.spilt
NoMethodError: undefined method `spilt' for "asdf":String

    Did you mean? #split

Or tell you how to call it, if you forget:

>> 'asdf'.howtocall(:first)
first(limit)

In addition, you can see which modules have been mixed into a particular object:

>> 'asdf'.mlp
=> [#<Class:#<String:0x007f66bfa28fc8>>, String, Amatch::StringMethods, ToRegexp::String, JSON::Ext::Generator::GeneratorMethods::String, Comparable, Object, Debugging, InteractiveEditor::Editors, Looksee::ObjectMixin, MethodLocator, FileUtils::Verbose, FileUtils, FileUtils::StreamUtils_, ORI::Extensions::Object, ActiveSupport::Dependencies::Loadable, JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject]

Or even get a handsome table of callable methods grouped by module and color-coded by visibility:

>> 'asdf'.lp

lp

You can edit any object in the editor of your choosing, where it gets converted to YAML and back:

>> a = (0..10).to_a
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>> b = a.vim

vim

I’m only scratching the surface here—there’s lots more along these lines if you check out the Tux docs.

2. Test Code Locally

Tux loads your Sinatra environment, which means it has access to all of your models and all of the logic you’ve written. This means you can directly invoke application code from Tux, so you can test specific logic without restarting your Sinatra server and crafting a HTTP request. If you do want to make a HTTP request, Tux lets you fake HTTP requests with rack-test to hit your endpoints super quickly.

>> puts get('/').status
200
>> puts get('/poop').status
404

3. Query Production with ActiveRecord

If you hook Tux up to your production database, you can use ActiveRecord’s handy DSL to query your database as well as invoke any of your application logic that you’ve written, such as a custom method on a model. There’s no easier way to tweak data, rerun a faulty piece of logic, or put a user back on their feet. Once upon a time, I kept a MySQL CLI open at all times for quick querying, but I’ve since upgraded to ActiveRecord where I can use application-specific filters, methods, and scopes.

4. Test Code Against Production Data

Taking this to the next level, you can easily paste or execute large chunks of code against production systems. This is obviously pretty dangerous, but if you’re iterating on an analytics tool or a read-only function, you can test it against production before even committing it, eliminating the write-commit-deploy-check feedback loop. For example, let’s say we’re working on a method called guess_color on an ActiveRecord model called Animal:

class Animal < ActiveRecord::Base
   def guess_color
     ...
   end
end

Let’s write and test a more accurate guess_color. Assuming the above exists on production already, we can monkeypatch Animal with a new guess_color and test it against live data to see how it performs.

>> class Animal
|    def new_guess_color
|      # new algorithm
|    end
|  end
=> :new_guess_color
>> Animal.all.select { |a| a.guess_color != a.new_guess_color }.each do
|  |a| puts "#{a.id} changed behavior: #{a.guess_color} -> #{a.new_guess_c!"
|  end

Now you can safely and quickly iterate on new functionality against live data, allowing you to more quickly converge on an accurate solution.

5. Display All Data With Tables

Tux integrates with hirb to give beautiful tables for ActiveRecord results.

>> User.take(2)

Table with two users

The same table can be displayed vertically too, if you don’t have enough space.

List with two users

In fact, you can use Hirb’s table-rendering logic yourself in Tux!

>> words = %w(correct horse battery staple)
=> ["correct", "horse", "battery", "staple"]
>> words_with_length = words.map { |w| [ w, w.length ] }
=> [["correct", 7], ["horse", 5], ["battery", 7], ["staple", 6]]
>> puts Hirb::Helpers::Table.render(words_with_length, headers: %w(word length))
+---------+--------+
| word    | length |
+---------+--------+
| correct | 7      |
| horse   | 5      |
| battery | 7      |
| staple  | 6      |
+---------+--------+
4 rows in set
=> nil

You can imagine how useful this is for visualizing multidimensional information from the command line.

6. Customize Hirb With Smart Timestamps

You can customize Hirb’s table rendering with your own filters. Here’s an example:

>> User.take(2)

Table with Unix timestamps

Wouldn’t be it great if that created_at field could be automatically transformed from a Unix timestamp into a human-readable date? It is with Tux, if you put the following in your ~/.irbrc:

Behold:

>> User.take(2)

Table with human-readable dates

7. Iterate With Cheap, Scrappy Analytics

We keep a flock of analytics methods that generate DAU graphs and do other analytics chores like cohorting, funnel tracking, and retention modeling. These methods are only invoked from Tux and never from the application server. At our small size, these mini-analytics tools are significantly easier to write and change than a separate dashboard or system. For example, here’s output from one of our tools, an onboarding funnel tracker:

Onboarding funnel

Here’s another example: generating confusion matrices for pairwise binary variables.

Confusion Matrix

That’s all for now! We covered Tux’s basic improvements to IRB, using Tux to accelerate development, accessing production data with Tux, using and customizing Tux’s table output, and building custom analytics tools. I’ve left out some details from this post, like how to go about connecting Tux to production, but I’ll discuss that in a future post!