"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.
17 November, 2008
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 Supporters | McCain Supporters | Me | |
---|---|---|---|
Community | 3.0 | 2.2 | 2.0 |
Country | 3.0 | 3.7 | 3.2 |
World | 3.3 | 2.6 | 3.6 |
Moral Dilemmas Results
In part II of the continuing series on morality, I took the "Moral Dilemmas" quiz at yourmorals.org. The results:
Average | Me | |
---|---|---|
Impersonal Dilemmas | 3.0 | 6.0 |
Personal Dilemmas | 3.2 | 1.0 |
Moral Foundation Results
I just took the highly informative "Moral Foundation" quiz at yourmorals.org. The results:
Liberals | Conservatives | Me | |
---|---|---|---|
Harm | 3.6 | 2.9 | 4.0 |
Fairness | 3.7 | 3.0 | 4.0 |
Loyalty | 2.2 | 3.2 | 2.7 |
Authority | 2.1 | 3.3 | 2.2 |
Purity | 1.3 | 2.9 | 1.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 RoutingError
s 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.
- git checkout -b nifty_name_for_nifty_new_feature
- git pull [repository [branch]]
- for each submodule of interest: cd path/to/submodule; git pull
- [code code code]
- [test test test]
- git add files/related/to/commit
- git commit -m 'nifty feature done'
- take 5 minute break to feed puppy or check roast in oven
- git checkout master
- git merge nifty_name_for_nifty_new_feature
- git branch -D nifty_name_for_nifty_new_feature
- 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:
- The "class method" version does not allow manual caching.
Will break, as Adam T. mentioned in the comments.class Person < ActiveRecord::Base def self.find_active @active ||= find(:all, :conditions => ["active = ?", true]) end end
-
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.
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
- Put everything but the lettuce and the cheese into a large bowl.
- Mix vigorously
- Tear up the lettuce and toss in the bowl
- 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.
- 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 ActionView
s 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 asses14 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:
- Hire a small number of really good programmers
- Hire one Information Assurance (IA) superstar
- 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:
- Joel has brought up these themes before, usually more eloquently and thoroughly
- Anderson and Moore come to very similar conclusions in Information Security Economics — and Beyond
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 NoMethodError
s 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