Alex Chaffee's blog



Alex ChaffeeAlex Chaffee
git config push.default matching
edit Posted by Alex Chaffee on Thursday June 04, 2009 at 04:29PM

Upgraded to git 1.6.3 yet? You should, and Jason Rudolph says why (and if you're on a Mac, Rob Sanheim says how.)

Sadly, after you do upgrade, when you start doing "git push", your console will start to be littered with the following oddly patronizing message:

warning: You did not specify any refspecs to push, and the current remote
warning: has not configured any push refspecs. The default action in this
warning: case is to push all matching refspecs, that is, all branches
warning: that exist both locally and remotely will be updated.  This may
warning: not necessarily be what you want to happen.
warning: 
warning: You can specify what action you want to take in this case, and
warning: avoid seeing this message again, by configuring 'push.default' to:
warning:   'nothing'  : Do not push anything
warning:   'matching' : Push all matching branches (default)
warning:   'tracking' : Push the current branch to whatever it is tracking
warning:   'current'  : Push the current branch

While I'm generally in favor of verbose warnings, this one is kind of bizarre. Essentially, it's saying, "Warning! The command you just ran will continue to operate exactly as it did before!" Guys, telling us about new options is great but that's what release notes are for.

Worse, they don't provide keystroke-level instruction beyond the offhand gerund "configuring" on how to shush it. Here's the result of my 8-minute speluking inside the output of "git help config":

git config push.default matching

There, now, that wasn't so hard after all, was it?

Alex ChaffeeAlex Chaffee
Monkey Patch Du Jour
edit Posted by Alex Chaffee on Sunday May 24, 2009 at 12:15AM

The following monkey patch gives a bit more information in the ActiveRecord SQL logs. Instead of just saying "User Load" it also says the file and line number in your code that asked AR to perform the operation. That way you can have a hope of tracking it down and optimizing it away if at all possible.

  User Load (0.2ms) views/main_page.rb:107:in `filters_box'   SELECT * FROM `users`

Code after the jump. I guess you put it in environment.rb with all the other monkeys.

Alex ChaffeeAlex Chaffee
Capturing Standard Out In Unit Tests
edit Posted by Alex Chaffee on Monday May 11, 2009 at 03:28AM
    def capturing_output
      output = StringIO.new
      $stdout = output
      yield
      output.string
    ensure
      $stdout = STDOUT
    end

then...

    it "exits immediately from --version" do
      output = capturing_output do
        lambda {
          Erector.new(["--version"])
        }.should raise_error(SystemExit)
      end
      output.should == Erector::VERSION + "\n"
    end

Alex ChaffeeAlex Chaffee
Erector 0.6.3 - Now Ready to Conquer The World
edit Posted by Alex Chaffee on Wednesday May 06, 2009 at 09:36PM

[Updated: added instructions "If you are using a widget in rails, you now need to inherit from RailsWidget"]

Erector has been around for almost 2 years now, but we've always been a little reluctant to market it heavily. One reason has been that the API was a little inelegant. Another is that Rails integration wasn't as seamless as we'd like.

With today's release of version 0.6.3, we have hopefully fixed both of those problems. With the new RailsWidget we've got a clean separation between core Erector functionality and the magic we need to make it work with Rails. We've renamed "render" to "content" so we don't conflict with the standard Rails render method. And we've changed the API for smoother lifecycle management -- the constructor is about initializing the widget, and the refurbished "widget" method is about setting it up to emit its HTML.

The bad news is that you'll have to change your existing code. The good news is there's an update guide, which you'll find below the fold in this blog post.

Please visit our Google Group to register comments or complaints, our project web site for full documentation and FAQs, and feel free to clone or fork our GitHub repo.

(Why 0.6.3 and not 0.6.0? Because we had to work through some glitches in the new deploy process with GitHub and Jeweler and whatnot. We're only human...)

Alex ChaffeeAlex Chaffee
Safari 4 "Zoom Text Only" fixes Google Reader and GMail
edit Posted by Alex Chaffee on Tuesday March 24, 2009 at 06:11PM

Problem: every since I upgraded to Safari 4 I've been annoyed that zooming in and out seems to confuse GMail and and Google Reader. When you zoom out, GMail refuses resize its panels, leaving a big blank space on the right side; when you zoom in, Google Reader loses its button panel at the bottom of the main area if you're in a feed with a lot of entries.

Solution: go to the "View" menu and select "Zoom Text Only".

New problem: the other setting is cooler for other sites, since it magnifies images and keeps non-fluid layouts from wrapping stupidly when you really need the text to be a little bit bigger. I wish there were a way to set it per site, but it's a global setting. Oh well, no big deal, at least now I know where it is if it comes up.

Alex ChaffeeAlex Chaffee
How to tell Apple/DotMac/MobleMe Backup that .Trash is trash
edit Posted by Alex Chaffee on Tuesday August 26, 2008 at 07:14PM

First of all, fie on Apple for giving both their cloud storage service and their backup program names that are almost completely google-proof. They've recently corrected one of those by renaming "dot mac" to "MobileMe" but calling your backup program "Backup" is a great way to make it really hard to investigate. It's like, imagine how hard it would be to do a background check on someone named John Doe.

So I use the Dot Mac Backup and it works pretty smoothly, which is the second most important feature in a backup program. (The most important feature is the ability to actually restore files.) But then one day it said that to incrementally back up my "Home Minus Media" set -- the set containing my Home Folder, but excluding big-ticket items like Music, Movies, Backups, Downloads, and so on -- would require 63 DVDs. WTF?

It turned out that the problem occurred after I trashed a few old DVD rips that I had finished watching, and the culprit was the directory /Users/chaffee/.Trash. Seems like the UI was helpfully excluding it from the list of subdirectories of /Users/chaffee, it being a system file and all, so I couldn't mark it to exclude. That's OK, I think, I'm a power user, so I'll just check the box that says "Show invisible system files."

Except there's no such box. Try as I might, I can't find a way to exclude the Trash folder from the UI. I had to dig into the file system and edit Backup's own data file, as follows.

Alex ChaffeeAlex Chaffee
JAVA_HOME on Mac OS X
edit Posted by Alex Chaffee on Thursday June 26, 2008 at 06:57PM

For the millionth time, cause I always forget...

Put this in ~/.bashrc:

export JAVA_HOME=/Library/Java/Home

Also, run "sudo visudo" and add the line

Defaults        env_keep += "JAVA_HOME"

or else commands like "sudo gem install" won't be able to find Java.

Without the above, I got the following error (which seemed to have been run through a baby-talk filter) when running "sudo gem install rjb":

extconf.rb:44: JAVA_HOME is not setted. (RuntimeError)

Alex ChaffeeAlex Chaffee
XPath CSS Class Matching
edit Posted by Alex Chaffee on Tuesday March 25, 2008 at 06:01PM

I'm writing Selenium tests again, which means a lot of XPath. Here's a trick I learned thanks to this article on Push Button Paradise.

The problem is, how do you write XPath that matches one class in a multi-class element like

<div class='foo bar'>

? The standard XPath equality operator matches a full string, so

//div[@class='foo']

won't work. The solution is arcane but I promise it works:

//div[contains(concat(' ',normalize-space(@class),' '),' foo ')]

Note that there must be spaces on either side of the class name 'foo'.

Since this is quite a mouthful, I've extracted it into a helper method. Here it is in Java:

/**
 * Generates a partial xpath expression that matches an element whose 'class' attribute
 * contains the given CSS className. So to match &lt;div class='foo bar'&gt; you would
 * say "//div[" + containingClass("foo") + "]".
 *
 * @param className CSS class name
 * @return XPath fragment
 */
protected static String containingClass(String className) {
  return "contains(concat(' ',normalize-space(@class),' '),' " + className + " ')";
}

Alex ChaffeeAlex Chaffee
Can less leave the screen alone when it quits?
edit Posted by Alex Chaffee on Tuesday February 26, 2008 at 04:36PM

From the less faq:

blah blah blah ti/te blah blah blah -X blah blah.

Also, -R makes it show ANSI color. So I put this in my .bash_profile:

export LESS=-RX

Alex ChaffeeAlex Chaffee
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?

Other articles: