A Datamapper is remixable example

I struggled a bit this afternoon getting Datamapper’s dm-is-remixable plug-in as there aren’t too many posts out there and some are out of date. Hopefully this quick overview will spare you my pain :)

Many sites allow you to comment on blog posts, images, videos, status, etc. having one comments table with post_id, image_id, etc. as with a One-to-Many relationship leads to a giant table of unrelated (other than by user_id) data. In my opinion it’s better to have a table for each e.g. post_comments, image_comments, etc. Enter dm-is-remixable.

Step 1: Install

We’ll install dm-is-remixable and friends. Open up a terminal and enter:

sudo gem install do_sqlite3
sudo gem install datamapper
sudo gem install dm-migrations
sudo gem install dm-is-remixable

Step 2: Setup

Create a new file called remixable.rb we’ll user this file from now on. First enter the required gems and set Datamapper’s log and sqlite file.

require 'rubygems'
require 'dm-core'
require 'dm-migrations'
require 'dm-is-remixable'

# setup

DataMapper::Logger.new($stdout, :debug)
DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/remixable.db")

Step 3 Define the Models

We’ll create four models, one module and three classes. User, Post, and Image are classes, and Comment will be a module. The relationships are a user has many posts and images, posts and images belong to a user, nothing new yet, and post and image remix many comments for a user. What? This is the same as saying a post has many comments and said comment(s) belong to a user.

# module and classes

module Comment
  include DataMapper::Resource

  property :id, Serial
  property :comment, Text

  is :remixable
end

class User
  include DataMapper::Resource

  property :id, Serial
  property :username, String

  has n, :images
  has n, :posts
end

class Post
  include DataMapper::Resource

  property :id, Serial
  property :title, String
  property :body, Text

  belongs_to :user
  remix n, :comments, :for => 'User'
end

class Image
  include DataMapper::Resource

  property :id, Serial
  property :path, String

  belongs_to :user
  remix n, :comments, :for => 'User'
end

Step 4: Migrate

Next we’ll finalize our models and run auto_migrate to create the tables. During this step Datamapper, via is remixable, will generate two anonymous model classes PostComment and ImageComment. Five tables will be created users, posts, images, post_comments, and image_comments.

# lock and load

DataMapper.finalize
DataMapper.auto_migrate!

Step 5: Do Something

The last step is to create some dummy data to test out our models. We’ll create two users ‘foo’ and ‘funk’, foo will create post and ‘image’ and ‘funk’ will comment on them. The last two lines show how to access post and image comments for a user.

# go!

foo = User.create(
  :username => "foo"
)

funk = User.create(
  :username => "funk"
)

post = Post.create(
  :user_id => foo.id,
  :title => "My great post",
  :body => "This is my great post"
)

post_comment = PostComment.create(
  :user_id => funk.id,
  :post_id => post.id,
  :comment => "ballz I say!"
)

image = Image.create(
  :user_id => foo.id,
  :path => "/some/image/path"
)

image_comment = ImageComment.create(
  :user_id => funk.id,
  :image_id => image.id,
  :comment => "you look funny!"
)

puts funk.post_comments[0].comment
puts funk.image_comments[0].comment

That’s it!

A Sinatra before only filter

In a Sinatra application you can use the ‘before’ filter to run something before every each event.

before do
  puts "I will run all the time..."
end

Here’s a module that will allow you to run code only before certain routes:

module Sinatra

  module BeforeOnlyFilter
    def before_only(routes, &block)
      before do
        routes.map!{|x| x = x.gsub(/\*/, '\w+')}
        routes_regex = routes.map{|x| x = x.gsub(/\//, '\/')}
        instance_eval(&block) if routes_regex.any? {|route| (request.path =~ /^#{route}$/) != nil}
      end
    end
  end

  register BeforeOnlyFilter

end

Use it like below, note that you insert ‘*’ for routes that use variable placeholders like ‘:id’…

before_only(['/post', '/comment/*/user/*']) do
  puts "I will only run before the routes '/post' & '/comment/*/user/*'..."
end

Getting Netbeans 6.9 to work on OS X 10.5.8

netbeans69osxerror

After downloading and installing Netbeans 6.9 I launched the app. It bounced a couple of times in my dock as dreams of exciting new features danced in my head. Then… nothing, well not quite nothing, I received a message informing me that:

“Java 6 Standard Edition or newer required. Cannot run on older versions of Java than Java 6 Standard Edition. Please install Java 6 Standard Edition or newer or use –jdkhome switch to point to its installation directory.”

How to solve this issue:

Step 1. Figure out which version of Java you have

Open Terminal.app and enter:

java -version

You’ll most likely see the following:

java version "1.5.0_24"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_24-b02-357-9M3165)
Java HotSpot(TM) Client VM (build 1.5.0_24-149, mixed mode, sharing)

Obviously this is the wrong Java version since Netbeans is asking for Java 6 (aka Java 1.6).

Step 2. Get Java 1.6

However if you head over to Oracle you’ll find downloads for Linux and Windows but none for Mac. Why has the mighty Oracle deemed you unworthy of the latest Java?

Because you already have it! Your Mac is just not setup to use it.

Go Back to the Terminal and enter the following:

cd /System/Library/Frameworks/JavaVM.framework/Versions; ls;

You’ll get a list of all the Java versions available.

1.3		1.4		1.4.2		1.5.0		1.6.0		Current
1.3.1		1.4.1		1.5		1.6		A		CurrentJDK

Step 3. Configure Netbeans

The hint to get Netbeans working is in the error message; “or use –jdkhome switch to point to its installation directory”.

In the Finder browse to the NetBeans 6.9.app (in Applications/NetBeans/). Apps on OS X are really just packages so you can explore and edit their contents. Right-click (or control-click) on the app and select ‘Show Package Contents’ this will open a new Finder window. Then browse to Contents/Resources/NetBeans/etc and open ‘netbeans.conf’ in a text editor. Uncomment (remove the pound sign from) the line that starts with ‘#netbeans_jdkhome’ and set it to point to your Java 1.6 home as below:

netbeans_jdkhome="/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home"

Save the file.

That’s it!

Try launching the NetBeans 6.9 app again, it should now work.

The post in which I run back to my iPhone

Dear Leader Jobs,

I am sorry I wrote my last post. I’ve spent a couple of weeks with an Android Phone (Nexus One) and to paraphrase Llyod Bentsen “Android, I know the iPhone and you sir are no iPhone”. It’s not that Android is unusable, it’s just rough around the edges. Most of the tasks I do on my iPhone were harder or less intuitive on an Android phone.

The OS is the killer app, it’s why I use a Mac, and it’s why I’ve run back into the arms of my beloved iPhone.

Apple 4 Ever,
Alastair

Bad Apple

Update: It seems apple has approved Flex/Flash based apps made with OpenPlug’s ELIPS Studio have been approved. So Apple is just targeting Adobe. Don’t know if that makes it better or worse?

Apple has been doing some crazy stuff lately. I went with an iPhone over an Android phone because of my investment in Apple hardware and software. Maybe it’s time to ’switch’, I’ll at least be following Lee and not be buying anything through iTunes anymore.

Personally I will not be giving Apple another cent of my money until there is a leadership change over there. I’ve already moved most of my book, music, and video purchases to Amazon and I will continue to look elsewhere. Now, I want to be clear that I am not suggesting you do the same and I’m also not trying to organize some kind of boycott. Me deciding not to give money to Apple is not going to do anything to their bottom line. But this is equivalent to me walking into Macy’s to buy a new wallet and the salesperson spits in my face. Chances are I won’t be buying my wallets at Macy’s anymore, no matter how much I like them.

Did you know you can get free engraving on a Nexus One? The unlocked version can run on AT&T :)

Flex/Flash Builder will soon be the easiest way to develop mobile apps

OpenPlug just released the latest beta version of their ELIPS Studio, which adds Android support. Currently ELIPS Studio is Windows only but in a month they will add OS X support, yay!

The latest version of ELIPS Studio has just been released. It brings the ability for developers to create native mobile apps in ActionScript and Flex for mobile devices running Google’s Android platform.

With this new release, developers can now address all major smartphone platforms (iPhone, Android, Symbian, Windows Mobile) from a single code base using powerful web 2.0 languages and technologies from Adobe.

The next version of ELIPS Studio will bring the support of MacOSX as desktop development platform.

If I were Adobe I’d buy French OpenPlug toute suite and turn ELIPSE studio into AIR Mobile (or Mobile AIR).

HTML5 vs Flash !

Lee Brimelow caught some major heat this week from the Apple f-boys and the open source zealots over his post on the iPad’s lack of Flash. The biggest complaints against flash seem to be CPU usage spikes and/or annoying animation. Not to worry HTML5 has both those covered :P

html5 goes boom

Try it for yourself, my macbook sounds like it’s getting ready for lift off on that page.

I can’t wait for the animated HTML5 ads that can’t be blocked without turning off Javascript :)

Poor coding is poor coding be it in Flash or Javascript. The blame doesn’t lie with the platform but with ignorant developers who write inefficient code.

Automate font compiling for Flex with Ruby

I came up with this solution when I had to compile over 100 fonts into SWF files for a recent project. Doing this by hand would have been madness so I wrote a ruby script and a shell script to automate the process.

Step 1: Setup

The directory structure I used was as follows.

convert.rb (the ruby script)
compile.sh (the shell script)
fonts/ (a directory for font files - .ttf and .otf)
as/ (a directory for the generated ActionScript)
swfs/ (a directory for the compiled swf files)

Step 2: Prep fonts

Ok told a tiny white lie when I said it was all automated. Since (to my knowledge) you can’t inspect a font file to determine if it’s normal, regular, bold, italic, or bold italic (the weights and styles Flex understands) you’ll have to set up a naming convention that the Ruby script can parse. You’ll be using the font name to create an ActionScript class so it should also be a legal name.

Here’s an example using the Arial family.

Arial.ttf (regular fontWeight and normal fontStyle)
Arial_Italic.ttf (regular fontWeight and italic fontStyle)
Arial_Bold.ttf (bold fontWeight and normal fontStyle)
Arial_BoldItalic.ttf (bold fontWeight and italic fontStyle)

Step 3: The Ruby Script

require 'find'

# delete any previous as
Find.find( 'as' ) do | as |
  if File.extname( as ) == ".as"
    File.unlink as
  end
end

# generate new as
Find.find( 'fonts' ) do | font |
  if File.file?( font )
    # extension name
    ext = File.extname( font )
    # is font
    if ext == ".ttf" || ext == ".otf"
      # file name
      full_name = File.basename( font )
      name = File.basename( font, ext )
      # font weight and style
      font_weight = ""
      font_style = ""
      if full_name.include? "_Bold" + ext
        font_weight = "fontWeight='bold',"
      end
      if full_name.include? "_Italic" + ext
        font_style = "fontStyle='italic',"
      end
      if full_name.include? "_BoldItalic" + ext
        font_weight = "fontWeight='bold',"
        font_style = "fontStyle='italic',"
      end
      # generate as
      f = File.new("as/#{name}.as",  "w+")
      f.write "package
      {
        import flash.display.Sprite;

        public class #{name} extends Sprite
        {
          [Embed(source='../fonts/#{full_name}', fontName='#{name}', #{font_weight} #{font_style} unicodeRange='U+0000-U+00FF,U+2100-U+214F')]
          public var Font:Class;
        }
      }"
      # some helpful output
      print ',"', "#{name}", '"'
    end
  end
end

In TextMate you can open this script and hit Command-R to run it, or run it via the command line ‘ruby convert.rb’. Once the script runs you’ll have generated ActionScript files in the ‘as’ directory ready to be compiled.

Step 4: The Shell Script

echo "<h2>Fonts Custom Compile</h2>";
echo "<code> Started @ `date "+%H:%M:%S"`</code><br />";

for i in `cd as/; ls *.as`; do
  swf=`echo $i |  awk -F. '{print $1}'`
  swf="$swf.swf"
  "/Applications/Adobe Flex Builder 3/sdks/3.3.0.4589/bin/mxmlc" -file-specs="as/$i" -o="swfs/$swf" -managers="flash.fonts.AFEFontManager" 2>&1;
done

You’ll need to customize the script for your Flex SDK location, mine is at "/Applications/Adobe Flex Builder 3/sdks/3.3.0.4589/bin/mxmlc". The hidden gem in there is -managers="flash.fonts.AFEFontManager", about 90% of fonts will compile without it but the rest were blowing up until I added that argument.

Again with TextMate you can run the script with Command-R. Each font will take about five seconds to compile, my set of over 100 fonts took over ten minutes :)

That’s it! The SWFs are compiled and ready to be runtime loaded into a Flex app. Creating the ActionScript for 100+ fonts would have been a multi-day process but with a little scripting it took less than an hour.

PureMVC for JavaScript Released

I won’t be dropping my beloved Flex anytime soon but it’s nice to know if you must do JavaScript (and let’s be honest Flex isn’t always the best tool) you can at least use a familiar framework.

Check out PureMVC for JavaScript.

Paperclip for easy Rails file uploads

It’s my first post in months*, so it must be worth it right?

Rails Inside has the details on Paperclip as an alternative file upload/association plugin, I’ve tried them all and paperclip covers all your file upload bases.

*I’ve been busy with Fatherhood 101 and my new job as a Flex Dev at Captial Group (the largest company you’ve never heard of).