MATTENOBLE

rubygem

CSSTree - An ultra-simple CSS parser

I needed something to parse a bunch of CSS and gave me a manipulatable object. I tried a couple parsers and none of them worked. It wasn’t that they didn’t do everything I needed, they just flat out didn’t work at all.

So then I made CSSTree. It’s dead-simple and does next to nothing. Other than parsing CSS that is.

tree = CSSTree.parse("body { color: #000000; }")
# => #<CSSTree:0x000000>
tree.find("body").color
# => "#000000"
tree.find("body").margin = "10px" 
# => "10px"
tree.render
# => "body { color: #000000; margin: 10px; }

And that’s pretty much it. Go team!

Ruby Enumerables

If you’re writing any type of API client library, you’ll probably need some sort of Collection class that’s iterable. It’s quite simple, but pretty powerful; most things in Ruby are.

It’s All About Each

The Ruby stdlib has this handy module named Enumerable. It basically means that if you mix it into a class which responds to each, you get all the fanciness that is select, map, all?, etc.

This sounded odd to me at first. How would implementing the method you use to iterate an object… make it iterable? It only feels weird because we’re used to each being an interface, not an implementation. It plays both roles!

An Egg Sample

class Carton
  include Enumerable

  def each
    @eggs.each { |egg| yield egg }
  end

  def drop
    @eggs = []
  end
end

Now whenever you create a Carton object with a bunch of eggs, you’ll be able to iterate over those eggs one at a time. The eggs themselves can live in an Array, Hash, whatever. The important thing is to yield them one at a time via each.

With the above code, a Carton object can now do everything any other enumerable object can, but with the added bonus of breaking all over the fucking parking lot…

Tabby - iTerm2 Environments

If you’ve ever created a Jekyll site with, say, SASS and Coffeescript,
you know how annoying it is to set up your terminal environment every time. Open a tab, cd to your project, open a new tab, jekyll --server --auto, open yet another tab, cd to your project, sass --watch whatever.sass:whatever.css, etc.

I got tired of doing that multiple times per day, week, whatever. And so, Tabby was born.

I created Tabby for two purposes, first to solve the problem described above and second, to play around with the idea of pure Ruby configuration. There’s no crazy DSL (sorta), no YAML, no hassle; just Ruby in all it’s glory.

A Quick Tutorial

With Tabby, you set up Projects. Projects are just collections of iTerm2 tabs and what each one runs. Let’s walk through creating my blog environment. First, create the project:

$ tabby create blog

This will open up your new project in whatever you have $EDITOR set to. Tabby assumes you use ~/Dev as your project directory because, well frankly, I do. It gives you a skeleton for your project right off the bat:

class Blog < Tabby::Base
  basedir "~/Dev/blog"

  def server
    exec "rails s"
  end
end

basedir is the root of your project. Tabby takes each method in your project class and makes it a tab. The tab gets the name of the method. So above, we’d have a tab created and titled “server”. It would immediately run rails s.

Since we’re making a Jekyll blog, we can get rid of the Rails tab. We do want to have the Jekyll server running though and also SASS and Coffeescript.

class Blog < Tabby::Base
  basedir "~/Dev/blog"

  def jekyll
    exec "jekyll --server --auto"
  end

  def sass
    exec "sass --watch public/sass:public/stylesheets"
  end

  def coffee
    exec "coffee --watch -c public/coffee/ -o public/javascript/"
  end
end

So now every time you go to work on your blog, just kick it off with:

$ tabby open blog

and you’ll get:

tabby blog environment

Usage

Here’s a quick run down of the other commands, straight from the horse’s mouth:

tabby create [project]  # Creates an empty project config.
tabby edit [project]    # Opens the project config with $EDITOR.
tabby list              # List all projects.
tabby open [project]    # Starts up the environment for a project.