29. tammikuu 2011, 14:56

Blogia nyt komentoriviltä

Noniin. Koska sain tuon lyhyiden mietteiden sovelman toimimaan melko hyvin, ajattelin nyt laajentaa tavalliset blogikirjoituksetkin tehtäväksi komentoriviltä, jossa olen melko luonnollisessa olotilassa.

Ensimmäinen kokeilu tuotti ikävän yllätyksen, kun sain kaiken näennäisesti toimimaan, ja lopulta pieni typo python-koodissani sai ohjelman keskeytymään ennen kuin se lähetti datan (isohko blogikirjoitus) palvelimelle. Temppitiedosto tietenkin meni, joten se tieto hävisi komeasti.

Python

Tein parannuksia python-koodiin siitä, mitä se tweet.py-tiedostossa oli. Ja lisäsin pari varmistelua. Ja tein koodista enemmän python-henkistä. Mutta voi kamala, miten sotkuista se imperatiivinen purkkailu onkaan. Täytyy sanoa kuitenkin kaikki huomioonottaen, että Python on todella nättiä verrattuna siihen bash-koodiin, jota useimmiten tämäntyylisessä käytettäisiin.

Ensin tein oikeaoppisen editorihaun ympäristömuuttujasta:

import os
EDITOR = os.environ['EDITOR']

Ei ollut vaikeata. Seuraava vaihe on tehdä pieni pohjateksti käyttäjälle avuksi. Sekä käyttäjälle että parsivalle ohjelmalle avuksi. Demosin sitä jo pari postausta aikaisemmin: muoto on tämmöistä:

Otsikko:
Tagit:
----- Viesti -----

Ja sitten siihen loppuun kirjoitellaan iloisesti (kuten nyt) tarinaa. Idea on selvästi Emacsin mail modesta, mutta vastaavaa olen varmasti ajatellut ennen tietoa Emacsin moodiloista. Onhan tuo melko helppo ratkaisu, ja toimivakin, ellei käyttäjä mene sössimään noita esitäytettyjä tekstejä.

Itse tiedostoa parsitaan Pythonin melko C-kielisellä rajapinnalla. Siirsin sen omaan funktioonsa, koska sitä piti käyttää useammassa kohdassa:

def parse_file(f):
  """ Given file handle f, read and parse according to the format.
  Return 3-tuple (title, message, tags). """
  f.seek(0)
  # now just go through the file format
  title = f.readline().strip()
  tags = f.readline().strip()
  f.readline() # the separator
  message = f.read().strip()
  # some final handling
  title = re.sub(r"\A.*?: ?", "", title)
  tags = re.sub(r"\A.*?: ?", "", tags)
  return (title, message, tags)

Sotkuista, ehkä. Tiedostokahva kelataan alkuun varmuuden varalta. Jo yksinään readline-metodin ansionsta alkeelliset formaatit, kuten nämä, on helppo koodata vapaasti. Tietysti jäykkähän tämä on kuin mikä. Parempi ratkaisu voisi olla jakaa kaikki rivit ennen separaattoria sanakirjoiksi, joissa avainsana määräytyy ensimmäisen sanan myötä. Avainsanaa vastaava sisältö tietenkin :-merkkiä seuraavalla tekstillä. Kuitenkin nyt on näin. Tyydyin käyttämään säännöllisiä lausekkeita laiskuuttani tässä.

Seuraavaksi itse ydin, eli luodaan tilapäinen tiedosto Pythonin erinomaisen tempfile -kirjaston avulla. Sitten siihen tallennetaan alkuteksti ja kutsutaan editoria. Myöhemmin mukaan tuli pieniä kehityksiä:

with tempfile.NamedTemporaryFile(suffix=".textile") as tempfile:
  tempfile.write(initial_message)
  tempfile.flush()
  title = "" # ensures the loop below

  while len(title) < 2 or len(message) < 10:
    call([EDITOR, tempfile.name])
    (title, message, tags) = parse_file(tempfile)

Määrään mielelläni temppitiedoston päätteeksi jotain järkevää, koska nyt voin Vimissä konfiguroida näyttämään tiedostot sopivalla värityksellä, ja vaikkapa apuplugineilla (joita ei kyllä näin alkeelliseen merkintäkieleen tarvitse). Myös SnipMate pelaa tiedostopäätteiden kanssa oletuksena, joten sekin vaihtoehto meille avautuu. Kuten arvata saattaa, with -rakenteella luotu TemporaryFile poistetaan automaattisesti lohkon loputtua. Silmukassa pyörimme tyydyttävästi vain sen verran, että käyttäjän tekemät selkeät virhetallennukset jäävät haaviin.

Sivuhuomautuksena mainittakoon, että call tuossa kutsussa on modulista subprocess. Mainittua kutsua suositellaan käytettäväksi esimerkiksi os.system()-kutsun sijaan. Suosittelen käyttämään, toimii hyvin ja ilman ongelmia.

Loppukoodi on samanlaista edellisen kanssa. Laitamme viestin menemään maailmalle, ja kohta nähdään, miten ensimmäinen isompi viesti (tämä) tulee läpi. Kokeilujen valossa pitäisi mennä kerralla.

Tageja: , ,

---
---

---

Aiheen vierestä