Archive for November, 2008

Git versus SVN Presentation

November 24th, 2008

Last week I made a presentation about Git and compared it to Subversion. There is an obvious bias in the slides however, I tried to make a point to show the downsides of Git as well. One slide that is missing is one on security and the idea of Git storing all the commit history on each machine can be a security risk in some scenarios. Feel free to use these slides in your own presentation, but post a link back as a thank you.

Slides: git-presentation

Tags: , , ,
Posted in Development | Comments (0)

RMagick install frustrations

November 24th, 2008

I had a frustrating afternoon after my RMagick mysteriously blew up and refused to run. If you have encountered this error:

“This version of RMagick was created to run with ImageMagick x.x.x (not y.y.y)”

You will be happy to know you just have to uninstall and reinstall RMagick. Apparently the gem is not only specifically built to your machine but also bound to the ImageMagick that was installed at the time.

Posted in Development | Comments (0)

Pivotal Tracker API Ruby Wrapper

November 11th, 2008

I have been playing around with the recently released public API for Pivotal Tracker. In the process of converting this into a Datamapper Adapter, I tested it with some simple Net::HTTP Ruby code. It provides a nice simple, and limited, illustration of what is possible with this public API. One thing I would like to see added to the API however is the ability to limit the number of results when querying with filters. Attached is the slightly modified source code (removed my project id and token key). Tests are included as always, but fair warning, some are brittle! I will post another revision once the Datamapper Adapter is created.


require 'rubygems'
require 'hpricot'
require 'net/http'
require 'uri'
require 'cgi' 

##
# Pivotal Tracker API Ruby Wrapper
# November 11, 2008
# Justin Smestad
# http://www.evalcode.com
##

class Tracker
  def initialize(project_id = changeme, token = changeme)
    @project_id, @token = project_id, token
  end

  def project
    resource_uri = URI.parse("http://www.pivotaltracker.com/services/v1/projects/#{@project_id}")
    response = Net::HTTP.start(resource_uri.host, resource_uri.port) do |http|
      http.get(resource_uri.path, {'Token' => @token})
    end

    doc = Hpricot(response.body).at('project')

    @project = {
      :name             => doc.at('name').innerHTML,
      :iteration_length => doc.at('iteration_length').innerHTML,
      :week_start_day   => doc.at('week_start_day').innerHTML,
      :point_scale      => doc.at('point_scale').innerHTML
    }
  end

  def stories
    resource_uri = URI.parse("http://www.pivotaltracker.com/services/v1/projects/#{@project_id}/stories")
    response = Net::HTTP.start(resource_uri.host, resource_uri.port) do |http|
      http.get(resource_uri.path, {'Token' => @token})
    end

    doc = Hpricot(response.body)

    @stories = []

    doc.search('stories > story').each do |story|
      @stories << {
        :id => story.at('id').innerHTML.to_i,
        :type => story.at('story_type').innerHTML,
        :name => story.at('name').innerHTML
       }
    end
    return @stories
  end

  # would ideally like to pass a size, aka :all to limit search
  def find(filters = {})
    uri = "http://www.pivotaltracker.com/services/v1/projects/#{@project_id}/stories"
    unless filters.empty?
      uri << "?filter="
      filters.each do |key, value|
        uri << CGI::escape("#{key}\"#{value}\""
      end
    end

    resource_uri = URI.parse(uri)
    response = Net::HTTP.start(resource_uri.host, resource_uri.port) do |http|
      http.get(resource_uri.path, {'Token' => @token})
    end

    doc = Hpricot(response.body)

    @stories = []

    doc.search('stories > story').each do |story|
      @stories << {
        :id => story.at('id').innerHTML.to_i,
        :type => story.at('story_type').innerHTML,
        :name => story.at('name').innerHTML
      }
    end
    return @stories
  end

  def find_story(id)
    resource_uri = URI.parse("http://www.pivotaltracker.com/services/v1/projects/#{@project_id}/stories/#{id}")
    response = Net::HTTP.start(resource_uri.host, resource_uri.port) do |http|
      http.get(resource_uri.path, {'Token' => @token, 'Content-Type' => 'application/xml'})
    end

    doc = Hpricot(response.body).at('story')

    @story = {
      :id => doc.at('id').innerHTML.to_i,
      :type => doc.at('story_type').innerHTML,
      :name => doc.at('name').innerHTML
    }
  end

  def create_story(story)
    story_xml = build_story_xml(story)
    resource_uri = URI.parse("http://www.pivotaltracker.com/services/v1/projects/#{@project_id}/stories")
    response = Net::HTTP.start(resource_uri.host, resource_uri.port) do |http|
      http.post(resource_uri.path, story_xml, {'Token' => @token, 'Content-Type' => 'application/xml'})
    end
  end

  def update_story(story)
    story_xml = build_story_xml(story)
    resource_uri = URI.parse("http://www.pivotaltracker.com/services/v1/projects/#{@project_id}/stories/#{story[:id]}")
    response = Net::HTTP.start(resource_uri.host, resource_uri.port) do |http|
      http.put(resource_uri.path, story_xml, {'Token' => @token, 'Content-Type' => 'application/xml'})
    end
  end

  def delete_story(story_id)
    resource_uri = URI.parse("http://www.pivotaltracker.com/services/v1/projects/#{@project_id}/stories/#{story_id}")
    response = Net::HTTP.start(resource_uri.host, resource_uri.port) do |http|
      http.delete(resource_uri.path, {'Token' => @token})
    end
  end

  private

    def build_story_xml(story)
      story_xml = "<story>"
      story.each do |key, value|
        story_xml << "<#{key}>#{value.to_s}</#{key}>"
      end
      story_xml << "</story>"
    end
end

Read the rest of this entry »

Posted in Datamapper, Development, Ruby | Comments (2)

destroy_all with conditions

November 3rd, 2008

In a has_many relationship, there should be a way to add conditions to destroy in order to eliminate an explicit find.


@post.comments.find(:all, :conditions => "name LIKE 'stupid%'").each {|record| record.destroy }

With a patch I recently submitted to Rails core, you can now trim this line into:


@post.comments.destroy_all "name LIKE 'stupid%'"

Jump on over to Lighthouse bugtracker and try out the patch.

Tags: , ,
Posted in Development, Rails | Comments (0)