12:49 AM EDT Tuesday, July 7 2009
Are you using Ruby on Rails? Are you using Git? Do you have a need to track how long you spend on things? Then I have just the thing for you.
I threw together a quick rake task that gets all of your commits in a git repo and parses out the times and commit message from them. Then it formats them with the time and also the time interval between them. You can get the rake task to track your time from this gist.
The output will look something like this:
Fri, Jul 07 10:55AM 20m 49s Added toolbar for controllers using temp...
Fri, Jul 07 10:34AM 21h 52m Added support for using page templates i...
Thu, Jul 07 12:42PM 37m 57s LH#77, fixed issue with tests failing on...
Thu, Jul 07 12:04PM 12m 18s LH#67, added a limit option to the rende...
Thu, Jul 07 11:52AM 17m 30s Removed debug statement ...
Thu, Jul 07 11:34AM 19h 52m LH#66, added :path option to render menu...
Wed, Jul 07 03:41PM Added DSL for modifying portlet behavior...
Tue, Jun 06 02:05PM 18h 44m LH#119, multiple HTML fields on one bloc...
Mon, Jun 06 07:20PM 6h 21m Converted docs to textile ...
Mon, Jun 06 12:58PM Fix for LH#118, create directories in ge...
Sat, Jun 06 10:22PM Added support for other template handler...
Fri, Jun 06 04:49PM 0m 58s bump build ...
Fri, Jun 06 04:48PM 23m 11s Fix LH#106: Section not correctly loadin...
Fri, Jun 06 04:25PM 34m 25s Fix for LH#107, images were not showing ...
Fri, Jun 06 03:51PM 9m 48s Fix for LH#110, can't view usages of a p...
Fri, Jun 06 03:41PM 11m 12s Fix for LH#113, check to see if there is...
Fri, Jun 06 03:30PM 2m 52s Fixed LH#114, documentation typo ...
Fri, Jun 06 03:27PM 0m 38s bump build number ...
Fri, Jun 06 03:26PM 5h 38m Fix for LH#98, tags not getting updated ...
Fri, Jun 06 09:48AM 33m 14s Fixed LH#105, deleted portlets showing u...
It doesn't actually truncate the commit messages, I just did that here to make each one fit on a line. If the time interval is over 24 hours, it doesn't bother printing the interval, because you probably didn't actually work on that one commit for 37 hours straight. I've been thinking if you really want to track time this way then each time you sit down to start hacking on a project, you just make a minor change to the .gitignore or something and then commit it with a message like "started hacking on foo", so then when you commit your first chunk of actual work, you will know how long you spend on that.
Posted in Technology | Tags Rake, Git, Ruby | 2 Comments
12:37 PM EDT Sunday, June 28 2009
A few weeks ago I received my printed copy of Programming Clojure by Stuart Halloway in the mail. I had been a technical reviewer of the book so I was excited to see it finally in print. In case you haven't heard of it yet, Clojure is a programming language designed by Rich Hickey, a Lisp dialect, that runs on the Java Virtual Machine and is designed support concurrent programming.
Clojure has excellent documentation and Rich has posted several great videos of talks he has given that cover the rational for Clojure as well as an introduction into the major concepts. I highly recommend that you watch those videos if you haven't already because Rich does a great job explaining why concurrency is hard using the typical Object-Oriented model that we program in today and how the features of Clojure support a better model for concurrency. Whether you are programming in Java, C#, Erlang, Haskell, Python, Ruby, etc., you will probably be able to learn something from these talks, and plus Rich is just an interesting guy to listen to.
So after all that, you might be saying why do we need a book about Clojure? The answer is that although the documentation is good, it can be a little intimidating when first learning Clojure. For programmers with little or no Lisp or functional programming experience, figuring out how to do basic things the idiomatic way in Clojure can be a daunting task. Stuart's book does an excellent job filling this gap.
The book covers all the major feature of Clojure and is very up-to-date. As a reviewer I got to see the evolution of this book from revision to revision and it was amazing to me to see how much work Stuart put in. Chapters were often completely re-written to keep up with changes in the language that occurred before it stabilized in a 1.0 release. I think the final product greatly benefited from that work and is an excellent resource for learning Clojure. I encourage you to pick up a copy today.
Posted in Technology | Tags Clojure | 1 Comments
2:17 AM EDT Saturday, June 27 2009
So you're building the next big social networking website using Rails and like all the other hip kids you are going to need to allow your users to search for other users near them. The fancy term for this is "Proximity Search". For our search, we just want be able to find other people that are generally within some radius, like 5, 10 or 25 miles. For this, there is no need to geocode the address for each user in our database, we'll just use their zip code. So effectively, in our system, every user's location is just the center point of their zip code.
For starters we want to create a zip code model:
script/generate model zip code:string city:string state:string lat:decimal lon:decimal
That will create a model and a migration. You need to alter the migration to specify the precision and scale for the lat and the lon.
t.decimal :lat, :precision => 15, :scale => 10
t.decimal :lon, :precision => 15, :scale => 10
So to populate this database, luckily the good people over at the US Census Bureau have the data readily available for us. I've created a rake task to download and load that data into your zips table. Simply put the load.rake file from this gist into the lib/tasks directory of your Rails app.
So now when you run rake load:zip_codes you should see something like:
== Loaded 29470 zip codes in ( 1m 40s) ========================================
Next we need a table for our users. So let's generate a model and a migration:
script/generate model user
I'll save you the hassle of typing out all the fields at the command-line and just give them to you here. Paste this into the create_users migration that was generated:
t.string :username
t.string :email
t.string :password
t.string :password_confirmation
t.string :first_name
t.string :last_name
t.string :address
t.string :city
t.string :state
t.integer :zip_id
Next you need to hook up the relationship between the zip and the user. This is basic stuff, the zip has many users and the user belongs to a zip.
Now we need some users to play with. A great tool for this is Mike Subelsky's Random Data gem. I've already created a rake task that uses this gem to create some test user accounts. You call it like this:
rake load:random_users[10000]
The 10000 is the number of users we want the rake task to generate for us. Did you know you can pass command-line arguments to a rake task like that? Pretty spiffy. 10000 is a pretty good number because it gives us a fairly large dataset to work with and is still able to load in a reasonable amount of time. 10000 users finished in about 6 minutes and 30 seconds for me.
Next we need to setup our methods to do the querying. For this I basically used Josh Huckabee's Simple Zip Code Perimeter Search method, but re-worked it a little so we can use named scope with it. You can grab the code for both zip.rb and user.rb from the gist.
There are a couple of things we get here. First is a named scope to easily find zip codes. Looking at the output of the loading of the random users, the last one for me was Mr. Steven Moore of Koloa, HI, 96756. So let's see how many other people are in that zip code. Start up script/console and run this:
>> Zip.code(96756).users.count
=> 1
Hmm...I guess it's lonely in Hawaii. Let's find the zip code that randomly ended up with the most inhabitants:
>> Zip.count_by_sql "select zip_id, count(*) as count
from users group by zip_id order by count desc limit 1"
=> 18177
Ok, so that's the id of the zip record, not to be confused with the actual zip code. So let's find the first person in this zip code:
>> user = Zip.find(18177).users.first
=> #<User id: 1267, username: "cabel1266", ...>
I got Ms. Cheryl Abel of Bloomville, NY. So now for the big moment. What we really want to do is find everyone within 25 miles of Cheryl.
>> user.within_miles(25).count(:all)
49
Looks like Cheryl has 49 people nearby. Let's see who they are:
>> user.within_miles(25).all.each{|u|
?> puts "%.2f %20s, %2s, %5s" %
?> [u.distance, u.city, u.state, u.zip.code]}
0.00 Bloomville, NY, 13739
0.00 Bloomville, NY, 13739
0.00 Bloomville, NY, 13739
0.00 Bloomville, NY, 13739
0.00 Bloomville, NY, 13739
7.04 Worcester, NY, 12197
7.04 Worcester, NY, 12197
7.43 Maryland, NY, 12116
8.09 Meredith, NY, 13753
8.54 De Lancey, NY, 13752
8.71 Livingston Manor, NY, 12758
9.11 Roseboom, NY, 13450
9.88 Jordanville, NY, 13361
...
So there you have it! I'm still trying to work out some kinks with this and get it to work with count and will paginate, so if you have any suggestions, fork the gist, hack away and leave a comment. I'll update this post when I get count and pagination working.
Posted in Technology | Tags Rails, Ruby | 0 Comments
10:43 AM EDT Saturday, June 13 2009
Thanks to everyone who attended my talk yesterday at Ruby Nation about BrowserCMS. I've posted my slides online here. Unfortunately the demo part of the talk wasn't record, so I'll try to record a screencast of the demo. Look for that in the next few days.
If you did attend my talk, I would appreciate it if you take a minute to rate it.
Posted in Technology | Tags Ruby | 0 Comments
2:15 PM EDT Monday, May 11 2009
Some people think of JavaScript as that crappy language that runs inside of browsers. The truth is that the languages is not that bad, aside from a few warts (void/explicit return, global by default I'm looking at you), it's pretty nice. I think it's gotten a bad wrap for a few reasons.
First of all, the DOM. Before modern JavaScript libraries like jQuery and Prototype came along, developers were constantly pulling their hair out dealing with incompatibilities across different browser implementations of the DOM. Modern libraries have done a lot to normalize behavior across browsers and browser implementations have gotten better, but many developers still have bad memories of dealing with "JavaScript" back in the day. The truth was this wasn't really a problem in JavaScript the language, more so the DOM and browser implementations. If the language that Netscape put into the browser originally was Ruby, we would blame Ruby for all of these problems too.
Next, I think there was a whole class of Java developers upset that OO didn't work in JavaScript the way it did in Java. JavaScript wasn't considered a "real" OO language and was therefore inferior to Java. JavaScript has it's own way of dealing with OO and the sooner you understand how that works, the more comfortable you will be with JavaScript.
In the opposite way that many Java developers despised JavaScript, many Ruby developers, including Java developers converted to Ruby developers, started to appreciate JavaScript. JavaScript has anonymous functions just like Ruby has anonymous functions. Ruby makes ubiquitous use of anonymous functions through blocks. I think for many developers, Ruby was the first language they used that showed how useful anonymous functions can be. I think this is also the reason that you see some many Ruby developers interested other functional languages like Erlang, Haskell and Lisp.
Lastly, I think many developers don't see JavaScript as a general purpose language simply because it's trapped inside the browser. You can't run a JavaScript script from the command line just like you can run a Ruby, Python or Perl script.
Well, it turns out that last one isn't true and I want to show you how to get started writing some JavaScript as a "real" language, and specifically, a functional language.
The first thing you'll need is a JavaScript interpreter. There are two that I'm aware of, SpiderMonkey, the C-based JavaScript interpreter, and Rhino, the Java-based JavaScript interpreter. Let's go with SpiderMonkey.
First, download the tarball and untar it somewhere on your machine. I did that in the src directory in my home directory. Then you go into the js/src directory and run the make command. Here's what that looks like:
cd ~/src
wget http://ftp.mozilla.org/pub/mozilla.org/js/js-1.8.0-rc1.tar.gz
tar xvzf js-1.8.0-rc1.tar.gz
cd js/src
make -f Makefile.ref
Now you should have a directory like Darwin_DBG.OBJ, it will be named differently if you aren't on a Mac. Inside that directory there is a js program you can run. To make life easier, add src/js/src/Darwin_DBG.OBJ to your path. Now you should be able to just type js and be at an interactive JavaScript interpreter, with js> as the prompt:
$ js
js> print("Hello, World")
Hello, World
You can also run js -f my_awesome_script.js to run a script saved into a file. I have created a quick hack of a textmate command to be able to a JavaScript file. Click on the image below to see:

So now let's write a little JavaScript. First things first, open a file called hello.js in Textmate and put this into it:
print("Hello, World!")
If you've created the command properly, you should see Hello, World! printed out. If you aren't using Textmate, then you will have to figure out how to get your editor to run the file. Even if you can't do that, it's as simple as running js -f hello.js from the command line.
Now we can write some real code. What we want to focus on doing is functional programming. Most of the basic functions for functional programming aren't defined in JavaScript by default, but it's easy enough to write our own that handle the basic things. Note that this kind of functional programming is going to be functional in that we are going to pass functions to and return functions from functions, a.k.a higher-order functions, but we aren't going to focus on another popular aspect of functional programming, which is immutable data. Baby steps. :)
So the first thing we need is some kind of implementation of an iterator function, because we're not writing for loops. Let's do something like Ruby's each:
function each(f, arr) {
for(var i in arr) {
f.apply(null, [arr[i]])
}
}
What this does is take a Function and an Array and applies the Function to each element of the Array. To test this out, let's also add this line of code to test it:
each(print, [1,2,3,4,5])
You can see that we can pass the print function to each and have it print the numbers from 1 to 5. Ok, next up is map, which takes a Function and an Array and returns a new Array which contains the result of applying the Function to each element of the Array.
function map(f, arr) {
var result = []
each(function(e) {
result.push(f.apply(null, [e]))
}, arr)
return result
}
We can test that out with:
print(map(function(e){
return e * e
}, [1,2,3,4,5]))
This time, we are passing an anonymous Function as the first argument to the map Function. This Function takes one value and multiplies it by itself, better know as square. Now for our last trick, we will do the functional programming equivalent of hello world, fibonacci:
function fib(n) {
if(n <= 1) {
return n
} else {
return fib(n-1) + fib(n-2)
}
}
We can test this with:
each(print, map(fib, [1,2,3,4,5,6,7,8,9,10]))
Here's the entire code in one gist.
Now that JavaScript is being viewed as a "real" language, it's even got it's on conference! There's also some IRC channels devoted to JavaScript as well and of course, Stack Overflow. Happy JavaScripting!
Posted in Technology | Tags Javascript | 3 Comments