CommonThread

Textmate Footnotes with vim support

Posted by ben, Wed Jun 11 01:31:00 UTC 2008

I just switched to doing rails development in vim rather than textmate but I sure did miss my textmate footnotes. I found a post about a plugin called redit that converted stacktraces over to links that would open in vim (textmate footnotes style) so I decided to take that and patch Textmate Footnotes. I had to make sure not to messup any of the developers who were going to still use Textmate so it patches it to do both based on an env variable we will talk about later.

Redit Controller

First I took the controller from the afore mentioned plugin and tweaked it to make sure we were running in development mode before executing code on the server and changed it to use MacVim as the vim app. Simply create a new controller called ReditController and paste the code below changing the system call if you use something other than MacVim.

require 'base64'
class ReditController < ApplicationController
  def open
    if ENV['RAILS_ENV'] == 'development'
      file = Base64.decode64(params[:id])
      line = params[:line].to_s

      # Run editor here
      Thread.new do
        ### MacVim
        # Open file in new tab of vim server
        system("mvim","--remote-tab","+#{line}",file)
      end 
    end
    redirect_to :back
  end
end

Textmate Footnotes Patch

Next you need to replace the lib/textmate_footnotes.rb with this one. I am working with an older version of textmate footnotes so be forewarned that my file may not work 100% with your version … I will update to the latest soon and update my file. Here is an example of how the patch changes the urls generated:

def controller_url
    if ENV['FOOTNOTE_APP'] == 'vim'
      escape(
        "/redit/open/" +
        CGI.escape(Base64.encode64(controller_filename)) +
        (index_of_method ? "&line=#{controller_line_number + 1}&column=3" : "")
      )
    else
      escape(
        textmate_prefix +
        controller_filename +
        (index_of_method ? "&line=#{controller_line_number + 1}&column=3" : "")
      )
    end
  end

Environment Variable

And lastly to make the plugin give you vim links rather than textmate links you need to set the FOOTNOTE_APP env variable. To make this happen every time you login place the following snippet in your ~/.bash_profile

export FOOTNOTE_APP=vim

0 comments | Filed Under: | Tags:

Twitter Hacking

Posted by ben, Thu Jun 05 13:59:00 UTC 2008

I got overloaded with work the other night so I decided to take a break from it and hack out something fairly useless but fun. I landed on a twitter bot that updates a few times daily with weather updates for my area or others I might care about. Right now I only have a Birmingham Weather and a Montgomery Weather.

The code requires 2 gems twitter & yahoo-weather. you can install them both with:

sudo gem install yahoo-weather twitter --no-ri --no-rdoc

Then the code was very simple for querying and updating:

#! /usr/bin/env ruby

require 'rubygems'
require 'yahoo-weather'
require 'twitter'

client = YahooWeather::Client.new

cities = [['35212', 'wxbhm'], ['36108', 'wxmgm']]

cities.each do |city|
  response = client.lookup_location(city[0])
  forecast = "Today's weather: #{response.forecasts.first.text}, Hi: #{response.forecasts.first.high}F, Lo: #{response.forecasts.first.low}F (Currently #{response.condition.text}, #{response.condition.temp}F)" 
  Twitter::Base.new(city[1], 'SUPER_SECRET').update(forecast)
end

Then to make it happen automagically, welcome cron:

00 13 * * * /home/deploy/twitter_wx/update_wx.rb
45 21 * * * /home/deploy/twitter_wx/update_wx.rb

It updates at 8:00am & 4:45pm. I had to put the dates in UTC and take into consideration that I am Central Timezone and add 5 hours to the time for now … if someone knows a better way to handle this in cron please let me know.

0 comments | Filed Under: | Tags:

Phusion Passenger

Posted by ben, Mon Jun 02 02:57:00 UTC 2008

We have been testing out mod_rails Phusion Passenger for a few weeks now on our staging server and one production server that hosts our company website and blog. Today we finally got our hands on the Ruby Enterprise Edition early release, so we are now running the full enterprise passenger stack and I must say that I am loving not having to deal with so many deploy issues like configuring monit, nginx & mongrel_cluster configs for every new app and for almost any configuration change, which we find almost unnecessary now since passenger is handling how many app instances to spawn up and it keeps an eye on instances that crash or get hosed for some reason.

We are able to able to really make better use of our VPS slices with the memory reduction we get from running passenger VS nginx+mongrel.

checkout this screencast or head over to the Phusion Passenger website to try it out for yourself.

0 comments | Filed Under: | Tags:

Slicehost API Saves The Day

Posted by ben, Tue May 20 22:25:00 UTC 2008

Thanks to slicehost for giving me an API for managing my DNS zones and records via ActiveResource becauase it saved me lots of time and tedious work. I needed to update my TTL settings in all my domains and rather than having to edit all 61 entries I simply made a ruby script to do it for me:

require 'rubygems'
require 'activeresource'

API_PASSWORD = "MY_SECRET_PASSWORD" 
DEFAULT_TTL = 86400

class Record < ActiveResource::Base
  self.site = "https://#{API_PASSWORD}@api.slicehost.com/" 
end

records = Record.find(:all)

for record in records
  record.ttl = DEFAULT_TTL
  record.save
end

and while we are at it lets output all of our info:

require 'rubygems'
require 'activeresource'

API_PASSWORD = "MY_SECRET_PASSWORD" 

class Zone < ActiveResource::Base
  self.site = "https://#{API_PASSWORD}@api.slicehost.com/" 
end

class Record < ActiveResource::Base
  self.site = "https://#{API_PASSWORD}@api.slicehost.com/" 
end

zones = Zone.find(:all)
records = Record.find(:all)

for zone in zones
  puts "zone: #{zone.origin}" 

  for record in records.find_all{|record| record.zone_id == zone.id}
    puts "  #{record.record_type}: #{record.name} - #{record.data}" 
  end
end

There, that was easy.

1 comment | Filed Under: | Tags:

Running and "The Zone"

Posted by jason, Sat Apr 26 00:14:00 UTC 2008

With any team, while your differences bring true creativity and problem-solving, it is good to have things in common as well. For CommonThread, one of the passions that we all share is participation in triathlons. Of course, triathlons take training and preparation, which brings me to an observation I had the other day while on one of my long runs (as I prepare for the Florida Ironman 70.3 in May).

Climbing the Hill

In quite consistent fashion, I have noticed that it takes a solid 2-3 miles of running to get my body in “the zone” for going long distances. Up to that point, it seems like a fight to maintain pace and maintain determination for what I am trying to accomplish. In simple terms, I have to force myself to get to that point without stopping…what I refer to as “climbing the hill”. I have heard others describe it as a wall, but I see it much more as a steady climb that finally arrives at a place of better performance.

The Zone in Development

Similar to running, I think that getting into “the zone” when developing is not some mystical happenstance. I think it requires good planning and a solid effort to maintain focus when there is such a strong desire to occupy yourself with non-important tasks, such as: checking email, twittering, reading blogs, checking the web, etc. While there is time for that, it is those activities that seem quite beneficial when you are making the effort to get to that place of happy, effortless development.

How I Do It

As I noted above, the most important thing is to take the time to lay out something you want to accomplish and place it in a format that you can look upon often. This will always give you an answer to that question of “Hmm…what should I be doing.” Secondly, make a conscientious effort to turn off distractions for a while. Pick out some good music that doesn’t require your attention at the end of each song, close down twitter and email, and begin the process of climbing the hill. It takes effort on your part to get there and your initial desires will be to break out and look at irrelevant information. But, after 5-10 minutes of effort to maintain focus, the zone will begin to establish itself and you will find yourself immersed in what you need to get done.

Final Thoughts

The zone, while it sounds completely cliche´, is really where some of your best work emerges. Superficial work that you complete while stretched thin in a world of constant interruptions, is generally average and will require additional attention in the future. The zone is important…climb the hill…make the effort to get there.

1 comment | Filed Under: | Tags:

Cherry-Pickin' in Git

Posted by ben, Sat Apr 19 09:47:00 UTC 2008

if you are trying to update to a specific commit of a git repository and can’t seem to get git pull to allow you pull that specific commit, that is because it doesn’t work that way. so you type git to see what command are available but it only shows you these common commands none of which are useful for this:

usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]

The most commonly used git commands are:
   add        Add file contents to the index
   bisect     Find the change that introduced a bug by binary search
   branch     List, create, or delete branches
   checkout   Checkout and switch to a branch
   clone      Clone a repository into a new directory
   commit     Record changes to the repository
   diff       Show changes between commits, commit and working tree, etc
   fetch      Download objects and refs from another repository
   grep       Print lines matching a pattern
   init       Create an empty git repository or reinitialize an existing one
   log        Show commit logs
   merge      Join two or more development histories together
   mv         Move or rename a file, a directory, or a symlink
   pull       Fetch from and merge with another repository or a local branch
   push       Update remote refs along with associated objects
   rebase     Forward-port local commits to the updated upstream head
   reset      Reset current HEAD to the specified state
   rm         Remove files from the working tree and from the index
   show       Show various types of objects
   status     Show the working tree status
   tag        Create, list, delete or verify a tag object signed with GPG

What you need is git cherry-pick which allows you to update to a specific commit.

usage: git-cherry-pick [options] <commit-ish>

    -n, --no-commit       don't automatically commit
    -e, --edit            edit the commit message
    -x                    append commit name when cherry-picking
    -r                    no-op (backward compatibility)
    -m, --mainline <n>    parent number

git cherry-pick will do a fetch and merge to any commit object and then do an auto commit for you. It will automatically use the commit message of that the select commit object. IF you wish to use a different message use the -e option.

0 comments | Filed Under: | Tags:

Complex Forms ... Just Easier

Posted by ben, Thu Apr 17 00:33:00 UTC 2008

I love having the ability to easily create/update multiple objects with a single form. There are some nice railscasts by Ryan Bates that describe how to do this in Ruby on Rails. What I needed was a way to make writing the attribute accessor methods easier. I also decided that there just weren’t enough rails plugins out there … so off to kill two birds with one stone.

The Plugin

The plugin is called association-attributes and it can be found on github. The goal was to make the process more semantic and most of all DRY. I decided that since we already had to have a method on the model to handle the association we would pattern after that. So, the two methods available are has_one_attr & has_many_attr.

The Model

So for a practical example of what this looks like in your model we will use a persons contact info. We also have a plugin out there that makes contact info easier since that is such a standard need and there is no reason to rewrite that all the time.

class Person < ActiveRecord::Base
  has_one :address, :as => :addressable, :dependent => :destroy
  has_one_attr :address

  has_many :phone_numbers, :as => :phoneable, :dependent => :destroy
  has_many_attr :phone_numbers
end

What that does is creates the methods address_attributes & phone_number_attributes on Person so that we can use them in our form. These newly created methods handle creating & updating existing entries for addresses and phone numbers.

The View

We use HAML for all of our views so these examples are no exception.

- fields_for("person[phone_numbers_attributes][]", @person.phone_numbers.new) do |phf|
  %label{:for => "number"} Phone Number:
    = phf.hidden_field :id
    = phf.text_field :number
A few things to note from this example are:
  • The fields_for has an extra [] on the first parameter … this is because we have a has_many and that tells the browser to treat that as part of an array so that we can have more than one of that same name and it will get put into the array.
  • We are only doing a new item but you would use the same technique to display existing items by replacing @person.phone_numbers.new with a variable of the actual phone number.
  • We have an id hidden field … this is if we use an existing phone number object it will update rather than creating a new object. (it still works without that but deletes the old number and creates a new one)
- fields_for("person[address_attributes]", @person.build_address) do |af|
  %p
    %label{:for => "line_1"} Street Address:
    = af.text_field :line_1
  %p
    %label{:for => "city"} City:
    = af.text_field :city
  %p
    %label{:for => "state"} State:
    = af.select :state, Address::VALID_STATES.map{|s| [s,s]}.sort
  %p
    %label{:for => "zip"} Zip:
    = af.text_field :zip

In future versions I will have a helper method that writes the fields_for for you as well. Looping through current objects and having an option to put a blank one at the end.

The Result

The result of this is that now when you submit a form to create or update a person that has these subforms using fields_for then the appropriate phone number and address objects will get created or updated as well. No more having to create the person first then associate the extra objects later. Even in the case of a has_many where the object is new it will create the object for you then create all the association objects next.

0 comments | Filed Under: | Tags:

Jason Presents HAML to Barcamp

Posted by ben, Tue Apr 15 15:10:00 UTC 2008

At BarCampBirmingham2 Jason made a presentation on HAML & SASS.

You can view the slides here on slideshare.net

0 comments | Filed Under: | Tags:

Setting Up a Git Server

Posted by ben, Sun Apr 13 21:07:00 UTC 2008

Setting up a remote git server is as easy as setting up a new user. In fact if you have git installed on the machine that is about all you need to do. We will not discuss setting up git … just how to set it up to be used as a remote repository.

Setup git User

First we need to setup a user with a home folder. We will store all the repositories in this users home folder.

sudo adduser git

Rather than giving out the password to the git user account use ssh keys to login so that you can have multiple developers connect securely and easily.

Create a Repository

Next we will make a repository. For this example we will work with a repository called example. Login as the user git and add the repository.

# login to remote server
ssh git@REMOTE_SERVER

# once logged in
mkdir example.git
cd example.git
git --bare init

That’s all there is to creating a repository. Notice we named our folder with a .git extension.

Also notice the ‘bare’ option. By default the git repository assumes that you’ll be using it as your working directory, so git stores the actual bare repository files in a .git directory alongside all the project files. Since we are setting up a remote server we don’t need copies of the files on the filesystem. Instead, all we need are the deltas and binary objects of the repository. By setting ‘bare’ we tell git not to store the current files of the repository only the diffs. This is optional as you may have need to be able to browse the files on your remote server.

Commit to Remote Repository

Finally all you need to do is add your files to the remote repository. We will assume you don’t have any files yet.

mkdir example
cd example
git init
touch README
git add README
git commit -m 'first commit'
git remote add origin git@REMOTE_SERVER:example.git
git push origin master

replace REMOTE_SERVER with your server name or IP

4 comments | Filed Under: | Tags: