La version 4.0.0 de Ruby est sortie et introduit « Ruby Box » et « ZJIT ». Ruby Box est une nouvelle fonctionnalité (expérimentale) qui permet de séparer les définitions. ZJIT est un nouveau compilateur juste-à-temps (JIT), développé comme la prochaine génération de YJIT. Ractor, le mécanisme d'exécution parallèle de Ruby, a bénéficié de plusieurs améliorations. En termes de performances, de nombreuses structures de données internes ont été améliorées afin de réduire considérablement les conflits sur un verrou global, ce qui permet un meilleur parallélisme.Ruby est un langage de programmation polyvalent. Il a été conçu dans un souci de productivité et de simplicité. En Ruby, tout est un objet, y compris les types de données primitifs. Il a été développé au milieu des années 1990 par Yukihiro « Matz » Matsumoto au Japon. Ruby est un langage interprété, de haut niveau et à typage dynamique ; son interpréteur utilise le ramasse-miettes et la compilation juste à temps (JIT). Il prend en charge plusieurs paradigmes de programmation, notamment la programmation procédurale, orientée objet et fonctionnelle. Selon son créateur, Ruby a été influencé par Perl, Smalltalk, Eiffel, Ada, BASIC et Lisp.
La version 4.0.0 de Ruby est sortie et introduit « Ruby Box » et « ZJIT ». Ruby Box est une nouvelle fonctionnalité (expérimentale) qui permet de séparer les définitions. ZJIT est un nouveau compilateur juste-à-temps (JIT), développé comme la prochaine génération de YJIT. ZJIT est plus rapide que l'interpréteur, mais pas encore aussi rapide que YJIT. Cette version apporte également des mises à jour des classes principales.
Ractor, le mécanisme d'exécution parallèle de Ruby, a bénéficié de plusieurs améliorations. En termes de performances, de nombreuses structures de données internes ont été améliorées afin de réduire considérablement les conflits sur un verrou global, ce qui permet un meilleur parallélisme. Les Ractors partagent désormais moins de données internes, ce qui réduit les conflits de cache CPU lors de l'exécution en parallèle.
Ruby Box
Ruby Box est une nouvelle fonctionnalité (expérimentale) qui permet de séparer les définitions. Ruby Box est activée lorsque la variable d'environnement RUBY_BOX=1 est spécifiée. La classe est Ruby::Box.
Les définitions chargées dans une boîte sont isolées dans celle-ci. Ruby Box peut isoler/séparer les monkey patches, les modifications des variables globales/de classe, les définitions de classe/module et les bibliothèques natives/ruby chargées des autres boîtes.
Les cas d'utilisation prévus sont les suivants :
- Exécuter des cas de test dans une boîte pour protéger les autres tests lorsque le cas de test utilise des monkey patches pour remplacer quelque chose
- Exécuter des boîtes d'applications web en parallèle pour effectuer un déploiement bleu-vert sur un serveur d'applications dans un processus Ruby
- Exécuter des boîtes d'applications web en parallèle pour évaluer les mises à jour de dépendances pendant une certaine période en vérifiant les différences de réponse à l'aide du code Ruby.
- Utiliser comme API de base (bas niveau) pour implémenter une sorte d'API « package » (haut niveau) (elle n'est pas encore conçue).
ZJIT
ZJIT est un nouveau compilateur juste-à-temps (JIT), développé comme la prochaine génération de YJIT. Vous avez besoin de Rust 1.85.0 ou d'une version plus récente pour compiler Ruby avec le support ZJIT, et ZJIT est activé lorsque --zjit est spécifié.
L'équipe développe un nouveau compilateur pour Ruby afin d'augmenter les performances maximales (taille d'unité de compilation plus importante et SSA IR) et d'encourager davantage de contributions externes (en devenant un compilateur plus traditionnel).
ZJIT est plus rapide que l'interpréteur, mais pas encore aussi rapide que YJIT. Les développeurs sont encouragés à tester ZJIT, mais il n'est pas recommandé de ne pas le déployer en production pour le moment.
Améliorations de Ractor
Ractor, le mécanisme d'exécution parallèle de Ruby, a bénéficié de plusieurs améliorations. Une nouvelle classe, Ractor::Port, a été introduite pour résoudre les problèmes liés à l'envoi et à la réception de messages. De plus, Ractor.shareable_proc facilite le partage d'objets Proc entre les Ractors.
En termes de performances, de nombreuses structures de données internes ont été améliorées afin de réduire considérablement les conflits sur un verrou global, ce qui permet un meilleur parallélisme. Les Ractors partagent désormais moins de données internes, ce qui réduit les conflits de cache CPU lors de l'exécution en parallèle.
Ractor a été introduit pour la première fois dans Ruby 3.0 en tant que fonctionnalité expérimentale, l'objectif est de supprimer son statut « expérimental » l'année prochaine.
Modifications du langage
- *nil n'appelle plus nil.to_a, de la même manière que **nil n'appelle pas nil.to_hash.
- Les opérateurs binaires logiques (||, &&, and et or) au début d'une ligne continuent la ligne précédente, comme le point fluide. Les exemples de code suivants sont équivalents :
| Code Ruby : | Sélectionner tout |
1 2 3 4 | if condition1 && condition2 ... end |
Auparavant :
| Code Ruby : | Sélectionner tout |
1 2 3 | if condition1 && condition2 ... end |
| Code Ruby : | Sélectionner tout |
1 2 3 4 | if condition1 && condition2 ... end |
Mises à jour des classes principales
Array
- Array#rfind a été ajouté comme alternative plus efficace à array.reverse_each.find.
- Array#find a été ajouté comme remplacement plus efficace de Enumerable#find.
Binding
- Binding#local_variables n'inclut plus de paramètres numérotés. De plus, Binding#local_variable_get, Binding#local_variable_set et Binding#local_variable_defined? refusent de traiter les paramètres numérotés.
- Binding#implicit_parameters, Binding#implicit_parameter_get et Binding#implicit_parameter_defined? ont été ajoutés pour accéder aux paramètres numérotés et au paramètre « it ».
Enumerator
- Enumerator.produce accepte désormais un argument clé facultatif size pour spécifier la taille de l'énumérateur. Il peut s'agir d'un entier, de Float::INFINITY, d'un objet appelable (tel qu'un lambda) ou de nil pour indiquer une taille inconnue. Si elle n'est pas spécifiée, la taille par défaut est Float::INFINITY.
| Code Ruby : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | # Infinite enumerator enum = Enumerator.produce(1, size: Float::INFINITY, &:succ) enum.size # => Float::INFINITY # Finite enumerator with known/computable size abs_dir = File.expand_path("./baz") # => "/foo/bar/baz" traverser = Enumerator.produce(abs_dir, size: -> { abs_dir.count("/") + 1 }) { raise StopIteration if it == "/" File.dirname(it) } traverser.size # => 4 |
ErrorHighlight
Lorsqu'une erreur ArgumentError est levée, elle affiche désormais des extraits de code pour l'appel de méthode (appelant) et la définition de méthode (appelé).
| Code Ruby : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | test.rb:1:in 'Object#add': wrong number of arguments (given 1, expected 2) (ArgumentError) caller: test.rb:3 | add(1) ^^^ callee: test.rb:1 | def add(x, y) = x + y ^^^ from test.rb:3:in '<main>' |
Fiber
Introduction de la prise en charge de l'argument Fiber#raise(cause:) similaire à Kernel#raise.
Fiber::Scheduler
- Introduction de Fiber::Scheduler#fiber_interrupt pour interrompre une fibre avec une exception donnée. Le cas d'utilisation initial consiste à interrompre une fibre qui attend une opération d'E/S bloquante lorsque l'opération d'E/S est fermée.
- Introduction de Fiber::Scheduler#yield pour permettre au planificateur de fibres de continuer le traitement lorsque les exceptions de signal sont désactivées.
- Réintroduction du hook Fiber::Scheduler#io_close pour IO#close asynchrone.
- Appel de Fiber::Scheduler#io_write lors du vidage du tampon d'écriture IO.
File
- File::Stat#birthtime est désormais disponible sous Linux via l'appel système statx lorsqu'il est pris en charge par le noyau et le système de fichiers.
IO
- IO.select accepte Float::INFINITY comme argument de délai d'expiration.
- Un comportement obsolète, la création de processus par les méthodes de classe IO avec un | en tête, a été supprimé.
Kernel
- Kernel#inspect vérifie désormais l'existence d'une méthode #instance_variables_to_inspect, ce qui permet de contrôler les variables d'instance affichées dans la chaîne #inspect :
| Code Ruby : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | class DatabaseConfig def initialize(host, user, password) @host = host @user = user @password = password end private def instance_variables_to_inspect = [:@host, :@user] end conf = DatabaseConfig.new("localhost", "root", "hunter2") conf.inspect #=> #<DatabaseConfig:0x0000000104def350 @host="localhost", @user="root"> |
- Un comportement obsolète, la création de processus par Kernel#open avec un | en tête, a été supprimé.
Math
Math.log1p et Math.expm1 ont été ajoutés.
Pathname
Pathname est passé du statut de gem par défaut à celui de classe centrale de Ruby.
Proc
- Proc#parameters affiche désormais les paramètres optionnels anonymes sous la forme [:opt] au lieu de [:opt, nil], ce qui rend la sortie cohérente avec le cas où le paramètre anonyme est obligatoire.
Ractor
- La classe Ractor::Port a été ajoutée pour un nouveau mécanisme de synchronisation permettant la communication entre les Ractors.
| Code Ruby : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | port1 = Ractor::Port.new port2 = Ractor::Port.new Ractor.new port1, port2 do |port1, port2| port1 << 1 port2 << 11 port1 << 2 port2 << 12 end 2.times{ p port1.receive } #=> 1, 2 2.times{ p port2.receive } #=> 11, 12 |
- Ractor::Port fournit les méthodes suivantes :
Ractor::Port#receive.
Ractor::Port#send (ou Ractor::Port#<<)
Ractor::Port#close.
Ractor::Port#closed?.
En conséquence, Ractor.yield et Ractor#take ont été supprimés.
- Ractor#join et Ractor#value ont été ajoutées pour attendre la fin d'un Ractor. Elles sont similaires à Thread#join et Thread#value.
- Ractor#monitor et Ractor#unmonitor ont été ajoutées en tant qu'interfaces de bas niveau utilisées en interne pour implémenter Ractor#join.
- Ractor.select n'accepte désormais que les Ractors et les Ports. Si des Ractors sont fournis, elle renvoie une valeur lorsqu'un Ractor se termine.
- Ractor#default_port a été ajouté. Chaque Ractor dispose d'un port par défaut, qui est utilisé par Ractor.send et Ractor.receive.
- Ractor...
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.