iPhone App: FriendFeed Touch

Posted by shane
on Tuesday, April 08

[This video demo has been removed]

Here’s my first iPhone app demo, a client for FriendFeed, created with the official SDK. It’s not the first one I did but it’s the only one that is presentable so far. I tried to keep the design true to standard iPhone apps without too much customization. In the future I plan adding the ability to post to FriendFeed, including directly posting photos taken with the iPhone camera. Currently, you can see your personal feed (once authenticated), your friends’ feed, and the public feed for everyone.

This is still in the initial stages. Lots more work has to be done, like making links clickable, and extracting out more specific data in the detail view. I also want to tailor the detail view based on the service. For example, Flickr feed items can be shown in a in an interface where you swipe between photos, and YouTube videos can be opened in the iPhone media player. And yes, the tab-bar images are just placeholders and will be changed to something more meaningful.

When released, this will probably go under a different name than FriendFeed Touch, since it has to be obvious that third-party apps aren’t affiliated with FriendFeed.

iPhone Development

Posted by shane
on Friday, April 04

For those who are following me on Twitter, it’s quite obvious that I’ve been playing with the iPhone SDK for the past couple of weeks. I’m taking the next 2-3 months off of client work just to build out some iPhone apps. I have list of 30+ ideas but will focus on a handful of them and hopefully get them ready by the time the App Store launches in June.

I’ll be posting some video demos of app prototypes soon. Stay tuned.

Spacer, Yes with an 'e', Released

Posted by shane
on Monday, February 11

DESCRIPTION

Ruby API for the MySpace Platform REST API

FEATURES/PROBLEMS

  • Implements v1.0 of the MySpace Platform REST API
  • Uses OAuth to securely authenticate with MySpace
  • Uses JSON for minimal transport footprint

PLAY

@myspace = Spacer::Client.new(api_key, secret_key)
user = @myspace.user('3454354')
puts user.interests.music
puts user.photos.first.caption

REQUIREMENTS

  • OAuth
  • ActiveSupport
  • Mocha (for testing)

INSTALL

  • sudo gem install spacer

DOCUMENTATION

Rubyforge: http://rubyforge.org/projects/spacer/ (submit bugs here)

RDocs: http://spacer.rubyforge.org/

Goolge Group: http://groups.google.com/group/spacer-ruby

NOTES

MySpace is still actively making changes to their API, so this is far from a 1.0 release. However, as of the day of this post, it implements all the features of their REST API.

Thanks to Ken Pelletier for coming up with the very creative name.

photo credits: bub.blicio.us and Scott Beale / Laughing Squid

Introducing YouTube-G

Posted by shane
on Monday, February 11

Walter Korman and I are proud to release youtube-g version 0.4.1.

youtube-g is a pure Ruby client for the YouTube GData API. It provides an easy way to access the latest YouTube video search results from your own programs. In comparison with the earlier Youtube search interfaces, this new API and library offers much-improved flexibility around executing complex search queries to obtain well-targeted video search results.

More detail on the underlying source Google-provided API is available at:

http://code.google.com/apis/youtube/overview.html

FEATURES

Aims to be in parity with Google’s YouTube GData API. Core functionality is currently present—work is in progress to fill in the rest.

USE

Create a client:

require 'youtube_g'
client = YouTubeG::Client.new

Basic queries:

client.videos_by(:query => "penguin")
client.videos_by(:tags => ['tiger', 'leopard'])
client.videos_by(:categories => [:news, :sports])
client.videos_by(:categories => [:news, :sports], :tags => ['soccer', 'football'])
client.videos_by(:user => 'liz')

Standard feeds:

client.videos_by(:most_viewed)
client.videos_by(:top_rated, :time => :today)

Advanced queries (with boolean operators OR (either), AND (include), NOT (exclude)):

client.videos_by(:categories => { :either => [:news, :sports], :exclude => [:comedy] }, :tags => { :include => ['football'], :exclude => ['soccer'] })

DOCUMENTATION

Rubyforge project: http://rubyforge.org/projects/youtube-g/

RDoc: http://youtube-g.rubyforge.org/

Google Group: http://groups.google.com/group/ruby-youtube-library?hl=en

INSTALL

  • sudo gem install youtube-g

Changes:

0.4.1 / 2008-02-11

  • Added 3GPP video format [shane]
  • Fixed tests [shane]

0.4.0 / 2007-12-18

  • Fixed API projection in search URL [Pete Higgins]
  • Fixed embeddable video searching [Pete Higgins]
  • Fixed video embeddable detection [Pete Higgins]
  • Fixed unique id hyphen detection [Pete Higgins, Chris Taggart]

0.3.0 / 2007-09-17

  • Initial public release

NOTES

Our previous library, youtube, has been deprecated. Please use youtube-g from now on.

Who can guess what the name youtube-g is in reference to? Hint: Like us, you probably used BBS’s before the days of the web, when wide adoption of TCP/IP was still a few years away.

Super Rewards Client API Released

Posted by shane
on Sunday, February 10

DESCRIPTION

A Ruby client for the $uper Rewards API by KITN Media, the Facebook monetization tool.

FEATURES

  • Aims to implement all the functionality of the $uper Rewards service
USE
offer_code = SuperRewards::Client.offers_display(:iframe, uid)
points = SuperRewards::Client.get_points(uids).first.user.points

REQUIREMENTS

  • API / Secret keys for the $uper Rewards service
  • Shoulda gem (for testing)

INSTALL

  • sudo gem install superrewards

DOCUMENTATION

Rubyforge: http://rubyforge.org/projects/superrewards/

RDocs: http://superrewards.rubyforge.org/

NOTES

I released this on December 17th, 2007, so the service may have changed since then. All the tests still pass as of the day of this post.

Thanks to Eugene from KITN Media for helping me with debugging and testing, and Jason Bailey for moral support.

YouCast: White-label video sharing site

Posted by shane
on Saturday, October 27

YouCast™ is a Ruby on Rails video sharing application that you host on your own servers. It can be rebranded easily for your company or used as is.

Main features:

  • Upload videos, images, and music via web or mobile phone via SMS/MMS attachment
  • Create a playlist of your videos, images, and music
  • Play your media in a Flash player
  • Get the code for the player to embed in any site (myspace, blog, etc)
  • Generates thumbnails for videos
  • Multi-user support with user login and user management
  • Export your playlist in XSPF/Spiff format

Tech specs:

  • Ruby on Rails application designed with RESTful methodology
  • Supports all major video and image formats, and mp3 for music
  • Encodes all video to Flash
  • Uses MMS2R for mobile media processing
  • XSPF/Spiff format used for playlists for maximum portability

What you get:

  • Full source code
  • 10 hours of free consulting, including help with installation and migration
  • Option to hire me for additional consulting

What can you do with YouCast™?

  • Create an internal video sharing site for your company or small business
  • Use it as a base for your own video-related site
  • Merge it with your existing site to add video and mobile media support
  • Re-create YouTube to impress your friends

How much does it cost?

  • YouCast™ will cost a yet-to-be-determined one-time fee, which includes free updates to that version. I will determine the cost once I get a better idea of demand.

Email me at the address in the About Me page if you are interested in seeing a demo and/or purchase.

Video Jukebox Facebook Application Launched

Posted by shane
on Wednesday, October 10

Video Jukebox finds music videos of your favorite music and lets you put them on your profile.

You must have the favorite music section in your profile filled out for Video Jukebox to figure out what you like.

This uses a pre-release version of youtube-g, a Ruby API for the GData version of YouTube’s API.

Thanks to Walter Korman for brainstorming the idea with me and Jesus Duran for help with the name.

MyFitBuddy.com Launched!

Posted by shane
on Saturday, September 01

MyFitBuddy.com logo

I’m pleased to announce the launch of MyFitBuddy.com, a workout tracking tool with social networking features. It allows you to log your workouts at the gym, sports training, your run in the park, or any other type of physical activity, and see the improvement over time. You can add your workout buddies as friends, and keep in touch with their workouts as well.

I mainly built this site for myself, as I wanted a super simple way to keep a record of my workouts and see graphs of my improvement. I thought it would be a great idea for a social site, as many studies have shown that people exercise more when they have a workout buddy or do it as part of a group. In MyFitBuddy.com, you will be motivated to exercise by seeing the activity of your friends and others on the site.

Some of the other interesting features on the site include user generated exercise information from Wikipedia, and videos of exercise form from YouTube. Soon I’ll be adding weight and calorie tracking, as well as the ability to SMS text in your workouts from your mobile phone. The site is currently completely free to use.

Give it a spin and help me knock off some bugs. I’d love to hear feedback and any suggestions.

Update: KillerStarups, a sort of digg for startups, is the first to review MyFitBuddy.com. If you are in a generous mood, please vote for it.

Pardon the Dust

Posted by shane
on Tuesday, August 14

I recently migrated this blog from Typo to Mephisto and have a few cleanup activities to perform. Markdown formatting has to be converted, sidebar stuff has to be added, and the design needs some minor tweaks to get things looking like how they did before. So sorry for the temporary ugliness.

I’ve been really busy working on client projects and trying to get my own startup launched, and therefore have been falling behind on the open source work. Thanks to those who sent me contributions to the youtube gem. I plan on making one more release before working on version 2. youtube2 will use the GData format since YouTube is changing the API to fit more with Google’s other APIs. It is slated for release later in the year.

> YouTube Gem 0.8.6 Released

Posted by shane
on Tuesday, June 12

This is mainly a bugfix release but also makes it easier to search for videos by category. Searching by category greatly helps in finding videos that are more relevant. You can now do:

videos = videos_by_category_and_tag(YouTube::Category::MUSIC, 'bush')
or if you wanted to:
videos = videos_by_category_and_tag(YouTube::Category::NEWS_POLITICS, 'bush')

For more details check out the CHANGELOG. Thanks to all the contributers, Walter Korman, Lucas Carlson, Rob Tsuk, and Thomas Cox.

Related posts:

Managing database.yml with Capistrano 2.0

Posted by shane
on Wednesday, May 30

Jeremy Voorhis posted a really great Capistrano recipe for managing database.yml which dynamically creates a database.yml file in your shared directory on setup, and symlinks your app’s database.yml once it’s deployed. This is great if you don’t version control your database.yml file for security reasons or working with multiple developers.

changes the syntax for task callbacks and gets rid of the useful render method.  However, using ERb, Ruby's built-in templating system, isn't much more difficult than using the old render method.  Here is Jeremy's script updated for Capistrano 2.0 using ERb and the new namespaced callback syntax.
require 'erb'

before "deploy:setup", :db
after "deploy:update_code", "db:symlink" 

namespace :db do
  desc "Create database yaml in shared path" 
  task :default do
    db_config = ERB.new <<-EOF
    base: &base
      adapter: mysql
      socket: /tmp/mysql.sock
      username: #{user}
      password: #{password}

    development:
      database: #{application}_dev
      <<: *base

    test:
      database: #{application}_test
      <<: *base

    production:
      database: #{application}_prod
      <<: *base
    EOF

    run "mkdir -p #{shared_path}/config" 
    put db_config.result, "#{shared_path}/config/database.yml" 
  end

  desc "Make symlink for database yaml" 
  task :symlink do
    run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml" 
  end
end

Until I get better syntax highlighting for this blog, check out the Pastie for the color version. For more info on whats new in Capistrano 2.0, check out Jamis’ preview and Geoff’s post. Also, props to Jamis for suggesting I use ERb directly.

Update: Updated code to use its own :db namespace instead of the default one. The database yaml file will be created by the default :db task, and the symlink will be created by the db:symlink task. Note how namespaces in Cap 2.0 allows us to have two symlink tasks, one in the deploy namespace and the other in db.

RailsConf 2007 Notes

Posted by shane
on Tuesday, May 29

All my notes from the RailsConf sessions are here. They don’t contain everything from the sessions I attended, just mostly things that were either new to me or were of some importance. O’Reilly put up most of the presentation slides on their site. Does anyone have notes on Uncle Bob’s Clean Code presentation? The one on the O’Reilly site is Java-specific. He didn’t do a Java talk at RailsConf did he?

If anyone was at Dante’s on Saturday night, and took pictures of the Exta Action Marching Band, I’d love to see them.

Giving You More Free Time

Posted by shane
on Tuesday, May 29

(and previously Hobo and the Sexy Migrations plugin) gave us automatic created\_at and updated\_at fields in our migrations, using the timestamps keyword.

How about bringing some of this sexiness to generators and taking it a step further? Well my patch was accepted and Rails now automatically adds timestamps to all generated migrations. So when you generate a model, scaffold, or resource, you will get timestamps for free. It is the equivalent of adding created\_at:datetime and updated\_at:datetime to your generators. So

script/generate model post title:string
will do the same thing as
script/generate model post title:string created\_at:datetime updated\_at:datetime

This is nothing significant but I hope it saves people a few keystrokes. If you don’t need timestamps you can always just delete the associated lines from your migration file and the fixtures. Just another example of Rails making it easier to do common things. This is currently only available in Edge Rails.

assert_difference Exposed

Posted by shane
on Wednesday, May 23

assert_difference is my favorite Rails test helper, and until a few weeks ago, was sitting in a helper class that I used to add to all my projects. It is now in Rails core. There were a few versions of it floating around, so it is good that we now have only one version to deal with.

What can you do with it?

One of the most common idioms I’ve run into in testing, is to count the number of records associated with a Model, create a new one, and make sure the count incremented by one. In the old days, we had to do this:

def test_should_create_user
  num_users = User.count
  user = create_user
  assert !user.new_record?, "#{user.errors.full_messages.to_sentence}" 
  assert_equal num_users + 1, User.count
end

Now we can do:

def test_should_create_user
  assert_difference 'User.count' do
    user = create_user
    assert !user.new_record?, "#{user.errors.full_messages.to_sentence}" 
  end
end

We saved one line, and got rid of repeating User.count. assert\_difference gets very close to my limit of too much magic, but I still like how it cleans up tests, especially if you use it with assert\_no\_difference as well. You aren’t forced to use it, just like you aren’t forced to scaffold.

How does it work?

Here is what the source looks like:

 # File vendor/rails/activesupport/lib/active_support/core_ext/test/difference.rb
22:       def assert_difference(expression, difference = 1, &block)
23:         expression_evaluation = lambda { eval(expression, block.binding) }
24:         original_value        = expression_evaluation.call
25:         yield
26:         assert_equal original_value + difference, expression_evaluation.call
27:       end

We pass in our expression 'User.count', the default difference of 1, and the block to assert_difference. We then evaluate the expression User.count and store it in a Proc object, since lambda converts a block to a Proc object. A Proc object allows us to store a chunk of code and evaluate it at a later time, while maintaining the context of its original definition. If we currently have 3 users, original\_value will have a value of 3 in line 24. Then we yield to the block and create the new user. Finally we will add 1 to the original\_value of 3 and re-evaluate the expression User.count by calling the Proc object. Since the new user was created, the User count is now 4 and the test will pass. Notice how eval is passed in the binding of the block. This causes the evaluated expression to run in the context of the block. I don’t think this makes a difference in this specific example, but it makes sense, since User.count is more associated with the block than the top-level binding of the test method.

Why are you telling me all this?

Of course you don’t need to know all of this to use assert_difference. I just thought it was a well written method that demonstrates practical use of Proc objects.

Update:

If you are using acts\_as\_authenticated or restful\_authentication, you will have to go in and change your model unit test to use assert\_difference 'Model.count' do instead of assert\_difference Model, :count do. If you are working on a new project and going to use aaa, use this patch to fix your tests.

Finally Made the Plunge

Posted by shane
on Monday, May 07

I did it. I’m no longer a full-time Java developer. At nearly 2.5 years of doing Rails part-time, I’m practically an old-timer. Many of you who started learning Ruby and Rails around the time I did have had much success doing freelance work. I’m happy to announce the creation of CrimsonJet, LLC., which will provide Agile, test-driven Rails development solutions.

I also hope to introduce a few web apps that I have been working on for the past few months and step up my open-source contributions. Check out my RailsConf plan and definitely get in touch with me if you want to meet up in Portland.

More real content coming soon. Watch this space! :)

Side note: I am not anti-Java or pro-Ruby (okay fine, maybe a little). I believe in using the right tool or mix of tools for the job. For far too long people have been using sledge-hammers to drive in push-pins.