Vendredi 12 juin 2009
Pour tous les symfonistes (et quelques autres), manipuler des fichiers yml d'une bonne centaine de lignes minimum est une activité normale et quotidienne, indispensable pour se mettre de bonne humeur au réveil. Pour ceux qui ne connaitraient pas le parser Yaml, il s'agit d'un animal susceptible, ne tolérant que les indentations de 2 espaces et haïssant les tabulations au point de refuser de parcourir un fichier en contenant (même une petite). Il est assez facile de configurer Vim une bonne fois pour toute afin de proposer les options suivantes :

- indentation par défaut : 2 espaces
- transforme les tabulations en 2 espaces
- affiche les caractères de fin de ligne, les tabulations et espaces entre le dernier caractère et la fin de la ligne

set tabstop=2

      set shiftwidth=2

      set expandtab

      set listchars=eol:¤,trail:-


Les listchars ne seront affichés que si vous le demandez avec un «set list» pour le désactiver : «set nolist»

Cela évite les problèmes les plus courants. Par contre, dès que vos Yml deviennent consistants, il devient délicat de repérer les niveaux d'imbrication des blocs. Il est pour cela possible de surligner la ligne et la colonne courante pendant le mode édition. Vim vous permet en effet de modifier sa conf suite à un évènement. Demandez le surlignage lors du passage en mode édition et seulement pour les fichiers Yml pour les colonnes :

" Changement de configuration lors des transitions

       " mode commande & mode insertion

       autocmd insertLeave * set nocursorline

       autocmd insertEnter * set cursorline

       autocmd insertLeave *.yml set nocursorcolumn

       autocmd insertEnter *.yml set cursorcolumn

       "  Le choix des couleurs...

       highlight CursorLine                    cterm=none ctermbg=DarkBlue

       highlight CursorColumn                  cterm=none ctermbg=DarkRed



Et voila le travail, en mode insertion, les lignes sont surlignées en bleu et dans les fichiers Yml uniquement, la colonne courante est marquée en rouge pour permettre de voir rapidement le niveau d'indentation des blocs :


Par greg - Publié dans : vim
Ecrire un commentaire - Voir les 0 commentaires - Recommander
Mardi 26 mai 2009
Bonjour à toutes et tous,

Je sors de ma grotte pour dans un premier temps parler du symfony live qui aura lieu à Paris les 11 et 12 juin prochains. Ce sera l'occasion d'écouter plein de conférences qui tourneront autour des avantages que procure le framework coté technique d'une part et des retours d'expérience de grand comptes sur le sujet. Les confs techniques seront menées par quelques brillants Sensiomen et quelques personnes (non moins brillantes) de l'AFUP, de clever age etc etc. Pour le programme, c'est par ici et les inscriptions c'est par là.

Une fois ce coup de pub passé, peut être êtes vous curieux de savoir ce qui me tient loin de mon clavier ces derniers temps ...



C'est effectivement à mi chemin entre l'apprentissage du russe et l'histoire de la conquête spatiale : l'électronique des tubes. Le fer à souder à pris la place de la souris (quoique la souris avec Vim... ) enfin bref ... ça reviendra.

Dernier point pour ceux qui savent qu'il ne peut y avoir de post sur ce blog sans un Tips Vim, le bouquin sur Vim a dépassé ses 35 pages et j'envisage de le libérer sous une forme LaTeX ou Wiki pour le rendre participatif mais un gros travail de remaniement reste à faire...

Ah ... le Tips Vim : dans une fonction et/ou méthode, le curser sur une variable : «gd» vous permettra d'atteindre la définition de cette variable (ie première affectation ou déclaration) ... gd pour Goto Definition évidemment.

Par greg
Ecrire un commentaire - Voir les 2 commentaires - Recommander
Jeudi 15 janvier 2009
Bonsoir à tous,

D'abord la basherie

entre deux articles sur Doctrine, je profite de quelques minutes de répis pour vous soumettre (enfin) la basherie dont je me sers depuis quelques semaines maintenant : la récupération des arguments de la ligne de commande précédente.

Vous pouvez récupérer de façon simple à l'aide de l'opérateur !:n (ou n est un entier) le nième argument de la ligne de commande précédente. C'est très pratique car d'une commande à l'autre on se sert souvent deux fois de mêmes arguments, typiquement, bouger un fichier et faire un lien symbolique dessus :
shell$ mv frontend.php frontend_prod.php
shell$ ln -s frontend_dev.php !:1
ln -s frontend_dev.php frontend.php

Le shell est en plus assez sympa pour vous afficher l'expansion réalisée sous votre commande, on ne pourra pas dire que bash n'est pas user-friendly sur le coup.

Puis les bouts de Vim

Deux nouvelles choses sont venues agrémenter ma vie de Vimiste ces derniers mois. La première et pas des moindres dans mon travail de symfoniste est l'utilisation des marqueurs majuscules. Les marqueurs majuscules fonctionnent exactements comme leurs homonymes minuscules à part qu'ils ont la particularité d'être persistants et multi-fichiers ... je m'explique : une fois placés, à l'aide d'un «mX» ou X est le marqueur, les marqueurs suivants par exemple dans un projet symfony :

marqueur pseudo fichier
S Schéma /config/schema.yml
F Fixtures /data/fixtures/fixtures.yml
A Action /apps/appli_courante/modules/module_courant/actions/actions.class.php
R Routing /apps/appli_courante/config/routing.yml

Etc etc ... Cela veut dire que si je veux jeter un coup d'oeil ou modifier le routing, un coup de «'R» voila le fichier chargé dans mon éditeur. Imbattable et cela ne pose aucun problème avec l'utilisation de Project.

 Les admins système préfèreront sans doute mettre des marqueurs sur les fichiers de conf d'Apache ou Postgresql en choisissant judicieusement les marqueurs A et P par exemple ... Comme ces marqueurs sont persistants il est inutile de les remettre à chaque fois que vous lancez Vim.

Deuxième petite chose intéressante : la navigation entre les onglets grâce à «gt» et «gT» (Go Tab) qui facilite quand même grandement la vie.

@bientôt.
Par greg - Publié dans : vim
Ecrire un commentaire - Voir les 3 commentaires - Recommander
Jeudi 8 janvier 2009
Hello, this is time for the second article on Doctrine with symfony about inheritance this time. As I am used to Postgresql's inheritance mechanism, I was curious as Doctrine proposes 3 ways to create inheritance with your objects model :
  • simple inheritance
  • concrete inheritance
  • column aggregation inheritance
Let's (again) take an example: we want to create an application for a show that rents bikes, motorcycles and maybe more. We can say, our shop rents vehicules. All of the vehicules can be one of bike, motorcycle, car or whatever. We can easily understand a car is different from a bike and they do not have the same caracteristics.

The first step is to create 2 tables, one vehicle and one bicycle table:
config/doctrine/schema.yml:
Vehicle:
tableName: vehicle
actAs: [Timestampable]
columns:
ref: { type: char(6), primary: true }
brand: { type: varchar(255), notnull: true }
Bicycle:
inheritance: { type: simple, extends: Vehicle }
columns:
bike_type: { type: enum, values: [city, mountain, race], default: city, notnull: true }
gears: { type: integer(32), default: 1, notnull: true }
seats: { type: integer(4), default: 1, notnull: true }
checks:
gears_min: gears > 0
seats_min: seats >


We see here, we have defined a simple inheritance. So what did Doctrine ?
data/sql/schema.sql:
CREATE TABLE vehicle (
ref CHAR(6),
brand VARCHAR(255) NOT NULL,
bike_type VARCHAR(255) DEFAULT 'city' NOT NULL,
gears BIGINT DEFAULT 1 NOT NULL,
seats INT DEFAULT 1 NOT NULL,
created_at TIMESTAMP without time zone,
updated_at TIMESTAMP without time zone,
PRIMARY KEY(ref)
);
(Our check statements do no appear) It sounds rather limited but let's see what we can do with that, assuming we add 2 bikes in the database using fixtures:
./symfony doctrine:dql "SELECT * FROM Bicycle"
>> doctrine executing dql query
DQL: SELECT * FROM Bicycle
found 2 results
-
ref: BK0478
brand: peugeot
bike_type: city
gears: '4'
seats: 1
created_at: '2009-01-04 17:18:25'
updated_at: '2009-01-04 17:18:25'
-
ref: BK0734
brand: raleigh
bike_type: mountain
gears: '21'
seats: 1
created_at: '2009-01-04 17:18:25'
updated_at: '2009-01-04 17:18:25

This isn't really an inheritance mechanism because the children doesn't inherit from its parent. It is more like the parent get richer with every child classes. This may work with very simple cases because in this application, the motorcycle may have columns with «not null» attributes that bikes will never comply with. This isn't really what we are looking for.

Let's change our schema to use the concrete inhéritance :
config/doctrine/schema.yml:
Bicycle:
inheritance: { type: concrete, extends: Vehicle }
Launche the build-all-reload and see what we have:
data/sql/schema.sql:
CREATE TABLE vehicle (
ref CHAR(6),
brand VARCHAR(255) NOT NULL,
created_at TIMESTAMP without time zone,
updated_at TIMESTAMP without time zone,
PRIMARY KEY(ref)
);

CREATE TABLE bicycle (
ref CHAR(6),
brand VARCHAR(255) NOT NULL,
bike_type VARCHAR(255) DEFAULT 'city' NOT NULL,
gears BIGINT DEFAULT 1 NOT NULL,
seats INT DEFAULT 1 NOT NULL,
created_at TIMESTAMP without time zone,
updated_at TIMESTAMP without time zone,
PRIMARY KEY(ref),
CHECK (gears > 0),
CHECK (seats > 0)
);

It sounds like Doctrine has created two tables and wants to handle the inheritance by itself. Let's see what we have once the fixtures are loaded:
In our database:
dbtest=> \d
List of relations
Schema | Name | Type | Owner
--------+---------+-------+-------
public | bicycle | table | toto
public | vehicle | table | toto
(2 rows)

dbtest=> SELECT * FROM vehicle ;
ref | brand | created_at | updated_at
-----+-------+------------+------------
(0 rows)



dbtest=> SELECT * FROM bicycle ;
ref | brand | bike_type | gears | seats | created_at | updated_at
--------+---------+-----------+-------+-------+---------------------+---------------------
BK0478 | peugeot | city | 4 | 1 | 2009-01-04 17:25:26 | 2009-01-04 17:25:26
BK0734 | raleigh | mountain | 21 | 1 | 2009-01-04 17:25:26 | 2009-01-04 17:25:26
(2 rows)



We can see we have 2 bikes but it also appears we have no vehicules ! So Doctrine does not handle the inheritance by itself, if we want to have 2 bikes and also say we have 2 vehicles we have to overload the Bicycle definition. The other solution is to declare the Vehicle as an abstract class:
config/doctrine/schema.yml:
Vehicle:
tableName: vehicle
abstract: true

But this seems not to work (or I missunderstood the doc) because the table definition is still present in the SQL...

Anyway, I am now able to create a motorbike table adding the following to
config/doctrine/schema.yml:
Motorcycle:
inheritance: { type: concrete, extends: Vehicle }
columns:
type: { type: enum, values: [scooter, roadster, city], notnull: true, default: scooter }
cylinder: { type: integer, notnull: true }
plate: { type: string(11), notnull: true, unique: true }
checks:
cylinder_min: cylinder > 0
plate_format: plate ~ \'[0-9]{1,4}\\-[A-Z]{2,3}\\-[0-9]{1,2}\

So after adding some fixtures I have 2 tables with independant data:
dbtest=> SELECT * FROM motorcycle ;
ref | brand | type | cylinder | plate | created_at | updated_at
--------+--------+---------+----------+------------+---------------------+---------------------
MB1837 | vespa | scooter | 125 | 324-MA-92 | 2009-01-08 19:37:10 | 2009-01-08 19:37:10
MB6430 | yamaha | city | 750 | 2301-ZC-60 | 2009-01-08 19:37:10 | 2009-01-08 19:37:10
(2 rows)



dbtest=> SELECT * FROM bicycle ;

ref | brand | bike_type | gears | seats | created_at | updated_at
--------+---------+-----------+-------+-------+---------------------+---------------------
BK0478 | peugeot | city | 4 | 1 | 2009-01-08 19:37:10 | 2009-01-08 19:37:10
BK0734 | raleigh | mountain | 21 | 1 | 2009-01-08 19:37:10 | 2009-01-08 19:37:10
(2 rows)



dbtest=> SELECT * FROM vehicle ;
ref | brand | created_at | updated_at
-----+-------+------------+------------
(0 rows)



If I try to count the vehicles I have with a DQL query it would not be as simple as:
test$ ./symfony doctrine:dql "SELECT * FROM Vehicle"
>> doctrine executing dql query
DQL: SELECT * FROM Vehicle
>> doctrine no results found

Let's then try the last type of inheritance: the columns aggregation.

Bicycle:
inheritance: { type: column_aggregation, extends: Vehicle, keyField: type, keyValue: bicycle }
For the bicycles and
Motorcycle:
inheritance: { type: column_aggregation, extends: Vehicle, keyField: type, keyValue: motorbike }
for the motorbikes.

Then doctrine complains it cannot load the data because constraints. If I go and have a check at the database I see there is only one table with all the columns but with an extra column named type and none of my sql constraints:
dbtest=> SELECT * FROM vehicle ;
ref | brand | type | bike_type | gears | seats | cylinder | plate | created_at | updated_at
-----+-------+------+-----------+-------+-------+----------+-------+------------+------------
(0 rows)
At the end of this testing phase I am a bit confused about what these types of inheritance stand for. I am not sure I will ever use one of those. I was expecting Doctrine to have like a PHP implementation of what Postgresql's inheritance system is without the problems it has ... or maybe I am missing something :o)

Par greg - Publié dans : symfony
Ecrire un commentaire - Voir les 4 commentaires - Recommander
Vendredi 2 janvier 2009
Here is the first sequel of my experiments using Doctrine with symfony 1.2. I will go trough 4 chapters that I found interesting to test :
- Using postgresql's constraints
- Using inheritance
- Different types of relationship
- Playing with DQL

The basics of using Doctrine will not be described here, there are plenty of good docs on the web (at least here or here) that show how to enable doctrine and how to use it within symfony. I will spend time on some precise points.

Using postgresql's constraints

One more time, this is the place to say constraints are not implemented to turn developers'life into hell. There are here to report discrepencies as soon as possible, it is like turning on the warnings when you are developping, it helps you.
That's one of the very good news using Doctrine with symfony : the abitlity to handle databases's constraints. The other good news is, some of the constraints will be automatically implemented in the according forms ! Let's see that with the following example :

config/doctrine/schema.yml:
Employee:
tableName: employee
columns:
ref: { type: char(6), primary: true, notnull: true }
first_name: { type: string(50), notnull: true }
last_name: { type: string(50), notnull: true }
birthdate: { type: timestamp, notnull: true }
hiredate: { type: timestamp, notnull: true }
email: { type: string(100), notnull: true }
Here, we want to store some data about employees of a company. If we set that schema.yml up in the «config/doctrine» directory and run a «symfony doctrine:build-all» we can see the following result :

lib/form/doctrine/base/BaseEmployeeForm.class.php:
$this->setValidators(array(
'ref' => new sfValidatorDoctrineChoice(array('model' => 'Employee', 'column' => 'ref', 'required' => false)),
'first_name' => new sfValidatorString(array('max_length' => 50)),
'last_name' => new sfValidatorString(array('max_length' => 50)),
'birthdate' => new sfValidatorDateTime(),
'hiredate' => new sfValidatorDateTime(),
'email' => new sfValidatorString(array('max_length' => 100)),
));
data/sql/schema.sql:
CREATE TABLE employee (
ref CHAR(6),
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
birthdate TIMESTAMP without time zone NOT NULL,
hiredate TIMESTAMP without time zone NOT NULL,
email VARCHAR(100) NOT NULL,
PRIMARY KEY(ref)
);

We can see here the default behavior we are already used to. Let's now say the «ref» field has to be a 6 chars identifier with 2 uppercase letters and 4 digits, the «birthdate» cannot be a date older than the «hiredate» and the «email» has to be a real life email address.
Doctrine allows to use database contraints with the «checks» keyword. Our schema becomes :

config/doctrine/schema.yml:

Employee:
tableName: employee
columns:
ref: { type: char(6), primary: true, notnull: true }
first_name: { type: string(50), notnull: true }
last_name: { type: string(50), notnull: true }
birthdate: { type: timestamp, notnull: true }
hiredate: { type: timestamp, notnull: true }
email: { type: string(100), notnull: true }
checks:
correct_dates: hiredate > birthdate
ref_valid: ref ~ \'[A-Z]{2}[0-9]{4}\'
Now we can see the following result:

data/sql/schema.sql:

CREATE TABLE employee (
ref CHAR(6),
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
birthdate TIMESTAMP without time zone NOT NULL,
hiredate TIMESTAMP without time zone NOT NULL,
email VARCHAR(100) NOT NULL,
PRIMARY KEY(ref),
CHECK (hiredate > birthdate),
CHECK (ref ~ '[A-Z]{2}[0-9]{4}')
);

And no change in lib/form/doctrine/base/BaseEmployeeForm.class.php.
This means the constraints we just set are passed "as is" to the database which is very handy if we need to use database's functions to check the integrity of our data. In an other hand, Doctrine does not set any symfony validator to automatically configure our forms.
Be sure to escape quotes in the constraint definition in the «schema.yml» because it will be imported as is in the php file :

lib/model/doctrine/base/BaseEmployee.class.php:
    $this->check('hiredate > birthdate');
$this->check('ref ~ \'[A-Z]{2}[0-9]{4}\'');
So, how can we tell Doctrine to set up the validators for us to use in symfony forms ? Well, Doctrine allows us to easily declare application level constraints (See official documentation).

Change the email line in the config/doctrine/schema.yml:
email:      { type: string(100), notnull: true, email: true }
and re launch the «doctrine:build-all» command. You should see the following change in the lib/form/doctrine/base/BaseEmployeeForm.class.php:
'email'      => new sfValidatorEmail(array('max_length' => 100)),

But no change in our SQL file. So we need to handle the database constraints by ourselve (which is not DRY). What about simpler constraints about «first_name» and «last_name» if we want to say they need to be at minimum 2 chars lenght ?

In config/doctrine/schema.yml:
    first_name: { type: string(50), notnull: true, minlength: 2 }
last_name: { type: string(50), notnull: true, minlength: 2 }
Again, this only change symfony form's validators in lib/form/doctrine/base/BaseEmployeeForm.class.php:
      'first_name' => new sfValidatorString(array('max_length' => 50, 'min_length' => 2)),
'last_name' => new sfValidatorString(array('max_length' => 50, 'min_length' => 2)),

Something else ?


That's all for this first overview. This is very good already we can use database constraints in our schema file. It seems there are other good new features with doctrine like using your own sequences but I couldn't manage to make that to work.

Another good point is it is easy to make use of Postgresql's schemas using Doctrine. But, tell me if I am wrong, I have always seen Pg schemas good at owning applications model and Doctrine does not allow (yet) users to generate a per application model, everything is under de «lib/model/doctrine» directory for the project.

Enjoy.
Par greg - Publié dans : symfony
Ecrire un commentaire - Voir les 1 commentaires - Recommander
Lundi 29 décembre 2008
Bonsoir à toutes et tous,

Tout d'abord et comme d'habitude quelques mots pour vous présenter mes excuses de ne pas avoir bloggé plus souvent ces derniers temps. Ce n'est évidemment pas le manque de choses à dire, sf 1.2 est sorti, je secoue doctrine et suis agréablement surpris, j'ai encore quelques nouvelles basheries sous le coude et surtout ... j'ai commencé il y a un peu plus d'un mois, un livre sur Vim dont je vous parlerai plus longuement un autre jour.
Le sujet qui me préoccupe aujourd'hui sort après quelques semaines, voire mois, d'avoir l'impression que quelque chose me dérange du coté de la pomme (et suite à la lecture de Linuxfr).

Pour vous situer ma petite histoire, j'ai acheté en 2006 un mac mini équipé de OSX 10.4 et il y a un an, un macbook équipé de OSX 10.5. Pour être honnête, je ne suis pas l'utilisateur principal de ces machines pour des raisons que j'exposerai un peu plus tard. J'ai, depuis le début, vu d'un très bon oeil le fait que la part des utilisateurs de systèmes autres que ceux de Redmond était en augmentation constante. Je reste convaincu que la maturité de l'informatique viendra quand les utilisateurs pourront s'adapter à toutes sortes d'interfaces. Utiliser des interfaces différentes permet de mettre en place des schémas mentaux variables de l'utilisation d'un ordinateur et cela nous permet d'apprendre à penser différement pour créer les outils de demain. C'est dans cette voie qu'Apple a lancé avec succès le remplaçant de son obsolète prédécesseur et le fameux «think different» n'a jamais été aussi vrai que ces dernières années.

Je vous passerai mes tentatives d'utilisation d'OSX,  les diverses combinaisons pomme n'ont jamais réussi à faire comprendre à X11 qu'il y avait quelque chose à coller. Pas possible de faire des glisser-déposer en utilisant exposé, il faut donc arranger ses fenêtres avant.... on est toujours obligé de manipuler les fenêtres par la barre de tître ou les coins ce qui est fastidieux .... tout cela pour vous dire que j'ai sans doute manqué le comment du pourquoi un Mac rendait le travail du développeur plus facile (surtout pour faire du dev web). Je veux bien mettre ça sur le compte de mon incapacité à comprendre comment utiliser une souris qui n'a qu'un bouton. J'ai cependant utilisé au quotidien  AfterStep, Enlightenment, fluxbox et KDE avec Kompiz et testé quelques dizaines d'autres environnements graphiques aux philosophies exotiques (dont BeOS* 5) avec plus ou moins de bonheur.

Évidemment Ubuntu et consors sont très loin d'être parfaits (Branchez un deuxième écran sur Linux et sous OSX vous verrez la différence) et OSX est beaucoup plus utilisable que son cousin propriétaire à fenêtres (installez et désinstallez une appli vous verrez la différence). J'ai plusieurs amis qui travaillent sur des images ou de la vidéo et OSX leur facilite apparemment grandement la vie. En cela OSX a encore des longueurs d'avance sur tous ses concurrents mais cette facilité, même vernie d'une présentation léchée, a un prix caché qu'il convient de considérer.

Le premier «truc qui cloche» est la différence entre paroles et faits de la part d'Apple sur les mécanismes de protection de la propriété sur tout ce qui touche à la musique. Alors que Steeve Jobs avait, en pleine sortie de Vista, fait savoir que les DRM ne marchaient pas et que si ça ne tenait qu'à eux cela n'existerait pas mais qu'ils étaient obligés de les utiliser, il s'avère que les différentes générations d'I-pode et de Mac sont de plus en plus vérouillées et vont jusqu'à refuser de lancer leur logiciel si les signatures numériques ne sont pas vérifiées.

Le deuxième truc qui cloche, c'est l'I-phone ou les développeurs sont obligés de céder leur travail à Apple pour voir leur application installable sur votre téléphone. La firme se réserve le droit d'évincer en ligne les logiciels indésirables de votre terminal comprenez les logiciels dont apple aura sa propre version ou nuira à la marque. Avait on déjà vu un comportement aussi intrusif dans l'informatique personnelle ?

Le troisième truc qui cloche ce sont les petites différences entre OSX 10.4 et 10.5 qui ne sont pas sans rappeler les choix de Microsoft concernant Vista : une simplification (encore ?) de l'interface dans le but bien légitime de nous aider, nous pauvres utilisateurs d'ordinateurs. Dans un discours ambigu, le mot «simplification» rime souvent avec «faire comme untel  veut qu'on fasse». Ainsi de plus en plus de mécanismes nous «aident» à utiliser l'ordinateur toujours de la même façon pour tout le monde. La face cachée de cela est que ça rend la conception des système de blocage plus simple. Cela pourrait paraître tiré par les cheveux si on ne savait pas que les nouveaux mac book sont étonnemment équipés d'une puce de «contrôle des contenus».

À l'heure ou je vois fleurir des notes de blogs sur «N'est il pas plus important d'utiliser des contenus libres que des logiciels libres» je m'inquiète (encore une fois) qu'on puisse commencer à transiger sur la liberté de l'information vu la place croissante notre identité numérique dans la vie de tous les jours. L'orientation que prend le deuxième acteur le plus important de l'informatique personnelle ne fait que renforcer mes craintes. Il ne faut pas placer la charrue avant les beufs, les contenus libres et les informations personnelles ne le resteront qu'à partir du moment ou l'on utilise des logiciels libres.

Microsoft après bien des victoires pour imposer son système d'exploitation au monde entier a perdu la bataille d'internet ou seuls des Internet Explorer auraient été capables d'afficher des sites faits avec Frontpage et Internet Commerce (tout cela ne fonctionnant que sous Windows évidemment propulsé par IIS). Apple est en train de gagner celle de la diffusion de contenus numériques, les chaines Hi-Fi sont pourvues de prises propriétaires I-Pod, I-Tune supporte les CD «protégés» en refusant l'importation dans votre collection et tout le monde est d'accord sauf peut être vous ... qui acceptez implicitement de voir l'ordinateur que vous avez acheté lancer à votre insu des programme pour espionner et controller l'utilisation que vous en faites mais quand il s'agit de faire avaler un suppositoire à quelqu'un on s'arrange pour le rendre joli et sucré.

En retombant dans un panier numérique qui nous ramène sans cesse au tiroir-caisse pour utiliser légitimement nos contenus, c'est à dire ceux que nous avons créé ou acheté, nous sommes arrivés aujourd'hui loin du «think different» d'un système qui prétendait amener une autre approche de l'utilisation des ordinateurs. Encore plus loin de la publicité ou Apple comparait IBM a Big Brother et sa pensée unique. En fait avec IBM et Microsoft, nous connaissons déjà cette prison du «don't think at all», peut être celle d'apple est elle plus sexy, plus agréable.

* Utilisateurs de BeOS vous serez peut être intéressés par Haiku qui bien qu'encore instable est un OS libre extrèmement prometteur.
Par greg
Ecrire un commentaire - Voir les 1 commentaires - Recommander
Lundi 17 novembre 2008


Je pense qu'avaler le man de bash n'est pas un truc humain. La personne qui vous soutient l'avoir fait est probablement un droïde (qui sont également les seuls capables de replier un carte michelin dans le bon sens du premier coup). Du coup, on l'avale par petit coup, suivant les intérêts du moment.

En parcourant ladite page de man aujourd'hui je suis tombé sur le chapitre des «braces expansion». Il est dit la chose suivante :

$ echo a{b,c,d}e
abe ace ade

Sur le coup, on se dit «ah, tient, c'est joli». La chose devient vraiment utile quand on lit ça:

$ mkdir /var/www/{plop1,plop2,plop3}
$ touch /var/www/plop{1,2,3}/index.php

(J'ai modifié l'exemple du touch suite à la remarque de ph7, merci à lui).

Merveilleux exemple tiré de la continuation de Advancing in the Bash Shell (merci à Noel pour le lien)

$ ls /usr/{,local/}{,s}bin/jojo

Remarquez les expansions vides et imbriquées.

Bonne journée à tous.
Par greg - Publié dans : bash
Ecrire un commentaire - Voir les 6 commentaires - Recommander
Samedi 15 novembre 2008
Tout d'abord le vrac. Le mois de novembre est assez actif au niveau de la communauté symfony avec la préparation de la sortie de la version 1.2 et l'annonce de toutes les belles choses qu'elle apporte. On pourrait croire qu'avec cela en tête je passe toutes mes soirées à clearer du cache, hé bien non. Je viens d'ajouter une ligne à la longue liste des trucs captivants qui peuvent prendre du temps en soirée et en week end : la confection des pâtes.


Pour les raviolis, aujourd'hui la farce (trouvée sur internet) : épinards, ail, ricotta et parmesan. Le tout fond pendant la cuisson des pâtes, c'est une tuerie.

Les plus assidus d'entre vous auront remarqué que j'ai écrit les 2 derniers articles en anglais. J'ai en effet remarqué dans les stats que de plus en plus de lecteurs utilisent google translation pour lire les articles à dominante technique. J'ai pris la décision de publier les articles purement techniques en anglais. Ce n'est pas le cas de ma bafouille aujourd'hui puisque je vous propose un instant de détente en jouant avec la coloration dans Vim.

Pourquoi colorier Vim ?
Comme toujours dans Vim, le but est d'aller plus vite. Aller plus vite ça passe aussi par mettre en valeur  ce qui est pertinent. Je ne parle pas ici de la coloration syntaxique du code mais bien de ce que nous devons rendre plus ou moins visible à l'écran. La définition d'un jeu de définition d'éléments de présentation s'appelle dans vim un colorscheme. Il en existe un certain nombre par défaut dans Debian, vous pouvez les voir et en changer en tapant «:colorscheme <TAB>». En appuyant plusieurs fois sur la touche <TAB> vous verrez défiler la liste des colorschemes. Appuyez sur entrée pour valider. Pour vérifier quel colorscheme vous convient le mieux, essayez les sur une belle page de code avec le module project et un split horizontal par exemple. Si aucun de ceux installé sur votre ordinateur ne vous convient, vous pouvez en télécharger de nouveaux sur ce site.

Dans mon cas, par exemple pour les formations, mon écran est projecté sur un tableau et les caractères sombres sont très peu distincts. J'opte donc pour le colorscheme «pablo» qui est assez sobre mais surligne ce dont j'ai besoin : les mots clés ainsi que les fonctions PHP et les variables.
Ce colorscheme possède par contre quelques défauts génants. La barre de titre de la fenêtre d'édition active est en noir et se mélange avec le code. Sur la photo il est difficile de voir que j'ai ouvert 2 fichiers.


Je vais donc construire mon propre colorscheme à partir de pablo. Pour cela, je copie le colorscheme depuis /usr/share/vim/vim71/colors vers ~/.vim/colors et je le renomme en formation. Que y a-t-il dans un fichier de colorscheme ? Presque uniquement des appels à la fonction Vim «highlight».
Cette fonction permet de définir ou de vérifier comment s'affichent les différents éléments dans Vim suivant le type de terminal utilisé. Pour voir la définition actuelle tapez juste «:hi» (raccourci pour :«highlite»). Vous devriez voir s'afficher quelque chose comme ceci :
Le premier argument est le nom du motif concerné. Ensuite, Vim affiche le motif tel qu'il apparait dans votre terminal. Suit la définition de l'affichage dans les différents types de terminaux.
Vim connait 3 types de terminaux :
  • les terminaux textes (term)
  • les terminaux textes couleur (cterm) en 8 et 16 couleurs
  • les terminaux graphiques (gui)
Vim va cascader la définition des terminaux. La définition term s'applique tout le temps, cterm s'applique en plus si votre terminal le supporte, de même pour gui. La définition pour le terminal permet de définir l'allure générale du motif :
  • bold
  • underline
  • undercurl
  • reverse
  • inverse
  • italic
  • standout
  • NONE
Dans le cas des terminaux couleur il est également possible de préciser la couleur de la police (ctermfg) et du fond (ctermbg). Ce qui nous intéresse ici c'est la définition de «StatusLine» qui affiche le nom du fichier en cours d'édition. Dans le colorscheme «pablo», la définition est la suivante :

StatusLine     xxx term=none ctermfg=11 ctermbg=12 guifg=#ffff00 guibg=#0000ff

Enlevons les couleurs en effaçant les déclaration ctermfg et ctermbg.

StatusLine     xxx term=reverse guifg=#ffff00 guibg=#0000ff

Il est alors possible de recharger le fichier de colorscheme dans vim en tapant simplement «:colorscheme formation». La barre de status de la fenêtre active devrait alors passer en blanc brillant. Il peut également être intéressant de diminuter l'intensité du blanc sur les fenêtres inactives afin de mettre en valeur l'endroit de saisie du texte.

Pour afficher la définition courante de l'objet StatusLineNC «:hi StatusLineNC». Nous allons ajouter ceci dans notre fichier :

highlight StatusLineNC   term=reverse cterm=reverse ctermfg=grey gui=reverse

Notez que nous utisons ici ctermfg pour changer la couleur du fond, c'est parce que nous sommes en inverse vidéo. Pour changer la définition des replis de code (folds) afin de les rendre moins visibles :

highlight hi Folded term=standout cterm=bold ctermfg=DarkGrey ctermbg=0

Pour en savoir plus, l'aide de Vim sur le sujet est disponible en tapant «:help highlite».

Par greg - Publié dans : vim
Ecrire un commentaire - Voir les 1 commentaires - Recommander
Vendredi 31 octobre 2008
At last! I know why I feel unconfortable with simple database abstraction layers like propel. Just imagine you want to manage users. Users may be in one or several groups that grant them with credentials.

We need something like this:


If we do let our database schema as is, we let the complexity of data modelisation up to the application programmer. This often leads to multiple queries and poorly optimized database usage. In facts what we would really be interested in from this schema would be having a view combining every elements of app_user and the associated credentials so in one query we can get everything we want. The problem here is we might have multiple credentials for each user. The solution would be here to collect all the credentials associated with a user and put them in an array in our view.

Collecting data over a query and sending them as a single value is an aggregate, so we are going to declare an aggregate collect_elt that returns an array of all the values of a column and return them in an array.

CREATE AGGREGATE collect_elt(anyelement) (SFUNC = array_append, STYPE = anyarray, INITCOND = '{}');

Now we can safely create our view in an other schema to supersed our app_user table:

CREATE VIEW greg.app_user AS
  SELECT
    a.first_name,
    a.last_name,
    a.email,

    collect_elt(b.credential)
  FROM
    app_user_group
      JOIN app_user a ON a.id = app_user_group.user_id
      JOIN app_group b ON b.name = app_user_group.group_name
  GROUP BY
    a.first_name,
    a.last_name,
    a.email
    ;

So if I am logged as the user greg, a SELECT on the app_user table should show me something like this

 first_name | last_name |       email        |      collect_elt
------------+-----------+--------------------+------------------------
 firstname2 | lastname2 | email2@domain.com  | {administrator,normal}
 firstname1 | lastname1 | email1@domain1.com | {normal}
(2 rows)

With only one query, we are able to retrieve all the relevant informations about our user. Of course, app_group is still available if you want to deal with groups administration. Doing this, we saved lot and lot of extra queries.

As we know now about arrays, it may be intersting to say : let s have several credentials for a group stored in an array in the table group. This presents some advantages :

  • no need for a new complex set of tables to handle a N-M relation between groups and credentials.
  • we let the application admins free to save whatever credentials they want without having a table credentials polluted with 80% of non used records.
           Table "public.app_group"
   Column    |        Type         | Modifiers
-------------+---------------------+-----------
 name        | character varying   | not null
 credentials | character varying[] |

SELECT * FROM app_group ;
   name    |       credentials
-----------+--------------------------
 normal    | {normal_users}
 admin     | {normal_users,admins}
 webmaster | {normal_users,webmasters}
The type VARCHAR[] indicates our credentials are now an array of VARCHAR. What we would like now is an aggregate that collect elements of arrays that are not already in my collected array of credentials. This means, if a user has several times the same credential, we want it to appear once in our view. Such a function does not exist with a fresh install of Postgresql, we need to create it (assuming the language plpgsql is available in this database).

CREATE OR REPLACE FUNCTION array_has_element(array1 anyarray, elt anyelement) RETURNS boolean AS $$
DECLARE
  i integer;
BEGIN
  FOR i IN SELECT * FROM generate_series(1, array_upper(array1, 1)) LOOP
    IF array1[i] = elt THEN
      RETURN true;
    END IF;
  END LOOP;
  RETURN false;
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION array_merge(array1 anyarray, array2 anyarray) RETURNS anyarray AS $$
DECLARE
  i integer ;
  return_array array1%TYPE;
BEGIN
  return_array := array1;
  FOR i IN SELECT * FROM generate_series(1, array_upper(array2, 1)) LOOP
    IF NOT array_has_element(return_array, array2[i]) THEN
      return_array := return_array || array2[i];
    END IF;
  END LOOP;

  RETURN return_array;
END;
$$ LANGUAGE plpgsql;

Let's try it :

SELECT array_merge('{a,bb,ccc}'::VARCHAR[], '{bb, ccc, dddd}'::VARCHAR[]);
   array_merge
-----------------
 {a,bb,ccc,dddd}
(1 row)
That looks good. Let's now create an aggregate using our new function :
CREATE AGGREGATE merge_arrays (anyarray) (
  SFUNC = array_merge,
  STYPE = anyarray
);
This aggregate is even simplier than the previous one ! ... Here is now the view of the corresponding app_user :

SELECT * FROM app_user;
 first_name | last_name |       email        |     merge_arrays
------------+-----------+--------------------+-----------------------
 firstname2 | lastname2 | email2@domain.com  | {normal_users,admins}
 firstname1 | lastname1 | email1@domain1.com | {normal_users}
(2 rows)


Did I tell you I love Postgresql ? ah ... maybe yes.

This comforts me with the idea we can have 2 layers in the database:
  • one «physical» layer with the tables to handle all the data
  • one «logical» layer to present to data depending on the application
In general, we work with only the first layer so our applications' models are complicated and is merely about combining data from different tables using numerous queries. There must be a way to implement a second layer with some logic of data presentation in order to make the developpers life more easy and save database ressources.
Par greg - Publié dans : postgresql
Ecrire un commentaire - Voir les 0 commentaires - Recommander
Mardi 28 octobre 2008
If you are aware of agile development methods, you have probably heard about test driven development. As I began to play more and more with symfony's unit testing tool (known as lime), I asked mysefl how to set up a test driven development (TDD).
In fact, I do not beleive in writing test before code. It is not easy to test a method that doesn't exist, especially if the class does not exist either. So begining with writing the test before a single line of code appeared to me like a masochist plan. To me it sounds we have several phases in writing code :
1 - write code until something work
2 - refactor the code to the right layer
3 - write the complete specifications of this code with tests.
4 - complete your code until all tests pass

I do think the first part is the creative part of the developer's work. The less you set structural constraints the better and the quicker it is. This part normally finish with a working prototype of code. The danger would be to let this as is and go in production with it.
The second part supposes the developers have a good understanding of the framework decoupled MVC structure and know the right place for everything. It can happen you work with a developper who can do these two steps in the same move, this is often the signature of well experienced developers.
The rest of this article will explain my experience of the two last steps.

So when I code, the first thing I do is to code until I had something working. Then I refactore little pieces of generic code in external classes that I placed in the lib directory of my plugin / project. This simply makes the code more easy to test.

When I began to write unit tests for my functions, I realized I could take advantage of this moment to also define how I exactly want this functions to behave!



So I tested these functions for things it wasn't doing yet, deciding when I was expecting it to send exceptions and handling different limit use cases. The whole process took me 10 minutes. In 10 minutes I exactly knew how I wanted it to interact with the rest of the code and in the same time, I also ensured I will have no regressions on that parts because it s all what tests are about
.
As expected, most of the tests didn't pass at first. Then I began to implement the rest of functionnalities. I was a bit surprised to notice I couldn't reach the 100% tests because sometimes PHP does not behave the way you think, by example getElementsByTagName method strangely do send any exception when you ask for a tag that doesn't exist nor when you feed it whith a non XML document. In this case, I could spot the limitations of my code and document them as long as there was nothing I could do to make this better.


Par greg - Publié dans : symfony
Ecrire un commentaire - Voir les 0 commentaires - Recommander
 
Créer un blog sur over-blog.com - Contact - C.G.U. - Rémunération en droits d'auteur - Signaler un abus