Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
LBRapid committed Jan 30, 2009
0 parents commit 9fc814f
Show file tree
Hide file tree
Showing 16 changed files with 362 additions and 0 deletions.
Binary file added .DS_Store
Binary file not shown.
9 changes: 9 additions & 0 deletions config/rackup.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
set :app_file, File.expand_path(File.dirname(__FILE__) + '/../shortener.rb')
set :public, File.expand_path(File.dirname(__FILE__) + '/../public')
set :views, File.expand_path(File.dirname(__FILE__) + '/../views')
set :env, :production
disable :run, :reload

require File.dirname(__FILE__) + "/../shortener"

run Sinatra.application
101 changes: 101 additions & 0 deletions lib/shorten.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
require 'time'
require 'digest/sha1'

require 'rubygems'

gem 'json'
require 'json'

class Shortener
def self.load
obj = self.new
obj.load
return obj
end

def self.shorten(url)
load.shorten(url)
end

attr_reader :store, :urls

def initialize(store='shorten.json')
@store = store
end

def load
@urls = load_json(store)
end

def shorten(url)
return @urls[hash] if @urls.has_key?(hash)
hash = hash_for(url)
store_hash(Url.build(url, hash), hash)
end

def lookup(hash)
@urls[hash]
end

def recent
urls.values.sort_by { |u| u.timestamp }
end

private

def hash_for(url)
Digest::SHA1.hexdigest(url)
end

module JsonStore

private

def load_json(path)
json = begin
File.read(path)
rescue Errno::ENOENT
'{}'
end
JSON.load(json).inject({}) do |urls, record|
url = Url.new(record['url'], record['hash'])
url.timestamp = Time.parse(record['timestamp'])
urls.update(url.hash => url)
end
end

def save_json
json = @urls.map { |(hash, url)| url.to_json }.to_json
File.open(store, 'w') { |f| f.write(json) }
end

def store_hash(url, hash)
@urls[hash] = url
save_json
url
end

end

include JsonStore

class Url
attr_accessor :url, :hash, :timestamp

def self.build(url, hash)
obj = Url.new(url, hash)
obj.timestamp = Time.now
return obj
end

def initialize(url, hash)
@url, @hash = url, hash
end

def to_json
{'url' => url, 'hash' => hash, 'timestamp' => timestamp.to_json}
end

end

end
Binary file added public/.DS_Store
Binary file not shown.
Binary file added public/images/.DS_Store
Binary file not shown.
Binary file added public/images/squeeze.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/javascript/.DS_Store
Binary file not shown.
32 changes: 32 additions & 0 deletions public/javascript/jquery-1.2.6.min.js

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions public/javascript/shorten.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
$(document).ready(function() {
$('input[type=text]').focus(function() {
$(this).attr('value', '');
});
});
100 changes: 100 additions & 0 deletions public/stylesheets/shorten.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Eric Meyer reset
* http:https://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/
*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-weight: inherit;
font-style: inherit;
font-size: 100%;
font-family: inherit;
vertical-align: baseline;
}
/* remember to define focus styles! */
:focus {
outline: 0;
}
body {
line-height: 1;
color: black;
background: white;
}
ol, ul {
list-style: none;
}
/* tables still need 'cellspacing="0"' in the markup */
table {
border-collapse: separate;
border-spacing: 0;
}
caption, th, td {
text-align: left;
font-weight: normal;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: "";
}
blockquote, q {
quotes: "" "";
}

/*
* Shorten
*/

body {
font-size: 87.5%;
font-family: Helvetica, Arial, sans-serif;
margin: 1em;
}

h1 {
font-family: Georgia, Times, serif;
font-size: 5em;
width: 60%;
margin: 0.5em auto;
}

p, ul {
width: 60% !important;
margin: 0 auto !important;
padding-bottom: 2em;
}

textarea {
display: block;
font-size: 1.17em;
font-weight: bold;
width: 100%;
}

form {
width: 60% !important;
margin: 2em auto !important;
}

input {
font-size: 2em;
}

#footer {
font-size: 0.75em;
padding-left: 3em;
height: 3em;
background-image: url(/images/squeeze.jpg);
background-repeat: no-repeat;
background-position: top/right;
margin-top: 2em;
}
Empty file added shorten.json
Empty file.
41 changes: 41 additions & 0 deletions shortener.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
$LOAD_PATH << File.join(Dir.getwd, 'lib')
require 'rubygems'
require 'sinatra'
require 'shorten'

before do
@shorten = Shortener.load
end

helpers do

def base_url
base = "http:https://#{Sinatra::Application.host}"
port = Sinatra::Application.port == 80 ? base : base <<
":#{Sinatra::Application.port}"
end

def url(path='')
[base_url, path].join('/')
end

end

get '/' do
erb :home
end

get '/:hash' do
url = @shorten.lookup(params[:hash])
redirect url.url
end

post '/shorten' do
url = @shorten.shorten(params['url'])
redirect "/info/#{url.hash}"
end

get '/info/:hash' do
url = @shorten.lookup(params[:hash])
erb :shortened, :locals => {:url => url}
end
23 changes: 23 additions & 0 deletions test/test_shortener.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require 'rubygems'
require 'sinatra/test/unit'
require File.join(File.dirname(__FILE__), '..', 'shortener')

class TestShortener < Test::Unit::TestCase

configure do
set :views => File.join(File.dirname(__FILE__), '..', 'views')
end

def test_home_renders_content
get '/'

assert_equal 200, @response.status
assert @response.body.length > 0
end

def test_shorten_redirects_to_info
post '/shorten', {:url => 'example.com'}
assert_equal 302, @response.status
assert_match %r{/info/.*}, @response['Location']
end
end
13 changes: 13 additions & 0 deletions views/home.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<h1>Shortener</h1>

<p>
Shortener makes your long URLs shorter. No longer will you
have to worry about sending people links that get messed
up by IM or email!
</p>

<form action="/shorten" method="post" accept-charset="utf-8">
<input type="text" name="url" value="Paste a URL..." id="url" />

<input type="submit" value="..and shorten it!" />
</form>
21 changes: 21 additions & 0 deletions views/layout.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" http:https://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-type" content="text/html;
charset=utf-8">
<link rel="stylesheet" href="/stylesheets/shorten.css"
type="text/css" media="screen" charset="utf-8">
<script src="/javascript/jquery-1.2.6.min.js"
type="text/javascript" charset="utf-8"></script>
<script src="/javascript/shorten.js"
type="text/javascript" charset="utf-8"></script>

<title>Shortener</title>
</head>

<body>
<%= yield %>

<p id="footer">&copy; 2009 John Dyer</p>
</body>
</html>
17 changes: 17 additions & 0 deletions views/shortened.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<h1>I shortened that for you!</h1>

<p>
Your new URL is
<a href="<%= url(url.hash) %>"><%= url(url.hash) %></a>. It points to
<a href="<%= url(url.url) %>"><%= url.url %></a>.
</p>

<p>
For your copy and pasting pleasure:
</p>

<p>
<textarea cols="64"><%= url(url.hash) %></textarea>
</p>

<p>Enjoy!</p>

0 comments on commit 9fc814f

Please sign in to comment.