17 November, 2008

English as She is Spoke, Part 2: the Good

"Meh" was recently added to the Collins English Dictionary. My fuddy-duddy post of yesterday notwithstanding, this makes me happy. I enjoy having an onomotopoetic word for apathy.

English as She is Spoke

<rant> Twenty percent of the words in the title of Richard Ford's The Lay of the Land are misspelled! In the title! You're telling me not even his editor remembers the word "ley?" I suppose I shouldn't be surprised: Firefox doesn't know the word. It snubs me with its little red dotted line, suggesting instead "la," and "lye," and even "hey" and "levy." </rant>

02 November, 2008

Sometimes, having been a music major is a curse

There's a moment in Mendelssohn's Hebrides Overture that reminds me of something, but I can't pin it down. It's about halfway through; 4'55" in on the André Previn recording. It starts out in the celli, I think, and then moves up. Could it be in a recent action movie?

Later...I'm not sure this is what I was thinking of, but it's pretty similar to the base line of the new Dr. Who theme.

02 October, 2008

Supreme Court History

In response to the Know Your Supreme Court History meme, I offer Roberson v. Rochester Folding Box Company. Admittedly, it's a New York Court of Appeals decision, not a U.S. Supreme Court decision, but it has stood the test of time.

What happened

"The complaint alleges that the Franklin Mills Co., one of the defendants, was engaged in a general milling business and in the manufacture and sale of flour; that before the commencement of the action, without the knowledge or consent of plaintiff, defendants, knowing that they had no right or authority so to do, had obtained, made, printed, sold and circulated about 25,000 lithographic prints, photographs and likenesses of plaintiff, made in a manner particularly set up in the complaint; that upon the paper upon which the likenesses were printed and above the portrait there were printed, in large, plain letters, the words, "Flour of the Family," and below the portrait in large capital letters..."

In other words, a company used a woman's picture to advertise their product, but it didn't ask her permission or offer her payment for the picture and/or the endorsement.

Why it's important

Roberson is perhaps the bedrock privacy case in American history. There is no obvious precedent: it is the first case to set the standard that "identity" is a legal object and that it is legally owned by its subject. The decision states that,

"It may be said in the first place that the theory upon which this action is predicated is new."

The case also demonstrates that even though privacy rights are not explicitly enumerated in the Constitution, they can still trump the First Amendment. It's important that the plaintiff did not allege libel, merely that they misappropriated her likeness.

14 September, 2008

Loyalty Scale

In part III of the continuing series on morality, I took the "Identification with All Humanity" quiz at yourmorals.org. The results:

 Obama SupportersMcCain SupportersMe
Community3.02.22.0
Country3.03.73.2
World3.32.63.6

Moral Dilemmas Results

In part II of the continuing series on morality, I took the "Moral Dilemmas" quiz at yourmorals.org. The results:

 AverageMe
Impersonal Dilemmas3.06.0
Personal Dilemmas3.21.0

Moral Foundation Results

I just took the highly informative "Moral Foundation" quiz at yourmorals.org. The results:

 LiberalsConservativesMe
Harm3.62.94.0
Fairness3.73.04.0
Loyalty2.23.22.7
Authority2.13.32.2
Purity1.32.91.0

05 July, 2008

Comcast, Airport Express, and DHCP

I just got a new Comcast high-speed cable account today. It was a bit of a hassle to get the setup utility to run properly on OSX, but it did eventually. Then I had a working connection from laptop to cable modem to the world.

I wanted to use my Airport Express as a wireless router; this went less smoothly. I fiddled with this setting and that, but could not get the Airport Express to get a DHCP lease. This discussion, however, solved my problem immediately: the trick is that the cable modem remembers the MAC address of the computer you set up the account with. To fix the problem, just power-cycle the modem while the Airport Express is plugged in to the LAN port.

25 June, 2008

Ruby Needs a StringBuffer

john has written a little post about using a String as a File (really as an IO) in Ruby. He does a great job explaining how StringIOs work for reading characters. They're particularly good for unit tests on IO operations.

What john doesn't mention, however, is that StringIO is only an 'I.' It has no 'O.' You can't do this, for example:

s = StringIO.new
s << 'foo'
s << 'bar'
s.to_s
# => should be "foo\nbar"
# => really is ''

Ruby really needs a StringBuffer just like the one Java has. StringBuffers serve two important purposes. First, they let you test the output half of what Ruby's StringIO does. Second, they are useful for building up long strings from small parts -- something that Joel reminds us over and over again is otherwise very very slow.

So I wrote a StringBuffer, but it's not very good, and it's not very fast. What we need is one written in C in the core Ruby library. Now that will help Rails scale.

27 May, 2008

Handling Routing and Dispatch Errors in Rails

I've been trying to show nice error pages for RoutingErrors and MethodNotAllowed errors, which are raised outside of the context of a Controller. I dug into the routing and dispatch code and finally realized that those errors cause a direct call to :rescue_action, bypassing :rescue_action_with_handler.

I've put the result at http://pastie.caboo.se/204355.

25 April, 2008

9PM: End of the World

I went to check the weather on weather.com today. I like their hour-by-hour feature. Unfortunately, today it gave me some odd information:
So 8PM: Thunderstorms; 9PM: world ends?

16 April, 2008

Really Simple Development With Git

Once you've got your hot new app up on GitHub, you want to work on it, but you're used to the Subversion world of update-code-test-update-commit. What does a good code cycle look like in Git?

My friends, I tell you I have the answer. And it's simple.

  1. git checkout -b nifty_name_for_nifty_new_feature
  2. git pull [repository [branch]]
  3. for each submodule of interest: cd path/to/submodule; git pull
  4. [code code code]
  5. [test test test]
  6. git add files/related/to/commit
  7. git commit -m 'nifty feature done'
  8. take 5 minute break to feed puppy or check roast in oven
  9. git checkout master
  10. git merge nifty_name_for_nifty_new_feature
  11. git branch -D nifty_name_for_nifty_new_feature
  12. git push

This keeps all development in tight little branches. The branches only exist locally, and go away when the feature makes its way to master. Happiness. Especially when teammates ask you to stop working on nifty_feature and fix acts_as_pointy_haired_boss. In that case, I recommend "fixing_bug_12345" as the branch name; that helps you remember what the branch does after you get back from the really boring meeting on how you can sell more purple pleather pants to Auckland this year.

Thank You For Arguing

I bought Jay Heinrichs' Thank You For Arguing last summer, but never got around to more than glancing at it. I've been reading it at pretty much every chance over the past few days, though. It's absolutely fantastic!

One of the main theses of the book seems to be that people shouldn't think of rhetoric as manipulation, and Jay even does little sidebars to point out when he's using techniques within the book to convince you of his points, but I still can't help but feel manipulated. Ah well, it doesn't stop me from wanting to practice my rhetoric more.

27 March, 2008

New Gem: Avatar

I released Avatar version 0.0.3 today. This gem offers avatar support for a variety of sources. It's not Rails-specific, but to use it in a Rails app, do something like the following.

In app/helpers/people_helper.rb:

class PeopleHelper
  include Avatar::View::ActionViewSupport

  def default_avatar_url(size)
    req = controller.request
    "#{req.protocol}#{req.host_with_port}#{image_path("/images/avatar_default_#{size}.png")}"
  end
end

app/views/people/show.html.erb:

<%= avatar_tag(@current_user, :size => 40, :default => default_avatar_url(:small) %>

The default settings will check for a Gravatar for @current_user.email. There are other implementations, including one that works with the file_column plugin. I'll be happy to add more implementations; the project is hosted on GitHub.

11 March, 2008

Shelves: Rack Extensions

I think Christian's Rack is fantastic. It's such a good idea, in fact, that Ab5tract and I are starting a GitHub projct called Shelves for Rack extensions. Our mission is to do request and response support for all the non-HTTP types of interaction that a website needs to do these days. We envision SMS, Email, and Twitter queries, and maybe even Port Knocking. Shelves will be modular, with lots of support classes for new request/response media.

More info as we get near a usable version. If anyone wants to contribute, drop us a line.

01 March, 2008

The Final Word on Rails Association Extension

There has been a great deal of debate on how to extend Rails Associations. Ryan discusses the "block" method:

class Organization < ActiveRecord::Base
  has_many :people do
    def find_active
      find(:all, :conditions => ["active = ?", true])
    end
  end
end

This is identical to the "extend" method; in fact Rails converts a "block" into an "extend":

module FindActiveExtension
  def find_active
    find(:all, :conditions => ["active = ?", true])
  end
end

class Organization < ActiveRecord::Base
  has_many :people, :extend => FindActiveExtension
end

The commenters then debate the merits of the "class method" method:

class Person < ActiveRecord::Base
  def self.find_active
    find(:all, :conditions => ["active = ?", true])
  end
end

class Organization < ActiveRecord::Base
  has_many :people
end

In all three cases (really two), you can call something like:

organization.people.find_active

There are differences, though! I ran some experiments to find out how each works, and found that unless you have some particular reason not to, you should always use the "block" or "extend" version, for two reasons:

  1. The "class method" version does not allow manual caching.
    class Person < ActiveRecord::Base
      def self.find_active
        @active ||= find(:all, :conditions => ["active = ?", true])
      end
    end
    
    Will break, as Adam T. mentioned in the comments.
  2. The association version is slightly faster then the class version. I created the same has_many relationship to two pairs of classes (Person has_many Things; User has_many Widgets). I then added 6 sub-association selectors (red, green, blue, small, medium, large) in different ways: Thing had class methods; User had the same methods embedded in the has_many association. I then ran benchmarks on 100 users/people and 5000 things/widgets (with identical respective associations). The x1 times are for finding all of 6 sub-association lookups on every Person (Class) and User (Association). The x2 times are for finding and reloading all 6 (that is, to gain the benefit of any automatic caching done by Rails or the database). In absolute times:
                               user     system      total        real
    Class (x1):            4.650000   0.680000   5.330000 ( 11.320903)
    Association (x1):      4.530000   0.670000   5.200000 ( 10.861711)
    Class (x2):            9.240000   1.360000  10.600000 ( 21.934539)
    Association (x2):      9.000000   1.330000  10.330000 ( 21.066327)
    
    Dividing the bottom two rows in half:
                               user     system      total        real
    Class (x1):            4.650000   0.680000   5.330000 ( 11.320903)
    Association (x1):      4.530000   0.670000   5.200000 ( 10.861711)
    Class (x2)/2:          4.620000   0.680000   5.300000 ( 10.967270)
    Association (x2)/2:    4.500000   0.665000   5.165000 ( 10.533164)
    
    Dividing all rows by the number of queries performed (per/query time):
                               user     system      total        real
    Class (x1)/600:        0.007750   0.001133   0.008883 (  0.018868)
    Association (x1)/600:  0.007550   0.001117   0.008667 (  0.018103) 
    Class (x2)/1200:       0.007700   0.001133   0.008833 (  0.018279)
    Association (x2)/1200: 0.007500   0.001108   0.008608 (  0.017555)
    
    The association version is a little faster, and gains more from the automatic caching Rails does.
  3. You can check out the experiment at https://svn.u-presence.com/svn/experiments/association_vs_class/ (username guest, no password).

26 February, 2008

Pesto Caesar Salad

I've been experimenting with salad dressings for a head of Romaine I got recently, and finally came up with the following. For one large salad:

  • 5 leaves Romaine (I leave the rib in; if you don't like it, use 7 rib-less leaves)
  • 1½-2 tsp lemon juice
  • 2-3 tsp olive oil
  • 8-10 drops Worcestershire sauce (instead of anchovies!)
  • a few (ok, several for me) turns of fresh-ground black pepper
  • 1 tsp pesto (I use Classico if I haven't recently made a fresh batch)
  • about 2 Tbsp. freshly shaved Parmesan (see below)
  • ¼ tsp onion powder or some finely minced white onion
  1. Put everything but the lettuce and the cheese into a large bowl.
  2. Mix vigorously
  3. Tear up the lettuce and toss in the bowl
  4. Shred the Parmesan. You can use a vegetable peeler, but I find the best method is to use the back of a paring knife to peel off shreds. Don't use a cheese grater — at least, not a fine one. The goal is about 1cm2 shreds.
  5. Eat tastiness

19 February, 2008

with_modules_unavailable and some Module helpers

I've been trying to test a new Rails plugin (stay tuned!), and I've found that I need to have certain Modules unavailable. This is useful when you need to test that missing Modules will raise errors or if you have behavior conditional on what gems are installed.

I wanted something like:

...
with_modules_unavailable(Foo, Bar::Baz::Goo) do
  test stuff
end

To get this working, just put the following in your test_helper.rb (this version requires Inflector):

Module.class_eval do
  
  def defining_module
    chain = self.to_s.split(/\:\:/)
    chain.pop
    if chain.empty?
      Object
    else
      chain.join('::').constantize
    end
  end
  
  def simple_name
    self.to_s.split(/\:\:/).pop
  end
  
end

Test::Unit::TestCase.class_eval do

  def with_modules_unavailable(*mods, &block)
    Thread.exclusive do
      mods.each do |mod|
        mod.defining_module.send :remove_const, mod.simple_name.to_sym
      end
      yield block
      mods.reverse.each do |mod|
        mod.defining_module.send :const_set, mod.simple_name.to_sym, mod
      end
    end
  end
  
end

You can test that it works with:

def test_with_modules_unavailable
  with_modules_unavailable(ActiveRecord::Base) do
    assert_raise(NameError) { ::ActiveRecord::Base.class_eval { } }
  end
  assert_nothing_raised { ::ActiveRecord::Base.class_eval { } }
end

17 February, 2008

Updates to active_support_hacks

I've made a couple of updates to my active_support_hacks

First: DateRange#include?(other)

This accepts a Date, Time or another TimeRange. It assumes inclusive range ends

4.days.ago.until(1.day.ago).include?(2.days.ago)                    #  => true
4.days.ago.until(1.day.ago).include?(3.days.ago.until(2.days.ago)   #  => true
5.hours.from_now.until(10.hours.from_now).include?(6.days.from_now) #  => false

Second: Pretty Date Formatters

These generate human-readable times and dates, like "9 hours from now" and "earlier this week"

f = ActiveSupport::CoreExtensions::Time::PrettyNumericDateFormatter.new
f.call(5.hours.ago)       # => "5 hours ago"
f.call(37.days.ago)       # => "1 month ago"

f = ActiveSupport::CoreExtensions::Time::PrettySimpleDateFormatter.new
f.call(5.hours.ago)       # => "earlier today"
f.call(55.days.from_now)  # => "later this year"

You can load these into the ActiveSupport formatting code like so:

require 'active_support/core_ext/time/pretty_numeric_date_formatter'
require 'active_support/core_ext/time/pretty_simple_date_formatter'

#each formatter must either respond to #call(Date) and #call(Time) or be a String for strftime

formatters = {
  :pretty_numeric => ActiveSupport::CoreExtensions::Time::PrettyNumericDateFormatter.new,
  :pretty_simple => ActiveSupport::CoreExtensions::Time::PrettySimpleDateFormatter.new
}
formatters[:pretty] = formatters[:pretty_numeric]
formatters[:default] = formatters[:pretty]

ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(formatters)
ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!(formatters)

I have that in my Rails app in /config/initializers/date_formats.rb. If you don't want to override the default formatting of dates, don't include the formatters[:default] = formatters[:pretty] line. By including a [:default] in the hash, all ActionViews will automatically use this formatter.

16 February, 2008

Frustrated with Media

I'm really just tired of it all.

I've been trying all evening to watch some old TV shows on my nice Netflix unlimited subscription. Problem: I've got a Mac. I've got Parallels, and occasionally it'll run Windows, but mostly it just crashes. I'm sick and tired of Microsoft writing code that crashes constantly.

I'm sick and tired of Apple being greedy and refusing to license their DRM. Hey, Apple: you do realize that licensing it out to Netflix makes your products more valuable, right? You're sure as hell not going to get me to use your iTunes Movie Rental service; it's a load of crap. Watch one movie once for $4 or watch unlimited movies unlimited times for $15/month? No question. Apple makes a better product than Microsoft, but they're just as obnoxious about it.

I'm sick and tired of the music and movie industries treating me like a criminal. Yeah, I used to download music. You know what happened? I spent $300 in the last couple years on CDs. I spent $200 on concerts. That's $500 on music, or about $490 more than I spent in the 20 years before I started downloading. I've since stopped downloading illegally and my purchases have plummeted. I just can't find the good music any more.

So, in conclusion, to Steve Jobs, Steve Ballmer, Harry Sloan, Philippe Dauman, Sumner Redstone, Reyer Maker, and the rest of your ilk: Stick it up your fat, greasy, selfish asses

14 February, 2008

ActiveSupport additions: TimeRange and Distance

I've created some utility classes that I use in many of my projects. I've broken them out into a Rails plugin, but they should really be part of ActiveSupport.

First: TimeRange

t = 5.minutes.ago.until(1.second.ago)
s = 10.minutes.ago.until(3.minutes.ago)
overlap = t & s
overlap.start_time # => 5.minutes.ago
overlap.end_time   # => 3.minutes.ago

Second: Distance

4.miles + 6.miles  # => 10.miles
5.yards.to_feet    # => 15.feet
12.miles.in_km     # => 19.312128.km
12.miles.as_km     # => 19.312128.km
2.meters > 2.yards # => true

Eventually, I plan on moving some of GeoKit into some sort of ActiveRecord::DistanceSupport in the plugin.

If you want the plugin, you can get it at https://svn.u-presence.com/svn/plugins/active_support_hacks/ (Username guest, no password). I'd love any other suggestions or comments on the utilities.

10 February, 2008

Reliable Software in 3 Simple Steps

(or: How I Realized Intro Economics Applies to Software Engineering)

The Rules:

  1. Hire a small number of really good programmers
  2. Hire one Information Assurance (IA) superstar
  3. Hire as many testers as you can without regard to past performance

The Rationale:

  • Software development is largely a weakest-link game. If you hire one crappy programmer, he'll write crappy code that the stars have to fix. They'll be slower and more resentful. Therefore, only hire really good programmers.
  • Security and reliability measures are a best-effort game. You don't need a whole slew of IA stars to see the big picture. I'm a believer in the idea of "more heads..." thinking, so I might hire two experts if I could afford it, but this position has rapidly diminishing returns
  • Bug fixing is a sum-of-efforts game. The more eyeballs the better. This is particularly true because even really good developers make assumptions about users. Having average-Joe people doing testing will get the developers good feedback early in the life-cycle

Finally, the credits:

09 February, 2008

Hacking Rubygems' #require, #require_gem, #gem

I have some old gems in my latest Rails app, and Rubygems has changed its syntax since those gems were built. The gems have require_gem in them, but the newest version of Rubygems doesn't add that command to Kernel, so you get NoMethodErrors when the gem loads. This simple hack in config/environment.rb will fix it:

# hack rubygem's change to #require:
Kernel.class_eval do
  def require_gem(*args)
    gem *args
  end
end
I have it right before require File.join(File.dirname(__FILE__), 'boot') in case my config/environments/xxx.rb loads an old gem.

The Problem With Rails Resource Routes

Today I show how to easily solve an incredibly annoying (but small) problem in Rails Routing for Resources.

For my past few Rails projects, I've created a module called ModelLoader that I include in my Controllers to load requested Models from the database. For each of my models, I have a #load_xxx and a require_xxx!. For an app that contains People and Tickets, the model loader would look something like this:

module Utilities
  module Controller
    module ModelLoader
      
      def load_person
        safe_load :@person, Person, :person_id
      end

      def require_person!
        require_exists! :@person, Person, :person_id
      end

      def load_ticket
        safe_load :@ticket, Ticket, :ticket_id
      end

      def require_ticket!
        require_exists! :@ticket, Ticket, :ticket_id
      end

      private

      def safe_load(variable_name, klass, parameter_name)
        begin
          instance_variable_set(variable_name, klass.find(params[parameter_name]))
        rescue ActiveRecord::RecordNotFound => e
          nil #swallow it; must have a statement here for coverage to see the line
        end
      end
      
      def require_exists!(variable_name, klass, parameter_name)
        raise error_for(klass, parameter_name) unless instance_variable_get(variable_name)
      end
      
      def error_for(klass, parameter_name)
        if params[parameter_name]
          msg = "Could not find #{klass} with id #{params[parameter_name]}"
        else
          msg = "Parameter #{parameter_name} is required"
        end
        ActiveRecord::RecordNotFound.new(msg)
      end
      
    end
  end
end

In my Controllers, I just do something like append_before_filter :load_person, :only => [:foo, :bar]

This is almost perfect. The problem is that some of my actions are accessible via more than one route. In particular, a nested- and non-nested version of the same resource:

  map.resources :people do |people|
    people.resources :tickets
  end
  map.resources :tickets
gives routes like
  • /people/:id/edit
  • /people/:person_id/tickets/:id
  • /tickets/:id

That means that somestimes :id is a Person#id and sometimes it's a Ticket#id. This wreaks havoc on my model loader. (It's also a problem for Sutto's similar, but more elegant solution.)

The solution is simple:

module ActionController
  module Resources
    class Resource
      def member_path
        @member_path ||= "#{path}/:#{singular}_id"
      end
    end
  end
end

Now all route segments have the class name in them:
  • /people/:person_id/edit
  • /people/:person_id/tickets/:ticket_id
  • /tickets/:ticket_id

30 January, 2008

First Ruby Gem!!!

I've just created my first Ruby Gem out of the with_probability code I've been working on. Simply

sudo gem install nondeterminism
Much thanks also to the initial author of the Sometimes Pastie Any problems with or suggestions for the gem? Join the Google Ruby-Nondeterminism Group

29 January, 2008

with_probability

In fuzzing my database for testing (see Fuzzing your Database and Faker), I've found the following to be very useful:

Object.class_eval do
  def with_probability(prob, &block)
    if rand <= prob
      block.call 
      return ProbabilisticDoer::Done.new
    else
      return ProbabilisticDoer::NotDone.new
    end
  end
end

module ProbabilisticDoer
  class NotDone
    def else_with_probability(prob, &block)
      with_probability(prob, &block)
    end
    def else(&block)
      with_probability(1, &block)
    end
  end
  
  class Done
    def else_with_probability(prob, &block)
      return self
    end
    def else(&block)
      return self
    end
  end
end

With that, you can do things like

u = User.create(...)
with_probability(9/10.0) do
  u.stuff_that_most_users_should_do
end

with_probability(0.01) do
  u.stuff_that_very_few_users_should_do
end.else_with_probability(0.2) do
  u.stuff_that_some_but_none_of_the_above_users_should_do
end.else do
  u.stuff_the_rest_of_the_users_should_do
end