Ever get the urge to update a ton of files? I know I do. For example, I recently changed multiple hundred coffeescript files from the syntax of
MyGreatClass = Backbone.Model.extend(
defaults:
awesome: true
)
to
class @MyGreatClass extends Backbone.Model
defaults:
awesome: true
How long did it take me? A couple of minutes. Here’s how.
I like ack. To find all the files I need to edit, I’d write something like this:
ack '^[^\s].*\=.*\.extend\($' app/assets/javascripts -l
This finds everything that doesn’t start with a space, has an equals sign, and
has .extend( at the end of the line.
After looking over the results of ack and ensuring that everything that matched is what I want to edit, I’ll open those files in vim.
vim $(ack '^[^\s].*\=.*\.extend\($' app/assets/javascripts -l)
If you’ve been using vim and haven’t taken advantage of macros (especially if
you’re editing a lot of files in a similar fashion), you’re missing out. Open
up vim and type :help q to get the nitty-gritty; I’ll summarize here.
To start recording a macro, press (in normal mode) q and then a letter or number. This will record a macro to whatever register you chose (via the letter or number).
Once you’re recording a macro, anything you type will be recorded to that macro so that it can be replayed. What I would type to change these files to the new format would be:
qqgg0iclass @<esc>f=cwextends<esc>2f.DGdd:wnq
Whoa, brain overload. Let’s break it down:
qq # records the macro to the q buffer
gg # first line in file
0 # first character in line
iclass @<esc> # inserts class @ at the cursor and returns to normal mode
f= # finds the first equal after the cursor
cwextends<esc> # changes the word (=) and moves to insert mode, adds extends, and returns to normal mode
2f. # finds the second period after the cursor
D # deletes the remainder of the line
G # moves to the end of the file
dd # deletes the line
:wn # writes the file and moves to the next file in the list
q # stops recording
This should be fairly straightforward; the only thing I really want to point
out is the :wn. The n in that command moves to the next file in the list
of files you opened with vim. This is one half of what makes editing all these
files really fast.
Now that you have your macro, it’s time to replay it. To replay a macro, press
(in normal mode) @q (assuming you stored your macro into the q register). If
you were to run that macro, it’ll run it against the current file, write the file,
and move to the next. Since vim supports prefixing many commands with a number
(for the number of times to repeat the command), running 100@q will run that
macro on the first one hundred open files that I’ve opened with vim.
Typically, this should be all you need to batch-edit, but if there are more
files, just run that command again (or start with a higher number). If there
are no more files to edit, vim will let you know.
Ben also mentioned recursive macros (my mind was blown) by adding @q right
before the last q (which will run the q macro before stopping recording).
Just make sure your q register is empty! This would allow you to run your macro
once, without specifying the number of times to run it, because vim will run
the macro until it’s out of files. Fancy!
Want to kick ass at vim? Pick up a copy of Vim for Rails Developers and become blazing-fast! If you want to hang out with fellow vim users to swap awesome tips like this, be sure to head to the Boston Vim Meetup!
I’m a big fan of Jekyll, but boy do I love SCSS and CoffeeScript. I recently set out to create a static site using Rails 3.1, to take advantage of the lovely Sprockets integration. There are alternatives (like Middleman, and Octopress) but I wanted to use Rails itself instead.
Our homebrewed high_voltage gem allows for static pages, so I wanted to use that to hook up my little static site that will eventually be dynamic. Here’s the process I used.
Generate the app:
gem install bundler --pre
gem install rails --no-ri --no-rdoc
rails new danger_danger
Swap out your Gemfile with:
source 'http://rubygems.org'
gem 'rails', '3.1.1'
gem 'flutie'
gem 'high_voltage'
gem 'jquery-rails'
gem 'redcarpet'
gem 'sass-rails', '~> 3.1.4'
gem 'coffee-rails', '~> 3.1.1'
gem 'uglifier', '>= 1.0.3'
Rebundle and let’s remove some other cruft:
bundle
rm config/database.yml public/index.html
rm -rf app/{helpers,mailers,models} test/ doc/ db/
Rails includes all of the subframeworks (ActiveRecord, ActionMailer, etc) by default. We don’t need those, so at the top of config/application.rb, you can replace require 'rails/all' with:
require 'rails'
require 'action_controller/railtie'
There’s references to ActionMailer in the various config/environments/ files…it’s best to just comment them for now since we may want it back later.
# comment out this in config/environments/development.rb
config.action_mailer.raise_delivery_errors = false
# comment out this in config/environments/test.rb
config.action_mailer.delivery_method = :test
I want to write templates in Markdown, so we’ll need to tell Rails to handle that. Drop this into config/initializers/redcarpet.rb, thanks to this gist. Hopefully in future versions of Rails this will be easier if Tilt is integrated into ActionView.
class ActionView::Template
class Redcarpet < Handler
include Handlers::Compilable
def compile template
::Redcarpet.new(template.source).to_html.inspect
end
end
register_template_handler :md, Redcarpet
end
Let’s start with just a homepage. Change vim to your editor of choice!
mkdir app/views/pages
vim app/views/pages/home.html.md
In that file, you can write Markdown as normal:
# Welcome to the home page!
This should say something important.
In your config/routes.rb, point to it:
root :to => 'high_voltage/pages#show', :id => 'home'
Fire up your server, and you should be able to see your home page!
rails server
Awesome! You should now see your home page rendered in markdown. What’s even better is that you can include CoffeeScript and SCSS like you normally would with a Rails app. The Rails Guide on the asset pipeline is a great read for this if you haven’t seen it.
For more static pages, you just need to drop different markdown files into app/views/pages, and high_voltage will render them as normal at /pages/:yourpage, like so:
echo "Fire in the" > app/views/pages/disco.html.md
open http://localhost:3000/pages/disco
I’ve put a repo up on GitHub if you want to check out a working version of this.
Ok sure, this is a lot of setup for a static site. The idea is that eventually I want to be using Rails anyway, so why not just use it to start? If I end up creating another one of these, I may end up making a Rails Template, which makes the legwork of setting this kind of Rails app up way easier. For now, this works great, and I hope it helps you out too!
I’ve been writing some CoffeeScript lately, and it’s been fantastic. I wish I had started looking into this language sooner. Here’s some thoughts about it.
Writing CoffeeScript instead of JavaScript feels like I’m fighting a whole new battle. JavaScript is not a verbose language. Writing JavaScript properly, and in an OO manner, requires you to be verbose. What I like best is that CoffeeScript is simply…spartan.

You bring only this snippet of code to battle?

You! What is your keyword?

It’s function, sir.

And you?

I’m _.bindAll, sir.

CoffeeScript! What are your keywords?

-> ! => ! -> !

See old friend, I brought better code than you did.
I’m most excited about how accessible functions have become in CoffeeScript, and how the worry of doing _.bindAll to keep the current object in this just vanishes. Even our old friend $(document).ready loses a few pounds of syntax weight:
$ ->
new ItemsRouter()
Backbone.history.start()
It’s ridiculously neat to me that it just works. If you’re doing a loop or something in a Backbone.View to render many things, you can use the “fat arrow” to make sure this stays as the current object.
class ItemView extends Backbone.View
render: ->
@options.items.each(@renderItem)
renderItem: (item) =>
@el.append item.get("title")
No more worrying about _.bindAll! Oh yeah, using @ for instance methods (it substitutes this.) is a great little cupcake of syntax sugar that makes code so much easier to read.
We know the Ruby 1.8 syntax for hashes is dead, but CS takes this one step further. In this example, Item is a Backbone.Model:
item = new Item title: "Awesome", id: 2
Omitting parentheses is something I’ve been trying with this transition. My philosophy here is to push it to the limit and see how it feels. We’ll see if it passes code review in the next few weeks.
By default, JavaScript creates all variables in the global scope. How useful.
By default, CoffeeScript makes local variables by default and makes sure to stick var in front of declarations.
test = ->
foo = "bar"
console.log(foo)
>> test() "bar" >> foo ReferenceError
This is reason enough to use CoffeeScript. I think anyone writing JavaScript has to pay such close attention to scope that it’s simply just a waste of time.
How many times have you written something like:
var html = "<option value='" + this.id + "'>" + this.get("title") + "</option>";
This is such nonsense. Why did we put up with this? In CoffeeScript, you can write:
html = "<option value='#{@id}'>#{@get("title")}</option>"
By the way, the latest version of Backbone has a make method that helps doing little element creation like this.
The official docs on the subject put it best:
JavaScript’s prototypal inheritance has always been a bit of a brain-bender
So far I’ve used inheritance only in context with subclassing Backbone’s core classes, but I like what I’m seeing so far with the class and extends keywords.
class Item extends Backbone.Model
url: ->
"/events/#{@get('event_id')/items/#{@id}"
This has been a major concern of mine since we’ve switched. Luckily it hasn’t been too bad yet, the JavaScript that is generated is actually readable. Of course, there’s the problem of there’s not a one-to-one mapping between the JS and CS, but we manage to get by with SASS/CSS just fine.
I have a feeling this will be an issue going forward, at least until Chrome or Firefox can understand CoffeeScript natively.
“Silly” is probably the only way I can describe this:
true, yes, on true false, no, off false
Not sure why we couldn’t just stick with true and false. There are always quirky parts to every language, but if I see @item.has("title") == yes in a pull request I’ll be sending a storm of commit comments.
I’ve been using Barista to integrate with Rails 3.0 which has worked out quite well.
Our current config/initializers/barista_config.rb looks like:
if Rails.env.development? || Rails.env.test?
Barista.configure do |c|
c.root = Rails.root.join("app", "assets")
c.output_root = Rails.root.join("public", "coffeescripts")
c.bare = true
c.add_preamble = false
end
end
This tells Barista to look for coffeescripts in app/assets, which hopefully will make the move to Rails 3.1 a little easier. We’re dumping them into public/coffeescripts, which is is ignored by git so we don’t check in the generated files. Finally, there’s some extra unnecessary noise that Barista adds so the two final configuration options turns that off.
We’re also using Kumade to deploy to Heroku’s bamboo stack. I’m really hoping this entire situation gets easier in the next few months, because right now it’s a real annoyance to set up all of this.
Hopefully this gives you a good overview of the nice additions that CoffeeScript provides. We talked internally about using CoffeeScript for months before integrating it. Part of me wishes we had done it sooner, but to really enjoy it fully you have to understand the problems JavaScript has, especially in a large codebase.
Huge thanks go out to the folks at DocumentCloud and Jeremy Ashkenas for making JavaScript application development less painful. There’s plenty of features I didn’t cover and pages of beautifully documented source code on the project’s site that you should read.