This forum is in archive mode. You will not be able to post new content.

Author Topic: Ruby link shortener  (Read 858 times)

0 Members and 1 Guest are viewing this topic.

Offline Fur

  • Knight
  • **
  • Posts: 216
  • Cookies: 34
    • View Profile
Ruby link shortener
« on: October 06, 2014, 01:06:11 PM »
Wrote this because I thought it would be cool. Wanted to make it as small and simple as possible.Took 4 hours because DataMapper was being weird and I don't do a lot of Ruby (or much programming in general these days ;_;).

Anyway, the code:

Code: (Ruby) [Select]
# linkshorten.rb
# Sinatra app to shorten urls.
# Date: 6th October 2014
# Author: Fur
 
# DataMapper stuff taken from: https://github.com/tomaszj/sinatra-datamapper-sample/blob/master/app.rb
 
# TODO:
  # Deduplicate argument validation (but where to put the functions?).

require 'rubygems'
require 'uri'
require 'sinatra'
require 'data_mapper'
require 'json'

DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/links.db")

class ShortenedUrl
  include DataMapper::Resource
  property :id, Serial
  property :url, String, :required => true
end
DataMapper.finalize.auto_upgrade!

class Base32
  # Base32 encode a number.
  def self.encode(number)
    number.to_s(32)
  end
 
  # Decode a base32-encoded string
  def self.decode(str)
    str.to_i(32)
  end

  # Is str encoded in base32?
  def self.is_encoded?(str)
    str =~ /[a-z0-9]+/
  end
end
 
class LinkShortener
 
  # Shortens a link and returns its code
  def self.shorten(url)
    if url !~ URI::regexp
      throw ArgumentError, "url must be a valid uri"
    end
    Base32.encode(ShortenedUrl.first_or_create(url: url).id)
  end
 
  # Gets the long url for a short url code
  def self.expand(code)
    if !Base32.is_encoded?(code)
      throw ArgumentError, "code must be a valid base32 string"
    end
    ShortenedUrl.get(Base32.decode(code)).url
  end

  # Gets the short url (like domain.tld/aaaa3) for a code and the route which will redirect short urls to their long ones.
  def self.code_to_short_url(code, base_url)
    (base_url.end_with?('/') ? base_url : base_url + '/') + code
  end

  def self.valid_code?(code)
    Base32.is_encoded?(code) && ShortenedUrl.all(:id => Base32.decode(code)).count > 0
  end
end
 
class Main < Sinatra::Base
  set :environment, :production
  set :show_exceptions, false

  post '/shorten' do
    if params[:url] !~ URI::regexp
      JSON.generate({:error => "url is not valid"})
    else
      code = LinkShortener.shorten params[:url]
      JSON.generate({:shortenedUrl => LinkShortener.code_to_short_url(code, request.base_url)})
    end
  end
 
  get '/:code' do
    if !LinkShortener.valid_code?(params[:code])
      "Invalid url"
    else
      redirect LinkShortener.expand(params[:code]), 302
    end
  end
end
Main.run!

Dependency installation (on Ubuntu at least):
Code: (Bash) [Select]
sudo gem install sinatra

sudo apt-get install libsqlite3-dev
sudo apt-get install ruby1.9.1-dev # Sometimes data_mapper fails to build native modules. This fixes it.

sudo gem install data_mapper

CHANGELOG:
  Reorganised code
  Removed code attribute in JSON output.
  Now uses dynamic JSON generator for readability reasons.
  Changed wording of exceptions a little
  Fixed an exception where trying to follow an invalid short url would cause an exception becaused by a forgotten else.
  Cleaned up the design a bit
  Redirect now redirectes with HTTP code 302.
  Cleaned TODO
« Last Edit: October 07, 2014, 04:38:40 PM by Fur »

Offline lucid

  • #Underground
  • Titan
  • **
  • Posts: 2683
  • Cookies: 243
  • psychonaut
    • View Profile
Re: Ruby link shortener
« Reply #1 on: October 06, 2014, 10:57:42 PM »
Nice to see someone else using Ruby ;D

I've never used sinatra or data_mapper but it looks useful.
"Hacking is at least as much about ideas as about computers and technology. We use our skills to open doors that should never have been shut. We open these doors not only for our own benefit but for the benefit of others, too." - Brian the Hacker

Quote
15:04  @Phage : I'm bored of Python

 



Want to be here? Contact Ande, Factionwars or Kulverstukas on the forum or at IRC.