Created
December 13, 2012 11:00
-
-
Save kimoto/4275733 to your computer and use it in GitHub Desktop.
Tinyurl sinatra + datamapper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env ruby | |
# encoding: utf-8 | |
# Author: kimoto | |
require 'sinatra' | |
require 'erubis' | |
require 'dm-core' | |
require 'dm-migrations' | |
require 'dm-timestamps' | |
# Models | |
class ShortUrl | |
# properties | |
include DataMapper::Resource | |
property :id, Serial | |
property :digest, String, :length => 64, :unique_index => true | |
property :url, String, :length => 1024, :unique => true | |
timestamps :at | |
# exceptions | |
class MaxRetryError < StandardError; end | |
# class methods | |
MAX_RETRY = 100 | |
@@table = [ | |
('0' .. '9'), | |
('a' .. 'z'), | |
('A' .. 'Z'), | |
["-", "_"] | |
].map(&:to_a).flatten.freeze | |
# copied from http://lokka.kksg.net/bitly | |
def self.conv64(i) | |
digit = [] | |
begin | |
i, c = i.divmod(62) | |
digit << @@table[c+1] | |
end while i > 0 | |
return digit.reverse.join('') | |
end | |
def self.gen_random_digest | |
self.conv64(rand(256**4)) # 256**4 (4294967296) pattern | |
end | |
def self.digest_to_url(digest) | |
if r = self.first(:digest => digest) | |
r.url | |
else | |
nil | |
end | |
end | |
def self.url_to_digest(url) | |
self.first_or_create(:url => url).digest | |
end | |
def digest_already_exist? | |
if self.class.first(:digest => self.digest) | |
return true | |
else | |
return false | |
end | |
end | |
def gen_digest | |
MAX_RETRY.times{ |n| | |
self.digest = self.class.gen_random_digest | |
if not digest_already_exist? | |
return | |
end | |
} | |
raise MaxRetryError | |
end | |
before :create do |short_url| | |
short_url.gen_digest | |
end | |
end | |
# Sinatra | |
configure do | |
enable :inline_templates | |
set :erb, :escape_html => true | |
DataMapper.setup(:default, "mysql://127.0.0.1/tinyurl") | |
DataMapper.finalize | |
DataMapper.auto_upgrade! | |
end | |
helpers do | |
def base_url | |
@base_url ||= "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}" | |
end | |
end | |
get '/' do | |
erb :index | |
end | |
get '/:digest' do | |
if url = ShortUrl.digest_to_url(params[:digest]) | |
redirect url | |
else | |
not_found | |
end | |
end | |
post '/new' do | |
begin | |
digest = ShortUrl.url_to_digest(params[:url]) | |
redirect URI.join(base_url, "/created/#{digest}").to_s | |
rescue => RetryMaxError | |
not_found | |
end | |
end | |
get '/created/:digest' do | |
URI.join(base_url, ShortUrl.first(:digest => params[:digest]).digest).to_s | |
end | |
not_found do | |
"404 Not Found" | |
end | |
__END__ | |
@@ index | |
<h1>shorturl</h1> | |
<form method="post" action="/new"> | |
<input type="text" name="url" style="width: 500px;" value="" /> | |
<input type="submit" value="create" /> | |
</form> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment