Solargraph is a Ruby Language Server. It’s meant to add code completion and inline documentation onto IDEs.

We have to install the gem first

gem install solargraph

Within Sublime Text Control Panel (CTRL+Shift+P) :

  1. Find Package Control: Install Package
  2. Then LSP
  3. Hit enter

By default, the ST plugin will look for rvm, not rbenv. We have to force the settings Preferences > Package Settings > LSP > Settings, and paste this :

Note : you need to adjust the value of the path on line 8. You can find the exact installation path of solargraph on your system with the following command

which solargraph

Finally we can enable the server via the Sublime Text Control Panel (CTRL+Shift+P)

C’était ton premier jour d’école, aujourd’hui. Je n’aurais manqué ça pour rien au monde.

J’ai mal dormi cette nuit, remplis de doutes, d’incertitudes et de questions. Jusqu’à présent, nous t’avions gardé rien que pour nous, et désormais, tu aurais ta propre petite vie, en dehors de la maison. J’ai passé une bonne partie de la nuit à me demander si nous t’avions bien préparé.

Tu t’es réveillé de bonne humeur ce matin, tu as pris ton lait, tes céréales, et regardé un épisode des Pyjamasques. Je t’ai encore expliqué ce qui allait se passer, ta maman aussi. Je n’étais pas tout à fait sûr que tu comprenais bien toutes les implications que ça avait, mais tu es resté stoïque.

Quand l’heure de partir est arrivée, je n’en menais pas large. Toi par contre, tu as été brave. Très brave. Bien plus que je ne pouvais l’être. Dans la voiture, tu m’as demandé la vraie chanson. Tu parlais bien sûr de Californication. La vraie chanson, pas la berceuse que je te fais écouter le soir avant de dormir.

Nous sommes arrivés à l’école, ton petit cartable sur le dos, tu as traversé la cours en regardant tout autour de toi. Calme et silencieux, comme souvent, tu te contentais d’observer ce qui t’entourait. A l’intérieur, nous t’avons montré ton porte-manteau, ton prénom y était écrit à côté d’un dessin de petite voiture. Tu as déposé tes affaires avant de me montrer la petite cuisine, dans le couloir.

Enfin nous sommes entrés en classe. Tu as déposé ta collation et ta gourde dans le tiroir à ton nom, puis tu t’es précipité vers le garage des petites voitures. Tu étais à la fête : plein de jouets dans une salle remplie d’enfants. Intérieurement, je fondais en larmes de voir mon petit bonhomme devenir un grand, mais il ne fallait rien laisser transparaître.

Alors je me suis tu. Je t’ai souris, je me suis accroupi pour regarder de plus près le jouet que tu me montrais. Quand vint l’heure de partir, maman t’as expliqué que nous te laissions là, jouer avec tes nouveaux amis, mais qu’elle viendrait te rechercher un peu plus tard. Tu as hoché la tête, en disant « oui ». Tu nous a pris dans tes bras, fait un bisou, puis tu t’es dirigé vers la fenêtre pour nous faire « coucou ».

Nous nous sommes éloignés sans pour autant quitter l’école tout de suite. Je t’ai vu revenir à la fenêtre quelques minutes plus tard. Tu as regardé un petit moment, puis, ne nous voyant pas, tu es retourné dans l’espace de jeu.

C’était un moment dur pour ta maman et moi, mais bien heureusement, il a semblé bien plus facile pour toi. J’ai hâte de rentrer à la maison, ce soir, et de t’entendre me raconter ta journée.

 

Rubocop is a static code analyzer and formatter for Ruby. Long story short : it helps you to write better code.

Installing it pretty straight-forward :

gem install rubocop

Within Sublime Text Control Panel (CTRL+Shift+P) :

  1. Find Package Control: Install Package
  2. Then Rubocop (currently v2018.12.05.18.01.20)
  3. Hit enter

By default, the ST plugin will look for rvm, not rbenv. We have to force the settings Preferences > Package Settings > Rubocop > Settings - Users, and paste this :

Now we can have a list of the available options by typing rubocop withing the Control Panel (CTRL+Shift+P).

Il y a quelques jours, j’ai travaillé sur une mise à jour majeure d’une application écrite en Ruby on Rails. L’application tournait sur la version 3.2 du framework, et celle-ci étant dépréciée depuis longtemps, il était largement temps de la faire passer en version 5.2.

Cela signifie donc deux passages de versions majeures et 4 passages de versions mineures. Avec, pour chaque saut de version, la nécessité de mettre à jour les versions des gems utilisées. Autant dire que la commande bundle a été sollicitée.

Le point de frustration était l’approche itérative de bundle (la première dépendance est vérifiée et mise à jour, puis on passe à la seconde, etc) dans un fichier qui comptait pas moins de 137 dépendances. Ce qui m’a poussé à fouiller la documentation de bundle pour y découvrir l’option --jobs qui permet de définir un nombre de processus concurrentiels.

Pour lancer 4 jobs en parallèle, on peut donc lancer la commande comme ceci :

bundle install --jobs=4

Il est également possible de définir cette configuration par défaut pour ne plus avoir à s’en soucier à l’avenir :

bundle config --global jobs 4

En bonus, on peut également demander à ne plus installer les documentations par défaut (soyons francs, tout le monde va chercher la documentation sur Internet, il est inutile d’avoir une version locale). Pour ce faire, il est nécessaire de créer un fichier ~/.gemrc et d’y inclure :

gem: --no-rdoc --no-ri

Il y a maintenant plusieurs semaines que j’utilise ProtonMail. Bien que rassembler mes 7 adresses précédentes sur une seule m’a grandement simplifié la vie, je ne suis toujours pas satisfait des clients disponibles. Sous Linux, seul Thunderbird est actuellement disponible, à moins d’utiliser de webmail – ce que je fais pour l’instant.

Il y a quelques années, j’avais testé Mutt un peu comme un jeu. La raison pour laquelle j’avais arrêté de l’utiliser était justement le nombre d’adresse que je devais gérer : l’outil était certes intéressant, mais difficile à utiliser avec autant de compte.

Maintenant que j’ai résolu ce problème, j’avais envie de redonner une chance à ce client minimaliste et, par la même occasion, voir s’il était possible de faire cohabiter Mutt et ProtonMail.

Installation et premier lancement

Pour installer mutt, il suffit d’installer le paquet du même nom :

sudo apt install mutt

En lancant pour la première fois la commande mutt, je reçois une erreur :

/var/mail/cedric: Aucun fichier ou dossier de ce type (errno = 2)

Je crée le fichier en question et je lui donne les permissions nécessaire à mon utilisateur :

sudo mkdir -p /var/mail/$(whoami)
sudo chown $(whoami):$(whoami) /var/mail/$(whoami)

J’en profite pour initialiser le fichier de configuration .muttrc

vim ~/.muttrc 
set realname = "Your Name"
set header_cache =~/.mutt/cache/headers
set certificate_file =~/.mutt/certificates
set message_cachedir =~/.mutt/cache/bodies

Lancer une nouvelle fois la commande mutt, ne donne plus d’erreur.

Premier écran du logiciel Mutt – un client mail en ligne de commande. Au moins, c’est épuré 🙂

Configuration de mutt

Note : je pars du principe que le Bridge pour Linux est installé et lancé.

J’ajoute au fichier de configuration .muttrc les lignes suivantes:

# "+" substitutes for `folder`
set mbox_type=Maildir
set folder=/var/mail/cedric/
set spoolfile=+INBOX
set record=+Sent
set postponed=+Drafts
set trash=+Trash
set mail_check=2 # seconds

# smtp
source ~/docs/keys/mail
set smtp_url=smtp://$my_user:$my_pass@127.0.0.1:1025
set ssl_force_tls
set ssl_starttls

Et dans le fichier ~/docs/keys/mail:

set my_user=EMAIL
set my_pass=MOT_DE_PASSE_DU_BRIDGE

Installation et configuration de OfflineIMAP

J’installe OfflineIMAP :

sudo pip install offlineimap

Puis je crée un fichier de configuration .offlineimaprc :

[general]
accounts = main

[Account main]
localrepository = main-local
remoterepository = main-remote

# full refresh, in min
autorefresh = 0.2

# quick refreshs between each full refresh
quick = 10

# update notmuch index after sync
postsynchook = notmuch new


[Repository main-local]
type = Maildir
localfolders = /var/mail/cedric

# delete remote mails that were deleted locally
sync_deletes = yes


[Repository main-remote]
type = IMAP
remoteport = 1143
remotehost = 127.0.0.1
remoteuser = EMAIL
remotepass = MOT_DE_PASSE_DU_BRIDGE
keepalive = 60
holdconnectionopen = yes

# delete local mails that were deleted on the remote server
expunge = yes

# sync only these folders
folderfilter = lambda foldername: foldername in ['INBOX', 'Archive', 'Sent']

# is broken, but connecting locally to bridge so should be ok
ssl = no

On lance la commande offlineimap, et, si tout s’est bien passé, on peut commencer à voir la progression de la synchronisation avec ProtonMail :

OfflineIMAP 7.2.1
  Licensed under the GNU GPL v2 or any later version (with an OpenSSL exception)
imaplib2 v2.57 (bundled), Python v2.7.14, OpenSSL 1.0.2g  1 Mar 2016
Account sync main:
 *** Processing account main
 Establishing connection to 127.0.0.1:1143 (main-remote)
 Creating folder INBOX[main-local]
 Creating new Local Status db for main-local:INBOX
 Creating folder Archive[main-local]
 Creating new Local Status db for main-local:Archive
 Creating folder Sent[main-local]
 Creating new Local Status db for main-local:Sent
Folder Archive [acc: main]:
 Syncing Archive: IMAP -> Maildir
Folder INBOX [acc: main]:
 Syncing INBOX: IMAP -> Maildir
Folder Archive [acc: main]:
 Copy message UID 1 (1/263) main-remote:Archive -> main-local:Archive
Folder INBOX [acc: main]:
 Copy message UID 1 (1/49) main-remote:INBOX -> main-local:INBOX
Folder Archive [acc: main]:
 Copy message UID 2 (2/263) main-remote:Archive -> main-local:Archive
Folder INBOX [acc: main]:
 Copy message UID 2 (2/49) main-remote:INBOX -> main-local:INBOX

Il ne reste plus maintenant qu’à relancer la commande mutt pour visualiser ses mails.

Mutt est maintenant configuré pour fonctionner avec ProtonMail
L’interface de Mutt une fois la configuration terminée

Je viens à de terminer l’écoute de « Père riche, père pauvre« , de Robert T. Kiyosaki. Ce livre m’a permis de mettre en perspective le vide abyssal de mes connaissances financières et m’a mis face à face avec mes envies et les moyens que je me suis donné jusqu’aujourd’hui pour y parvenir.

Autant vous dire que le choc fut violent.

Le titre du livre est certes très vendeur, et le sous-titre l’est encore plus. Ceci dit, le livre ne prodigue aucun conseil réel quant à la manière de devenir riche, mais il ouvre des perspectives de réflexion pour qui a l’esprit suffisamment ouvert aux nouvelles idées. En substance, l’auteur dit deux choses primordiales :

  1. Travailler la colonne des actifs : en résumé, il faut faire travailler l’argent pour gagner de l’argent. Notre temps (et donc notre temps de travail qui permet de faire rentrer un salaire) est limité, et il est donc fort probable qu’un travail « classique » ne nous rendra jamais riche. De même, le travail est automatiquement imposé à la source, et une partie des revenus d’une personne donnée repart donc immédiatement à la collectivité (l’État).
    L’auteur propose donc d’investir son argent pour générer des revenus passifs (revenus locatifs, dividendes, investissements dans des petites sociétés, etc);
  2. L’éducation est l’investissement le plus précieux que nous pouvons faire : l’auteur conseille d’investir dans sa propre éducation dans des compétences pratiques telles que l’investissement, les marchés boursiers, la vente, le marketing ou encore la comptabilité. Il répète à l’envi que les gens n’arrivent pas à faire d’argent car ils ne comprennent pas l’argent. L’éducation financière – qui bien souvent fait défaut – est donc la clé de l’enrichissement.

J’ai donc fait un brin d’auto-critique, et il faut admettre que mon éducation – et ma gestion – financière sont, au mieux, catastrophique. Même si j’essaie de m’améliorer, il y a encore fort à faire. Mon éducation financière, si l’on peut l’appeler ainsi, s’est limité à 3 conseils qui m’ont été prodigués tantôt par ma mère, tantôt par mon grand-père :

  1. N’achète rien que tu ne puisses acheter deux fois;
  2. Sois toujours en possession d’un fond de secours correspondant à 6 mois de dépenses courantes;
  3. Sois toujours capable de pouvoir remplacer dans l’instant ton bien le plus cher et le plus utile (typiquement : ma voiture).

A défaut d’avoir une une réelle éducation financière, je dois reconnaître que ces 3 conseils sont plein de bon sens. J’ai tenté des les appliquer avec plus ou moins d’assiduité mais ils ont le mérite d’être censés.

« N’achète rien que tu ne puisses acheter deux fois » me force à réfléchir, avant chaque achat, à son utilité réelle et à sa compatibilité avec la règle #3.

« Sois toujours en possession d’un fond de secours » est une règle de bon sens qui me permet de vivre relativement sereinement, même en cas de perte ou de diminution de revenu passagère

Enfin « Sois toujours capable de pouvoir remplacer dans l’instant ton bien le plus cher et le plus utile » est également une règle de bon sens. J’ai besoin de ma voiture pour me déplacer et pour travailler; le travail est ma principale source de revenu, et si je suis privé de moyen de locomotion, j’ai du mal à remplir mes obligations professionnelles.

En conclusion, je ne deviendrai certainement pas riche demain, mais je m’efforcerai d’approfondir mon apprentissage et ma compréhension des mes finances personnelles pour me donner les moyens d’atteindre mes objectifs.

Enfer et damnation, vous venez de constater un bug dans votre code. Évidemment, il est difficile de savoir à quel moment cette régression est apparue et en trouver l’origine pourrait nous permettre de comprendre et donc de résoudre le bug.

Heureusement, git-bisect vient à votre secours, pour peu de savoir l’utiliser.

On commence donc par signifier à git que nous sommes dans un état « mauvais » du code :

git bisect bad

Vous devez démarrer avec "git bisect start"
Souhaitez-vous que je le fasse pour vous [Y/n] ? y

Il faut maintenant remonter suffisamment longtemps dans l’historique dans l’objectif de trouver l’état du code ou la régression constatée n’existait pas. Un petit git log devrait suffire à identifier le commit-id correspondant.

git checkout <commit-id>

Après avoir vérifié que la régression n’existait pas dans cet état du code, on signifie à git-bisect qu’on a une sous la main une version du code correcte.

git bisect good
Bissection : 132 révisions à tester après cette (à peu près 7 étapes)
[<commit-id>] <commit-message>

En retour, git-bisect nous donne le nombre de révisions à tester (ici : 132), et le nombre d’étapes estimées avant d’obtenir le nom du coupable (ici : 7). Enfin, git-bisect à effectué un checkout automatique sur un autre <commit-id> et attend vos instructions.

Il ne reste qu’a tester le code et à donner comme instruction soit un git bisect good, soit un git bisect bad en fonction du résultat observé. L’opération sera plus ou moins longue en fonction du nombre de commits à tester.

➜  webapp git:(6ae90d246) git bisect good
Bissection : 132 révisions à tester après cette (à peu près 7 étapes)
[49cbe40d5cb63b9f2a036560190983b2848d6df0] Merge branch 'master' into deploy/staging
➜  webapp git:(49cbe40d5) ✗ git bisect good
Bissection : 66 révisions à tester après cette (à peu près 6 étapes)
[dc9c093633ca9af720ae560b01ff455d4bd4fb51] <commit-message>
➜  webapp git:(dc9c09363) ✗ git bisect good
Bissection : 33 révisions à tester après cette (à peu près 5 étapes)
[4f8b4fd5f7ecb71141510823e89f3d941f6d892b] <commit-message>
➜  webapp git:(4f8b4fd5f) git bisect bad                                       
Bissection : 16 révisions à tester après cette (à peu près 4 étapes)
[0e5acfb262de5f692f8383cd51fe5c4bed729b92] <commit-message>
➜  webapp git:(0e5acfb26) git bisect good
Bissection : 7 révisions à tester après cette (à peu près 3 étapes)
[7623848ffee8d72429623e3b5fb8fb1a8040aeed] <commit-message>
➜  webapp git:(7623848ff) ✗ git bisect good
Bissection : 4 révisions à tester après cette (à peu près 2 étapes)
[50f6b9ebf42ff5cda83d33d4489e944829f87c56] <commit-message>
➜  webapp git:(50f6b9ebf) ✗ git bisect good
Bissection : 2 révisions à tester après cette (à peu près 1 étape)
[d763c0336e13cbc91befbe853194dd077775e6cd] <commit-message>
➜  webapp git:(d763c0336) git bisect good
Bissection : 0 révision à tester après cette (à peu près 1 étape)
[c1af98fc24e031d0d87a567caa7615c0c2c3d66c] <commit-message>
➜  webapp git:(c1af98fc2) git bisect bad 
Bissection : 0 révision à tester après cette (à peu près 0 étape)
[026f9bf37555815c0efc9dfb16e90473faacf48f] <commit-message>

Une fois la dernière étape passé, git-bisect vous donne l’identité du coupable :

git bisect bad
026f9bf37555815c0efc9dfb16e90473faacf48f is the first bad commit

Pour terminer, nous pouvons revenir à l’état initial du code (HEAD)

git bisect reset

First, check that your development machine has both docker and docker-machine installed

which docker
which docker-machine

Create a new droplet on Digital Ocean

docker-machine create --digitalocean-size "s-1vcpu-1gb" --driver digitalocean --digitalocean-access-token YOUR_DIGITALOCEAN_ACCESS_TOKEN invoiceninja-prod

Set up the right environment

eval $(docker-machine env invoiceninja-prod)

Run the container

docker run -d -e APP_ENV='production' -e APP_DEBUG=0 -e APP_URL='http://ninja.dev' -e APP_KEY='SomeRandomStringSomeRandomString' -e APP_CIPHER='AES-256-CBC' -e DB_TYPE='mysql' -e DB_STRICT='false' -e DB_HOST='localhost' -e DB_DATABASE='ninja' -e DB_USERNAME='ninja' -e DB_PASSWORD='ninja' -p '80:80' invoiceninja/invoiceninja

Retrieve your IP

docker-machine ip invoiceninja-prod

Today on #indieweb-wordpress, I’ve been asked why, given my technical background, I did not used some of the Ruby based solution to jump in and try the Indieweb principles.

As a reminder, I (re)discovered Indieweb and POSSE a few days ago now, and even if I’ve been using Ruby and Rails as my main languages for almost a decade now, I choose to setup a new WordPress blog to play around with it.

There are a few reasons for this :

  1. Setting up a WordPress was a one-click task with my current host (gandi.net, thanks for asking)
  2. I read along the Indieweb wiki for a few days, gathering information about how it is supposed to be done, and why everyone should have their own website. In the wiki, most of the tutorials were WordPress based and it seems to me like a good place to start. To be completely honest I did not even noticed there was a Ruby page.
  3. Even if I do not like WordPress, I have to admit that the community around it is huge, thus, more chance to find every plugin I would need to setup my new home on the Internet
  4. I never said I’d stick with WordPress. More likely I am going to play around with it for a few, then find my way back home with a Ruby on Rails solution.