• I've been using eklablog for some time now (approximately 5 years) and it's time for me to move on. A web-based WYSIWYG editor is not the best publication pipeline for me anymore. I need my tools to work offline and to offer me the same flexibility as when I write code.

    That's why I've switched to a text-only publication system, based on Hakyll, backed up by git and deployed on the clever cloud. That's were my future posts will be.

    For now, it's available at http://blog.clement.delafargue.name

    If you're interested on how it works, check out http://blog.clement.delafargue.name/2012-10-21-blog-deployment-system.html

     


  • Je suis en train de finir la rédaction de mon rapport de stage. J'ai utilisé sphinx, l'outil de documentation de python, ce qui me permet de rédiger le rapport en ReST, puis de l'exporter dans un des formats disponibles (LaTeX, HTML, ePub…).

    Le fichier de configuration permet de spécifier la langue du document, mais il y a d'autres options à changer pour que l'export LaTeX se passe bien.

    language = 'fr_FR'

    latex_elements = {
        "fncychap": "\\usepackage[Sonny]{fncychap}"
        "babel": "\\usepackage[francais]{babel}"
    }
    [code=python]
    language = 'fr_FR'

    latex_elements = {
        "fncychap": "\\usepackage[Sonny]{fncychap}"
        "babel": "\\usepackage[francais]{babel}"
    }
    [/code]


  • I've been working for a few months with Lift, a really nice web framework. Lift takes ideas and concepts from a few other frameworks. The main difference between Lift and other frameworks is that Lift does not enforce MVC (even though you can do MVC if you want to). Lift's approach is view-first, which means you first create the view, then you tell which part of the code will take care of dynamism.

    For more propaganda: Seven Things and Web Framework Manifesto

    I'll explain how to build REST-y URLs in a type-safe manner, with the SiteMap. The goal is to access a blog post with this kind of URL: /posts/{id}

    I'll illustrate this article with something tremendously original: a Blog, with posts. I'll use mongoDB as a backend, but it's not really important.

    The model

    It's a simple blog post. Let's just assume the author is stored in plain text.

    class BlogPost private() extends MongoRecord with ObjectIdPk[BlogPost] {
      def meta = BlogPost
      object author extends StringField(this, 32)
      object date extends DateField(this)
      object content extends TextareaField(this, 500)

      val url =// We'll see that later
    }

    object BlogPost extends BlogPost with MongoMetaRecord[BlogPost] {
      val entry =// We'll see that later
      def calcHref(bp: BlogPost) =// We'll see that later
    }
    [code=scala]
    class BlogPost private() extends MongoRecord with ObjectIdPk[BlogPost] {
      def meta = BlogPost
      object author extends StringField(this, 32)
      object date extends DateField(this)
      object content extends TextareaField(this, 500)

      val url = … // We'll see that later
    }

    object BlogPost extends BlogPost with MongoMetaRecord[BlogPost] {
      val entry = … // We'll see that later
      def calcHref(bp: BlogPost) = … // We'll see that later
    }
    [/code]

    The template

    Nothing special there. Just save it in webapp/posts.html. We have a h1 for the title, a p for some info, and a p for the actual post.

    <div class="lift:surround?with=default;at=content">
    <div class="lift:BlogPostSnippet">
    <h1 class="title"></h1>
    <p class="info"></p>
    <p class="blogpost"></p>
    </div>
    </div>
    [code=html]
    <div class="lift:surround?with=default;at=content">
    <div class="lift:BlogPostSnippet">
    <h1 class="title"></h1>
    <p class="info"></p>
    <p class="blogpost"></p>
    </div>
    </div>
    [/code]

    The snippet

    This class will be instantiated with the blog post we want to display. We just inject data in the markup.

    class BlogPostSnippet(val blogPost: BlogPost) {
      def render = ".title *" #> blogPost.title.is &
        ".info *" #> ("By " + blogPost.author.is) &
        ".blogpost *" #> blogPost.content.is
    }
    [code=scala]
    class BlogPostSnippet(val blogPost: BlogPost) {
      def render = ".title *" #> blogPost.title.is &
        ".info *" #> ("By " + blogPost.author.is) &
        ".blogpost *" #> blogPost.content.is
    }
    [/code]

    The SiteMap

    So, back to BlogPost.entry, where the magic happens. We define an entry of the sitemap which is associated with the BlogPost class. The two first arguments are the id and the displayed name of the link. The third argument is a function which takes a String and returns a Box[BlogPost]. This tells Lift how to instantiate BlogPostSnippet with the right blog post. The fourth argument is used to create an url from a given blog post. Finally, we specify the address and tell Lift we don't want this entry to show up in the menus.

    The calcHref method is just a shortcut.

    class BlogPost … {
      /* Snip */
      val url = BlogPost.calcHref(this)
    }

    object BlogPost … {
      val entry = Menu.param[BlogPost](
        "blogpost",
        S ? "blogpost.view",
        (id: String) => BlogPost.find(id),
        (bp: BlogPost) => bp.id.is
      ) / "posts" / * >> Hidden

      def calcHref(bp: BlogPost) = entry.toLoc.calcHref(bp)
    }
    [code=scala]
    class BlogPost … {
      /* Snip */
      val url = BlogPost.calcHref(this)
    }

    object BlogPost … {
      val entry = Menu.param[BlogPost](
        "blogpost",
        S ? "blogpost.view",
        (id: String) => BlogPost.find(id),
        (bp: BlogPost) => bp.id.is
      ) / "posts" / * >> Hidden

      def calcHref(bp: BlogPost) = entry.toLoc.calcHref(bp)
    }
    [/code]

    Don't forget to add BlogPost.entry to the SiteMap

    val entries = /* other entries */ :: BlogPost.entry :: Nil
    LiftRules.setSiteMap(SiteMap(entries: _*))
    [code=scala]
    val entries = /* other entries */ :: BlogPost.entry :: Nil
    LiftRules.setSiteMap(SiteMap(entries: _*))
    [/code]


    Next time I'll show you how to display comments after the blog post, while keeping the HTML structure of every comment in the template :)


  • Du 9 au 14 juillet avaient lieu les douzièmes Rencontres Mondiales du Logiciel Libre. L'occasion de rencontrer tout un tas de libristes et de contributeurs dans une ambiance sympa et détendue. Des conférences et des keynotes très intéressantes réalisées par (entre autres) Richard M. Stallman et Benjamin Bayart.

    Ces RMLL ont été l'occasion de présenter notre retour d'expérience sur différents projets libres menés à l'École Centrale de Nantes. Avec Morgan Magnin, Benjamin Vialle et Nelle Varoquaux, nous avons eu la chance de faire trois conférences autour de MarkUs, l'application de correction de TP, et d'OpenOffice.org.

    Les supports de ces présentations, ainsi que de plus amples explications sont disponibles dans la suite de l'article.

    Lire la suite...


  • Durant mon stage, j'ai eu l'occasion de peaufiner ma conf vim.

    D'abord le remappage bépo

    Grosso modo, je me suis borné à remapper les touches de façon à avoir les touches de déplacement sur ctsr. J'ai mis la conf dans un fichier à part, que je source à la fin du .vimrc
    J'ai bricolé ça grâce au Wiki de vim.fr : Page consacrée à vim
    Il y a plusieus niveaux de remappage, du plus léger au plus extrème. J'ai opté pour un remappage assez léger, de manière à ne pas être trop perdu sur un vim normal

    Ensuite les plugins

    L'ajout de plugins est capital pour bien utiliser vim. Voici ceux que me suis installés :

    Ceux dont je ne pourrais pas me passer, c'est snipMate (Texmate-like snippets) et template (templates pour les nouveaux fichiers). phpComplete et JavaComplete permettent d'avoir l'omnicomplétion pour Java et PHP, ce qui est pas mal aussi. Project peut être sympa pour les gros projets.

    ftplugin

    Ftplugin permet d'associer à chaque type de fichier ouvert une configuration particulière. Par exemple, pour des règles spécifiques à python, il suffit de mettre ces règles dans ~/.vim/ftplugin/python.vim

    " Active l'auto-complétion pour python
    set omnifunc=pythoncomplete#Complete
    " Indentation à 4 espaces
    setlocal tabstop=4
    setlocal shiftwidth=4
    setlocal expandtab
    setlocal softtabstop=4

    Je m'en sers aussi (entre autres) pour mettre le correcteur orthographique pour les mails et les documents LaTeX et ReST

    Le .vimrc, pour finir

    Mon .vimrc complet (et mes autres fichiers de conf) est dispo sur github. Mais en gros ce que j'y ai mis, c'est

    • la coloration syntaxique
    • une petite fonction pour avoir une autocomplétion intelligente mappée sur Ctrl-Space
    • un mapping de certaines extensions à un type de fichier (quand ce n'est pas fait automatiquement)

    Mes sources

    Un bon fichier de conf se construit par tatonnements, et surtout grâce à l'inspiration fournies par les autres. Voici une liste (non exaustive hélas) de ce qui m'a inspiré.






    Suivre le flux RSS des articles
    Suivre le flux RSS des commentaires