just a dude abiding

Android scripting for fun and profit

Okay the last part isn’t exactly likely given that you can’t directly package a script application as an APK. I doubt you’ll be making much “profit” from it anytime soon. Regardless, ASE support is a great boon to hackers, and allows for a whole new level of customization of your phone.

I decided to organize and prune my book collection the other day, and remembered reading a brief tutorial on scanning barcodes using Python and the ASE. I thought this would be a great chance to learn a bit about ASE and Android in general. Here’s the basic steps I took, hopefully they’ll be of some use to someone.

Despite the instructions which recommend starting with the ASE install, I found it easier to download the python interpreter to the phone first. http://code.google.com/p/android-scripting/wiki/InstallingInterpreters

Then install the most recent version of ASE to your phone (either using the QRCode at http://code.google.com/p/android-scripting/ or downloading the APK straight to your phone).

The ASE site has a fair bit of sample code, so I took the barcode sample and made a few adjustments that will let me track my book collection easier.

The script is admittedly pretty simple: read the barcode, check to make sure we got an actual result, then send it on to the webserver. Make sure to fill in the proper server name before you use the code. For my purposes I was going to be scanning a bunch of books all at once, so I put it in an infinite loop so I didn’t have to relaunch it for every book. To exit the loop simply hit the “back” button on your phone.

Now that we can scan the barcodes locally, we need to do something with them on the server side.

Above is a simple PHP script that will write the ISBNs to a text file. The most important part is parseUPC method, which converts a UPC barcode to an ISBN. If the barcode isn’t formatted as an ISBN it’s left in it’s original format.

And that’s basically it. Drop the PHP code on your web server, make sure the path and server name match in the python script, and you’re off and scanning!

Add in some queries to Amazon ECS or Google Books, and you’re halfway to your own personal version of LibraryThing.

Migrating from Sinatra::Test to Rack::Test

After seeing the release of Sinatra 0.9.2 mention (again) that Sinatra::Test would vanish by 1.0, I decided to get with it and move to Rack::Test. It was really pretty painless and my tests were forced to become a bit more explicit (still not convinced I really LIKE this). Since I found a few bits of fun along the way I thought I’d share.

I use Test::Spec so some of this may not apply, or may look a bit ‘off’ to you, but I think the point should be clear.

Anywhere you’re using @response/response, or @request/request you need to change to last_response or last_request.

Anywhere you were checking a redirect URL, you now need to check for a full hostname not a relative path. The default hostname for requests is http://example.org.

Also be aware that that Rack::Test tracks cookies. I haven’t looked heavily into what that will mean in practice, but if you were manually twiddling the cookies around, you need to look into the CookieJar and how it may affect what you’re doing.

That’s all that I ran into when moving my tests over. What did you find?

Pushing an entire Sinatra app into a Rackup file

The title pretty much says it all. This is a pretty pointless thought experiment inspired by this post by the guys at devver. They came up with a simple way to put both a sinatra application AND it’s tests into a single file. Nothing TOO crazy, but definitely cool.

Not satisfied with simple and effective, I went to complete overkill. I put together a way to not only embed a sinatra app and it’s tests into a single file, but for that file to be a rackup compliant file. Also, as a pointless but neat bonus, I forced the tests to run before successfully before the app can start. What’s the point? I don’t really know, but it seemed cool so I thought I’d share. And no, I’m not using this anywhere, I don’t think.

Extracting subdomains in Sinatra

As part of my continuing education in Sinatra, I decided to learn how Sinatra handles subdomains. It turns out that neither Rack, nor Sinatra seem to have any native subdomain handling code. So I took a quick stab at it.

The easiest method I could come up with was simply to re-open the Rack::Request class and add a subdomain method. The method implementation is adapted from Rails, except with Rack style caching.

To test this you will need modify your hosts file with something like: sample.test.dev

Then after running the above script, use the url http://sample.test.dev:4567. You should see just the word “sample” as the output.

I’m not sure that this is the best method, but seems to work for now.

Multiple Sinatra .90 applications in one process

I recently started work on a new application based on the current Sinatra edge code. I’m not new to Ruby, but I’m definitely new to Sinatra. So I thought I’d start a small series of posts based on the things I find either interesting, or difficult. Today’s post probably falls into both categories.

One of the things that drew me to Sinatra was the absolute simplicity in it’s approach to web apps. One of the keys to this simplicity is leaning heavily on Rack. Rack provides a variety of what they call Middleware, small bits of code that insert themselves into the request/response process, handling things like caching, session management, or even JSON parsing.

Now that we’re through with the background, let’s hit my find of the day.

As I started working I found that I felt more comfortable with my application being defined inside of a class instead of just floating around in files (the default method of building a Sinatra app). It turns out this is one of the lesser documented parts of the new Sinatra .9 release. (In all fairness this seems to be due to the fact that a lot of the infrastructure that allows this to happen is either brand new, or heavily refactored in this release)

It turns out I could do a whole lot more, such as making each portion of my application it’s own standalone Sinatra application, then using some Rack Middleware to mount each portion into it’s own URL space. Why would I want to do this? I think it will make for a very extensible, and potentially scalable infrastructure. All of that aside, let’s see HOW you do this!

For starters you need to define a class for your application to live in.

There’s a simple set of classes that function as little application stubs. Notice that we require sinatra/base instead of just sinatra. This is one of the new things in the .9 release. By requiring just sinatra/base we get all of the sinatra goodness, without any of the intrusive top-level methods. Since we’re going to encapsulate our application in our own classes, this is perfect for us! For these little applications to fully work we’ll have to define some views, which I’ll leave up to you (or you can check the full project files at GitHub at the end of this post).

Now here is where we define our Rack magic. We’ll create a config.ru file, which uses what’s called RackUp syntax to specify some options for Rack compliant servers to use to configure and start our application. For this example I’m using Thin, but you can use whatever you prefer!

Up until line 15 it’s pretty standard boilerplate for getting any Sinatra application going, but after that is where things get interesting. Rack automatically includes the URLMap Middleware which gives us access to the ‘map’ method. This method takes two parameters, a URL prefix, and a block specifying that applications configuration. We could do any configuration we can do at the top level inside of that block, giving some pretty powerful per-application configuration.

And that’s it! Start it with thin -p 4567 -R config.ru start, or the equivalent. You should be able to navigate to / and see your first index, and /blog and /blog/list respectively to see their content. Notice how our Blog class never uses the /blog URL prefix anywhere. This would let us pass the exact same class into a different application, at a different URL space, and the application wouldn’t be any wiser for it.

Want to see the whole thing already setup? Check out the GitHub link below for the full sample application.