Affichage des articles dont le libellé est ruby. Afficher tous les articles
Affichage des articles dont le libellé est ruby. Afficher tous les articles

mercredi 1 avril 2009

Algorithme naïf de cryptage d'entrée

Je vous propose aujourd'hui un petit algorithme dans le domaine de la cryptographie, implémenté en Ruby. Comme vous allez le voir, il s'agit d'un algorithme à clef secrète générée aléatoirement au moment du chiffrement. Cette méthode est assez peu intéressante pour la plupart des applications de cryptage (transfert de message notamment) de par le fait que la clef doit être transmise afin que le destinataire puisse décrypter le message. Dans ce cadre, on utilise plus volontiers la cryptographie asymétrique (RSA, etc...), ou, pour des raisons de performances, une méthode symétrique dont la clef est cryptée de façon asymétrique.


En revanche, cet algorithme me semble utilisable pour un autre genre d'applications : de façon locale, afin de crypter une réception de donnée par exemple.

Contexte

Plusieurs hypothèses tout d'abord. La donnée à recevoir peut être accédée par morceaux (bits, lettres, chiffres, lignes, pages, etc...). On ne connait pas à priori sa taille. On suppose également que l'on peut pareillement accéder à un nombre important de données similaires.



Principe : Se fondre dans la masse

Le coeur de la méthode consiste à noyer l'information que l'on souhaite recevoir (notée A dans la suite, data dans le code) la recevant par morceaux, au milieu d'une foule d'autres informations similaires, de façon aléatoire.
Pour cela, on construit des "cycles" de taille aléatoire, dont seuls certains index (aléatoires eux-aussi) contiennent des parts de données intéressantes. La clé consiste en la liste des cycles utilisées (plus simplement, la liste des couples [occurences de part de A, taille du cycle]).

Le code

Dans mon implémentation en Ruby, j'applique l'algorithme à un tableau. L'input dummies correspond donc à une liste de données. La sortie est la paire [données cryptée, clé]

Cryptage :



A noter que je clone l'entrée data afin que la méthode soit non destructive sur celle-ci.

Décryptage :



On décrypte par morceau correspondant chacun à un cycle de la clef.

Exemple :

Pour tester cette méthode :



Ce qui donne un résultat du genre (pour rappel, la clef est profondément aléatoire...) de celui-ci.


Conclusion

Encore une fois, il s'agit d'une méthode naïve, à utilité limitée (je suis un grand débutant en crypto). Cependant, pour un usage local, elle me semble adaptée, bien que probablement peu performante en terme de vitesse (celle-ci étant conditionnée par l'ampleur des cycles et le nombre d'occurrences par cycle, ici en dur).
J'ai du mal à me figurer de grosses failles dans cet algorithme, si ce n'est pour ce qui est de l'utilisation de la randomisation : 1/ sa complexité étant dans l'absolue aléatoire, elle ne peut être calculée que par majoration dans le meilleur des cas (le meilleur des cas en crypto étant en fait le pire des cas en algorithmique), 2/ des failles existent sur des implémentations standards des méthodes random (présence de cycles, etc... Des méthodes plus abouties existent cependant, notamment celles utilisant des propriétés physiques du matériel informatique, comme la température par exemple).

Notes :
1/ Crédit photo : Jan Chipcase
2/ Ceci n'est pas un poisson d'Avril. J'aime pas cette tradition de clampes.

lundi 16 mars 2009

Animal Quiz en Ruby

Allez, comme ça fait un moment que je n'ai pas posté de code, je vous propose un petit jeu rigolo : le quiz des animaux, implémenté en Ruby.
Il s'agit d'un petit algorithme tentant de deviner à quel animal vous pensez : pour ce faire, le programme vous pose un certain nombre de questions, puis vous propose un animal. Si celui-ci est l'animal auquel vous pensiez, le programme gagne. Sinon, il vous demande d'ajouter une question (ayant pour réponse oui ou non) permettant de différencier l'animal proposé et le votre, et l'ajoute dans sa base de question.
La structure employée est un arbre binaire dont les branches sont les questions et les feuilles les animaux. Celle-ci est enregistrée dans un fichier YAML dans mon code en fin de partie.

Le code étant un peu long, et en plusieurs fichiers, au lieu de le coller ici, je vous propose d'aller le consulter/télécharger chez pastie (un fichier d'exemple en YAML inclus) :


Vous noterez la méthode list_animals de la classe Game, non employée dans mon code, mais permettant d'inspecter le contenu de l'arbre de données (Combien d'animaux ? Plusieurs occurrences d'une même espèce ? Etc...). Le principal défaut de cette approche est que l'ordre des questions influe énormément sur la structure. Par ailleurs, il est parfois difficile de différencier deux animaux avec une question "oui/non" non ambiguë (dans l'appli web du "Génie" ci-dessous, il y a la possibilité de ne pas se prononcer...) : un tigre mange-t-il des souris ?

Pour ce code, je me suis basé sur les règles fixées par le défi Ruby Quiz n°15. L'implémentation qu'ils proposent est d'ailleurs bien plus concise que la mienne... A lire pour plus de détails.

Liens



Crédit photo : L-ines, sous CC. Lien.

dimanche 15 février 2009

Langages en construction

Il existe littéralement plusieurs centaines de langages de programmation. Et malgré ce, de nouveaux langages continue d'apparaître chaque année, développés par de grosses boîtes ou par quelques passionnés. Je n'ai pas vraiment envie de trop discuter de l'intérêt de développer de nouveaux langages aujourd'hui, simplement :


  • Oui, il existe déjà de nombreux langages de très bonne qualité, spécialisés ou non, largement employés ou non, dans la plupart des paradigmes connus.
  • Oui, la qualité de langages récents comme Io, ou le succès d'autres comme Lua justifie de continuer à en développer d'autres.
  • Non, un langage n'est pas "indémodable" ou éternel : le Fortran et le Cobol, notamment, doivent être progressivement abandonnés et remplacés.
Par ailleurs, quand on aime la programmation, le processus de création d'un langage, ses étapes de développements, les choix faits sur ses caractéristiques, son (ou ses) paradigme(s), son implémentation, etc... sont particulièrement intéressants.

Je vous propose donc de jeter un coup d'oeil à 4 langages actuellement en construction :


Cat

Cat est un langage interprété de haut niveau, "stack-oriented", comme le Forth, et fonctionnel. Des 4 que je vous propose dans cet article, c'est probablement le plus avancé au niveau de son développement, celui-ci ayant débuté en 2006, malgré la présence de bugs conséquents (flottants et récursivité notamment).

Les langages de ce type, à pile, sont relativement peu nombreux : Forth, Joy, Factor, PostScript et quelques assembleurs en gros... Cat ne rentre donc pas dans une niche trop saturée. Ce paradigme est assez intéressant et original... et déroutant : il utilise la notation post-fixée (on en parlait ici) qui reste plutôt rare, et la manipulation de la pile demande un certain temps d'adaptation. Cela dit, pris comme un jeu, c'est assez amusant.
Le côté fonctionnel du langage est dû au fait que toute instruction correspond à une fonction appliquée à la pile. Le langage supporte aussi une forme de macro.
Petit plus, le typage est statique et inféré (comme en OCaml par exemple).

La version actuelle de Cat est implémenté en C#. Oui, je sais, berk. Cela dit, d'une il compile sous Mono et donc est utilisable partout (théoriquement...), et d'autre part, une machine virtuelle en C++ est actuellement en cours de développement par Christopher Diggins.

Vous pouvez aller jouer avec, directement en ligne sans rien installer, grâce à cet interpréteur online (Allez y je vous dis, c'est rigolo ! Par contre, tout le langage n'est pas dispo dessus...).

Exemple de la factorielle naïve (récursive) :





Ioke

De ces 4, Ioke est peut-être le plus "sérieux" et le plus suceptible de connaître le succès auprès des programmeurs amateurs et même professionnels. Ioke (prononcé "Ayoki", comme "Io" en anglais et "Loki", le dieu scandinave) est développé par Ola Bini qui travaille également sur JRuby (implémentation de Ruby sur la JVM), entre autres.
Ioke est un langage dynamique, orienté objet, à prototypes, tournant sur la JVM, et inspiré par Io, Smalltalk, LISP et Ruby. Sa première version est sortie il y a seulement quelques mois.

Bien que je ne l'ai pas testé, je trouve Ioke très prometteur pour plusieurs raisons. D'abord parce qu'il s'inspire de très bons langages et que son paradigme (OO à prototype) est très intéressant. Ensuite, qu'on le veuille ou non, parce que le fait qu'il tourne sur la machine virtuelle Java lui ouvre les portes du monde professionnel : ce n'est pas une garantie d'utilisation par les entreprises, mais ça augmente significativement ses chances. Il contient une foule de concepts/features intéressantes : syntaxe, blocks, macros, "lecros", aspects, introspection... La documentation est particulièrement riche et bien faite.

Ola Bini, son développeur principal, est un blogger assidu et un passionné des langages de programmation : il est possible de suivre les étapes de réflexion et de construction de Ioke, et bien d'autres choses sur son blog. C'est assez enrichissant.

Exemple de "99 Bottles" (oui, on dirait vraiment du Io...) :




Potion

L'un des derniers projets de Why's the Lucky Stiff s'appelle Potion. Comme d'habitude avec ce hacker, il s'agit d'un petit OVNI. Potion est un tout petit langage, qui se veut rapide, orienté "objet et mixin".

Sa machine virtuelle fait à peine 4000 lignes de code, en C. Il faut croire que c'est une obsession pour _Why de réduire au maximum la taille de tout code : Shoes pour la GUI et Camping comme micro-framework web en Ruby, ou Yown en Io. Une bonne partie de Potion est inspiré par Lua.

La syntaxe est assez particulière, et le langage s'appuie sur l'approche suivante :

  • Tout est un objet
  • Même les mixins sont des objets
  • Et bien sûr, les fermetures sont des objets
  • CEPENDANT, les objets ne sont pas tout : ils ne sont rien sans les mixins.
Les objets n'ont pas de classe : les données (attributs) sont au niveau de l'objet lui-même, et les méthodes sont conservées dans des mixins. Tout objet possède par contre des mixins.
Je n'ai pas encore testé Potion, n'ayant pas réussi à le compiler sous Windows. On va le tenter prochainement sous 'nix, ça a l'air vraiment marrant...

Exemple de Fibonacci récursif :



Tinyrb

Plus qu'un langage à proprement parler, Tinyrb est une toute nouvelle machine virtuelle pour le langage Ruby. Elle s'annonce comme la plus petite VM du langage, mais aussi comme étant plus que raisonnablement rapide. Il s'agit pour l'instant d'une version "allégée" du langage Ruby : tout code Tinyrb tournera avec un autre inerpréteur Ruby, mais l'inverse n'est pas vrai (il manque notamment un certain nombre de classes du core standard de Ruby) .

Marc-André Cournoyer a lancé ce projet en s'inspirant de Lua (encore !), Potion (tiens donc !) et Tinypy. Ici, comme pour Lua, l'aspect intéressant, c'est le côté portable et embarquable. C'est un côté de plus en plus présent dans les langages récents (Lua, Io...)

Comme pour Potion, je n'ai pas encore réussi à compiler la VM sous Window$ : à retenter aussi sous Linux... Pas de code ici, c'est du Ruby, pas plus (mais un peu moins).

~~~~

Voilà, n'hésitez pas à jeter un coup d'oeil à ces "petits" projets, et bon hack !

NOTE : les images de cet article sont libres/dans le domaine public et liées aux projets associés, hormis celle employée pour Potion , qui est l'avatar actuel de Why's the Lucky Stiff, et qui lui appartient.

mercredi 24 décembre 2008

Sortie de Tabz Converter

Allez hop ! Pour les fêtes, je vous propose une petite application de bureau que j'ai codée récemment : Tabz Converter. Il s'agit d'un petit logiciel libre (licence BSD) avec interface graphique permettant de convertir des partitions musicales au format texte, d'une notation vers une autre. Il est surtout orienté vers les partitions d'harmonicas, ce type d'outil existant déjà pour la plupart des instruments plus répandus (guitare, etc...).


A quoi ça ressemble ? Comment ça marche ?


Il s'agit d'une application toute simple : 2 petites listes déroulantes pour choisir les notations de départ et d'arrivée, à choisir parmi les suivantes :
  • Solfège
  • Notation Américaine
  • Harmonica chromatique (12 trous en Do / accordage standard)
  • Harmonica diatonique (10 trous en Do / accordage Richter standard)
Ensuite, il suffit de taper sa partition dans l'edit box de gauche, appuyer sur "Convert", et le résultat apparaîtra dans l'edit box de gauche (dans laquelle il peut être copié et/ou modifié). La syntaxe pour les partoches est la suivante :







Un petit bouton "Help" permet d'ouvrir une fenêtre d'aide avec le détails des syntaxes utilisées, avec exemples.

Comment l'installer ?


Cette application est basée sur Shoes (et donc implémentée en Ruby) : l'application ne nécessite donc pas d'installation en elle même, cependant pour la faire tourner il faut avoir préalablement installé le programme Shoes. Celui-ci est disponible librement sous la plupart des plates-formes connues à cette adresse :



Tabz Converter lui-même est disponible dans la Shoebox (un répertoire de petites applications pour Shoes - quitte à installer Shoes, essayez en quelques unes, certaines sont très rigolotes...) à cette adresse :



Sous forme de .zip ou .rar. Une fois décompressé, il suffit de lancer le fichier tabz_converter.rb avec Shoes, et l'application se lance (shoes tabz_converter.rb via un terminal sous Windows comme sous Nix).

La suite ?

Je vais tenter d'améliorer ce petit programme régulièrement (l'utilisant moi même de façon conséquente). Parmi les améliorations fortement envisagées pour l'avenir, on peut trouver la prise en compte des altérations pour les harmonicas (overnote, bend, etc...) et un moyen (boutons "+"/"-") de monter/descendre d'une octave sur les partitions où cela est possible (pas pour l'harmonica diatonique donc).

Tout commentaire, suggestion ou rapport de bug est le bienvenu, via cet article, la page de l'application dans la Shoebox voire même par mail (cf. page de profil).

~=o=~

Bonnes fêtes à tous.

vendredi 31 octobre 2008

Pourquoi utiliser Ruby ?

Note préliminaire :

Il y a quelques temps, j'avais rédigé cette présentation à la demande de gars du Site du Zéro, dans le but de faire un topic de comparaison objective (Mama mia !) du Ruby et du Python. Ne connaissant que très peu le Python, je me suis chargé de la partie Ruby. Initialement rédigée en zCode, la première version de celle-ci est disponible à l'adresse suivante (à toute fin utile) : version zCode. (Merci par avance de me prévenir si vous détectez un problème dans cet article : lien mort, texte "bizarre" ou autre).

-~=.=~-

Pourquoi Ruby ?

Ruby

Ruby est un langage de programmation libre, interprété, à typage dynamique fort et orienté objet. L'écriture de ce langage d'origine japonaise a débuté en 1993 et est dirigée par différents principes :
En Ruby, toute donnée est un objet, et toute fonction est une méthode (une méthode étant elle même un objet...) : il n'existe pas de type primitif comme dans certains autres langages.

irb(main):001:0> 1.class
=> Fixnum
irb(main):002:0> Fixnum.class
=> Class
irb(main):003:0> Class.class
=> Class


Ruby est dynamique et flexible : possibilité de modifier le code à l'exécution, et/ou de redéfinir son implémentation de base.

# Exemple de modification du code natif # en cours d'execution

a = 1

puts a.class
#=>Fixnum

# to_s : methode native de conversion en String
puts a.to_s
#=>"1"

# Modification de to_s
class Fixnum
def to_s
"Huhuhu !"
end
end

puts a.to_s
#=>"Huhuhu !"


Le principe de moindre surprise veut que le développeur (expérimenté, ou venant d'un autre langage) soit le moins surpris/dépaysé/perturbé possible par la syntaxe ou les mots clés de Ruby.

"Convention plutôt que configuration." Ruby favorise ce concept, très repris dans certaines applications du langage, dont Rails.

Ruby est à comparer à d'autres langages dynamiques interprétés, dont : Python, Groovy, PHP, Io, Perl et Scheme, entre autres.

Pourquoi Ruby ?

Quelques avantages :



  • Entièrement objet, mais autorise le procédural, et dans une certaine mesure inspiré du fonctionnel. Le développeur est donc libre. De même il y a "Plusieurs façons de faire la même chose". Cela ne veut pas dire pour autant que toutes se vaillent.

  • Le core et l'API standard fournissent tout le nécessaire pour débuter (et continuer !) : threads, benchmark, gestion d'exceptions, parseurs...

  • Grandes possibilités de métaprogrammation.

  • Différentes implémentations du langage sont disponibles : MRI pour la principale en C, mais aussi JRuby (en Java, pour la JVM), IronRuby (pour la plate-forme .Net), Rubinius (en Ruby) et dernièrement MagLev, et quelques autres.

  • La prise en main est généralement rapide pour quelqu'un ayant déjà de premières bases en programmation et en POO.

  • Contrairement à ce qu'on peut souvent entendre, la documentation du coeur et des librairies standards est bonne et claire. Les ouvrages traitant du langage sont également assez nombreux, et parfois de très bonne qualité. Notamment : Why's (Poignant) Guide to Ruby, le Pickaxe, Ruby par l'Exemple, Design Patterns in Ruby...

  • Outils associés : TextMate (pour MacOS), Aptana RadRails (pour Eclipse ?), RDoc (génération automatique de documentation), RubyGems (gestionnaire de packages, appelés "gem" en Ruby), etc...

  • Communauté importante et active : RubyForge.

  • De nombreuses gems, portages et librairies de qualité pour le web (Rails, Merb, Ramaze, Camping...), pour la GUI (GTK, WxWidgets, FOX, Shoes, tk...), pour les sciences (BioRuby, LaPack...)...




  • Et quelques (malheureux) défauts :



    • D'abord, les performances en terme de vitesse d'exécution sont assez mauvaises pour un langage de ce type. A relativiser cependant : les performances sont rarement critiques pour un langage de ce type d'une part, et d'autre part, les améliorations sont régulières sur chacune des implémentations du langage (avec une certaine compétition qui favorise les progrès).

    • Manque de sécurité sur certains points : peu de warnings, constantes pas constantes... Ceci est principalement dû à la grande liberté du codeur.

    • Métaprogrammation riche, mais incomplète (à comparer à Io pour l'introspection/réflexion notamment).
    • Communauté très (trop ?) orientée Rails et web. Très anglophone également.

    • Gestion perfectible des blocks.

    • Certaines parties des librairies standards contestables (Math et Matrix entre autres).

    • Langage "non-pur" : à comparer à Io, Smalltalk ou Scheme (encore que le Scheme ne soit peut-être pas "purement" fonctionnel...). Ici encore, c'est surtout une conséquence de la liberté du programmeur. Et en conséquence, la relative facilité pour commencer à coder en Ruby peut donner de mauvaises habitudes aux débutants (ou l'impression d'avoir rapidement fait le tour...) ; on le constate régulièrement dans des codes pour Rails ou RPG Maker XP.



    • Ah ! Et dernier avantage du langage : son créateur est aussi un grand comique ^^




dimanche 14 septembre 2008

Ruby : Renommer un ensemble de fichiers

Logo Ruby Juste un petit code pour renommer un ensemble de fichiers. Sous Unix, un petit shell serait sans doute suffisant, mais étant sous Windows à la maison et n'aimant pas des masses le Batch, voici ce que ça pourrait donner... Dans cet exemple, on associe à d le répertoire dans lequel on souhaite renommer les fichiers dont le nom commence par "PICTURE_" (sortie d'appareil photo dans mon cas) en "starpics_000X" avec X s'incrémentant.


d = Dir.new("C:/Documents and Settings/utilisateur/Photos/Star")
Dir.chdir("C:/Documents and Settings/utilisateur/Photos/Star")
i = 1
d.each do |file|
if file.to_s[0..7] == "PICTURE_" then
File.rename(file.to_s, "starpics_000#{i}.jpg")
i += 1
end
end
Rien de bien méchant dans ce court code. Quelques remarques cependant : on remarque que même sous Windows, les séparateurs dans le chemin du répertoire est un slash et non pas un anti-slash... Il me semblait qu'il y avait une méthode de base pour faire cette conversion un peu pénible mais je ne l'ai pas retrouvée... Une chose un peu pénible avec cette partie du core de Ruby, sur les fichiers et répertoires, c'est que c'est assez peu homogène : ici, on itère sur les fichiers grâce à la méthode d'instance each de la classe Dir (Directory), on change le répertoire courant grâce à la méthode de classe chdir, mais la méthode de renommage de fichier est une méthode de classe ! Pourquoi pas une méthode d'instance sur sa cible ?

Au passage, il est possible de renommer plusieurs fichiers en même temps sous Windows via l'explorateur : les sélectionner puis faire F2. On en renomme un, les autres prennent le même nom, suivi de " (X)" avec X s'incrémentant. La beauté de Windows ? Des anti-slashs dans les chemins et surtout de superbes espaces et parenthèses dans les noms de fichiers...

Un bon tutoriel sur Ruby pour la partie "Manipulation de fichiers", par JB Naigeon (:fr).
Blogged with the Flock Browser

mardi 19 août 2008

Medicolor : le code

Je viens de me rendre compte que j'ai oublié de publier le code de Medicolor : mon petit programme fait avec Ruby et Shoes générant les images de 2 articles précédents... Honte à moi ! Donc, basiquement, Medicolor est une petite appli manipulant les couleurs : à partir d'un pattern de départ (et les conditions aux limites associées), le programme moyenne à chaque itération (déclenchée par un simple clic dans la fenêtre) les couleurs de chaque disque présent avec celles de ses voisins.



Pas clair ? Vous pouvez l'essayer à partir des sources (nécessite Ruby et Shoes version r751 ou suivante).


En ligne de commande : $>shoes shoes_medicolor.rb

Le nom du fichier d'entrée (medicase_01.rb par exemple) peut être directement changé dans le require. Les conditions aux limites sont périodiques ou fixées, les points peuvent être également de couleur fixe (voir cas d'exemple avec les sources).

Amusez vous bien !

mercredi 6 août 2008

Classe Struct en Ruby

Je suis récemment tombé (par hasard, pour changer...) sur une classe de Ruby pour le moins rare : Struct. Basiquement, il s'agit d'une classe permettant d'implémenter rapidement des conteneurs simples, et fixés. Par rapport à un Hash, il n'est possible que de passer des symboles comme clefs, et il n'est pas permis d'ajouter de nouvelles clefs après déclaration. Struct possède également moins de méthodes que Hash, mais conserve les plus importantes (celles héritées d'Enumerable).

J'avoue être assez surpris par l'existence de cette classe. D'une part, parce que je ne l'ai rencontrée dans aucun code Ruby. Jamais. Ensuite parce qu'elle semble assez peu intéressante par rapport à un hachage (hormis pour l'aspect "déclaré" et "fixé" de ses clefs). Enfin, parce qu'elle n'apporte pas à priori de meilleures performances qu'un hachage (car elle est implémentée avec... eh voui...).

Deux liens sur cette classe :

Enfin, encore un côté surprenant, les clefs d'une structure ne semblent pas en être des attributs...



Fiche = Struct.new(:nom, :prenom, :adresse, :phone)

# Exemple d'initialisation
roger = Fiche.new "Dupont", "Roger", \
"3 rue des Lilas, \
55555 Canardville", \
"0800555222"

p roger
#=> #struct Fiche nom="Dupont", prenom="Roger",
# adresse="3 rue des Lilas, 55555 Canardville",
# phone="0800555222">

chuck = Fiche.new

chuck.prenom = "Chuck"

puts chuck.prenom
#=> Chuck

class Fiche
def foo
puts @prenom

end

def bar
puts self.prenom
end
end

chuck.foo
#=> nil

chuck.bar
#=> Chuck

lundi 28 juillet 2008

Forgotten Ruby methods

Ou plutôt les méthodes que je n'utilise pas assez... Sur les tableaux, les chaînes de caractères et quelques autres petites choses très mignonnes comme l'opérateur ternaire, l'affectation multiple (à consommer avec modération...) et le ||. 21 autres choses très intéressantes dans cet article.

Petit mot sur la méthode extend : d'un point de vue POO, elle permet en quelque sorte "d'instancier un module". Si une classe étend un module Mod, les "méthodes d'instance" de celui-ci seront transmises à la classe en tant que méthode de classe. Si l'on étend Mod avec un simple objet (bon, d'accord, une classe est un objet... mon explication précédente reste valable.), celui-ci se comportera comme une instance de Mod, avec les méthodes qui vont avec... Deux bonnes sources sur le sujet : [Ruby's Cube, :fr] et [Juixe TechKnow, :en].


### Multiple affectation  and || ###
a, b = nil, 10
#=> [nil, 10]
a || b
#=> 10

### On Arrays... ###
a = [0,"111",2,3,3,3,3]
a.class
#=> [0,"111",2,3,3,3,3]
a.delete 3
#=> 3
a
#=> [0,"111",2]
a.delete_at 1
#=> "111"
a
#=> [0,2]
a.insert(1,"1")
#=> [0,"1",2]
a += [3,4,5]
#=> [0,"1",2,3,4,5]
a.inspect
#=> "[0,\"1\",2,3,4,5]"
a.map!{|v| (v.is_a? Numeric)? v : v.to_i}
#=> [0,1,2,3,4,5]
a = a.join "-"
#=> "0-1-2-3-4-5"
a = a.split '-'
#=> ["0", "1", "2", "3", "4", "5"]
a | ["1", "6", "7"]

#=> ["0", "1", "2", "3", "4", "5", "6", "7"]


### And Strings... ###
str = " trop d'espace tue l'espace... "
#=> " trop d'espace tue l'espace... "
str = str.strip
#=> "trop d'espace tue l'espace..."
str.crypt "Oz" # "Oz" est le 'sel'
#=> "Oz2SDpLQ4HL02"
str.count "e"
#=> 5

### Finaly, the Object#extend method ###
module Mod
def homerize
p "Doh!"
end
end

class Simpson
extend Mod
end

Simpson.homerize
# "Doh !"
#=> nil

bart = Simpson.new
# bart can't homerize, unless...


bart.extend Mod
bart.homerize
# "Doh !"
#=> nil

jeudi 24 juillet 2008

Algorithme Rho de Pollard en Ruby

L'algorithme Rho de Pollard permet de décomposer un entier en son produit de facteurs premiers. Cet algorithme se base sur une fonction dite aléatoire f, permettant d'obtenir une suite cyclique :

xi+1 = f(xi) % n


avec n l'entier à décomposer.

Attention, si :

pgcd(|xi - x2i|, n)

prend n pour valeur, l'algorithme produit une boucle infinie (il faudrait (y a qu'à...) alors changer la fonction f ou aller se faire cuire un steak de soja) : dans mon code, je lève une erreur, en l'occurrence.
Sinon, beaucoup de récursion...

Code prime.rb :
(Ruby 1.8.6 : $ prime.rb [integer])

def pgcd m, n
(n==0)? m : pgcd(n, m%n)
end

def f x, n
(x**2 + 1) % n
end

def x i, n
(i==0)? 2 : f(x(i-1,n), n)

end

class Integer
def is_prime?
res = true
if self < 2 then
res = false
else
for i in 2..Math.sqrt(self).to_i
if i.is_prime? and (self%i == 0) then
res = false
end

end
end
res
end
end

def pollard n
r = []

if n.is_prime?
r.push n
elsif n != 1
i, p = 0, 1
while p == 1
i += 1
p = pgcd((x(i,n)-x(2*i,n)).abs, n)
end

raise "Pollard Algorithm: Cycle FAIL" if p==n

if p.is_prime? then
r.push p
else
r.push pollard(p)
end

r.push pollard(n/p)
end
r.flatten!
r
end

input = ARGV[0].to_i
pollard(input).each {|x| puts x}

mardi 22 juillet 2008

Ruby : Plus ou Moins en moins de 100

Suite à cet article rigolo (tiré d'un blog tout à fait intéressant au passage), essayons de faire le jeu du "Plus ou Moins", en Ruby avec le moins de caractères possibles...

Code :
n=(100*rand).to_i;loop{d=gets.to_i;(d==n)?(puts "bravo !";break):puts((d>n)?"lower":"greater")}

Désolé, ça dépasse encore un poil... (ctrl ou pomme + molette)

95 caractères donc... mais pas top lisible. Je regrette surtout que ce ne soit pas "vraiment" en une ligne (objectivement, là, il y en a 3), mais on ne peut pas tout avoir...

jeudi 17 juillet 2008

Dummydgets pour Shoes : Bulles

Allez hop, deux petits programmes profondément inutiles faits avec les pieds, pour Shoes. Dans ces deux là, j'utilise le bloc motion{} qui permet d'effectuer une action en fonction de la position courante du curseur. La syntaxe est la suivante :


motion do |x,y|
foo(x)
bar(y)
foobar(x,y)
# etc...
end
Dès lors, le code contenu dans ce block (ici les méthodes foo, bar et foobar) sera exécuté dès que la position du curseur (désignée par x et y) change. Attention, l'axe Y est dirigé vers le bas (il serait plus rigoureux d'écrire |left,top| plutôt que |x,y|).

J'utilise aussi la méthode move(x,y) qui permet... de déplacer sa cible à la position (x,y). Easy, isn't it ?

Bubbles

Dans celui-ci, la fenêtre contient une dizaine de bulles qui se déplacent selon des fonctions plus ou moins complexes qui donnent une impression assez "chaotique"... mais en fait non.

Bubbles (pointeur non-représenté)

Le code est disponible ici, et l'image de fond ici (penser à modifier le chemin dans votre code).

Gogle Head

Là, le "dude" suit le curseur du regard lorsqu'on le déplace. Les trajectoires de mouvement des yeux sont simplement des cercles (attention, trigonométrie !). J'ai laissé en commentaire quelques lignes qui facilitent l'ajustement des caractéristiques des trajectoires, si certains veulent s'amuser en changeant l'image de fond (de préférence au format PNG).

Gogle Head (pointeur en haut à droite de la fenêtre,
non-représenté)


Le code est disponible ici, et l'image de fond ici (penser à modifier le chemin dans votre code).

Liens :

jeudi 10 juillet 2008

ShoesFests


Demain, Vendredi 11/07/2008 à partir de 8am GMT (soit 21H en France, Belgique, Suisse et Luxembourg ou 15H à Québec) pendant 24H, est organisée la ShoesFests sur le chan #shoes du réseau IRC Freenode (irc.freenode.net) ! Il s'agit de découvrir Shoes, le curieux toolkit de GUI de Why's The Lucky Stiff pour Ruby, d'écrire et partager de petits programmes avec Shoes en s'amusant, le tout en présence de Why's et d'autres rubyistes sympas. Cet event a pour but de tester et diffuser ce programme, tout en identifiant les problèmes de documentation et de clarté. Une seconde édition est prévue est prévue aux mêmes horaires le Vendredi 25 Juillet.

Après ça, on ne pourra plus dire que "Nobody Knows Shoes" !

Je vais essayer d'y passer demain soir, ça a l'air prometteur !


L'annonce chez :
More :

samedi 7 juin 2008

Ruby Duck-Safe interface

Suite à un précédent article sur DiamondBack Ruby, j'ai un peu réfléchis à la question de la sécurisation de l'appel de fonctions/procédures/méthodes, au niveau des types dans un langage dynamique tel que Ruby (/Python,/Perl/Etc...).

Finalement, quel est le problème ? Quelque soit le paradigme, il se situe au niveau de la capacité d'une fonction/procédure/méthode à traiter ses arguments en fonction de leur type, classe ou comportement. Problème simple donc. (Les aspects plus bas niveau sont ici peu intéressants : on est actuellement capables de les éluder).

Tout est dans la notion d'interface : dans les langages statiques, une interface n'est pas seulement un moyen d'appeler un "service" (fonction/méthode/...) mais c'est également un "contrat" qui impose des conditions sur les informations passées à l'appel (le plus souvent sur leur type). Par exemple, la fonction acheter_une_baguette ne peut se contenter de prendre 0.45 en argument : il faut que 0.45 soit en €, "de type €".

Ruby est un langage dynamique comme tant d'autres. Mais de par sa conception, sa "philosophie", il fait le choix de se concentrer sur ce que fait un objet plutôt que sur ce qu'il est : c'est le Duck Typing. On peut facilement critiquer cette approche du typage pour plusieurs raisons. Cet article sur Otaku en expose plusieurs. Pour ma part, je me contenterais de dire qu'elle réside dangereusement sur la langue (quel rapport entre Balançoire.balancer et Coupable.balancer ?).

Mais les langages statiques ne sont pas nécessairement satisfaisants sur ce point non plus. Pour faire un parallèle avec les mathématiques, on peut considérer que :

f : R -> R
x |-> x + 2

avec R l'ensemble des réels, est une déclaration de type statique.

Pour autant, f reste valable de N dans N (naturels), de C dans C (complexes), etc... Le Duck Typing assure que f est valable du moment que x possède une méthode "+", ce qui évite de redéfinir f pour chaque espace où cette fonction est valable.

Mais est-ce suffisant ? Prenons :

f : x |-> 2 / x

Dans ce cas, on doit de plus assurer que x n'est pas nul. Si mathématiquement, cela s'exprime sur l'espace sur lequel est défini x, "informatiquement" on aura le plus souvent x entier ou flottant. Les contraintes sur un argument ne se limite donc pas à son type/classe, ni à son comportement (possède méthode "+"), mais aussi à d'autres paramètres, comme son état (ici sa valeur). De plus, s'il s'agit ici d'un exemple simple : il existe probablement d'autres exemples mettant en évidence l'influence du contexte d'appel.

Je vous propose ici un module (naïf) permettant d'exprimer assez simplement, lors de l'implémentation d'une méthode, les contraintes associées à ses arguments. Le but est d'assurer ces contraintes sans pour autant surcharger le code de structures conditionnelles avec gestion d'exceptions : on déclare simplement notre contrat.

(sources également disponibles **sans fuck1n' coupure** ICI)

module Safety

# Negator for error message
@@neg_converter = {:is_a? => "is not a",
:respond_to? => "does not respond to",
:include? => "does not include",
:each_element_is_a? => "contains element(s) that is(are) not"}

# Ensure that constraints are respected
def ensure_it cstr
cstr.each do |arg, cstrs|
value = cstrs[0]
cstrs[1...cstrs.size].each do |pair|
if not value.method(pair[0]).call(pair[1]) then
raise "Argument #{arg} (#{value.inspect}) \
#{@@neg_converter[pair[0].to_sym]} #{pair[1]}."
end
end
end
end

private

# A simple example of constraint method
def each_element_is_a? klass
assertion = true
self.each do |elt|
assertion = false if not elt.is_a? klass
end
assertion
end

end


La méthode ensure_it checke les contraintes passées. Une contrainte est facilement exprimable par une méthode telle que each_element_is_a?.

Exemples :


require 'Safety'

class Fixnum
include Safety
def mult_by_plus num1, num2
ensure_it({:num1 => [num1, [:is_a?, Fixnum]],
:num2 => [num2, [:respond_to?, :next]]})
self*num1+num2
end

end

a = 1
puts a.mult_by_plus(1,2)
puts a.mult_by_plus(1,1)
puts a.mult_by_plus(1,1.0) #=> Error raised


Et :


require 'Safety'

include Safety

def potamok tab
ensure_it({:tab => [tab, [:respond_to?, :each],
[:each_element_is_a?, Fixnum]]})
val = 0
tab.each do |elt|
val += elt**2
end
val
end

puts potamok [42,33,59]
puts potamok [1,2,3,6,59.3] #=> Error raised


Toute remarque est la bienvenue.