Pivotal Labs

Standup 02/29/08

edit Posted by David Goudreau on Friday February 29, 2008 at 05:30PM

Ask for Help

Standup 02/28/2008

edit Posted by David Goudreau on Thursday February 28, 2008 at 05:24PM

Interesting Things

  • If you want to run your Selenium tests in parallel, it looks like ThoughtWorks has released Selenium Grid.
  • When testing Live Query, you don't always want the event queue to be processed asynchronously, so we've submitted a patch that will allow a triggered event to return synchronously instead. The patch has not been integrated into Live Query yet.
  • Git - lets investigate where or when we can spike on this using a small internal project.

Standup 02/27/2008

edit Posted by David Goudreau on Wednesday February 27, 2008 at 05:30PM

Interesting Things

  • Rails is gradually moving to git. Should we? There's a brown bag today about git from a guest speaker. We'll talk about it then.
  • port install bash-completion
  • plus your custom completion configuration
  • plus your alias
  • equals

    work proj[TAB]

  • mod_proxy_html - if you're hoping to get this to work, you may have to worry about INFLATEing the html response coming from the server you're proxying to before being able to parse the html and change its urls. We ended up using SetOutputFilter INFLATE;proxy-html;DEFLATE to pass the html through the Apache2 proxy instance correctly.

jQuery & greasemonkey while being considerate to John's bandwidth

edit Posted by Brian Takita on Wednesday February 27, 2008 at 09:21AM

Here is a slight modification to Joan Piedra's jQuery greasemonkey script that loads the jQuery library on any page you visit. This gives you the power of jQuery when using Firebug or Greasemonkey. Here is an example of its usage.

var jQueryDefinition = (function() {/*jQuery library*/});
var GM_JQ = document.createElement('script');

GM_JQ.innerHTML = '(' + jQueryDefinition.toString() + ')();';
GM_JQ.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(GM_JQ);

Here is the full script. Here is the userscrips page.

Make sure that the jquery.user.js script is loaded before any other dependent Greasemonkey scripts.

The difference is you can put the jQuery library into the script itself. This causes the page to load faster and does not use up John Resig's bandwidth. Unfortunately, this also means you will need to manually upgrade your greasemonkey script when the next version of jQuery comes out.

[Update] Edited the Greasemonkey script to make jQuery compatible with other js libraries. [Update] Pointing to userscripts.org

Stupid Ruby Quoting Tricks

edit Posted by Nick Kallen on Monday February 25, 2008 at 10:25PM

Let's start with something easy.

Here's the mirepoix

bar = "chicken"

You know single quotes and double quotes, right? These are our salt and pepper.

'frickin #{bar}' # => "frickin #{bar}"
"frickin #{bar}" # => "frickin chicken"

Have you seen %q and %Q?

%q(frickin #{bar}) # => "frickin #{bar}"
%Q(frickin #{bar}) # => "frickin chicken"
%q{frickin #{bar}} # => "frickin #{bar}"
%Q{frickin #{bar}} # => "frickin chicken"

You've also seen """ (triple-quotes) right?

"""frickin #{bar}""" # => "fricken chicken"
"""frickin '#{bar}'""" # => "fricken 'chicken'"
"""frickin "#{bar}"""" # => "fricken "

UPDATE: As John points out in the comments, in addition to triple quotes there are also quintuple quotes, septuple quotes, and so forth. In fact, you can invent your own quoting operator for any odd number of quotes. (Just kidding.)

The truth is, singly and doubly-quoted object concatenate simply by juxtaposition!

"frickin " "chicken" # => "fricken chicken"
'frickin ' 'chicken' # => "fricken chicken"
"frickin " bar # => kabooom!
%q{frickin } %q{chicken} # => kablooey!
"""" #=> ""
"""frickin chicken" # => "frickin chicken"

Hokay. So that is all child's play. These are the quoting operators for the big boys.

This is why Ruby's Grammar is not Context-Free:

def foo(x)
  x.reverse
end

foo(<<-EOS)
  Your mom
EOS
# => "mom ruoY"

foo(<<-EOS).reverse
  amanaplanacanalpanama
EOS
# => "amanaplanacanalpanama"

Even better:

puts(DATA.read.reverse)

__END__
Your mom
# => "mom ruoY"

You actually have to copy the above code into a ruby file and run it -- it wont work in IRB.

Removing Old Ruby Source Installation After a Leopard Upgrade

edit Posted by Chad Woolley on Friday February 22, 2008 at 02:38PM

Removing Ruby

I just upgraded to Leopard on my Mac. Previously, on Tiger, I had installed Ruby from source, in the default /usr/local/lib prefix. After reading the discussion on the Apple-provided Ruby installation, I decided to try it - mainly to ensure that my apps, such as GemInstaller, play well with it (on Pivotal's Mac pair workstations, we still install Ruby from source, so everything matches our demo/production environments as closely as possible, and things are in consistent locations).

So, I wanted to uninstall the old Ruby source installation, and only have the Apple-provided Ruby on disk. Googling for a few minutes did not provide exact instructions for this, so I'm writing up what I did, in hopes that it will help you!

I didn't use the "--prefix" option when I originally installed Ruby from source, so it was in the default location of /usr/local/lib/ruby, with binaries in /usr/local/bin.

WARNING: Use 'rm -rf' at your own risk - a sleep-deprived encounter with 'rm -rf' and a stray file named '~' is what "motivated" my Leopard upgrade in the first place...

First, I deleted the old ruby libraries/gems, which was easy enough, because they all lived under /usr/local/bin/ruby:

sudo rm -rf /usr/local/lib/ruby

However, this left all the old ruby/gems executables in /usr/local/bin. This resulted in errors when trying to run executable gems that I had not yet installed under the Apple Ruby installation:

$ cheat
/usr/local/bin/cheat:9:in `require': no such file to load -- rubygems (LoadError)
from /usr/local/bin/cheat:9

Instead of a cryptic rubygems error, I should get a 'file not found error':

$ sudo rm /usr/local/bin/cheat
$ cheat
-bash: /usr/local/bin/cheat: No such file or directory

So, I want to purge everything ruby-releated from my /usr/local/bin folder. I whipped up a quick ruby one-liner which just prints out (almost) all ruby-related files in /usr/local/bin:

ruby -e "old_ruby_execs = \`egrep 'rubygems|bin/ruby|env ruby' /usr/local/bin/*\`; require 'pp'; pp old_ruby_execs.split(\"\n\").collect{|line| line.split(':').first}.uniq"

Yeah, I know, ugly and obtuse, but one-liners are kind of fun, and help me remember that Ruby is great tool for sysadmin scripts. Feel free to put it in a class and test it if you are so inclined.

Even though I tried to make a fairly specific regexp for egrep, when inspecting that list, I did find a 'jgem' file, which was part of JRuby. I'm planning on reinstalling JRuby anyway, so I didn't care if that got deleted along with the other ruby stuff.

Anyway, if the output of that looks like everything you want to delete, then run this one-liner to do the actual deed (the 'sudo echo' is to 'prime' the sudo auth, so you don't get a noninteractive password prompt):

sudo echo; ruby -e "old_ruby_execs = \`egrep 'rubygems|bin/ruby|env ruby' /usr/local/bin/*\`; old_ruby_execs.split(\"\n\").collect{|line| line.split(':').first}.uniq.each { |exec| p 'removing ' + exec; \`sudo rm #{exec}\`}"

After that, the only thing that I saw left was the 'ruby' executable itself, which I whacked as well:

$ sudo rm /usr/local/bin/ruby

That seems to be about it, as least good enough to get all the old invalid executables off my path. I'm sure this could have been done cleaner if I had taken more care with the original source install. However, a good brute-force approach never hurt anyone. Much. Feel free to post links to relevant and helpful stuff.

Rails 2 on Windows with Oracle: notes about getting started

edit Posted by Shifra Pride Raffel on Wednesday February 13, 2008 at 09:31PM

I'm planning to make this the first in a series of random small notes about working on a Rails project in an enterprise (by which I mean large-scale, mature-company, high-demand) setting. I'm aiming for small bite-sized dispatches, not for comprehensiveness. [Edited to say: I'm now working on a Java project, so I'm not sure when I will have more to add.] Please chime on in with additions and comments. This post focuses on our installation process. If you've gotten here via google, you're going to find much more systematic guides than this, so be of good cheer!

Standup 02/11/2008

edit Posted by Corey Innis on Monday February 11, 2008 at 11:57PM

Interesting Things

  • Got Example?

    Don't forget to make use of the reserved (top- and second-level) domain names set aside by RFC 2606... especially if you find yourself writing something like:

    result = @model.do_request('http://www.somebogusdomain.com')
    result.code.should == 1001
    
    
    # NOTE: www.somebogusdomain.com actually exists!
    

Java Stink

edit Posted by Alex Chaffee on Monday February 11, 2008 at 05:07PM

After about two years in which the only Java I wrote had a "Script" after it, I've recently started working in my old favorite language again. It was clear to me long before I made the leap that somewhere along the line Java took a sharp turn towards Scarytown. (Maybe the writing was on the wall when the "Hello World" program comprised five lines, two declarations, and a static reference, but back in 1995 we were all so excited about getting objects without C++ that our judgement was clouded.)

Anyway, I will always have a place in my heart for the old bird (picture a portly English matron with flower dress and pocketbook and floppy hat), but Stu at Relevance Blog points out why coding in Java now feels like trying to sprint with 30-pound weights strapped to my ankles.

Java is a high-ceremony language. At every turn, Java enforces a high busy-work/real-work ratio. Specifically:

  1. Java's checked exceptions bloat code, make components harder to use and maintain, and lead to tons of boilerplate code, each line of which is a bug-in-waiting.
  2. Java's new operator/constructors cannot pick a return type. The amount of code that exists only to work around this is staggering. Two entire cottage industries have sprung up to deal with this single issue: factory patterns and dependency injection.
  3. Java has no metaprogramming features to automate common tasks such as field accessors, standard constructors, and simple delegation.
  4. Primitives, functions, and classes are not first-class objects, leading to huge code bloat to deal with these types specially.
  5. Java's core reflection and interception capabilities are clunky, requiring tons of bolt-on technologies to make them workable, including AOP, annotations, and code generators.

That's a pretty big stink, but if you are used to it you probably can't smell it anymore.

(And that's not even mentioning the prevalent idioms of programming with massive amounts of indirection and wrappers and statics and service locators and and BigLongClassNamesThatIncludeTheirAncestry (I always say, "Do we call it a DogMammalVertebrateAnimal? No, we call it a dog!") and redundant JavaDoc on every method and...)

I ranted and spoke and even blogged about some of these issues before, but now that I'm a visitor in that world I just feel vaguely amused and sad when I see all the hoops Java programmers still have to jump through. Yeah, control-space completion is nice, but gotapi works pretty well, and at the end of the day, no matter how many curly braces my IDE inserts for me, I'd rather have my code look like this:

parse_args(["--topping", "pepperoni"])

than this:

String[] args = {"--topping", "pepperoni"};
parseArgs(new ArrayList<String>(Arrays.asList(args)))

 Wouldn't you?

Screen Scrape No More...Seriously!

edit Posted by Parker Thompson on Sunday February 10, 2008 at 02:48PM

This week I had the pleasure of attending Dapper Camp put on by the folks at Dapper for their user community. Mitch Kapor kicked it off with a talk on disruptive technology, openness, and innovation. We then got to hear both from the Dapper team about new and upcoming features, and folks like Aaron Fulkerson of MindTouch about using Dapper to repurpose data. All around it was pretty interesting.

What I love about Dapper is that it helps solve one of the big issues I see our clients have: data. We can build just about anything, but if an application needs some specific data (and many do), products must be launched with sub-par (but available) data, or worse launches can end up being delayed. In many cases, we can end up spending a large amount of time (aka money) getting/munging data rather than developing features. Note: I also think the ease if pushing data out of apps via instant gadgets makes Dapper very interesting but that's a whole separate post.

The "Dapp Factory," a Rhino-based server application and a web front-end that deals with just about any site by proxying your requests and modeling the DOM on the proxy, then recording your actions for later replay. But, their secret sauce is a super-cool algorithm that figures out the structure of pages in such a way that your API can withstand changes to the target site, making your feed resilient to all but massive site overhauls. You then simply consume an XML or JSON feed, or use a simple API to dynamically construct paramaterized feeds.

There are other companies trying to make data less painful. Metaweb, for example, provides an incredibly fast graph engine and relational schemas (think RDF) that makes real-time use interesting. But, if the data you need isn't in Freebase (a likelihood until they get larger), or your data is continually being updated, you will still be stuck scraping and relating the data, and that's generally where most of the work is.

Take as a small example Dav's awesome Vacation Planner. The concept is simple, the feature set is small, but getting the data is a pain (see article). Some sites don't have APIs, and those that do provide unstansardized, sometimes buggy, and are often often missing the data you need.

I could imagine writing a dapp parser akin to ActiveResource pretty easily (I hear a ruby SDK came out of DapperCamp, but I can't find it). With a little more work, it would probably be easy to add cache_fu support, and ruby modules that could be mixed into models (for asynchronous data gathering) and controllers (for serve now vs. polling) to easily support Dav's polling mechanism.

This would leave Dav with pretty simple model (data) code, and the luxury of focussing on whether to add wikipedia integration for population figures or the Big Mac Index, rather than tweaking his Mechanize xpaths all weekend. I vote for the Big Mac Index.

So, the next time someone suggests you screen scrape to get that data you need, tell them to give Dapper a shot. And if anyone wants to write 'ActiveDapp' let me know. It could be really fun.

Note: In the spirit of full disclosure, Jon Aizen (Dapper CTO) is a friend of mine and they gave me a free t-shirt...and a sandwich (thanks).

Other articles: