Arkiv för kategori ‘Kod’

Potion, ett objekt- och mixin-orienterat språk

Why’s Potion

Författaren, tecknaren, musikern, konstnären, och programmeraren Why the Lucky Stiff har under en tid jobbat med ett litet och snabbt språk som han döpt till Potion. Språket är inte på något sätt färdigt eller ens menat att tas på allvar, men jag tycker att det är roligt att experimentera med nya och annorlunda språk.

Mantrat bakom Potion

”Allt är ett objekt, men objekten är inte allt” samt tillägget ”Oh, och allt är en funktion”

Vad är speciellt med Potion?

  • Potion kompilerar ner programmen till maskinkod
  • Det inkluderar en liten ”generational near-exact garbage collector”
  • Det är två språk i ett: ett för kod, ett för data
  • Det består av färre än 10.000 rader C

Potion är inspirerat av språken Io, Ruby, OCaml, Lua, REBOL och C. I den ordningen.

Installation under Mac OS X

Först måste man installera Ragel och det gör man enklast genom MacPorts:

sudo port install ragel

Och sedan klonar man källkoden med Git:

git clone git://github.com/why/potion.git

Efter det kompilerar man koden:

make

Dags att skriva lite kod

Enklast möjliga

'Athega' print

Kommer helt enkelt att skriva ut strängen ‘Athega’ genom att man skickar meddelandet print.

Något lite roligare

loop: 'Athega' print.

I Potion startar man block av kod med kolon och avslutar med punkt. Kommandot loop kommer att inte helt oväntat loopa över blocket (en oändlig loop). Meddelandet print sänds till strängen ‘Athega’. Strängar är objekt, som allt annat. De tar emot meddelanden. Meddelanden är separerade från objekt med mellanrum. (I de flesta programmeringsspråk använder man punkt för att separera meddelanden, här (precis som i Svenska) representerar punkt ett avslut på något.)

Listor

('kaffet', 'på', 'h21', 'rockar') at (2) print

Nu skriver vi ut strängen ‘h21′. Allt inom parenteser är listor. Vi skickar meddelandet at. Alla listor har ett at meddelande som hämtar poster baserat på positionen i listan.

Notera att efter at meddelandet kommer det en till lista. (2) är ett argument till at. Den ser ut som en lista (och det är en lista,) men vi kallar den för ett argument eftersom den kommer efter ett meddelande.

Den funktionella sidan

  minus = (x, y): x - y.
  minus (y=10, x=6)

Här har vi en variabel som innehåller en funktion. Funktionen subtraherar y från x. I detta fall returneras -4.
(Detta liknar hur nyckelordsargument fungerar i Lua och Python)

Den objektorienterade sidan

Person = class: /name, /age, /sex.
 
Person print = (): 
 ('Mitt namn är ', /name, '.') join print.
 
p = Person ()
p /name = 'Peter'
 
p print

En subklass

Developer = Person class (language): /language = language.
 
Developer print = ():
  ('Mitt namn är ', /name, ' och jag gillar ', /language, '.') join print.
 
u = Developer ('Ruby')
u /name = 'Peter'
 
u print

Licks

Till sist har vi Lick vilket är dataspråket jag nämnde tidigare. Men varför skulle man vilja ha två språk i ett? En anledning är att det kan vara svårt att uttrycka data i kod.

Genom att ha ett separat litet dataspråk kan man bygga trädstrukturer av godtyckliga element, ungefär som i HTML. (Man kan se det som kod som har blivit tolkad men inte exekverad)

[name (attr1='string', attr2=10) 'TEXT HERE']

Varje lick kan ha ett namn, en tabell med attribut och en lista med barn. Listan med barn kan även vara av någon annan datatyp. (tex nummer eller sträng)

Vidare läsning

Låt inte Tomcat jobba i onödan

Ett vanligt upplägg för en lastad sajt med någorlunda statiskt innehåll ser ut enligt nedan:

Upplägg, lastad sajt

Upplägg, lastad sajt

I korthet innebär det att den största delen av trafiken hanteras av enkla webbcachear som leverar sidor till slutanvändarna. Med ett visst intervall efterfrågar cachearna frontarna efter nytt innehåll. Frontarna kan exempelvis köra en eller flera Tomcat-instanser som genererar innehållet. På detta sätt kan även riktigt stora siter klara sig på ett tiotal maskiner.

För alla JSP-sidor som Tomcat-frontarna genererar åt cachearna skapas nu en session, precis som Servlet-standarden föreskriver. Det är helt i sin ordning, fast helt onödigt i det här fallet. Det genererade innehållet levereras inte direkt till slutanvändaren, utan till cachen. Kan man få servlet-motorn att inte skapa sessioner i onödan och på så sätt spara sina dyra resurser?

Ja, ett sätt är att överst i sin JSP-sida helt enkelt utbrista:

<%@page session="false"%>

Dock är det kanske inte att föredra i ett litet större projekt med hundratals JSP-sidor. Det man letar efter är ett sätt att slå av det centralt för alla JSP-sidor. Min första instikt var att konfiguerar Jasper, som kompilerar JSP-sidorna att inte skapa sessioner om man inte explicit bad om det. Någon sådan parameter hittade jag tyvärr inte. Personer som har liknande frågor på nätet får istället frågan; ”Varför vill du slå av sessioner? De är ju en del av standarden!”

Mitt nästa spår var att automatiskt försöka inkludera ovanstående direktiv för varje genererad sida. Från och med JSP 2.0 (som inte direkt kom ut igår) går det att få till ganska enkelt med något som kallas för implicit includes.

Börja med att lägga till ett jsp-config-direktiv i din web.xml:

<!-- Disable the use of sessions -->
<jsp-config>
  <jsp-property-group>
    <url-pattern>*.jsp</url-pattern>
    <include-prelude>/WEB-INF/jspf/disableSession.jspf</include-prelude>
  </jsp-property-group>
</jsp-config>

Detta matchar alla JSP-filer (med filändelsen .jsp) och inkluderar innehållet av filen disableSession.jspf precis som om du skulle ha skrivit

<%@include file="/WEB-INF/jspf/disableSession.jspf"%>

högst upp i varenda JSP-fil.

Notera att filen som inkluderas är av typen .jspf, ett JSP-fragment. Detta är nödvändigt och säkerställer bland annat att du inte råkar in i några oändliga inkluderingsloopar. Att filen ligger i mappen /WEB-INF/jspf är rekommenderat och förhindrar även direkt access för en slutanvändare.

Testa! Tomcat kommer att kasta fel i loggarna så fort du försöker skapa en session, men om du har det som jag är det precis så du vill ha det!

Athegas öppna källkod används av Valmyndigheten

I mitt förra inlägg berättade jag om en Perl-modul som vi släppt som öppen källkod. Det visade sig att denna kod ganska snabbt skulle komma till nytta. Häromdagen fick jag ett e-postmeddelande från Valmyndigheten där de berättade att de använder modulen och att den passar deras behov perfekt. De använder den för att konvertera positionen för alla vallokaler från RT90 till SWEREF99 för presentation på en karta på webben.

Modulen hittar ni här: Geo::SweGrid

Athega bidrar till öppen källkod

Athega har sedan länge, ända sedan starten 1997, arbetat mycket med programmeringsspråket Perl. Vi använder oss i mycket stor utsträckning av öppna och fria mjukvaror och verktyg för de system vi bygger. Därför är även en stor del av den kod vi själva producerar befriad från licenskostnader och betraktas som ”open source” även om den kanske i vissa fall inte finns publikt tillgänglig på nätet.

Saker som går att återanvända och andra kan ha nytta av delar vi gärna med oss av. Ett exempel på detta är Perl-modulen Geo::SweGrid som används för att konvertera geografiska koordinater mellan det system som används globalt och det som används på vissa svenska kartor.

Det distribuerade arkivet för Perl-moduler heter CPAN, dit kan alla bidra med sin kod. När en modul väl finns i arkivet kan den lätt installeras på vilken dator som helst så här:

[user@host ~]$ sudo cpan
 
cpan shell -- CPAN exploration and modules installation (v1.9304)
ReadLine support enabled
 
cpan> install Geo::SweGrid

Sinatra och Google Spreadsheet

Efter att ha sett scriptet follow_iphone_devs.rb fick jag idén att kombinera Sinatra och google-spreadsheet-ruby som ett exempel på vad man kan göra i Ruby om man inte har behov av ett större ramverk som Ruby on Rails.

Sinatra
Sinatra är ett DSL för att snabbt och enkelt skapa webbapplikationer i Ruby:

# myapp.rb
require 'rubygems'
require 'sinatra'
get '/' do
  'Hello world!'
end

Komma igång

Först av allt behöver vi Ruby och RubyGems. Eftersom jag använder OS X så är de redan installerade. (Men se till att du har en uppdaterad version av RubyGems)

Om du inte redan har lagt till GitHub i listan över dina gem sources:

gem sources -a http://gems.github.com

Nu är vi redo att installera de gems vi kommer att använda:

sudo gem install sinatra gimite-google-spreadsheet-ruby haml

Nu är vi redo att börja skriva vårt script:

sinatra-and-google-spreadsheet.rb

Först tar vi och laddar in de gems vi kommer använda (Sinatra kommer att ladda in Haml åt oss):

require 'rubygems'
require 'sinatra'
require 'google_spreadsheet'

Nu tar vi och aktiverar sessioner:

# We want to save the posts in a session variable
set :sessions, true

OBS: Detta är självklart ingen lösning som skalar men det fungerar bra för vårt syfte.

Metoderna för att hämta datat från Google Spreadsheet:

def get_posts
  # Retrieve and return the posts
  session["posts"] ||= retrieve_posts
end
 
def retrieve_posts
  # Empty posts hash
  posts = {}
 
  # Log in to Google Spreadsheet
  session = GoogleSpreadsheet.login('xxxxxxxx', 'xxxxxxxx')
 
  # First worksheet of 
  #  http://spreadsheets.google.com/ccc?key=peGTxx6h1WT0ihw9-QETbQg
  ws = session.spreadsheet_by_key("peGTxx6h1WT0ihw9-QETbQg").worksheets[0]
 
  # Iterate over all the rows in the spreadsheet
  for i in 1...ws.num_rows
    # Store the data Identify data using the slug
    posts[ws[i+1,5]] = {
      :title    => ws[i+1,1],
      :content  => ws[i+1,2],
      :date     => Date.parse(ws[i+1,3]),
      :author   => ws[i+1,4],
    }
  end
 
  # Return the retrieved posts
  posts
end

Vi använder memoization för att det bara ska bli en förfrågning till Google per session

Startsida listar helt enkelt alla poster:

get '/' do
  # Get all the posts
  @posts = get_posts
 
  # Render the index template
  haml :index
end

Respektive post har en ”slug” som används i urlen:

get '/:slug' do
  # Get the post
  @post = get_posts[params[:slug]]
 
  # Render the post template
  haml :post
end

Nu definierar vi de Haml-mallar vi använder på sidorna:

__END__
 
@@ layout
%html
  %head
    %title Sinatra and Google Spreadsheet
  %body
    = yield
 
@@ index
%h1.title All posts
 
- @posts.each do |slug, post|
  %ul
    %li
      %a{:href => slug}
        = post[:title]
@@ post
%h1.title
  = @post[:title]
 
%div
  Published
  %span.date
    = @post[:date]
  by
  %span.author
    = @post[:author]
 
%p.content
  = @post[:content]
 
%a{:href => '/'} << Back

Starta scriptet

$ ruby sinatra-and-google-spreadsheet.rb 
== Sinatra/0.9.1 has taken the stage on 4567 for development with backup from Thin
>> Thin web server (v1.0.0 codename That´s What She Said)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop

Om allt går som det ska så ska vi nu ha en server på http://localhost:4567/.

Resultat

Från ett kalkylblad på Google Spreadsheet:

Data från Google Spreadsheet

Data från Google Spreadsheet

Till en sida serverad med Sinatra:

Post om Ruby

Resultatet

Att man kan åstadkomma så mycket med under 100 rader Rubykod är rätt imponerande, speciellt om man tänker på att vi då även räknar in kommentarer och mallar.