Alias a Class in Ruby

I had a collegue looking for a way to alias a class in Ruby. Which I thought was a pretty interseting problem.

My first attempt was using eval, which really felt to clever:

class Daddy; def speak() puts "No!" end; end
%w{Leah Lars}.each {|k| eval "class #{k} < Daddy; end"}
Leah.new.speak
Lars.new.speak

Then it dawned on me, everything is an object, even classes. So could it be this simple?

class Daddy; def speak() puts "No!" end; end
Leah = Daddy
Lars = Daddy
Leah.new.speak
Lars.new.speak

It actually worked. Yes it is one line longer. But it is extremly readable and does not use evil^H^H^Heval



Making Vim play nice with Jekyll's YAML Front Matter

vim-jekyll-yaml-ugly

This just looks bad.

I had a little Vim script adventure tonight. I wanted to make the highlighting of the yaml front matter work as it should for Jekyll.

First thing I got hung up on was figuring out how to match multiline regex's. Which is when I found out about the \_ escape that Vim has, which adds an end of line to the character class it is adjacent to. Now could use the following search to select the yaml:

/^---\_.{-}---$/

Which would also find other --- markers in the document, which was no good.

More vimdocs and I finally came across \%^ which conveniently matches start-of-file. Progress!

Once I plug that in, and go look at a few of the built Vim syntax scripts, I discover that I can put them in one handy syntax match command:

syntax match Comment /\%^---\_.\{-}---$/

I discover I can do the same thing with syntax region:

syntax region Comment start=/\%^---$/ end=/^---$/

And even enable spell checking of my title by tacking on the contains param:

syntax match Comment /\%^---\_.\{-}---$/ contains=@Spell

But now that I figured out how to highlight the text that I care about, I need to figure out which file types use that syntax.

Just apply it to all the markdown files:

autocmd BufNewFile,BufRead *.markdown syntax match Comment /\%^---\_.\{-}---$/

My first take, and it didn't seem like the best solution. Plus if the markdown file is not in a jekyll blog I don't want it to highlight the ---'s (since it is probably not yaml)

I try to get tricky, look at the path and if it looks like a jekyll blog I invoke it, and try include the textile file type.

autocmd BufNewFile,BufRead */_posts/*.textile,*/_posts/*.markdown syntax match Comment /\%^---\_.\{-}---$/

Damn, Jekyll allows you to put yaml at the top of any templates, layouts or any other text file you have -- and I want those files to work.

Then it dawned on me, I have the jekyll_path defined in my plugin, I just need a way to use that variable in the file pattern. Seems like the only way to do that is construct the command in a string and exec the bad boy. Which lead me to my final solution:

execute "autocmd BufNewFile,BufRead " . g:jekyll_path . "/* syn match jekyllYamlFrontmatter /\\%^---\\_.\\{-}---$/ contains=@Spell"

vim-jekyll-yaml-pretty

Much Better.



Convert ugly HTML links to pretty Markdown links

Recently I have been converting a large number of old blog posts to markdown, and have been writing a bunch of little one off scripts to handle this. One of the things I needed to do was convert a bunch of oddly formatted HTML links to their shiny clean markdown equivalent.

#!/usr/bin/env ruby
# Convert HTML links to Markdown links
ARGF.each do |line|
    puts line.gsub /<a [^h]*href=["']([^"']*)["'][^>]*>([^<]*)<\/a>/, "[\\2](\\1)"
end

My script follows the standard unix convention, and reads from standard in or a file, and outputs to standard out. To use it you could do something like:

ruby html_links_to_markdown.rb <file.html> > file.markdown

I should note, there are a few minor caveats. It will not:

  • replace multi line links
  • replace links with nested tags. e.g. images <a href="#"><imr src="fail.png" /></a>
  • match any links that have an attribute that starts with 'h' before href. I don't think this is a very high use case. e.g.: <a height="4" href="#">fail</a>

Those cases should just result in the original ugly links remaining in the document, which can be manually fixed. I thought it was helpful, and handled many of the badly formatted >a< tags that haunted my old posts.



Couple of vim tips

When in command mode, you can grab the word that is under the cursor. Makes search and replace for those long function names painless.

C-r C-w

The other little trick I didn't know about until I accitently brought it up was the command history. This subtle little thing makes a huge diffrence. You can use normal vim movement keys to edit the commands, and when you are done just hit on the line and it will execute it.

q:

Of course you can do the same thing with search.

q/


Getting irb with readline support on Mac

I tend to install unix software on the mac the old school way by grabbing the tarball and building it. Well that was fun an all until I discovered that irb didn't like to honor backspace. Turns out I needed to build and install readline.

curl -O ftp://ftp.cwru.edu/pub/bash/readline-6.1.tar.gz
curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p248.tar.gz
tar -zxvf readline-6.1.tar.gz
cd readline-6.1
./configure
make
sudo make install
cd ..
tar -zxvf ruby-1.8.7-p248.tar.gz
cd ruby-1.8.7-p248
./configure --with-readline-dir=/usr/local --enable-pthread
make
sudo make install
sudo make install-doc
ruby --version
# woohoo!


Blogging with Vim

I was inspired by Jack Moffitt, and his Jekyll glue for Emacs.

Not willing to let Emacs win this one, I busted out a :h script and dove into the bizarre world of vim script. And unlike other forays into wacky programming languages, this actually resulted in something that I find useful.

Basically I have two functions, a way to list all the posts in my jekyll blog and a way to make a new post.

:JekyllPost Create a new post, which will create a new buffer populated with a basic template. This does not actually write the file, so if you are like me you can start a post, change your mine and :q! and have no regrets.

:JekyllList List the posts, opens the vim file system browser in the posts directory. Which lets you quickly search and open any of you previous entries.

If you use git to store you Jekyll blog (and who doesn't?), you can use the following:

:JekyllCommit Adds and commits all the modified posts in your jekyll blog.

:JekyllPublish Pushes the changes to the remote origin.

I also made a couple of short cuts that save those precious few keystrokes:

map <Leader>jn  :JekyllPost<CR>
map <Leader>jl  :JekyllList<CR>
map <Leader>jc  :JekyllCommit<CR>
map <Leader>jp  :JekyllPublish<CR>

You can grab a copy over on github.



Top 10 Mac apps for non-programmers

Recently a project manager friend of mine asked what he should get for his shiney new mack book pro, and I came up with the following list. Turns out it was 10 items long. So I was obligated by the internets to turn it into a blog post.

  1. Adium for chat (for when you don't care about video)

  2. LaunchBar commercial, for starting apps/switching/everything. TOTALLY worth the money. If you only buy one program for your mac buy this one. If you cant cough up the euros at least use QuickSilver.

  3. Tweetie for twitter best twitter client, just use the free version.

  4. Mac RDC client For those who need to remote into windows machines, but this does it.

  5. Skitch is screen capture and markup on steroids. Alghough I am biased to Captured, which is for programmers, so it does not fit the criteria.

  6. Cyberduck who doesn't need an ftp client?

  7. 1Password commercial, but by far the best password manager/form filler out there.

  8. Dropbox simple sync between computers, does great job with 1Password's keychain.

  9. OmniGraffle commercial, but has a knack of making visio look tard-tastic.

  10. OmniFocus commercial, but it is a fantastic GTD program. the WebDAV sync lets me keep my todo list up-to-date on multiple devices.



Open Xcode Project from the Command line

When I start to work on a programmign project I am conditioned to open terminal and change to that directory. And when working in xcode I used to run open MyBigLongProjectName.xcodeproj, but have to deal with the fact that I normally have other files in that directory that start with MyBigLongProjectName--making tab compleation annoying. The solution to this was to make an xcode alias:

alias xcode="open *.xcodeproj"

Now I can switch from terminal to xcode and back with out breaking my pace.



Creating custom ohai plugins

After spending a while googling for how to make a ohai plugin I was forced to Read The Source (tm). So I thought I would put to gether a quick ohai plugin howto.

Ohai, Iz's your new plugin

Install ohai

You will need the ohai gem installed to use it, so an easy way to do this:

sudo gem source -a http://gems.opscode.com/
sudo gem install ohai

Create a simple plugin

Ohai plugins use a ruby DSL. The following is about as simple as it gets:

provides "orly"
orly "yeah, rly."

Now that part I found tricky, loading it.

Create a "plugins" folder and put the above code in the plugins/orly.rb file.

Now to fire up irb (I am assuming you are in the directory that contains the "plugins" folder, if not adjust your path):

>> require 'ohai'
>> Ohai::Config[:plugin_path] << './plugins'
>> o = Ohai::System.new
>> o.all_plugins
>> o.orly #=> "yea, rly"

The entire script can be found in orly.rb

If you run o.orly and get nil the chances are the plugin path is probably incorrect. I battled with this for hours banging my head against the wall. Turns out I just forgot the 's' on the end of './plugins'

Using a Mash

Most of the information we want to lookup would be nested in some way, and ohai tends to do this by storing the data in a Mash. This can be done by creating a new mash and setting the attribute to it.

In plugins/canhas.rb:

provides "canhas"
canhas Mash.new
canhas[:burger] = "want"

Extending an existing plugin

Ohai makes it very easy to extend a current plugin with new information. Simply require the plugin you want to extend and extend away. In this example we want to add LOLCODE to languages.

In plugins/lolcode.rb:

provides "languages/lolcode"
require_plugin "languages"
languages[:lolcode] = Mash.new
languages[:lolcode][:version] = "TEH VERSHIONS"

Working with Different Platforms

One of the main reasons for using ohai is to gather information regardless of the operating system, luckily this is made easy by optionally loading recipes based on the platform. With that platform specific calls abstracted away you can keep your code DRY.

The builtin plugins that come with ohai use the following trick to load platform specific code. It works by creating a base cross-platform plugin that loads the platform specific plugin from a subdirectory.

In plugins/lolcode.rb:

provides "languages/lolcode"
require_plugin "languages"
require_plugin "#{os}::lolcode"

languages[:lolcode] = Mash.new unless languages[:lolcode]
languages[:lolcode][:version] = "TEH VERSHIONS"

In plugins/darwin/lolcode.rb:

provides "languages/lolcode"
require_plugin "languages"
languages[:lolcode] = Mash.new unless languages[:lolcode]
languages[:lolcode][:platform] = "MACKERS"

Checkout ohai's os.rb for the list of platform names.

All of these examples can be found in the ohai-plugin-howto github repo, you should be able to clone that and run the ruby scripts in the repo's root directory.



Install git man pages the easy way

There seems to be a few ways to install the git man pages, but these seems to involve some wacky tricks with a copy of the git repo checked out. I wanted to make sure I had the man pages for my exact version of git and just wanted them in place so I could do git help command and see some pretty helps.

First, figure out your version number. Mine was 1.6.4.2

git --version

Then download the tarball for that version and unzip to your manpage dir:

curl -O "http://kernel.org/pub/software/scm/git/git-manpages-1.6.4.2.tar.bz2"
sudo tar xjv -C /usr/local/share/man -f git-manpages-1.6.4.2.tar.bz2

If you really don't want to think, cut-n-paste the following:

cd /tmp
curl -O "http://kernel.org/pub/software/scm/git/git-manpages-`git --version | awk '{print $3}'`.tar.bz2"
sudo mkdir -p /usr/local/share/man
sudo tar xjv -C /usr/local/share/man -f git-manpages-`git --version | awk '{print $3}'`.tar.bz2