RailsConf 2008

Object Daddy

Posted by rick Tue, 27 Nov 2007 15:14:00 GMT

I’m posting at a new site (b.logi.cx) ... more news on that later. The first article is about a new piece of software I’m developing called Object Daddy, meant to do away with the need for Ruby on Rails fixtures and to greatly ease ActiveRecord model testing. The article about it is LONG, but don’t let that scare you, it’s all in good fun.

Tags , , , , , , , , ,  | no comments

A couple of random Rails tips

Posted by rick Wed, 03 Jan 2007 00:07:00 GMT

UPDATE: I edited the autotest hook to (1) fix a bug, and (2) to make it more readable (not sure if I succeeded, but worth a shot).

I figured out a couple of things that were useful enough to me that I thought I’d share.

First off, if you’re a big user of autotest (and if you’re not, you might oughta should be), and you’re working on a really large application, maybe you’ll find this useful:

Drop this in your ~/.autotest file:


Autotest.send(:alias_method, :real_find_files, :find_files)
Autotest.send(:define_method, :find_files) do |*args| 
  real_find_files.select do |k,v| 
     (ENV['AUTOTEST'] and ! ENV['AUTOTEST'].empty?) ?   
        Regexp.new(ENV['AUTOTEST']).match(k) : true
  end
end

and then you can do stuff like:

% AUTOTEST='users' autotest    # run all tests with 'users' in the name
% AUTOTEST='digital.*cont'  autotest   # run all the digital signaturing functional tests
% AUTOTEST='party|digital'   autotest  # run all tests for parties or digital signaturing

This allows you to focus in on a small area of concern and still get the rapid feedback autotest gives you. Be sure to periodically run your entire test suite to make sure you’re not missing action-at-a-distance errors.

The other tip is a purely Rails tip. If you’re ever used ActiveRecord’s polymorphic associations then you may have run into a situation where you want many many many things to be able to be on the other (has_many) end of the polypmorphic association. I ran into this while doing work with digital signatures: I want to be able to associate a signature with almost any model object in my system. I should be able to retrieve the signatures (if any) for an object by just saying “object.signatures”.

This would normally require a “has_many :signatures, :as => signable” in every signable class in the system. Maybe reasonable, but if I were to forget to add the has_many to a class signaturing would stop working. It’s actually worse in my case since the signing algorithm can sign a web of related objects, so forgetting the has_many in one class would result in failures in related but not identical classes.

I decided to add functionality to have this happen automatically. At first I tried just opening ActiveRecord::Base and adding the call, which doesn’t put the call in the right scope for the subclasses (as don’t a variety of other AR::Base hacks I tried). I realized at some point that I needed to use Ruby’s “inherited” method to get the subclass at the right time, but AR::Base already uses inherited for other nefarious purposes. It turns out, this is the incantation that works:


class ActiveRecord::Base
  def self.inherited_with_signaturing(subclass)
    self.inherited_without_signaturing(subclass)
    subclass.send(:has_many, :signatures, :class_name => 'DigitalSigDigest', :as => :signable) unless subclass.name =~ /^DigitalSig/
  end

  class << self
    alias_method_chain :inherited, :signaturing
  end
end

As you’ll notice, my signaturing model is actually DigitalSigDigest. Also, I have other DigitalSig-something classes lying around that are part of the signaturing library, and using inherited this way allows me to actually conditionally include/exclude which classes get the signaturing has_many relationship. That’s cooler than I expected. Chalk up another one for Ruby.

By the way, you’re probably also going to be interested in this ticket if you’ve got STI classes with polymorphic stuff linked to them.

Tags , , ,  | no comments

high-speed ruby debugger inline-able in Rails

Posted by rick Thu, 13 Jul 2006 01:07:00 GMT

Kent Sibilev posted a cool article, Tutorial on ruby-debug ,which shows off his new Ruby+C hybrid debugger suitable for use with large applications, such as Rails apps, where the debug.rb debugger was just too slow to be useful.

This brings most of the slickness of the breakpointer (just drop a line in your code and wait for the prompt to appear) to the power of the debugger (pop up and down stack frames with ease, step, breakpoint, watchpoint, whatever). Just gem install the thing and hack++.

Looks like the only thing is missing is the DRuby hooks to let the new debugger work with FastCGI (etc.) when there’s no console waiting, and I’m guessing someone will get to that before my lazy butt gets around to scratching that particular itch.

Very cool.

Tags , ,  | no comments

art-talk weather forecast rides again!

Posted by rick Mon, 27 Feb 2006 00:17:00 GMT

In order to make automated “7 day Art weather forecast” emails like these on the new AirSet art-talk calendar I had to update my ruby script. Here’s the new version (and you’ll note that the bulk of the code deals with cleanup of bastardized input):


#!/usr/bin/ruby

require 'open-uri'
require 'rexml/document'
require 'rexml/xpath'
require 'time'

URL = "http://www.airset.com/syndicate/public/1391/week.xml" 

def cleanup(text, keep_stars = false)
  result = text.
    gsub(/&amp;/, '&').
    gsub(/&[lr]?quot;/, '"').
    gsub(/&apos;/, "'").
    gsub(/&#39;/, "'").
    gsub(/&gt;/, '>').
    gsub(/&lt;/, '<').
    gsub(/&nbsp;/, ' ').
    gsub(%r{</?[^>]+>}, '').
    gsub(/\*\s*\*/, '**').
    gsub(/\342\200\235/, '"').
    gsub(/\342\200\234/, '"').
    gsub(/\342\200\231/, "'").
    gsub(/\342\200\223/, " -- "). 
    gsub(/\342\200\224/, " -- "). 
    gsub(/\303\242/, "a").
    gsub(/\303\251/, "e").
    gsub(%r{/+\s*$}, '')

  result.gsub!(/\s*\*\s*/, '') unless keep_stars
  result
end

def wordwrap(text, line_width = 70)
  text.gsub( /\n/, "\n\n" ).gsub( /(.{1,#{line_width}})(\s+|$)/, "\\1\n")
end

def output(title, time, location, link, description)
  title       = cleanup(title)
  time        = cleanup(time)
  location    = cleanup(location)
  link        = cleanup(link)
  description = wordwrap(cleanup(description, true))

  puts "#{time.chomp} - #{title}" 
  puts "    online:  <#{link.chomp}>" 
  puts "  location:  #{location}\n\n" 
  description.split("\n").each {|l| puts "   #{l}"}
  puts "" 
end

def fetch_document(link)
  open(link) { |f| return f.read.split("\n").join(' * ') }
end

def extract_location(doc)
  doc =~ %r{<span\s+class="evDescAndLoc">([^<]+)</span>}
  place  = $1 || ''
  place = place.sub(/^.* at /, '').gsub(/\s+\*\s+/, '')
  doc =~ %r{<span\s+class="evAddress">(.*?)</span>}
  address = $1 || ''
  address = address.gsub(/Get map/, '').gsub(/\s+\*\s+/, '')
  place += " / #{address}" unless address =~ /^\s*$/
  place
end

def extract_description(doc)
  doc =~ %r{<span\s+class="evNote">(.*?)</span>}
  return ($1 || '')
end

def retrieve_data(item)
  # Extract title and time
  if item.elements['title'].text =~ /\(([^)]+)\)\s*$/
    time = $1
  else
    t = Time.parse item.elements['pubDate'].text
    hour = t.hour % 12
    hour = 12 if 0 == hour
    time = "%02d/%02d/%4d (%d:%02d%sM)" % 
      [t.month, t.day, t.year, hour, t.min, t.hour > 11 ? 'P':'A']
  end

  title = cleanup(item.elements['title'].text.sub(/\([^)]+\)\s*$/, ''))
  link = item.elements['link'].text
  doc = fetch_document(link)
  location = extract_location(doc)
  description = extract_description(doc)

  [title, time, location, link, description]  
end

  puts "7 Day Art Weather Forecast" 
  puts
  puts "  ... see the Art-Talk Calendar for more events:" 
  puts
  puts "  online at: <http://www.airset.com/Public/Calendars.jsp?id=1391>" 
  puts
  puts " -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --" 
  puts

open(URL) do |f|
  xml = REXML::Document.new(f.read)
  REXML::XPath.each(xml, '//item') do |item|
    title, time, location, link, description = retrieve_data(item)
    output(title, time, location, link, description)
  end
end

Tags , , ,  | no comments

Slides re: Dependency Injection in Ruby

Posted by rick Sat, 25 Feb 2006 17:43:00 GMT

Here is an interesting presentation from OSCON2005 by Jim Weirich entitled Dependency Injection: Vitally Important or Totally Irrelevant?

Tags ,  | no comments


banned vocabulary
"+1" (and "-1")
"existential"
"onboarding"
"ferret"
"finesse"
"yeah."
<blank> <units> thin
<blank> warriors
<blank> years young
<blank>'s team
<x> of the moment
(it|)'s all good
(noo|new)b(|ie|y)
I.T.
ROI
P.D.I.
[web] portal
accountab(le|ility)
actuate
advocate (v. and n.)
anyhoo
assessment
belief system
best practice(s)
best practice(s)
blog(|ger|ging)
business rules
cautiously optimistic
celebrate
closure
construct (n.)
creative(s) (n.)
dialogue
divers(e|ity)
diversity
document (n.)
emerg(ing|ent)
emoticon(s)
enabler
eponymous
everyday heroes
extreme <blank>
facilitate
faith-based
foment
gestalt
git 'r done
gradation(|s) [sic]
guiding vision
hoi polloi
human drama
ill-fated
incentivise
jejune
kerfuffle
killer app
kudos
leverage
marginalize(d)
matriculate
merch
monetize
mouth-feel
multitask(|ing|er) (n.t.)
n(oo|ew)b(ie|)
network(|ing) (n.t.)
nexus
outsider art
podcast(ing)
proggy
protocol
quantum leap
reflect (v.)
repurpose
revamp
river system
schadenfreude
sea change
shopping (etc.) culture
shout-out
some <blank>-action
sophomore effort
strategic repositioning
synergy
team members / partners
the <blank> arena
the <x> Street
tix
under 30-set
value system
vertical
where('|i)s the outrage?
win-win
winders
Weltanschauung