Bonjour,
Actuellement je fait un pr�processeur C++ en Ruby.
L'int�ret ? C'est beaucoup plus simple et pratique � utiliser que le pr�processeur C++ normal, et puis Ruby est vraiment un langage tr�s agr�able pour faire des DSL. Si vous avez le temps, ce serait sympa de le tester et de me dire ce que vous en pensez, des fonctionnalit�s que vous aimeriez avoir, etc...
Ci dessous, quelques exemples pour illustrer l'int�ret de la b�te.
Quelques notes pr�liminaires :
Vous pouvez ins�rer du code Ruby � n'importe quel endroit du fichier avec les conventions suivantes :
<% code %> : Le code Ruby est interpr�t�.
<%= code %> : Le code Ruby est interpr�t� et son r�sultat est ins�r� en place.
% code : Si le premier caract�re de la ligne est %, toute la ligne sera interpr�t�e en Ruby.
Si vous avez un r�pertoire rppconf � la racine de votre projet, vous pouvez y ins�rer des fichiers en langage YAML (un langage simplissime et esth�tique pour s�rialiser des donn�es). Les donn�es du fichier seront ensuite accessibles n'importe o� dans votre source dans la variable <nom du fichier yaml>.!
Si vous avez un fichier rpphelpers.rb � la racine de votre projet, vous pouvez aussi y ins�rer des helpers (fonctions pratiques) qui vous permettent de garder un code Ruby propre et clair dans vos sources.
En Ruby, on dispose de "symboles", ce sont grossi�rement l'�quivalent de chaines de caract�res constantes. Un symbole se pr�fixe par deux points ":". Par rapport � des chaines de caract�res, l'int�ret c'est que les symboles sont des singletons.
Exemple 1:
Cr�er un fichier nomm� "project.yaml" dans le r�pertoire "rppconf", et mettre ceci dedans :
YAML est un langage qui fonctionne principalement sur le principe clef : valeur. Dans cet exemple nos clefs sont des symboles. On peut cr�er des listes en les pr�fixant par "-".
Code : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 --- :name: Ruby pre-processor example :authors: - NewbiZ :languages: - C++ - Ruby :website: http://www.speednova.cc :usage: Available arguments are listed below :arguments: - :char: h :text: Display RCPP's help. - :char: v :text: Display RCPP's version number. - :char: d :text: Deprecated argument. :version: 1.2
On dispose donc maintenant d'une variable "project" accessible partout dans nos sources, et contenant ces valeurs.
Cr�ons donc un fichier example1.rpp (notez l'extension) pour tester :
Apr�s avoir execut� ./rppgen.rb, vous obtiendrez le fichier example1.cpp suivant :
Code : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 %# Helper function displaying text while generating files (see rpphelpers.rb) % echo "Pre-processing \"example1.cpp\"" #include <cstdlib> #include <iostream> int main (int argc, char const* argv[]) { std::cout << "This is " << "<%= project[:name] %>" << " version " << "<%= project[:version] %>" << " build date: " << "<%= Time.now.to_s %>" << std::endl << std::endl; std::cout << "Visit us at " << "<%= project[:website] %>" << std::endl << std::endl; std::cout << "<%= project[:usage] %>" << std::endl; % project[:arguments].each do |argument| std::cout << "<%= argument[:char] %>" << " : " << "<%= argument[:text] %>" << std::endl; % end return 0; }
Exemple 2:
Code : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #include <cstdlib> #include <iostream> int main (int argc, char const* argv[]) { std::cout << "This is " << "Ruby pre-processor example" << " version " << "1.2" << " build date: " << "Thu May 08 20:17:38 +0200 2008" << std::endl << std::endl; std::cout << "Visit us at " << "http://www.speednova.cc" << std::endl << std::endl; std::cout << "Available arguments are listed below" << std::endl; std::cout << "h" << " : " << "Display RCPP's help." << std::endl; std::cout << "v" << " : " << "Display RCPP's version number." << std::endl; std::cout << "d" << " : " << "Deprecated argument." << std::endl; return 0; }
Imaginez que vous vouliez cr�er un tableau contenant toutes les lettres de l'alphabet. C'est assez simple dynamiquement, mais statiquement c'est un cauchemard avec le pr�processeur C++. Voici ce que cel� donne avec RPP :
On profite des facilit�s des "range" de Ruby pour g�n�rer le tableau.
Code : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 // The old static way char alpha1[] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}; // The RPP inline way char alpha2[] = {'<% $src << ('a'..'z').to_a.join("','") %>'}; // The RPP way using an helper function (see rpphelpers.rb) char alpha4[] = <%= c_array ('a'..'z') %>; // The dynamic way for (int i=0; i<26; i++) std::cout << "letter " << lcase1[i] << std::endl; // The RPP way % ('a'..'z').each do |c| std::cout << "letter " << '<%= c %>' << std::endl; % end
Vous obtenez exemple2.cpp :
Exemple 3:
Code : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 // The old static way char alpha1[] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}; // The RPP inline way char alpha2[] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}; // The RPP way using an helper function (see rpphelpers.rb) char alpha4[] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}; // The dynamic way for (int i=0; i<26; i++) std::cout << "letter " << lcase1[i] << std::endl; // The RPP way std::cout << "letter " << 'a' << std::endl; std::cout << "letter " << 'b' << std::endl; std::cout << "letter " << 'c' << std::endl; std::cout << "letter " << 'd' << std::endl; std::cout << "letter " << 'e' << std::endl; std::cout << "letter " << 'f' << std::endl; std::cout << "letter " << 'g' << std::endl; std::cout << "letter " << 'h' << std::endl; std::cout << "letter " << 'i' << std::endl; std::cout << "letter " << 'j' << std::endl; std::cout << "letter " << 'k' << std::endl; std::cout << "letter " << 'l' << std::endl; std::cout << "letter " << 'm' << std::endl; std::cout << "letter " << 'n' << std::endl; std::cout << "letter " << 'o' << std::endl; std::cout << "letter " << 'p' << std::endl; std::cout << "letter " << 'q' << std::endl; std::cout << "letter " << 'r' << std::endl; std::cout << "letter " << 's' << std::endl; std::cout << "letter " << 't' << std::endl; std::cout << "letter " << 'u' << std::endl; std::cout << "letter " << 'v' << std::endl; std::cout << "letter " << 'w' << std::endl; std::cout << "letter " << 'x' << std::endl; std::cout << "letter " << 'y' << std::endl; std::cout << "letter " << 'z' << std::endl;
Il arrive souvent qu'ait des classes � cr�er et qu'on se retrouve � retaper le m�me code pour les accesseurs, les classes � h�riter, etc... Voici un exemple de ce que cel� donne avec RPP :
Ici on a cr�� (en quelques secondes) des helpers pour clarifier notre code.
Code : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 class Displayable { std::string toString() const = 0; }; class Starship { private: % declare_fields :serialNumber => :int, :name => :string, :leftEngine => :Engine, :rightEngine => :Engine public: % encapsulate :serialNumber => :int, :name => :string % getters :leftEngine => :Engine, :rightEngine => :Engine }; % classdef(:Warship, % :implements => [ :Starship, :Displayable ], % :fields => { :ammo => :int, :turret => :Weapon, :target => :Position }) { public: string toString() const { std::cout << "ammo =" << get_ammo() << std::endl; std::cout << "turret=" << get_turret() << std::endl; std::cout << "target=" << get_target() << std::endl; } % }
"declare_fields" prend en param�tre une suite de noms d'attributs, suivis de leur type, et g�n�re leur d�claration.
"getters" g�n�re des fonctions de la forme get_<nom attribut> et
"setters" g�n�re des fonctions de la forme set_<nom_attribut>.
"encapsulate" g�n�re les getters et les setters en une seule fois.
On a d�j� �conomis� par mal de recopiage!
Pour encore plus de rapidit�, le dernier exemple est radical, le helper "classdef" prend en param�tre le nom de la classe, les noms des classes � impl�menter, et les attributs avec leurs types, et g�n�re directement la classe avec les getters et setters appropri�s. Comme on le voit dans l'exemple, vous pouvez tout de m�me rajouter ce que vous voulez dans le corps de la d�claration de la classe.
Voici ce que RPP a g�n�r� dans exemple3.cpp :
On pourrait aussi imaginer g�n�rer une batterie de constructeurs avec classdef, ce serait tr�s rapide � faire.
Code : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 class Displayable { std::string toString() const = 0; }; class Starship { private: Engine rightEngine; string name; int serialNumber; Engine leftEngine; public: void set_name( const string& value ) { name = value; } void set_serialNumber( const int& value ) { serialNumber = value; } const string& get_name() const { return name; } const int& get_serialNumber() const { return serialNumber; } const Engine& get_rightEngine() const { return rightEngine; } const Engine& get_leftEngine() const { return leftEngine; } }; class Warship : public Starship, public Displayable { public: void set_turret( const Weapon& value ) { turret = value; } void set_target( const Position& value ) { target = value; } void set_ammo( const int& value ) { ammo = value; } const Weapon& get_turret() const { return turret; } const Position& get_target() const { return target; } const int& get_ammo() const { return ammo; } private: Weapon turret; Position target; int ammo; public: string toString() const { std::cout << "ammo =" << get_ammo() << std::endl; std::cout << "turret=" << get_turret() << std::endl; std::cout << "target=" << get_target() << std::endl; } };
Voil� pour la petite pr�sentation, si vous voulez tester, voici un package comprenant RPP (Ruby PreProcessor) + les codes des exemples + les helpers des exemples + le fichier YAML des exemples.
J'esp�re que certains trouveront ca utileDans tous les cas n'h�sitez pas � poster vos avis, demandes, ...
Partager