Skip to content

Instantly share code, notes, and snippets.

@khy
Created February 11, 2012 04:31
Show Gist options
  • Save khy/1796178 to your computer and use it in GitHub Desktop.
Save khy/1796178 to your computer and use it in GitHub Desktop.
A File System for useless.io
module Useless
# Useless::Base is the Rack endpoint for useless.io proper. It has two
# responsibilties: show documentation, and serve file from Useless::FS.
class Base
autoload :Files, 'useless/base/files'
def call(env)
# Show platform documentation at root
app = Rack::URLMap.new '/' => Doc.new('index'),
# serve files out of /files/* via the Files Rack endpoint.
'/files/' => Files.new
app.call(env)
end
end
end
module Useless
class Base
# Useless::Base::Files simply retrieves files from Useless::FS and serves
# them up.
class Files
# Provide a helper method for file URLs to keep things consistent.
def self.url_for(id)
"http://useless.io/files/#{id}"
end
def call(env)
# The file ID is everything after the initial '/' in the path
id = env['PATH_INFO'][1..-1]
# Retrieve the file from FS
file = Useless::FS.get(BSON::ObjectId(id))
# and serve it up with the associated content type
return [200, {'Content-Type' => file.content_type}, file.read]
# Two things can go wrong, and they'll both raise an error:
# * the specified ID is not a valid object ID
# * there is no file corresponding to the ID in the FS
rescue BSON::InvalidObjectId, Useless::FS::FileNotFound
[404, {'Content-Type' => 'text/plain'}, "File not found: #{id}"]
end
end
end
end
describe 'useless.io/files' do
include Rack::Test::Methods
def app
Useless
end
describe 'GET /files/:id' do
it 'should return a file if one exists for the specified ID' do
file = File.open(asset_path('muffin-milk.jpg'))
id = Useless::FS.put(file)
get Useless::FS.url_for(id)
last_response.should be_ok
# See spec/useless/fs_spec.rb
file.rewind
blob = file.read
blob.force_encoding('BINARY')
blob.should == last_response.body
end
it 'should return a 404 if the file does not exits' do
get Useless::FS.url_for(BSON::ObjectId.new)
last_response.should be_not_found
end
it 'should return a 404 if the specified ID is invalid' do
get Useless::FS.url_for('invalid-id')
last_response.should be_not_found
end
end
describe '.url_for' do
it 'should return the appropriate URL for the specified file ID' do
Useless::Base::Files.url_for('abc123').should == 'http://useless.io/files/abc123'
end
end
end
module Useless
# Useless::FS is a minimal wrapper around Mongo::Grid.
module FS
class FileNotFound < StandardError; end
def self.put(file, opts = {})
Useless.mongo.grid.put(file, opts)
end
def self.get(id)
Useless.mongo.grid.get(id)
# To preserve the abstraction, raise our own exception when a file isn't
# found
rescue ::Mongo::GridFileNotFound => e
raise FileNotFound, e.message
end
end
end
describe Useless::FS do
it 'should allow for files to be added and retrieved via .put and .get' do
original_file = File.open(asset_path('muffin-milk.jpg'))
original_file_id = Useless::FS.put(original_file)
stored_file = Useless::FS.get(original_file_id)
# Useless::FS stores the file as an un-encoded binary blob, so in order to
# compare, we must strip the encoding, i.e. force a binary encoding.
original_file.rewind
original_blob = original_file.read
original_blob.force_encoding('BINARY')
original_blob.should == stored_file.read
end
describe '.get' do
it 'should raise Useless::FS::FileNotFound if the specified ID doesn\'t exist' do
-> { Useless::FS.get('nonexistant') }.should raise_error(Useless::FS::FileNotFound)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment