Exile on Keyboard St. - Blog sur Linux et Debian

Aller au contenu | Aller au menu | Aller à la recherche

jeudi 26 décembre 2019

Deux Plugins IDEA pour copier du code en tant qu'image et les utiliser dans des fichiers Markdown

Intégrer quelques lignes de code dans un fichier Markdown, README ou autre, ne pose pas de problème particulier.

On utilise alors:

  • Une indentation de 4 espaces (ou d'une tabulation)
  • Une séquence de code entre deux sections délimitées par trois backticks

Par exemple:

```console
$ sudo curl -L https://git.framasoft.org/grumpyf0x48/liar/raw/0.1/liar -o /usr/local/bin/liar
```

ce qui donne le rendu suivant.

Code in Markdown

Vous noterez qu'ici le caractère $ a été ajouté pour bien matérialiser la présence d'un Shell mais il n'est absolument pas requis dans la syntaxe Markdown.

Malheureusement, lorsque votre moteur de blog, par exemple la version de dotclear utilisée ici par Gandi, ne vous permet pas un rendu sympa des blocs de code, il faut bien trouver une solution !

Créer une image à partir d'une sélection de code dans IntelliJ

On va alors avoir recours à un plugin dans IntelliJ pour créer très rapidement une image à partir d'une section de code que l'on vient de sélectionner.

Ce plugin, c'est Code Screenshots, qui une fois installé va créer une image du code sélectionné chaque fois que vous utiliserez le raccourci: Ctrl+Alt+Shift+A.

L'image en question sera alors placée dans le presse papier (clipboard) du système.

On récupère l'image de la façon suivante:

xclip -selection clipboard -t image/png -o > $HOME/code-snippet.png

Notez qu'il nous faudra ensuite l'uploader sur le site du blog.

Copier une image dans un fichier Markdown depuis IntelliJ

Si maintenant nous avons une image dans le presse papier du système et que nous souhaitons l'intégrer dans un fichier Markdown édité avec IntelliJ, nous allons installer un deuxième plugin, et c'est Paste Images into Makdown.

Une fois installé, le raccourci Ctrl + V utilisé dans un fichier Markdown lorsqu'une image existe dans le presse-papier affichera la boite de dialogue suivante:

Paste Image into Markdown

Il ne nous reste alors qu'à choisir:

  • le nom de l'image
  • le répertoire où l'on souhaite la placer

et le fichier Markdown est alors modifié comme suit:

![](.README_images/040301ad.png)

Il nous reste enfin à donner un titre à cette image dans le Markdown.

mercredi 14 août 2019

10 raccourcis clavier indispensables dans IDEA

Les développeurs Java connaissent bien les raccourcis clavier les plus usuels d'IntelliJ IDEA comme par exemple:

  • Shift Shift: Search everywhere
  • Alt + Enter: Show intentions
  • Shift + F6: Rename

ou encore:

  • Alt + Ins (ou Fn + Alt + Suppr): Generate code

Mais il y en a bien d'autres que nous utilisons quotidiennement, et ce sont ceux-la qui nous intéressent aujourd'hui.

Ctrl + Shift + A permet de chercher directement une action sans avoir à parcourir la barre d'outils ou l'ensemble des menus.

Ctrl + N, Ctrl + Alt + Shift +N permet de chercher respectivement une classe ou un symbole (variable, méthode ...).

Les deux raccourcis précédents sont des "spécialisations" du menu principal de recherche auquel on accède par Shift Shift.

Seul regret, les raccourcis utilisant 4 touches comme Ctrl + Alt + Shift + N sont un peu fatiguants à la longue !

Ctrl + F12 affiche le popup "File structure", ce qui pour une classe affiche l'ensemble des champs et méthodes. Avec Eclipse, le raccourci était Ctrl + O, mais vous n'utilisez plus Eclipse depuis longtemps !!!

Un raccourci que j'utilise souvent pour naviguer au sein de l'ensemble des fichiers actuellement modifiés, c'est Ctrl + Alt + Left / Right, et ça rend la navigation plus simple que de cliquer chaque fois sur l'onglet du fichier suivant. Ces deux raccourcis sont accessibles dans la barre d'outils via les icônes Back / Forward. On peut aussi utiliser Ctrl + Shift + Backspace.

Dans la même veine Ctrl + E et Ctrl + Shift + E affichent le "Recent files / Recent locations" popup. Ctrl + E affiche les fichiers récemment ouverts et Ctrl + Shift + E les endroits précis de ces fichiers récemment ouverts.

Ces deux racourcis sont extrèmement commodes surtout qu'en cliquant sur "Show changed only", on peut restreindre les résultats aux seules modifications faites dans le code.

Toujours dans la catégorie Navigation, F2, Shift F2 permettent de naviguer vers la prochaine / précédente erreur dans le fichier courant. Cela va infiniment plus vite que d'aller cliquer sur la petite ligne rouge dans la scrollbar ! Par contre, c'est un peu dommage qu'on ne puisse pas passer d'un fichier à l'autre - quand on a plusieurs erreurs de compilation suite à un changement de signature par exemple, ce serait bien pratique.

Pour ceux qui font du TDD, Ctrl + Shift + T permet de créer un classe de test pour la classe courante, ou de naviguer vers celle-ci si elle existe, ou encore de revenir à la classe d'implémentation depuis la classe de test. C'est alors très rapide de voir qu'une classe ne comporte pas de test unitaire ...

Curieusement, ce raccourci semble ne pas figurer dans la ReferenceCard des raccourcis d'IDEA !

Ctrl + Alt + Maj + T est un de mes préférés, il affiche le menu contextuel "Refactor this", et vous évite de mémoriser tous les racourcis correspondants: Extract variable, Extract method ...

L'avant dernier, Ctrl + Maj + Up / Down déplace le bloc de code sélectionné, c'est toujours plus propre et moins casse gueule que le Copier / Coller.

Enfin, le dernier Ctrl + Alt + Shift + S accède aux propriétés du projet, c'est à dire la fenêtre "File structure". C'est là que l'on choisit notamment le JDK utilisé.

lundi 6 août 2018

Java: Bien utiliser le Builder pattern

Quand on maintient du code Java, on tombe malheureusement assez souvent sur des méthodes aux signatures complexes comme celle-ci:

public int myMethod(String id, String name, Boolean secure, Object obj, Object backupObj, boolean restart)

Et il n'est pas rare d'avoir encore plus de paramètres !

La situation se dégrade encore quand pour "simplifier", on surcharge la méthode précédente en:

public int myMethod(String id, String name, Boolean secure, Object obj, Object backupObj)

quand restart vaut false puis en:

public int myMethod(String id, String name, Boolean secure, Object obj)

quand en plus backupObj est null.

On peut avoir ainsi 3 à 5 signatures différentes pour la même méthode. Et cela devient vite unsupportable quand on veut refactorer ces méthodes, parce qu'elles sont référencées n fois dans le code de production et également dans les tests.

Si le développeur qui a créé la première méthode avait créé un object et l'avait passé en paramètre de sa méthode, on n'en serait pas là !

Imaginons maintenant la méthode suivante qui permet de créer un utilisateur:

public long create(final String firstName, final String name, final int age)

Elle retourne l'identifiant de l'utilisateur créé. Supposons que l'age n'est pas obligatoire et que l'on souhaite anticiper l'ajout de nouveaux champs pour créer un utilisateur.

On va alors plutôt procéder comme suit:

public long create(final User user)

La classe User commencera comme ceci:

public class User
{
    private long id;
    private String firstName;
    private String lastName;
    private int age;
}

Mais pour créer un utilisateur à passer en paramètre de la méthode create, on va créer un Builder pour construire l'objet User.

Pour cela, on peut installer le Plugin Builder Generator. Un autre plugin est également disponible: Inner Builder.

Après redémarrage d'IDEA, un clic-droit puis Generate propose maintenant l'option "Builder" et on a alors la boite de dialogue suivante:

Capture-CreateBuilder.png

Ici on a choisi un "innerBuilder" afin que le Builder soit une classe interne de l'objet lui même.

On choisit ensuite la liste des champs à inclure, on ne prends pas l'id puisqu'il ne sera pas calculé par l'appelant de la méthode create mais bien par celle-ci:

Capture-Select_Fields_to_Be_Available_in_Builder.png

Et on obtient:


    public static final class UserBuilder
    {
        private String firstName;
        private String lastName;
        private int age;

        private UserBuilder()
        {
        }

        public static UserBuilder anUser()
        {
            return new UserBuilder();
        }

        public UserBuilder withFirstName(String firstName)
        {
            this.firstName = firstName;
            return this;
        }

        public UserBuilder withLastName(String lastName)
        {
            this.lastName = lastName;
            return this;
        }

        public UserBuilder withAge(int age)
        {
            this.age = age;
            return this;
        }

        public User build()
        {
            User user = new User();
            user.lastName = this.lastName;
            user.age = this.age;
            user.firstName = this.firstName;
            return user;
        }
    }

On crée ensuite notre User comme suit:

        final User user = UserBuilder
                    .anUser()
                    .withFirstName("Brian")
                    .withLastName("Kernighan")
                    .build();

Cette façon de faire permet:

  • de faire évoluer l'objet User en changeant un minimum de code
  • de valider les différents champs dans la méthode build

Et les signatures des méthodes ne changent pas.

On peut même éviter de dupliquer les champs de la classe User dans la classe UserBuilder en procédant comme ceci:

public static final class UserBuilder
    {
        private User user;

        private UserBuilder()
        {
            user = new User();
        }

        public static UserBuilder anUser()
        {
            return new UserBuilder();
        }

        public UserBuilder withFirstName(String firstName)
        {
            this.user.firstName = firstName;
            return this;
        }

        public UserBuilder withLastName(String lastName)
        {
            this.user.lastName = lastName;
            return this;
        }

        public UserBuilder withAge(int age)
        {
            this.user.age = age;
            return this;
        }

        public User build()
        {
            return user;
        }
    }

Mais notre générateur ne sait pas le faire :-(

- page 1 de 2