faded picture of luke
a semi-random photo | click for the full photo gallery
click to browse photos
homepage navigation

Luke Melia

May 18, 2008

5 Tips for porting javascript from Prototype to jQuery

I've been really enjoying working with jQuery and the pattern of progressive enhancement.

But I haven't been enjoying supporting both Prototype/script.aculo.us and jQuery on in the same web app. It felt downright wrong to make my visitors download all that javascript.

So, this weekend, I set out to eliminate the last of the public-facing prototype-dependent code from weplay and gained some peace of mind along with a 50% reduction in javascript bytes required for the fattest page.

Here are a few tips based on my experience so far:

  1. Grab your inheritance. For porting components that rely on Prototype's Class.create mechanism, the most straightforward path is to leverage a jQuery-native implementation of the same concept. I used Dan Webb's $.klass code from his jQuery version of LowPro. I also came across the jquery-klass project, which looks like it would do the job.

    It feels a little dirty to bring Prototype's inheritance-based OO approach into jQuery -- the jQuery philosophy is more about embracing the prototype-based OO baked into the language. As part of a porting effort, though, I think this approach makes sense, at least for a step.

  2. Firebug is your friend. After I addressed the Class.create challenge, my approach was basically to repeatedly load the page in the Firefox and fix the first error that Firebug reported. By the time I worked through them all, dealing with a few remaining IE-specific issues was not too bad.
  3. Enjoy watching the code shrink. Here's a bit of code before and after the port...

    Before:

    JAVASCRIPT:
    1. this._arrow = document.createElement('img');
    2. this._arrow.border = 0;
    3. this._arrow.className = 'color_picker_arrow';
    4. this._arrow.src = this.settings.arrowImage;
    5. this._arrow.margin = 0;
    6. this._arrow.padding = 0;
    7. this._arrow.style.position = 'absolute';
    8. this._arrow.style.top = '0px';
    9. this._arrow.style.left = '0px';
    10. this._arrow.style.zIndex = 10000;
    11. document.body.appendChild(this._arrow);

    After:

    JAVASCRIPT:
    1. this._arrow = jQuery(document.createElement('img'))
    2.                       .attr({border: 0, src: this.settings.arrowImage})
    3.                       .addClass('color_picker_arrow')
    4.                       .css({margin:0, padding:0, position:'absolute', top:0, left:0, zIndex:10000})
    5.                       .appendTo(document.body);

  4. Grok the jQuery event model. jQuery has excellent support for working with events, but it is different from Prototype's. In particular, Prototype's bindAsEventListener method, which changes what this refers to in your event handler, is nowhere to be found. Figure out how to use closure to attain the same thing and revel in jQuery's simpler approach to "this".
  5. Consider jRails. If you're working in Rails and using the link_to_remote methods, consider jRails as a stop-gap measure to help you show Prototype the door. I say "stop-gap" because link_to_remote does not produce unobtrusive javascript and does not tend to support real progressive enhancement.
  6. Bonus Tip: Learn to write jQuery plugins. While not strictly required by my porting efforts, I wrote a few plugins along the way to help out. Writing a plugin sounds like it could be a big deal, but writing a jQuery plugin is very straightforward, and it's an addictive way to package up functionality as well as get more comfortable with the jQuery philosophy.

Good luck, and share your porting stories!

April 27, 2008

GoRuCo 2008

Gotham Ruby Conference was yesterday at Pace University. It was a great day - kudos to the organizers. If you missed it, check out the video from Confreaks when it is posted.

My badge from Gotham Ruby Conference 2008

UPDATE: A few more conference pics, courtesy of Sebastian, including some of the afterparty/hackfest, where Jeanhee & Chiara came out to meet the ruby geeks!

April 26, 2008

Finding code to hurt

After listening to Ryan Davis' inspiring talk, "Hurting Code for Fun & Profit" at GoRuCo today, I wrote this rake task to figure out what code to hurt. It looks though your git log, and takes the 15 .rb files in your Rails' app/ directory and runs them through flog, so you can see which are the most complicated.

RUBY:
  1. namespace :analyze do 
  2.   namespace :commits do
  3.     desc 'Flog the most commonly revised files in the git history'
  4.     task :most_changed_files do
  5.       counts = Hash.new(0)
  6.       IO.popen("PAGER=cat git log --name-only --pretty=oneline 2>&1") do |pipe|
  7.         while (!pipe.eof) do
  8.           line = pipe.readline
  9.           next unless line =~ /^(app|lib).*\.rb$/
  10.           counts[line.chomp] += 1
  11.         end
  12.       end
  13.       counts.sort_by{|item| item.last}.reverse.first(15).each do |item|
  14.         flog_score = `flog -s #{item.first}`.to_f.round
  15.         puts "#{item.first} (in #{item.last} commits) (Flog: #{flog_score})"
  16.       end
  17.     end
  18.   end
  19. end

Install it with sake from here.

UPDATE: If you're interested in watching Ryan's stellar talk, it will be up on Confreaks soon, or you can try the RubyConf edition of the talk.

April 22, 2008

the not-so-interesting life of my terminal

lmelia$ history 1000 | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | sort -rn | head
184 git
122 script/story
64 rake
26 sudo
12 dig
11 cap
9 script/rstakeout
9 sc
8 ./script/story
5 history
March 27, 2008

weplay.com has launched

The startup I work for, weplay, opened our beta to the public on Tuesday night, just a few hours ahead of a New York Times article about us. It's been an insane couple of weeks leading up to this launch, and I'm happy it's behind me, though it was fun and I really enjoyed working so intensely with my team.

We got covered on ABC News today, and have spawned a bunch of blog posts and conversations. Our "official" launch is in a few weeks.

If you have any connection to youth sports, I hope you'll consider using the site to help organize your team and activities!

Tracks 1.5 is out

We released Tracks 1.5 today. Tracks is the open source Rails app for implementing the Getting Things Done system. I contributed heavily to this app in the too-long time since the last stable release. Big kudos and thanks go to Reinier Balt in the Netherlands, who contributed some great statistical visualizations and generally ran the project the past few months while bsag and I have been busy with out professional commitments.

Anyway, lots of great changes since 1.043. Check it out and let us know what you think.

March 10, 2008

capistrano task autocompletion for bash

Remembering all those capistrano tasks can be tough for the sleep-impaired startup employee.... Help yourself out with this autocomplete script:

RUBY:
  1. #!/usr/bin/env ruby
  2.  
  3. # Save this somewhere, chmod 755 it, then add
  4. #   complete -C path/to/this/script -o default cap
  5. # to your ~/.bashrc
  6. #
  7. # If you update your tasks, just $ rm ~/.captabs*
  8. #
  9.  
  10. exit 0 unless /^cap\b/ =~ ENV["COMP_LINE"]
  11.  
  12. def cap_silent_tasks
  13.   if File.exists?(dotcache = File.join(File.expand_path('~'), ".captabs-#{Dir.pwd.hash}"))
  14.     File.read(dotcache)
  15.   else
  16.     tasks = `cap -qT`
  17.     tasks = tasks.select{|task| task =~ /^cap/ }.join
  18.     File.open(dotcache, 'w') { |f| f.puts tasks }
  19.     tasks
  20.   end
  21. end
  22.  
  23. after_match = $'
  24. task_match = (after_match.empty? || after_match =~ /\s$/) ? nil : after_match.split.last
  25. tasks = cap_silent_tasks.split("\n")[1..-1].map { |line| line.split[1] }
  26. tasks = tasks.select { |t| /^#{Regexp.escape task_match}/ =~ t } if task_match
  27.  
  28. # handle namespaces
  29. if task_match =~ /^([-\w:]+:)/
  30.   upto_last_colon = $1
  31.   after_match = $'
  32.   tasks = tasks.map { |t| (t =~ /^#{Regexp.escape upto_last_colon}([-\w:]+)$/) ? "#{$1}" : t }
  33. end
  34.  
  35. puts tasks
  36. exit 0

February 15, 2008

Valentine’s Dinner 2008

It was my year to cook Valentine's Day dinner this year. Working web startup hours meant I couldn't be as ambitious as in years past, but I tried to make up for it with creative presentation. And an artichoke theme(!).
Valentine's Dinner 2008

The menu:

* A garden love plate, with avocado, red pepper hearts, cucumber and marinated artichoke hearts
* a 5-grain heart-shaped seeded bread with artichoke Kalamata olive hummus, an Italian spiced artichoke spread, and olives
* ravioli, stuffed with artichoke and ricotta, topped with a dab of rich basil pesto

January 6, 2008

What I Do - a meme perpetuated

I'm not too into these blog memes, but I like Mike Moore, who "passed the pain" to me in his own What I Do post.

My Day Job

I recently left my job of almost 8 years at Oxygen, the cable television network for women. I'll quote and hack apart my goodbye email to give you a sense of it:

I fell in love with Oxygen when I saw all those baby fists get thrown up in the air on TV in 2000.

See the last paragraph of this for context. At the launch party two weeks after I started, I danced on stage with Luscious Jackson.

I had just started here as a web developer and didn’t know much about television, media… or software development, looking back.

I started with some Perl CGI, HTML & Javascript skills and better instincts than I realized I had. At Oxygen, I learned VB, Java and C#, SQL, and lots more geekery. I learned Ruby on my own and then introduced my team to it. I learned Agile by encouragement (thanks, Ken), reading, and trial and error, including a solid year pair programming with the same guy. (Thanks, Kris.)

I’ve grown a ton over my time here, both professionally and personally. I was a grown child when I started, and I’m leaving today a man.

What does it mean to have become a man while working at a women’s media company? I’m sure I’ll hash it out in therapy in a few years. Just kidding – it means most importantly that I’ll be a better father and husband to my daughter and wife (who I met here…).

The emotional growth that happens between 23 and 31 is pretty substantial, and Oxygen seemed to have grown up on about the same schedule.

Thanks to everyone who I had the pleasure to work with over the last 8 years, and in particular, my team and department, & Gerry: you are collectively responsible for the best moments of my professional life so far. Much love & respect.

I started off as a Web Developer, and got promoted to Senior Web Developer, which changed into Senior Software Developer after the world changed it's mind about the Web in 2001. Then Software Development Manager, and then Director of Software Development. It was all very rewarding, but best was the last year and half, when I hired a top notch team of developers and collaborated closely with our visionary CEO, putting everything we had learned about Agile into practice.

Mike tagged me because he wanted to know what I was going to do next, and all I've talked about is what I did the last 8 years. Sorry, Mike.

I'm involved with a startup that is not publicly discussing what we're doing quite yet. We're past the phase of totally secretive, so if you know me and ask me, I'll probably give you an overview.

I can say that I'm working my butt off, being challenged in lots of new ways and loving it.

My "Contribution"

I'm following Mike's format, because I'm a lazy blogger. So now I have a section about contribution to fill out.

The truth is, I'm kind of a selfish guy. I mean, we give a nice chunk of change to non-profits who we feel are doing important work. But everything else I do, I do either because I love it and enjoy it, or I can't figure out how to avoid it.

Some of those activities could pass as "Contribution," if you discount the impure motivations.

I helped organize GoRuCo last year, New York City's first Ruby conference. This year, I'm less involved, but still trying to help out. I attended the first session with my 2 year old daughter, and basically, we were more of a hindrance than a help.

I'm an active contributor to an open source project called Tracks, which helps people get stuff done GTD-style. Since I started working on it, a whole host of commercial products have been released.

My Night Job

Maybe following Mike's format is not such a good idea. I used to pick up freelance work here and there. A couple of projects for my friends the Sanborns helped me learn Rails. Anyway, I've cut out all of my "night job" because my day job is now my night job, too.

Other Stuff

I'm involved in the ALT.NET community, though I'm feeling like a stranger in a strange land now that I am working in Ruby and on my Mac 100%.

I prioritize my health and fitness pretty highly. A big piece of that is eating a mostly vegetarian diet full of all the stuff that is not fad-of-the-week but obviously a good idea, like organic fruits and veggies, whole grains and avoiding refined sugar. The other side is exercise: I use my inline skates as transportation most places in Manhattan, including my daily commute. I'm an avid beach volleyball player, and play a few times a week at my gym, which has an indoor sand court. By the way... playing sand doubles in your boardshorts when there is snow outside -- that is luxury.

My Family

I come from a big wonderful family. My siblings and I have managed to find the positive aspects of my parents' divorce -- great relationships with each of them as well as their 2nd spouses. My wife and I have loved becoming parents ourselves -- Chiara is a constant source of wonder and joy.

Who Next?

Pain begets pain it seems... I'm tagging:

December 29, 2007

pdf-storycards 0.0.1 Released - my first gem

I just released pdf-storycards 0.0.1, my first gem! Thanks to Ryan Davis for hoe, which made it a much easier process, and to Jacob Harris & Geoffrey Grosenbach for teaching me how to use hoe in their PDF and blog post respectively.

pdf-storycards version 0.0.1 has been released!

* <http://rubyforge.org/projects/pdf-storycards/>

## DESCRIPTION:

Provides a script and library to parses stories saved in the RSpec
plain text story format and saves a PDF file with printable 3"x5"
index cards suitable for using in agile planning and prioritization.

## FEATURES/PROBLEMS:

* Create a PDF with each page as a 3x5 sheet, or as 4 cards per 8.5 x 11 sheet
* Currently reads stories from a single file.
* TODO: Take a directory and find all stories in it
* TODO: Take stories via STDIN
* TODO: Improve test coverage

## SYNOPSIS:
/usr/local/bin/stories2cards /path/to/stories.txt

or

StorycardPdfWriter.make_pdf("/tmp/stories.txt", "/tmp/storycards.pdf", :style => :card_1up)

## REQUIREMENTS:

Changes:

## 0.0.1 / 2007-12-27

* Initial release

* <http://rubyforge.org/projects/pdf-storycards/>

LukeMelia.com created 1999. ··· Luke Melia created 1976. ··· Live With Passion!
Luke Melia on software development freelance web development how to contact me Luke Melia, Software Developer letters and more from my travels photo gallery personal philosophy