Aktuelles Gewicht für Kniebeugen: 97,5kg

Aktuelles Gewicht für Kniebeugen: 97,5kg, originally uploaded by cringe.

Auf dem Bild sind 97,5kg auf der Stange, mein aktuelles Gewicht für Kniebeugen. Ohne Gürtel oder andere Hilfsmittel versteht sich.

Letzten Samstag im Fitnessstudio hatte ich allerdings 95kg drauf, mit einer schwereren Stange – das waren dann wohl schon die 100kg…

Die erste Abfrage über clj-fitbit

Ich arbeite gerade an einer Clojure-Library für die Fitbit API und heute ist mir der erste Request gelungen:

;;REPL started; server listening on localhost:20161.
user=> (use 'example)
Open this URL in your browser: http://api.fitbit.com/oauth/authorize?oauth_token=XXXXXXXXXXXXXXXXXXXXX
Enter your PIN:
XXXXXXXXXXXXXXXXXXXXXXXXXX
{:activities [], :summary {:activeScore 606, :caloriesOut 2516, :distances [{:activity total, :distance 0}], :fairlyActiveMinutes 55, :lightlyActiveMinutes 164, :sedentaryMinutes 630, :steps 8632, :veryActiveMinutes 29}}
nil
user=>

Jetzt kann ich anfangen, alle API-Methoden in meine Library zu mappen. 🙂

Fitbit: Mahlzeiten zusammenstellen



Fitbit: Mahlzeiten zusammenstellen, originally uploaded by cringe.

Fitbit: Mahlzeiten zusammenstellen

Bei Fitbit kann man jetzt auch Mahlzeiten zusammenstellen. Damit ist das Erstellen des Ernährungstagebuchs noch einfacher geworden.

Das Prinzip ist einfach: Man legt eine neue Mahlzeit an und fügt anschliessend über die bekannte Eingabe einzelne Lebensmittel hinzu. Danach kann man die ganzen Lebensmittel mit einem Klick im Tagebuch notieren.

Sehr schön!

Funktion auf alle Elemente einer Hashmap anwenden

Ich habe einige Zeit gebraucht, bis ich das folgende Problem in Clojure lösen konnte:

Ich habe eine map mit einigen key-value-Paaren und möchte eine Funktion auf die keys dieser Elemente anwenden. Die Keys sind ausserdem Clojure keywords.

Heute bin ich dann auf die Lösung gekommen, mein Dank gilt wie so oft Stackoverflow.com.

;; map anlegen
(def m {:foo 'foo, :bar 'bar, :baz 'baz})
;; zipmap erstellt eine neue map aus einer 2 Listen mit Keys und Values
(zipmap (map #(str"key=" %) (keys m)) (vals m))
;; => {"key=:baz" baz,"key=:bar" bar,"key=:foo" foo}

Nochmal auf Deutsch: Zeile 4 erstellt mit der Funktion zipmap eine neue map aus der Liste der Keys und Values aus meiner map m.

Wer das jetzt nochmal Schritt für Schritt nachvollziehen will, der kann diese Befehle in die REPL kopieren:

;; Funktion zipmap mit 2 Listen aufrufen
(zipmap [:foo :bar :baz] ['foo 'bar 'baz])
;; => {:baz baz, :bar bar, :foo foo}

Das ist im Prinzip identisch zu meinem Aufruf, nur dass ich mit (keys m) und (vals m) die Listen aus meiner bereits existierenden map erstelle.

Meine Beispiele könnt ihr meistens kopieren und in eine REPL einfügen. Ich hab alles, was Fehler verursachen kann, mit Kommentaren versehen.

clj-apache-http und ein Proxy

Falls ihr mal in die Verlegenheit kommen solltet, eine HTTP-Verbindung per clj-apache-http debuggen zu wollen (z.B. wegen einer störrischen OAuth-Authorisierung), dann solltet ihr euch Fiddler installieren und anschliessend alle Requests durch diesen Proxy leiten. In clj-apache-http macht man das wie folgt:

(require ['com.twinql.clojure.http :as 'http])

(:content 
  (http/get (java.net.URI."http://www.kopis.de")
    :parameters (http/map->params {
      :default-proxy (http/http-host
        :host"127.0.0.1" 
        :port 8765)}) :as :string))

Compojure Setup für schnelle Entwicklung

Ich hab in den letzten Tagen weiter mit Compojure herumgebastelt und will jetzt meinen aktuellen Stand der Entwicklungsumgebung aufschreiben. Vielleicht hilft es euch ja beim Einstieg. Ich bin jedenfalls etwas enttäuscht, das man keine guten Tutorials und Hilfen findet, wenn man frisch in Clojure und gerade Compojure einsteigt.

Meine Dateien findet ihr jetzt auch in einem Repository bei github.

Als erstes lege ich mit leiningen ein neues Projekt an:

lein new CmpjrAjaxTest

Anschliessend editiere ich die Datei project.clj und füge die Abhängigkeiten für ein minimales Compojure-Setup ein:

(defproject CmpjrAjaxTest "1.0.0-SNAPSHOT"
  :description "FIXME: write description"
  :dependencies [[org.clojure/clojure "1.2.0"]
             [org.clojure/clojure-contrib "1.2.0"]
             [enlive "1.0.0-SNAPSHOT"]
             [compojure "0.6.0-RC4"]
             [ring/ring-jetty-adapter "0.3.5"]]
  :dev-dependencies [[lein-ring "0.3.2"]]
  :ring {:handler CmpjrAjaxTest.app/app})

Wichtig sind die beiden letzten Zeilen mit den Keys :dev-dependencies und :ring. Damit wird leiningen angewiesen, einen Ring-Server zu starten, der automatisch meine Äderungen nachlädt und immer den aktuellen Stand der Entwicklung präsentiert.

Mit :ring {:handler CmpjrAjaxTest.app/app}) gebe ich damit eine Referenz auf meinen Routen-Handler an leiningen. Die Definition findet sich in der Datei app.clj:

(ns CmpjrAjaxTest.app
  (:use compojure.core
        clojure.contrib.json
        net.cgrand.enlive-html
        ring.adapter.jetty
        CmpjrAjaxTest.core)
  (:require [compojure.route :as route]
    [compojure.handler :as handler]))

(deftemplate index "resources/test.html"
  [cmap]
  [:span#msg] (content (:msg cmap)))

(defroutes main-routes
  (GET "/" [] (index {:msg Hello World!"}))
  (GET "/msg/:msg" [msg] (index {:msg msg}))
  (GET "/json" []
    {:headers {"Content-Type" "application/json"}
     :body (json-str {:foo "foo", :bar "bar"})})
  (route/resources "/")
  (route/not-found "Page not found"))

(def app
  (handler/site main-routes))

(defn dev []
  (run-jetty #'app {:port 8080}))

Hier passiert jetzt einiges. Erst einmal übernimmt Compojure für mich alles, was mit Routing der Request zu tun hat. Ich definiere mit (defroutes NAME ...) nur die Zuordnung von Requests zu meinen Funktionen. Die Funktionen liefern anschliessend das Ergebnis, also eine HTML-Seite. Oder ein JSON-Objekt. Oder irgendwas ganz anderes.

Die erste Route führt ihr aus, wenn ihr einfach http://127.0.0.1:3000 im Browser öffnet. Dort wird nur das Template geladen und Hello, World! ausgegeben. Interessanter wird das zweite Beispiel:

(defroutes main-routes
  ...
  (GET "/msg/:msg" [msg] (index {:msg msg}))
  ...)

Diese Route führt ihr aus, wenn ihr im Browser http://127.0.0.1:3000/msg/blahfasel öffnet. Alles nach msg/ wird von Compojure jetzt als Parameter in meine Funktion übergeben.

Und noch interessanter ist das dritte Beispiel:

(defroutes main-routes
  ...
  (GET "/json" []
    {:headers {"Content-Type" "application/json"}
     :body (json-str {:foo "foo", :bar "bar"})})
  ...)

Wenn ihr also http://127.0.0.1:3000/json im Browser öffnet, wird euch ein JSON-Objekt mit 2 Attributen zurückgegeben. Das ganze läuft über die ganz normale clojure.contrib JSON API, hat also weder was mit Compojure oder meiner Template-Engine zu tun. Ich erzeuge einfach mit folgenden Aufruf ein JSON-Objekt aus einer Map:

(json-str {:foo "foo", :bar "bar"})

Und das Ergebnis ist folgendes:

{"foo":"foo","bar":"bar"}

Ich habe in meinem Beispiel bereits die Template-Engine Enlive verwendet. Damit kann ich meine Antwort aus einer HTML-Datei lesen, mit Variablen anreichern und dem Nutzer zurückliefern. Dazu definiere ich mir ein Template, das eine map mit Werten bekommt und in die Datei einsetzt:

(deftemplate index "resources/test.html"
  [cmap]
  [:span#msg] (content (:msg cmap)))

Enlive arbeitet mit Selektoren, wer CSS und/oder JQuery kennt, wird sich da gleich wohl fühlen. Für mich reicht das erstmal aus und ich will für meine Beispiele so einfach wie möglich bleiben. Nachher versteh ich das selbst nicht mehr… 😉

Jetzt kann ich mit folgendem Kommando den Server starten und meine Seite bewundern. Anschliessend kann ich meine Dateien bearbeiten. leiningen übernimmt für mich das Neuladen der Äderungen und ich brauche im Browser nur noch F5 zu drücken. Hiermit wird der Server gestartet:

$ lein ring server
2011-02-24 18:14:59.362:INFO::Logging to STDERR via org.mortbay.log.StdErrLog
2011-02-24 18:14:59.363:INFO::jetty-6.1.26
2011-02-24 18:14:59.382:INFO::Started SocketConnector@0.0.0.0:3000
Started server on port 3000

Bei mir öffnet sich der Browser dann selbst und ich sehe direkt die Startseite. Viel Spass! 🙂

PS: Ihr könnt euch mein Beispielprojekt auch als ZIP runterladen: CmpjrAjaxTest.zip
PPS: Ihr solltet euch doch lieber gleich mein Repository bei github clonen.

Politiker können sich mittlerweile alles erlauben.

Fefe drückt das schon richtig aus:

Dieses Gefasel von christlichen Werten, Ehre, Anstand und Moral bei Politikern ist auch jetzt schon eine Farce, aber bisher ist es so, dass es Konsequenzen hat, wenn man beim Bescheißen erwischt wird als Politiker. Wenn wir die Konsequenzen abschaffen, indem wir den Guttenberg weiter im Amt verweilen lassen, dann ist das ein Dammbruch. Dann werden die in Zukunft nicht mal versuchen müssen, Ehre, Anstand und Moral zu simulieren. Diesen Präzedenzfall müssen wir verhindern!

Was soll das denn bitte sein, wenn man aus Eitelkeit oder zur Steigerung der Karrierechancen als Politiker einen Doktortitel erlangen will, dabei aber aus anderen arbeiten kopiert und nicht mal die einfachste Regel bei der Erstellung wissenschaftlicher Arbeiten (Hier ist ein PDF der Uni Bayreuth über einige Richtlinien) beachtet, und anschliessend nicht mal zurücktreten will? Wenn das Plagiat eindeutig erwiesen ist und die Uni schon den Titel zurücknimmt?

Und dann bittet er um Rücknahme des Titels? Ist sich aber keiner Täuschung bewußt? Ja genau…

Es geht schon nicht, wenn Politiker ihre Wahlversprechen eher als grobe Richtlinien sehen und sich gern mal darüber hinwegsetzen. Aber wenn sowas jetzt auch für Doktortitel gelten soll, läuft was falsch.

Update: Am Samstag gibt es in Berlin eine Demonstration. Wer Zeit hat, sollte da mal hingehen – vielleicht kann man schonmal das Schuh-Werfen üben. 😉

Neue T-Shirts

Nachdem ich bei Fefe gelesen hatte, dass getdigital.de abgemahnt wurde, hab ich direkt nochmal bestellt. Das füllt ja auch die Kriegskassen, damit man solchen Leute vor Gericht begegnen kann. Hier also meine neuen Shirts:

Neue ShirtsNeue ShirtsNeue ShirtsNeue Shirts

Blogs über Clojure

Weil ich in den letzten Tagen selbst auf der Suche nach interessanten Blogs zu Clojure gewesen, aber nichts gefunden habe, will ich hier mal eine Liste von interessanten Stellen im Netz aufbauen.

Ich werde die Liste erweitern, wenn ich mehr Quellen finde.

Clojure Tutorial, Teil 4: Organisation in Dateien

Dies ist der vierte Artikel in einer kleinen Serie, die meine ersten Schritte in der neuen funktionalen Programmiersprache Clojure dokumentieren soll. Die Artikel werden in unregelmäßigen Abständen hier publiziert.

Bei der Arbeit mit Clojure ist das Standardvorgehen zur Organisation von Sourcecode das Aufteilen von logischen Einheiten von Funktionen in einzelne Dateien. Die Namespaces der Funktionen sollten diese logische Zusammengehörigkeit wiederspiegeln. Ich habe das ganze mal am Beispiel einer sehr einfachen HTML-Bibliothek ausprobiert.

Datei 1: Hauptprogramm im Namespace FitbitClj.core

(ns FitbitClj.core
  (:use compojure.core
        compojure.handler
        ring.adapter.jetty
        ring.middleware.reload
        ring.middleware.stacktrace
        FitbitClj.html))

; define compojure routes
(site (defroutes test-routes
  (GET "/" {params :params}
    (str (h1 "Testing") (debug (h2 "params") params)))
  (ANY "*" []
    {:status 404, :body "Page not found."})
))

(def app
  (-> (var test-routes)
      (wrap-reload '(FitbitClj.core))
      (wrap-reload '(FitbitClj.html))
      (wrap-stacktrace))
)

(defn dev []
  (run-jetty #'app {:port 8080})
)

Wie man sieht, verwende ich hier Funktionen wie h1 oder debug, um mir ein einige Ausgaben auf einer Webseite anzusehen. Diese Funktionen sind kein Teil von Clojure oder Compojure, sondern selbstgeschrieben und in der Datei FitbitClj/html.clj gespeichert.

Datei 2: HTML-Bibliothek im Namespace FitbitClj.html

(ns
  #^{:author "Carsten Ringe"
     :doc "Simple HTML formatting"}
  FitbitClj.html)

(defn h1
  ([heading] (str "<h1>" heading "</h1>")))

(defn h2
  ([heading] (str "<h2>" heading "</h2>")))

(defn debug
  ([heading elem] (str heading "<pre>" elem "</pre>")))

Damit ist mein Hauptprogramm übersichtlich, während das langatmige Erzeugen des HTML-Markups aus dem Blickfeld versteckt ist.