Posts from life.i.think...
Posted by Britt 3 days ago
There occurs an interesting problem when you are using Ruby’s GetText to translate a site that requires authentication.
Most likely, you have a before_filter that calls a method that authenticates the user for certain methods. Within this filter you probably have something like:
user = (attempt_oauth or
attempt_basic_auth or
attempt_session_auth or
attempt_cookie_auth or
(@authentication_attempt = nil))
If the user has clicked “Remember Me” and stored an cookie locally, than we’re going to validate the user using attempt_cookie_auth. But what if the user has a default language set (stored most likely in the database). We’ll assume there is a method user.lang that returns the default language or nil.
Your first attempt at setting this here may be this one.
NOTE: THIS IS WRONG!
# If the user has a default lang, set it here.
if u && u.lang && (LANGUAGE_CODES.include?(u.lang))
cookies[:lang] = u.lang unless cookies[:lang]
end
That sets the cookie for the user, but the GetText stack has already been invoked, so the language will be that sent over by the browser. Refreshing the page will cause GetText to pick up the cookie value and render the proper language.
Next, we try using set_locale (GetText.set_locale) to set the language manually, which seems like a perfectly reasonable option.
NOTE: THIS IS WRONG!
# If the user has a default lang, set it here.
if u && u.lang && (LANGUAGE_CODES.include?(u.lang))
cookies[:lang] = u.lang unless cookies[:lang]
set_locale u.lang
end
Why is this bad? The set_locale method persists for the life of the Ruby instance (in this case, Mongrel), not the session. This means that there will be a literal battle for contention over which language to use.
User A sets the language to JA and the page renders JA.
User B sets the language to EN and the page renders JA.
User A sets the language to JA and the page renders EN.
You see the problem! We want a clean slate at the beginning of each request so GetText has no pre-conceived notions about what the language should be. Hrm … let’s try something.
NOTE: THIS IS WRONG!
# If the user has a default lang, set it here.
if u && u.lang && (LANGUAGE_CODES.include?(u.lang))
cookies[:lang] = u.lang unless cookies[:lang]
set_locale u.lang
else
set_locale nil
end
Note … to be thorough, and because the authentication stack is not called for all methods, we also add this in our application.rb
before_init_gettext :set_default_locale
def set_default_locale; set_locale nil; end
Here, everything seems to work!
We can even write a test to verify that the contention above doesn’t occur.
def test_lang_should_be_set_on_a_per_session_basis
bob.lang = 'ja'
assert bob.save
bob.reload
assert_equal 'ja', bob.lang
post '/sessions', {:username_or_email => bob.screen_name, :password => 'foo'}
assert_response :redirect
follow_redirect!
assert_response :redirect
follow_redirect!
assert_response :success
assert_equal 'ja', Locale.current.language
phoenix.reload
assert_equal nil, phoenix.lang
post '/sessions', {:username_or_email => phoenix.screen_name, :password => 'foo'}
assert_response :redirect
follow_redirect!
assert_response :redirect
follow_redirect!
assert_response :success
assert_equal 'en', Locale.current.language
end
But alas, download the Japanese version of Firefox and visit the page.

The browser is hungry for UTF-8 data. As you can see, the part of the page in which we set the locale manually using set_locale is being pushed as SHIFT-JIS. The blue highlighted area is actually outside of the application.rb controller stack, so is sent via GetText’s default assumptions: UTF-8.
But this isn’t a problem in Safari or Internet Explorer. Why? Let’s look at the value of HTTP_ACCEPT_LANGUAGE.
Firefox : "HTTP_ACCEPT_CHARSET" => "EUC-KR,utf-8;q=0.7,*;q=0.7"
Safari : "HTTP_ACCEPT_CHARSET" => ???
Safari actually doesn’t pass one, while Firefox gives precedence EUC-KR (effectively SHIFT-JIS) over UTF-8.
Sigh. Things are looking grim. Back to the drawing board. Let’s look at the order of precedence for how the Rails GetText integration determines the langauge.
The language passed to GetText.bindtextdomain.
The lang query param. ( url?lang=foo )
The lang cookie.
The value of HTTP_ACCEPT_LANGUAGE passed by the browser.
The default (English).
Aha! GetText.bindtextdomain! Looking at the RDocs and source, this is not only called within the init_gettext method, but can be set on a per session basis without mucking with default language settings!
Let’s try!
NOTE: THIS IS CORRECT! CELEBRATE!
# If the user has a default lang, set it here.
if u && u.lang && (LANGUAGE_CODES.include?(u.lang))
cookies[:lang] = u.lang unless cookies[:lang]
GetText.bindtextdomain("Twitter", :locale => u.lang)
end
So finally, we can set the language on a request manually after the GetText stack has already been invoked. Whew!
Posted by Britt 51 days ago
You can script the declaration of constants easily enough with Module#const_set.
Sometimes you want to do this from environment.rb when you are loading the Rails stack. It’s not immediately clear which module this is encapsulated in. Turns out it’s not contained within anything specifically … just plain ol’ Object.
foo.each do |bar|
Object.const_set("CONSTANTLY_#{bar.upcase}", 42)
end
Posted by Britt 51 days ago
So yes, it’s true. I’ve been using Textmate lately. I’m still using Debian and the trusty Thinkpad (and eyeballing the sexy X300), but also have picked up a MacBook Air, and am dabbling in the world of Mate.
One thing that has bothered me about my typing in Mate (other than the lack of using modes) is that something I’m doing is leaving trailing whitespace. This, of course, is a problem. Eventually I’ll figure out what muscle memory reflex is causing this, but there are a few things I’ve found along the way to help identify these vile and unnecessary bytes in my documents.
Add Syntax Highlighting for Trailing Whitespaces
First we must at a rule to match trailing spaces in our language of choice.
{Q: Can we do this for all languages?}

Secondly, assign a color to this property in your theme of choice.

Keyboard Shortcut to Remove all Trailing Whitespaces
TextMate comes with a command to remove all trailing spaces from a document. Why not assign a keyboard shortcut to it?
{Q: I’d love to do this on-save of all documents.}

Posted by Britt 182 days ago
The other day Cameron and I were talking about a better way of labeling and prioritizing your mail in GMail. It is a system of his friend’s devise, who’s name I’ve forgotten (I’ll update this when I get it.)
The system is simply to create 4 labels, and then apply filters to the emails you receive on a regular basis.

1. Now (Mail you need to look at RIGHT NOW!)
2. Soon (Mail that you should probably read by the end of the day)
3. Later (Mail to read when you find that free time you’ve been looking for)
4. Never ( crickets .. I mean maybe you might want to read them … sometime …)
So for example, Twitter direct messages auto go to Now. An email about that fancy pants party you’re going to in 2 days would go under Soon. Facebook messages would be filed under Later. Financial statements might go to Never.
It’s important that you preface the words (Now, ...) with numbers so GMail orders them properly.
This works fantastically with Mihai Parparita’s wonderful GMail Macros Greasemonkey script.
Update: The aforementioned friend who devised this brilliant scheme is Ted Grubb.
Posted by Britt 233 days ago
5 1/2 hour train from Heidelburg to Berlin.
Arrived at the closed Tegel Airport at 1 AM and sat on a bench till they opened at 4 AM.
Waited for 7:30 AM flight to London.
Layover, and then ~12 hour flight to San Diego.
Through customs and flight to San Jose.
Bus to Cal Train Station.
1 1/2 hour Cal Train to the Bart Station.
Bart to 24 and Guerrero.
Home! Whew! What a ride.
Germany was absolutely beautiful. The conference was a blast, and had the best food I’ve ever had at a lunch break. The talk went well I think, and you can see the slides, which have a few cool rails tricks embedded, here:

Posted by Britt 305 days ago
Continuing with Ruby scripts that should probably be written in Bash, here’s one for the eyecandy inclined.
Situation:
- You are running an X stack that supports xrandr 1.2.
- You are running Compiz (Fusion).
- You want to switch back and forth between an external monitor, and your laptop’s display.
A couple of notes. Unfortunately, you cannot trigger an xrandr script on VGA plug/unplug events (yet). See this post. Also, if you are not running an accelerated desktop, or your 2 monitors fit within the bounds defined by a few X components (see this post), you can use your laptop as a secondary monitor.
For now, I’m just toggling between my two monitors via this small Ruby script.
#!/usr/bin/env ruby
def lappy; exec "xrandr --output VGA --off --output LVDS --auto"; end
def external; exec "xrandr --output LVDS --off --output VGA --auto"; end
case ARGV.first
when 'l' then lappy
when 'e' then external
else
external if `xrandr -q`.include?('VGA connected')
lappy
end
Download.
And before all you MacHeads out there smile to yourselves about all this work; You thought I forgot about you! I so vary rarely tinker with my desktop setup. This truly is the oddity! Oh, and http://twitter.com/blaine/statuses/153159902
Posted by Britt 309 days ago
Also known as “the most the most useful piece of software [someone else] wrote in [a] calendar year,” rewritten.
Today Mark Dominus blogged about f, a wholly fantastic and tiny Perl script that changes:
ps aux | awk ‘{print $2}’ to ps aux | f 2.
Of course there’s the deeply embedded urge of every geek to take something like this and reproduce it in all possible languages (plus there was a syntax error running the Perl script on my end), so here we have it in Ruby!
#!/usr/bin/ruby
($stderr.print "f.rb usage: fieldnumber\n"; exit) if ARGV.empty?
$stdin.each { |l| puts l.split[ARGV.first.to_i-1] }
Download.
Posted by Britt 325 days ago
As we walk down the street, she bounds into the air, biting at the leash. With joy in her face she pulls and skips. She flips in the air, much to the amusement of passersby.
“You are not in the present moment! [1]”, I think to myself. You are missing the enveloping smell of the Angel Trumpets to our left; The smile of the child’s face to our right. But then I realize that to Addi, in that moment, I am the present. I’ve spent the day at the office, as she’s spent the day on the couch, my bed, or whichever comfortable spot she deems appropriate in my tiny studio apartment.
She becomes the present moment for me. I no longer am distracted by what would normally grab my attention. I love her wholly and this moment is a precious one. I remember now words given to me that remind us that focusing our energy towards the present allows us to fully embrace all that we care about; my dog included. And me to her.
[1] “You shouldn’t chase after the past or place expectations on the future. What is past is left behind. The future is as yet unreached. Whatever quality is present you clearly see right there, right there.”
—Buddha
Posted by Britt 397 days ago
So many people seem to judge success based on how much money one makes. This is a terrible misconception though, as success is not defined by monetary gain, but by happiness. This inspires an entirely different way of thinking about our lives; in particular our jobs. What if we didn’t strive to make money, but instead to make happiness?
When I first iterated over this article, I went back and forth on whether or not to include bullet points refining the concept. I found it difficult to articulate, because I was quick to inject my own inspirations for contentment. Everyone has a different definition of “happiness,” but there are a various ways you can look at your job in which are most encouraging. I believe I’ll continue to post on this concept, but here are a few things I find important and that could lend themselves to others as well.
1) Layout a base set of criteria that makes you happy. Like profiling an application for performance gain, you can’t know you’ve reached your goal unless you’ve set one. But how does one determine what happiness means? It’s actually fairly easy. Slow down, take a deep breath, and think about what makes you smile (smiling on the inside counts as well). What makes your entire body reverberate with that indescribable feeling?
2) Make just enough money to be able to provide these things for yourself.
3) If you make more money than you need to be happy, use it to inspire happiness in others.
4) Ensure that your means of making money contributes to your overall happiness. Sacrificing your well-being for delayed reward is a broken model. Some would argue this point, saying that there are necessary evils; Someone has to do the dirty work. But one can be content in their work, glamorous or not, based on their perception of the work itself and its benefit to the greater good.
5) Love unconditionally.
6) Add pictures of cats to whatever projects you work on. This guarantees, without the glimmer of a doubt, the happiness of not only yourself but your users as well.
Ok ok, the last one was a joke, but seriously … who doesn’t like cat pictures.
Posted by Britt 432 days ago


Be sure to check out our new visualizer we have on display there if you haven’t yet!
Posted by Britt 432 days ago
- Wired: Twitter is Ruling SXSW
“When you’re down at SXSWi zipping to and from different venues, what’s the best way to stay in touch with your friends? This year, it’s not phone, IM or email, it’s Twitter.”
Posted by Britt 436 days ago
Dear friends, family, close relations, guys, gals, second cousins twice removed, and the web a large,
I’m moving. Moving to sunny, sunny California. I’m kinda flying by the seat of my pants right now, but I’ll initially be in Palo Alto for about 3 months, staying with Jesse, and then it’s a hop, skip,
and a jump into SF.
I’m very excited to announce that I’ve joined the team at Obvious, who of course made something called Odeo, to work on Twitter. I landed at Twitter for a number of reasons, but most importantly because I love and use it, as well as truly believe in what we’re working on. Twitter allows me (and you!) to talk about all the oddities of life, of which there are most definitely plenty. It provides an outlet for that strange little voice in your head that normally lies silent. The one that should at times stay quiet, but often wants to jump up and down and scream something like “HEY! Why is the mall Santa running through my neighborhood naked with a bottle of scotch!?”
Twitter the site aside, I’ll be joining an absolutely stunning team of passionate and creative people. I’ll also be leaving the same here in Lexington. I truly love the people at Voltaic, and words escape me in trying to describe the time I’ve spent there. I will miss them very much.
Anyway, enough for now. Lots of exciting stuff coming up!
Posted by Britt 441 days ago
This has been covered elsewhere. I did it in the past, but of course life has a way of kicking out old info to make space for the new.
Without being too terribly long winded, I will say that the reason for making this post is due to the fact that when I wanted to figure out how to dynamically create variables with ruby, I did a google search for a number of derivations of: ruby programmatically creating variables. This came up with a lot of nothing. I quickly realized this was turning into one of those dreaded cases of having to know the method name you’re looking for before you can find it. I’m a bit embarrassed to say I didn’t check this one, but thanks to blink on #ruby-lang, I’m posting just incase someone else searches with the same terms.
So at its very simplest:
eval "ans = 42"
Read more about eval at
Jim Weirich’s always excellent blog.
Furthermore, instance variables of a class can be set via set_instance_variable.
class DeepThought
end
question = DeepThought.new
question.instance_variable_set("@ans", 42)
def question.what_is_the_answer
return @ans
end
question.what_is_the_answer
=> 42
Posted by Britt 445 days ago
It’s commonality on the web. A site asks you for something you consider sacred (it’s a strong word, I know): your email, your username, your password, before it gives something useful back to you. Sure, it may give you view-only access to information, but in order to actually participate in a community, you have to supply them with something first.
But what if this didn’t have to be the case? What if it shouldn’t be the case? A web application should be giving, loving, and excited about its users, even if they aren’t already defined by a particular identity. The web, at its heart, is largely anonymous. Sure, it knows things about you without your consent: your browser, your IP, your location, whether or not you have flash, etc, etc. But the web doesn’t know you; you as a person. If you are most webapps (you know who you are), then you ask the user to give this up, oftentimes before showing them what exactly they’ll be getting in return.
You are standing at a bar, hanging out with a variety of webapps.
Sitting next to you are some people you have heard of before (hey, they have a rep!): Digg, Gmail, Flickr. You’re an outgoing person, and you’ve heard about how amazing these people are, so you introduce yourself.
But to your left is a newcomer. Maybe they’re respectable looking, maybe they’re not. Maybe you’re immediately intrigued by their mystique, instantly wanting to get to know them. Maybe you’re not. Now in a perfect world, everyone would introduce themselves to everyone and immediately get along famously, becoming instant friends. Unfortunately, that’s not the world we live in, and nor is it the web at large. There are people who want to know you for their own benefit. So you’re jaded, and quietly sit there sipping your appletini.
But what if they turned to you and and started telling you a fantastic story, something about themselves that you would have never gleamed at first sight, especially in a bar as big as this one. You talk back and forth for a while, entertaining each-other with common interests and tales of the good-ol’-days, and eventually it comes out.
“Hey, by the way, my name is Britt.”
“Oh hi, I’m Twitter.”
And there it is. The beginning of a beautiful relationship.
Posted by Britt 456 days ago
If you don’t already read Kathy Sierra’s Creating Passionate Users, you most probably should!
Her Valentines day post (linked above), was on “Loveocracy” and how what’s good for the user is good for you. I’d like to add something that she implied in the post, but didn’t mention specifically.
Not only do you want passionate users, but passionate developers. It seems obvious, and should go without saying, but is very important. Love the software you write. USE the software you write! In an ideal world we, as developers, could love every application we create. Unfortunately for some, especially in the case of contract development, this isn’t always the case. But whenever possible, one is blessed with working on an application that they not only enjoy developing, but using as well. When you care about something, you nurture it. In the software world, this means more creative and intuitive applications, which are ultimately well written with fewer bugs.
In the end, don’t simply create passionate users, but be one yourself.
Posted by Britt 458 days ago
Well, you don’t see this every day.
One client of ours wants to add some shopping cart jazz to a few of his websites. Nothing new here, especially since we’ve developed our own kick ass shopping cart. The oddity is that he wants most of the static content of some very old-school sites imported in pure HTML form to a CMS for online editing. No layouts or cleanup, just the old, pure HTML. Actually, one of the sites used image maps for navigation (the whole page is solely images!), so we are doing a bit of cleanup there.
Comatose is a nice ‘microCMS’ that sits happily ontop of an existing Rails app. Today I whipped up a script to import a static site into comatose.

It’s not much … you can download it here.
Usage is simple:
html2Comatose: Import HTML into the Comatose MicroCMS
Usage: ./html2comatose app-root html_pages_root [additional extensions you'd like to import]
Example: html2Comatose ~/devel/myapp ~/var/www/httpdocs php rhtml
After the import is complete, you’ll want to put something like this in your /config/routes.rb ..
map.comatose_admin
map.comatose_root '/site', :layout => nil
map.connect '', :controller => 'comatose', :action => 'show', :index => '', :page => 'index'
Haha, I’m not sure if anyone will every find a need for this, but let me know if you end up using it for anything.
Posted by Britt 459 days ago
They grow up so fast! After much hubbub and a bit of general hurah, the first stage in the major Userscripts.org rewrite has been released!

Thanks to all that helped make this possible!
Posted by Britt 462 days ago
“You are not here merely to make a living. You are here in order to allow the world to live more amply, with greater vision, with a finer spirit of hope and achievement. You are here to enrich the world, and you impoverish yourself if you forget the errand.”
- Woodrow Wilson.
Posted by Britt 466 days ago
After going through the process of building GD in OSX with all the relevant fonts, libraries and what-have-you, I was running into a terribly frustrating problem with Ruby-GD, specifically when trying to use the Captcha gem.
undefined method `stringFT' for GD::Image:Class
Luckily, this can be fixed very simply by:
sudo port install rb-gd
Posted by Britt 466 days ago
Every so often one has the desperate need beat RJS into evaluating javascript conditionals, say, if you don’t know if an element is going to necessarily be on the page or not.
For this one particular use case, luckily, Enrico Franchi pointed out a workaround for this.
page.select('element').each do |element|
page.replace_html element, replacement
end
But what if we want to compare equality, or any other type of conditional? We can use the unbelievably, ridiculously, mind bogglingly ugly hack:
page << 'if (el.value == 10) {'
page['block'].replace_html replacement
page << '} else {'
page['block'].replace_html replacement
page << '}'
Imagine if we needed both of these previous methods combined? My head is spinning!
Dann Webb provides a plugin that implements ejs (erb based javascript) that provides a very cool and interesting mesh between javascript and erb.
But tell me. Why, oh why, wasn’t this patch accepted?