Using the Nginx Upload Progress Module with Safari
February 29th, 2008
When using the nginx_uploadprogress_module you need to set the X-Progress-ID header in your progress polls. Safari sanitises header names, so X-Progress-ID ends up becoming X-Progress-Id in your request. Unfortunately Firefox does just the oppose renaming X-Progress-Id to X-Progress-ID (but only for this particular header). The current release of nginx_uploadprogress_module is case sensitive, so I've patched it to be case insensitive.
HTTP/AJAX debugging with Charles
February 29th, 2008
If you ever need to inspect an AJAX request from a browser such as Safari (which doesn't quite have a Firebug equivalent], Charles is a useful debugging proxy.
IrregularScience
February 19th, 2008
ImageScience is great. Just look at the code! One beautiful class wraps up FreeImage with some jucy inline C. If you can install FreeImage then nothing can go wrong. Much better than a bazillion lines of RMagick (which sometimes still can't so what you need)!
Simplicity is great but unfortunately ImageScience has this infatuation with squares. I'll explain.
Image science has two low level methods which allow arbitrary cropping and resizing. They look like this:
image.with_crop(left, top, right, bottom)
image.resize(width, height)
However what you really want to do is usually a combination of cropping and resizing. ImageScience helpfully provides:
# Resizes to fit within a square
image.thumbnail(size)
# Resizes and crops to be exactly a square
image.cropped_thumbnail(size)
This is great until you need an avatar that's a fixed ... rectangle. Or an image that will fit exactly inside a ... rectangle.
In this case you need IrregularScience!
You'll get rectangular versions of thumbnail and cropped_thumbnail:
# Resizes to fit within a rectangle
image.resize_within(width, height)
# Resizes and crops to be exactly a rectangle
image.resize_exact(width, height)
I gave my methods slightly different names because I'm like that ;)
There's also the case where you want a exact height or an exact width regardless of the other dimension (ever seen facebook?). That turns out to be a really horrible hack with RMagick involving all sorts of squashing and stretching unless you go really low level. Just follow these incantations and know that no horrible hacks are going on:
image.resize_to_width(width)
image.resize_to_height(height)
To get started download irregular_science.rb and require it. Then adapt this example:
ImageScience.with_image(upload_path) do |image|
self.thumbnails.each do |name, size|
image.resize_exact(*size) do |img|
img.save(attachment_path(name))
end
end
end
Enjoy!
P.S. This seems to be my first blog post here - so hi!
Micro-patterns in Ruby
February 5th, 2008
Yup. Micro-patterns. I've always wanted to begin a blog post with some highly sophisticated buzzword so it might as well be this one (sadly, I can't say I'm the first to use it).
This is a tiny one. Let's say we have a Factory that gives me Adapters#1 to a series of hosted media services (Flickr, YouTube, Vimeo, PhotoBucket, etc.).
The user of my code provides a service prefix and a URL to a picture or photo page in a given service, and the factory returns an instance from which the user can fetch different media sizes through a standardized API.
flickr_pic = ServiceParser.instance(
'flickr', 'http://www.flickr.com/photos/new_bamboo_london/2158168775/'
)
puts flickr_pic.thumbnail
# => http://farm3.static.flickr.com/2147/2158168775_01ae89cbfb_s.jpg
yt_video = ServiceParser.instance(
'youtube', 'http://www.youtube.com/watch?v=PCunD-_mOwQ'
)
puts yt_video.thumbnail
# => http://i.ytimg.com/vi/PCunD-_mOwQ/default.jpg
Simple enough. But it seems a bit redundant to have the user declare both the service name and the page URL. Since URL's are unique anyway, those should be enough for our smart factory to know what adapter to hand us, kindly.
We could have a set of regular expressions in the factory, one for each URL/service.
class ServiceParser
SERVICES = {
FlickrAdapter => /flickr\.com/,
YouTubeAdapter => /youtube\.com/,
VimeoAdapter => /vimeo\.com/,
PhotoBucketAdapter => /photobucket\.com/
}
# Factory method
#
def self.instance( url )
subclass = SERVICES.find(nil) {|klass, exp| url =~ exp}
raise 'not implemented' if subclass.nil?
subclass.new url
end
end
We could. But if we did, all hell would break loose and a mob of angry Design Patterns advocates would ram our door and... reprimand us.
While they're at it, they would tell us that one of the many golden rules of Object Oriented software design is, blockquote please:
The superclass should have no knowledge of the subclasses.
But you already know that. We need to take those URL's out of the factory class and into where they belong, in each adapter class. Also, adapters should be able to register their URL's with the factory, so it knows where to look. Ruby to the rescue.
# = The superclass / factory
class ServiceParser
# We register adapters into this class variable
#
@@adapters = []
# class reader
#
def self.adapters
@@adapters
end
# Factory method here, se below...
#
end
# = An example subclass / adapter
class FlickrAdapter < ServiceParser
def initialize( url)
end
# API methods
#
def thumbnail
# do something clever here...
end
# register ourselves with the Factory
#
ServiceParser.adapters << [self, /flickr\.com/]
end
The fun thing about Ruby, class definitions being executable code and all, is that you can just have subclasses add themselves (and their corresponding regex.) to the factory's list of adapters in load time.
ServiceParser.adapters << [self, /flickr\.com/]
Then it is a matter of modifying the factory method to search for matching URL's in the dynamically populated list of subclasses / URL expressions.
# Refactored factory. No pun intended.
#
def self.instance( url )
match = @@adapters.find(nil) {|klass, exp| url =~ exp}
raise 'not implemented' if match.nil?
match.first.new url
end
Finally, a little more elegance to make our adapter authors happy (and less prone to mess with the internals of our superclass!)
class FlickrAdapter < ServiceParser
# Initializer, API and protected methods here...
#
# We register our URL with a neat class method on the superclass
#
register_url /flickr\.com/
end
class ServiceParser
# Factory, abstract methods and cross-adapter utilities here...
#
# Class method for subclasses to register themselves.
#
@@adapters = [] #2 See note on class variables
def self.register_url( exp )
@@adapters << [self, exp]
end
end
#1 Two more buzzwords and just the second paragraph! And there's more...
#2 Class @@variables. These variables are not inherited but shared by all classes in the inheritance tree. That means that, whenever a subclass adds to the superclass' version of @@adapters, it'll actually have the new value in all subclasses. This is not an issue in our simple example, though.





