Cooked this one up this morning… It will iterate through `svn st | grep \?` and ask for confirmation before adding to your subversion project. Of course, all the cool kids are using git these days anyways ;) Shouldn’t be hard to modify for that.


namespace :svn do

  desc "Add files not under (sub)version control" 
  task :add do
    files = `svn st | grep \?`.map{|f| f.gsub(/\?\s+(.+)\n/){$1} }
    puts "No new files to add." and return if files.empty?
    files.each do |file|
      print "... #{file} [Yn]" 
     `svn add #{file}` unless STDIN.gets =~ /^n/i
    end
  end

end

I’m working on a project that does some graphing, I and needed to do a linear best fit. A quick google search didn’t find the ruby code snippet I was looking for, so I converted one from PHP. ( Original nasty looking quasi-OO PHP source ) Sorry, no unit tests :)


class LinearRegression
  attr_accessor :slope, :offset

  def initialize dx, dy=nil
    @size = dx.size
    dy,dx = dx,axis() unless dy  # make 2D if given 1D
    raise "arguments not same length!" unless @size == dy.size
    sxx = sxy = sx = sy = 0
    dx.zip(dy).each do |x,y|
      sxy += x*y
      sxx += x*x
      sx  += x
      sy  += y
    end
    @slope = ( @size * sxy - sx*sy ) / ( @size * sxx - sx * sx )
    @offset = (sy - @slope*sx) / @size
  end

  def fit
    return axis.map{|data| predict(data) }
  end

  def predict( x )
    y = @slope * x + @offset
  end

  def axis
    (0...@size).to_a
  end
end

delegate unless nil

An issue came up yesterday that involved an strange nil error, where an attribute was being delegated to a nil association.

I recalled reading this ticket opened by court3nay from caboo.se and thought it might come in handy for others if I put it in the blogosphere.

The ticket ended up being closed because it was deemed unnecessary. Someone with the moniker “protocool” (presumably trevor at http://protocool.com/) shared the final solution which works out of the box with no patches. It goes something like this:


delegate :some_method, :to => '(some_association or return nil)'

The cool thing about this solution, over the proposed patch, is that you can do whatever you like (rather than simply return nil), such as return a default value or raise a custom exception.

ruby Date extensions

I recently cooked these up, thought someone else might find them handy. Now you can say date.first_of_month, date.first_of_year, etc.


module DateExtensions
  def first_of_week
    self - self.wday
  end

  def first_of_month
    self - self.day+1
  end

  def first_of_quarter
    (self << (self.month%3 - 1 )%3) - self.day+1
  end

  def first_of_year
    (self << self.month-1) - self.day+1  
  end
end
Date.send :include, DateExtensions

Addendum: oops, looks like there are already similar methods in Rails’ ActiveSupport:

beginning_of_* rather than first_of_*

However, begining_of_week assumes Monday is the first day of the week, while my version assumes Sunday is the first day.

Here are my tests:

require File.dirname(__FILE__) + '/../test_helper'

class DateExtensionsTest < Test::Rails::TestCase

  def test_first_of_week
    day = Date.new( 2008, 1, 1 )
    w   = day.first_of_week
    # sunday is first day of week
    assert_equal 0, w.wday
    assert_equal 30, w.day
  end

  def test_first_of_month
    day = Date.new( 2008, 1, 15 )
    assert_equal 1, day.first_of_month.day
  end

  def test_first_of_year
    day = Date.new( 2008, 5, 27 )
    y   = day.first_of_year
    assert_equal 1, y.month
    assert_equal 1, y.day
  end

  def test_first_of_quarter_q1    
    [1,2,3].each do |month|
      day = Date.new( 2008, month, 13 )
      q   = day.first_of_quarter
      assert_equal 1, q.day
      assert_equal 1, q.month
    end
  end

  def test_first_of_quarter_q2
    [4,5,6].each do |month|
      day = Date.new( 2008, month, 13 )
      q   = day.first_of_quarter
      assert_equal 1, q.day
      assert_equal 4, q.month
    end
  end

  def test_first_of_quarter_q3
    [7,8,9].each do |month|
      day = Date.new( 2008, month, 13 )
      q   = day.first_of_quarter
      assert_equal 1, q.day
      assert_equal 7, q.month
    end
  end

  def test_first_of_quarter_q4
    [10,11,12].each do |month|
      day = Date.new( 2008, month, 13 )
      q   = day.first_of_quarter
      assert_equal 1, q.day
      assert_equal 10, q.month
    end    
  end

end

I just came across this cool tip from Tom Preston-Werner of rubyisawesome.com. Basically, if you end a mysql commandline query with \G instead of a semicolon, you’ll get a nicely formatted query that is suitable for pasting into a YAML file.

But what if you are not using mysql? We have a project with postgres. There’s probably a psql command to do something similar, but there is also a database agnostic way: Just use the rails console! :)


>> puts User.find(:all).to_yaml
---
- !ruby/object:User 
  attributes: 
    status: unverified
    salt: L52b2pxGCL
    can_invite: "0" 
    hashed_password: L50/yIQjPCBiU
    is_admin: "0" 
    id: "478674008" 
    first_name: Mickey
    last_name: Mouse
    watchlist_by_email: "0" 
    created_at: 2008-01-30 15:34:26
    email: mickey@mouse.com

		
		
	

I’ve been playing with block helpers for some time now, and I love them for their semantic goodness and clarity. I know that Rails 2 has an assert_email method, which plays nicely with assert_select assert_select_email method. However, as far as I could tell, this doesn’t allow you to assert any of the headers such as to, from, etc.

Enter assert_emails_sent:


  def test_send_crash_data
    device_id = 2
    assert_email_sent :to => AdminNotifier::CLIENT_CRASH_EMAIL,
                      :from => AdminNotifier::SYSTEM_EMAIL,
                      :subject => "Application crashed.",
                      :body => /device id #{device_id} crashed.+whoops I crashed/ do
      AdminNotifier.deliver_send_crash_data('whoops I crashed', device_id)                      
    end
  end

  • One cool feature is that the values of :to and :from will be automagically sent #email, so you can just say :to => @user, as long as @user.responds_to?(:email).
  • Another bonus feature is that you can use either strings or regexps.

grab the code here.

staying DRY with custom shoulds

Recently I’ve been refactoring legacy Test::Unit code to use shoulda. Sometimes you can’t factor out repetitive stuff into a context, but you still want to be DRY. Below is an example case of refactoring into a custom should. Note that you need to use class variables, and that the self.should_* method needs to be defined before it’s actually used, since shoulda is built upon metaprogramming which gets evaluated at the class level.


...

  def self.should_request sym
    sym = sym.to_s
    context "when requesting #{sym}" do
      setup do
        get :download, {:id => @@podcast.id, :type => sym}, @@session
      end
      should "ask for a device" do
         assert_match /Please select a device to download content/,  @response.body
      end
      should "increment the message count when sent #add_to_device" do
        assert_difference 'Message.count( :conditions => "device_id = 1")', @@podcast.episodes.size do
          xhr :post, :add_to_device, {:id => 1, :type => 'all', :podcast_id => @@podcast.id}, @@session
        end
      end
    end
  end

  context "A valid account" do
    setup do
      @account = accounts(:accounts_002)
      @@session = {:account_id => @account.id}
      @account.devices << Device.find(1)
      @@podcast = podcasts(:joe_cartoon)
      @@session.merge!({:podcast_episodes => @@podcast.episodes})
    end

    should_request :all
    should_request :latest
    should_request :episode
  end

...

NameMyPuppy beta launched

NameMyPuppy has been a fun personal project of mine. It is a way for friends and family to collaborate to help you name your puppy. You can upload and describe your puppy and then send out invitations to friends and family. They can suggest names and vote on their favorite names. You can also make your puppy posting public so anyone on the site can suggest and vote on names to get even more people voting. Happy naming!

Name My Puppy

I was suffering with a problem running tests inside of textmate on a Rails 2 project, until I found this comment by David Vrensk at the bottom of this blog post by Rob Sanheim:

Posted by David Vrensk 18 January 2008 @ 9am

I think the easiest solution can be gleaned from the TM ticket that you link to (http://macromates.com/ticket/show?ticket_id=F4DA8B03). I just modify test/test_helper.rb in my current projects so that it starts with

$:.reject! { |e| e.include? ‘TextMate’ }

No patching the distros, and svn still works the way it should.

Shoulda talk from SF Ruby Meetup

We hosted the SF Ruby Meetup last night, which was a smashing success. It was fun to have 50+ Ruby geeks crammed into our office. :)

Here are the slides from my presentation about Shoulda.

I like to use factory test helpers to generate attributes which I then pass to ActiveRecord. The default output is expected to be valid (hence the usage with create-bang below). If you want to override any of the defaults, you can simply use Hash#merge.

Here’s an example, using shoulda. It should be pretty clear how it can be applied to vanilla Test::Unit (or the testing framework du jour ;).


##  I put this in test_helper.rb so I can use it across all tests.
## You could put it in the actual derived test class as well.

  def valid_user_attrs( unique = DateTime.now )
    { :email => "{unique.hash.abs}@example.com", :first_name => "dummy", :last_name => "user_#{unique}", :profile_attributes => valid_profile_attrs }
  end

  def valid_profile_attrs
    ...
  end


## Here’s the actual test case
  
class UserTest < Test::Rails::TestCase

  context "Two Users" do
    setup do
      @user = User.create!( valid_user_attrs )
      @user2 = User.create!( valid_user_attrs.merge( :email => "dummy123@dummy.com" ) )
    end

    should "not be friends" do
      assert !@user.friends.include?( @user2 )
      assert !@user2.friends.include?( @user )
    end

  end
end

		
		
	

In a previous post, I posted a monkey patch to enhance the behavior of fixtures. I converted it into a plugin format for convenience and testing purposes. I am still aiming to submit it as a patch to Rails 2.0. I’d appreciate any feedback!

get it here:

svn export --username=public svn://internautdesign.com/public/plugins/friendly_fixtures vendor/plugins/friendly_fixtures

from the README:

FriendlyFixtures

This plugin is a simple extension to add some cool features to the fixtures macro in Test::Unit. It is intended for Rails 2.0, but works with 1.2.3 as well.

It enables you to:
  • load dependent models, which are found by object introspection on a model’s ActiveRecord associations.
  • assert that all the loaded fixtures are valid. This can be very helpful in finding bugs.

Example Usage:


class SomeTest < Test::Unit::TestCase
  fixtures :user, :dependencies => true, :validate => true
end

I recently wrote a functional test for an AJAX callback action. I wanted to assert that the RJS replaced some text with a particular string. This string is generated by a view helper. To keep this flexibility, I wanted to call the helper from the test.

It turns out to be quite simple. All you have to do is mix-in the helper to your TestCase class, like so:

class CompanyControllerTest < Test::Rails::TestCase
  include CompanyHelper
...
end

In a previous post, I mentioned Gabriel Gironda’s snippet showing how to use view helpers in a controller. Calling view-specific helpers from the controller is a particularly useful technique in AJAX callback methods where you need to replace some HTML. The alternative is rendering a partial, which I felt was cumbersome and overkill if you just need to replace a single string of text.

However, the above technique doesn’t work out of the box if you need to use a custom helper that you have written in your app/helpers directory tree. The trick is to use the extend method to mix-in your custom helper modules.

Here is an example, where I extend the help singleton object with the CompanyHelper module, in order to be able to the text_for_action and text_for_notice methods.


  def ajax_add_to_portfolio
    help.extend ::CompanyHelper
    raise "Company doesn't exist!" unless @company
    kind = params[:category]
    raise help.text_for_action( kind )+" already performed!" if @company.in_portfolio?( @current_user, kind )
    @current_user.portfolio_items.create!( :company_id => params[:id], :category => kind )
    action_text = help.text_for_action( kind, :past_tense => true )
    notice_text = help.text_for_notice( kind )
    render :update do |page|
      page.flash_then_fade :success, action_text
      page.replace_html kind, notice_text
    end
  rescue Exception => e
    handle_exception e
  end

I just cooked up some flexible zebra striping for prototype. I call it ...drumroll please… ProtoStripe!

badum-ching! ;)


// protostripe.js

Event.observe( window, 'DOMContentLoaded', function() {

  $$('.striped').each( function(e) {
    Selector.findChildElements(e, ['tr','li']).each( function(e, idx) {
      e.addClassName( idx % 2 == 1 ? 'odd' : 'even');
    });    
  });

});

Just include it in your HTML header, and any tables or lists with class=”striped” will have their appropriate children decorated with “odd” and “even” CSS classes. Unobtrusive JavaScript rocks! :)