Devel.cz Lupa Měšec Podnikatel Root Zdroják.cz DigiZone Slunečnice Vitalia TopDrive KupDnes Navrcholu NovýTarif Dobrý web Weblogy Woko Jagg Computer.cz SK: MojeLinky

Hlavní navigace

Sinatra.rb aneb nejsnazší cesta k Ruby

Mohlo by se zdát, že v programovacím jazyce Ruby existuje jediný webový framework: obdivované i proklínané Ruby on Rails. Možností je však více, a na jednu z nich se nyní podíváme blíže: ukážeme si, jak na pár řádcích napsat webovou aplikaci, pracující s JSON daty, v mikro-frameworku Sinatra.

Tweetni to Twitter Jaggni to! Jagg Del.icio.us Delicious

Při nezasvěceném pohledu zvenčí by se mohlo zdát, že v programovacím jazyce Ruby existuje jediný webový framework: Ruby On Rails. Zasvěcenější vědí, že existuje ještě framework Merb, který z Rails filosoficky a koncepčně vyšel. (Vývojáři obou nedávno oznámili kontroverzní spojení obou frameworků v dalších verzích.) Pro Ruby však existuje množství dalších frameworků, jako např. Mack nebo Webby, které vycházejí z odlišných principů.

Jedním z nich je i mikro-framework Sinatra Blake Mizeranyho , který je zajímavý hned z několika důvodů.

Jednak je skutečně maličký: v aktuální verzi se celý vejde do jednoho jediného souboru (45KB, 1500 řádků kódu), který si můžete celý prostudovat za půl hodiny.

Ruku v ruce s tím jde fakt, že Sinatra nepředpokládá o vaší aplikaci téměř nic: kromě toho, že bude napsaná v Ruby a bude mít URL. Na světě jste jen vy, Ruby a webový prohlížeč.

Díky tomu se velmi hodí na experimenty a zkoušení jazyka Ruby. To je asi nejdůležitější aspekt Sinatry (pozor! neskloňuje se podle vzoru „ondatra“, ale jako „Frank Sinatra“). Zejména Rails jsou pro zkoušení Ruby velmi, velmi nevhodnou platformou, neboť obsahují obrovské množství „magie“ a jsou zaměřené na rychlý návrh a implementaci webových aplikací založených na databázi. (V češtině navíc vyšla jen jedna kniha s takovým divným pánem na obalu.)

„Hello World“

Nejenom Sinatra je maličký, i aplikace v Sinatrovi je maličká. Takhle maličká:

# hello_world.rb
require 'rubygems'
require 'sinatra'

get "/" do
  "Hello, it's #{Time.now} at the server!"
end 

Spustíme ji jednoduše:

$ ruby hello_world.rb
== Sinatra/0.3.2 has taken the stage on port 4567 for development with backup by Rack::Handler::Mongrel 

Principy

Jak vidíme, Sinatra obsahuje opravdu minimální množství infrastruktury: HTTP požadavek GET na kořenové URL vypíše na http://localhost:4567 aktuální čas. Kolem Sinatry je opravdu všechno malé: veškerá důležitá dokumentace se vejde do README souboru.

Však také Sinatra neobsahuje žádnou zabudovanou podporu pro objektově-relační mapování (ORM), pro usnadnění práce s JavaScriptem nebo AJAXem, helpery pro snadnou práci s formuláři ani generátory kódu či vše ostatní, co je na práci v Rails tak poutavé. To vše si musíte dle své vůle a potřeb přilinkovat (nebo napsat?) sami: můžete samozřejmě prostým require "activerecord" využít obrovskou sílu ORM vrstvy z Rails. Nebo pro ORM využít úplně jinou knihovnu. Vzápětí podobným způsobem využijeme jeden z Ruby gemů pro snadnou práci s JSON.

Sinatra je filosoficky radikální v tom, že zcela vynechává ze hry koncept routování a controllerů, který nalezneme jinak v téměř každém webovém frameworku. Sinatra jednoduše mapuje určité URL (resp. HTTP požadavek) rovnou na kód aplikace. Není tedy typickým (nebo dalším) model-view-controller (MVC) frameworkem. Dle autorů frameworku není URL nic, čeho bychom se měli „bát“.

Nepotřebuje ani views („šablony“). Zobrazí prostě to, co vrátíte v bloku do...end. Jako webový framework pochopitelně obsahuje rozsáhlou podporu nejen pro views (dynamické šablony), ale i pro helpery, tedy pomocné metody zjednodušující (dle nejlepších zásad MVC) kód ve view.

Sinatra je rovněž RESTful framework, protože kromě GET podporuje také metody POST, DELETE a PUT. Umožňuje též pracovat s podmínečným zpracováním HTTP požadavku a zaslat 304 Not Modified, pokud má klient nacachovánu aktuální verzi.

A v neposlední řadě podporuje automatizované testování aplikace na úrovni HTTP požadavků a views pomocí jednotkových testů (nebo ostatních testovacích frameworků).

To není špatné na jeden soubor s patnácti sty řádky! Sinatra samotný je navíc jen tenkou slupkou kolem Racku, rozhraní pro webové servery, vykonávajícího Ruby kód (např. Mongrel, WEBRick, Thin, Ebb a Phusion Passenger). Jedním z důsledků je rychlost. Pomocí nástroje Apache benchmark si můžeme změřit výkon (pro zvídavé a kverulanty jsou v balíčku zdrojových kódů k článku připraveny příklady Hello World aplikací v dalších jazycích):

$ ab -n 100 -c 10 http://127.0.0.1:4567/
Requests per second:    704.34 [#/sec] (mean)
Time per request:       14.198 [ms] (mean) 

Naše Hello World aplikace je samozřejmě elegantní, ale čas zjišťujeme zpravidla pohledem na mobil (staromódní a bohatí pohledem na hodinky). Měli bychom v Sinatrovi zkusit napsat něco zajímavějšího — např. klienta webové služby poskytující JSON data, typicky Twitteru.

Instalace a jednoduchá aplikace

Nejprve si musíme Sinatru nainstalovat. Pokud máme správně nainstalovaný jazyk Ruby a balíčkovací systém Rubygems, měli bychom si vystačit s jednoduchým:

$ sudo gem install sinatra 

Spusťte Hello World aplikaci, jestli vše běží, jak má. Neběží-li, pište do komentářů k článku!

Nainstalujeme si pomocí příkazu $ sudo gem install json balíček pro snadnou práci s JSON, a můžeme se pustit do klienta, zobrazujícího zprávy z oblíbeného zdroje.

Všechny následující kroky kódu si můžete stáhnout nebo zkopírovat z Git repozitáře.

První krok je jednoduchý:

require 'rubygems'
require 'sinatra'
require 'json'
require 'open-uri'

get '/' do
  header 'Content-Type' => 'text/plain; charset=UTF-8'
  JSON.parse( open("http://search.twitter.com/search.json?q=from%3Azdrojak").read )['results'].
  collect { |r| '* ' + r['text'] }.
  join("\n")
end 

Aplikaci spustíme pomocí $ ruby json_client.rb a na výchozí adrese bychom měli vidět něco jako:

Screenshot Sinatra aplikace - JSON klient

To nevypadá špatně na pár řádků kódu! Knihovna json na řádku 8 zajišťuje snadné zpracování JSON dat do Ruby Hashe (asociativního pole). Takto zpracovaná data na řádku 9 projdeme pomocí collect a vytáhneme pouze položky s klíčem text. Na řádku 10 oddělíme položky pole koncem řádku a vrátíme jako prostý text.

Právě takováto extrémně jednoduchá webová aplikace či služba je pravou doménou Sinatry. Také jsou jedním z jeho nejznámějších produkčních nasazení webové služby pro post-receive hooky na serveru Github, hostujícím Git repositáře.

Výstup v prostém textu však zajisté není to, co od webové aplikace očekáváme. V dalším kroku do aplikace přidáme HTML kód ve view. Sinatra obsahuje zajímavou funkci právě pro podobné extrémně jednoduché aplikace: kromě views uložených v separátních souborech v adresáři views můžete jejich kód umístit (odděleně) též do samotné aplikace:

%w{rubygems sinatra json open-uri}.each { |lib| require lib }

get '/:tweeter' do
  @tweeter = params[:tweeter] || 'zdrojak'
  @results = JSON.parse( open("http://search.twitter.com/search.json?q=from%3A#{@tweeter}").read )['results'].
  collect { |r| { :created_at => Time.parse(r['created_at']).strftime('%d/%m %H:%M'), :text => r['text'] } }
  erb :index
end

use_in_file_templates!

__END__

@@ layout
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>JSON Client</title>
</head>
<body>
<h1>Novinky od <em><%= @tweeter %></em></h1>
<%= yield %>
</body>
</html>

@@ index
<ul>
<% @results.each do |result| %>
  <li><em><%= result[:created_at] %>:</em> <%= result[:text] %></li>
<% end %>
</ul> 

V tomto kroku jsme přidali dynamické vypisování vybraného Twitter feedu podle parametru tweeter, předaného přímo v URL (řádek 3). Na řádku 6 jsme převedli JSON data do jiné struktury a na řádku 7 renderujeme view index pomocí šablonovacího systému ERB. Díky deklaraci use_in_file_templates! na řádku 10 Sinatra hledá kód pro views — obecnou „slupku“ layout a vnitřní šablonu index  — v konstantě DATA (cokoliv za __END__). Samozřejmě pro aplikace se složitějšími views je vhodné je umisťovat do jejich vlastního adresáře.

Rozšíření aplikace

Abychom si předvedli, čeho jsou Ruby se Sinatrou schopni, můžeme naši jednoduchou službu v posledním kroku ještě rozšířit o jednoduché cachování. V tomto případě se již vyplatí převést logiku aplikace do objektového modelu. Kód zde vypisujeme zkrácený — v úplnosti si jej prohlédněte v souborujson_client.rb v repozitáři.

class TweetReader
  # ...
  def initialize(id)
    @id = id
  end
  # ...

  def load
    if cached? and not stale?
      load_cached
    else
      load_remote and cache!
    end
  end

  private
  # ...

  def load_cached
    puts "* Loading cached data"
    @results = YAML.load_file( cached_file )
  end

  def load_remote
    puts "* Loading data from remote service"
    @results = JSON.parse( open("http://search.twitter.com/search.json?q=from%3A#e_13").read )['results'].collect do |r|
      { :created_at => Time.parse(r['created_at']).strftime('%d/%m %H:%M'), :text => r['text'] }
    end
  end

  def cache!
    File.open(cached_file, 'w') { |file| YAML.dump(@results, file) }
  end

  def stale?
    File.mtime(cached_file) < Time.now-20 # Expirace po 20 sekundach
  end
  # ...
end

get '/' do
  redirect( "/#{DEFAULT_TWEETER}" )
end

get '/:tweeter' do
  @tweeter = TweetReader.new( params[:tweeter] || DEFAULT_TWEETER )
  if time = @tweeter.last_modified # 304 Not Modified, pokud se zdroj dat nezmenil
    last_modified( time )
  end
  @tweeter.load
  erb :index
end

... 

Možná z uvedeného kódu vidíte, proč některé programátory jazyk Ruby tak přitahuje: obsahuje velké množství podpůrných knihoven (jako v našem případě pro serializaci do YAML a pro práci s filesystémem) a umožňuje bez velké námahy psát čitelný, objektový kód: if cached? and not stale? load_cached() a podobně. Samotná Sinatra aplikace pak díky tomu může mít jedenáct řádků.

Díky nedávné podpoře rozhraní RackRails, můžete dokonce aplikace v Sinatrovi (stejně jiné Rack-kompatibilní aplikace) spouštět přímo jako součást větší Rails aplikace.

Sinatru můžeme snadno použít jako vizuální rozhraní pro zkoušky a cvičení v technikách objektově orientovaného programování, návrhových vzorů nebo tvorbě vlastních domain specific languages. Právě pro takové „průzkumné“ programování je Sinatra jako stvořený. Profese programátora je dnes náročná díky tomu, že celá IT sféra se pohybuje velmi, velmi rychlým tempem — a v každodenní rutině je leckdy obtížné nebo nemožné najít čas a prostor pro nezávazné zkoušení, „skicování“ a programování „zbytečností“. A bez cvičení se žádné řemeslo naučit nedá.

Hosting a další informace

Chcete-li si vyzkoušet aplikaci v Sinatrovi na serveru a nemáte možnost nebo nechcete instalovat Ruby, Gemy a aplikační server, můžete si ji jednoduše nainstalovat na Ruby hosting zadarmo od společnosti Kraxnet. Sinatra je totiž stejně jako Ruby on Rails kompatibilní s Apache modulem mod_rails (Phusion Passenger).

Zdrojové kódy použité v článku si můžete stáhnout: Ukázka frameworku Sinatra (ZIP 2508 bytů).

Další informace hledejte zejména v těchto zdrojích:

Pokud vám cokoliv z uvedených příkladů nebude fungovat správně, napište prosím do komentářů. A dejte vědět, jak vaše experimenty se Sinatrou dopadly!

Anketa

Jaký framework v Ruby používáte?

       

Karel Minařík

Karel Minařík navrhuje a programuje webové stránky a aplikace,
poskytuje konzultace a školení v oblasti vývoje pro web a žije v Praze
se svojí ženou a dvěma dcerami.

Školení Google Analytics pro pokročilé

DW - Školení Google Analytics
  • Jak využít nové funkce Google Analytics
  • Vyhodnocování kampaní díky používání Multichannel funnels
  • Kde návštěvníci vašeho webu utíkají z objednávacího procesu.
  • Nebudete opakovat časté chyby při vyhodnocování dat o návštěvnosti.

Detailní informace o školení Google Analytics pro pokročilé »

Přehled názorů

co je ruby?
mirozbiro 14. 1. 2009 09:13
Nový
├ 
Re: co je ruby?
Martin Hassman 14. 1. 2009 09:18
Nový
└ 
Re: co je ruby?
karmi 14. 1. 2009 10:35
Nový
 
└ 
Re: co je ruby?
Inkvizitor 14. 1. 2009 20:15
Nový
 
 
├ 
Re: co je ruby?
karmi 14. 1. 2009 21:02
Nový
 
 
└ 
Re: co je ruby?
darth 3. 2. 2010 22:53
Nový
sinatra
skrat 14. 1. 2009 09:40
Nový
├ 
Re: sinatra
karmi 14. 1. 2009 10:32
Nový
└ 
Re: sinatra
pm 15. 1. 2009 00:20
Nový
 
└ 
Re: sinatra
karmi 15. 1. 2009 13:52
Nový
 
 
└ 
Re: sinatra
karmi 17. 1. 2009 13:18
Nový
instalace na Debianu unstable
zoufalec 14. 1. 2009 19:33
Nový
├ 
Re: instalace na Debianu unstable
tmp 14. 1. 2009 20:02
Nový
│
└ 
Re: instalace na Debianu unstable
zoufalec 14. 1. 2009 20:14
Nový
│
 
└ 
Re: instalace na Debianu unstable
karmi 14. 1. 2009 21:08
Nový
│
 
 
└ 
Re: instalace na Debianu unstable
tmp 14. 1. 2009 22:03
Nový
│
 
 
 
└ 
Re: instalace na Debianu unstable
Kamil 14. 1. 2009 22:38
Nový
│
 
 
 
 
└ 
Re: instalace na Debianu unstable
karmi 15. 1. 2009 14:39
Nový
├ 
Re: instalace na Debianu unstable
karmi 14. 1. 2009 21:06
Nový
└ 
Re: instalace na Debianu unstable
pm 15. 1. 2009 00:12
Nový
 
└ 
Re: instalace na Debianu unstable
karmi 15. 1. 2009 12:39
Nový
 
 
└ 
Re: instalace na Debianu unstable
zoufalec 15. 1. 2009 19:04
Nový
RE: Sinatra.rb aneb nejsnazší cesta k Ruby
anonymní uživatel 17. 1. 2009 09:05
Nový
RE: Sinatra.rb aneb nejsnazší cesta k Ruby
DarkTatka 17. 1. 2009 19:43
Nový
└ 
RE: Sinatra.rb aneb nejsnazší cesta k Ruby
Martin Hassman 17. 1. 2009 19:49
Nový
 
└ 
RE: Sinatra.rb aneb nejsnazší cesta k Ruby
anonymní uživatel 18. 1. 2009 11:49
Nový
Vydána nová verze Sinatry (0.9.0)
karmi 19. 1. 2009 13:57
Nový
RE: Sinatra.rb aneb nejsnazší cesta k Ruby
Lukáš Stejskal 29. 1. 2009 13:54
Nový
       

Tento text je již více než dva měsíce starý. Chcete-li na něj reagovat v diskusi, pravděpodobně vám již nikdo neodpoví. Pro řešení aktuálních problémů doporučujeme využít naše diskusní fórum.

Zasílat nově přidané příspěvky e-mailem