Ruby 3.0.0 Preview 2 est disponible

Nous sommes heureux de vous annoncer la sortie de Ruby 3.0.0-preview2.

Cela introduit un certain nombre de nouvelles fonctionnalités et d’améliorations de performance.

Analyse statique

RBS

RBS est un langage qui décrit les types de programmes Ruby.

Les vérificateurs de type, y compris TypeProf et d’autres outils prenant en charge RBS, comprendront mieux les programmes Ruby avec des définitions RBS.

Vous pouvez écrire la définition des classes et des modules: les méthodes qui sont définies dans la classe, les variables d’instance et leurs types, et les relations d’héritage / mix-in.

Le but de RBS est de prendre en charge les modèles couramment observés dans les programmes Ruby et de vous permettre d’écrire des types avancés, notamment les unions de type, les surcharges de méthode et les génériques. Il prend également en charge le duck typing avec interface types.

Ruby 3.0 arrive avec la gemme ‘rbs’, qui inclue l’analyse et le traitement des définitions de type écrites en RBS.

Le code ci-dessous est un petit exemple de RBS une classe, un module et des définitions de constantes.

module ChatApp
  VERSION: String
  class Channel
    attr_reader name: String
    attr_reader messages: Array[Message]
    attr_reader users: Array[User | Bot]              # `|` means union types, `User` or `Bot`.
    def initialize: (String) -> void
    def post: (String, from: User | Bot) -> Message   # Method overloading is supported.
            | (File, from: User | Bot) -> Message
  end
end

Voir le README de la gemme rbs pour plus de détails.

TypeProf

TypeProf est un outil d’analyse de type inclus dans Ruby.

Actuellement, TypeProf permet une sorte d’inférence de type.

Il lit du code Ruby sans annotation de type, analyse quelles méthodes sont définies, comment elles sont utilisées et génère un prototype de la signature de type au format RBS.

Voici une simple démo de TypeProf.

Un exemple d’entrée :

# test.rb
class User
  def initialize(name:, age:)
    @name, @age = name, age
  end
  attr_reader :name, :age
end
User.new(name: "John", age: 20)

Un exemple de sortie :

$ typeprof test.rb
# Classes
class User
  attr_reader name : String
  attr_reader age : Integer
  def initialize : (name: String, age: Integer) -> [String, Integer]
end

Vous pouvez lancer TypeProf en sauvegadant le code dans un fichier “test.rb” et en appelant la commande “typeprof test.rb”.

Vous pouvez aussi essayer TypeProf en ligne. (Cela lance TypeProf coté serveur, donc désolé si cela ne fonctionne pas !)

Voir la documentation et les démos pour plus de détails.

TypeProf est expérimental et n’est pas encore mature. Seulement un sous ensemble du langage Ruby est supporté et la détection des erreurs de typage est limitée. Mais il continue de croître rapidement pour améliorer la couverture des fonctionnalités du langage, les performances d’analyse et la convivialité. Tout commentaire est le bienvenu.

Ractor (expérimental)

Ractor est un modèle d’acteur permettant une abstraction pour la concurrence. Il fournit un outil permettant l’exécution de code de façon thread-safe.

Vous pouvez créer plusieurs ractors et les lancer en parallèle. Ractor vous permet de créer des programmes thread-safe puisque les ractors ne partagent pas d’objets normaux. La communication entre ractors se fait par passage de messages.

Afin de limiter le partage d’objet, Ractor introduit plusieurs restrictions sur la syntaxe de Ruby (sans plusieurs ractors, il n’y a pas de restriction).

La spécification et l’implémentation ne sont pas matures et pourront donc changer. Cette fonctionnalité est marquée comme expérimentale et montre l’avertissement “experimental feature” au premier Ractor.new.

Le bout de code suivant calcul n.prime? (n est un entier relativement grand) en parallèle avec deux ractors. Vous pouvez vérifier que le programme est deux fois plus rapide que celui séquentiel.

require 'prime'
# n.prime? with sent integers in r1, r2 run in parallel
r1, r2 = *(1..2).map do
  Ractor.new do
    n = Ractor.recv
    n.prime?
  end
end
# send parameters
r1.send 2**61 - 1
r2.send 2**61 + 15
# wait for the results of expr1, expr2
p r1.take #=> true
p r2.take #=> true

Voir doc/ractor.md pour plus de détails.

Fiber Scheduler

Fiber#scheduler est introduit pour intercepter des opérations de blocage. Cela permet une concurrence légère sans changer le code existant. Voir “Don’t Wait For Me, Scalable Concurrency for Ruby 3” pour avoir un aperçu du fonctionnement.

Les classes et méthodes prises en charge :

  • Mutex#lock, Mutex#unlock, Mutex#sleep
  • ConditionVariable#wait
  • Queue#pop, SizedQueue#push
  • Thread#join
  • Kernel#sleep
  • Process.wait
  • IO#wait, IO#read, IO#write et les méthodes rattachées (e.g. #wait_readable, #gets, #puts etc.)
  • IO#select n’est pas prise en charge.

(Expliquer la gem Async avec des liens). Cet exemple de code permet de faire plusieurs requêtes HTTP de façon concurrente. (Expliquer ceci :)

  1. async est une gemme externe
  2. async utilise cette nouvelle fonctionnalité
require 'async'
require 'net/http'
require 'uri'
Async do
  ["ruby", "python", "c"].each do |topic|
    Async do
      Net::HTTP.get(URI "https://www.google.com/search?q=#{topic}")
    end
  end
end

Autres ajouts notables

  • Le filtrage par motif en une ligne utilise => au lieu de in.
    # version 3.0
    {a: 0, b: 1} => {a:}
    p a # => 0
    # version 2.7
    {a: 0, b: 1} in {a:}
    p a # => 0
    
  • Le pattern Find.
    case ["a", 1, "b", "c", 2, "d", "e", "f", 3]
    in [*pre, String => x, String => y, *post]
      p pre  #=> ["a", 1]
      p x    #=> "b"
      p y    #=> "c"
      p post #=> [2, "d", "e", "f", 3]
    end
    
  • La définition de méthode sans le mot clé end.
    def square(x) = x * x
    
  • Hash#except est désormais inclus.

    h = { a: 1, b: 2, c: 3 }
    p h.except(:a) #=> {:b=>2, :c=>3}
    
  • Memory view est ajoutée en tant que fonctionnalité expérimentale

    • C’est un nouvel ensemble d’API C pour échanger une zone mémoire brute, comme un tableau de nombre ou une image bitmap, entre des bibliothèques d’extension. Les bibliothèques d’extension peuvent également partager les méta données de la zone mémoire comprenant la forme, le format de l’élément, etc. En utilisant ce type de métadonnées, les librairies d’extension peuvent même partager des tableaux multidimensionnels de façon appropriée. Cette fonctionnalité a été conçue en utilisant le protocole tampon de python.

Amélioration des performances

  • Plusieurs améliorations sont implémentées dans MJIT. Voir NEWS pour les détails.
  • Coller du code dans IRB est 53 fois plus rapide qu’en Ruby 2.7.0. Par exemple, le temps nécessaire pour coller cet exemple de code passe de 11.7 secondes à 0.22 secondes.

Autres changements notables depuis la version 2.7

  • Les arguments de mot-clé sont séparés des autres arguments.
    • En principe, le code qui affiche un avertissement dans la version 2.7 de Ruby ne fonctionnera pas. Voir le document pour plus de détails.
    • La transmission d’arguments prend désormais en charge les arguments principaux.
      def method_missing(meth, ...)
        send(:"do_#{ meth }", ...)
      end
      
  • La fonctionnalité $SAFE a été completement supprimée. C’est désormais une variable globale.
  • L’ordre de la backtrace a été inversé depuis la version 2.5 de Ruby, mais cela a été remis comme avant. Cela se comporte comme la version 2.4 de Ruby. Le message d’erreur et le numéro de ligne où l’exception apparait sont affichés en premiers. Les appelants sont affichés après.
  • Plusieurs bibliothèques standard ont été mises à jour.
    • RubyGems 3.2.0.rc.1
    • Bundler 2.2.0.rc.1
    • IRB 1.2.6
    • Reline 0.1.5
  • Les librairies suivantes ne sont plus incluses. Il faut installer les gemmes correspondantes pour utiliser leurs fonctionnalitées.
    • net-telnet
    • xmlrpc
  • Les gemmes suivantes sont désormais incluses avec Ruby.
    • rexml
    • rss
  • Les fichiers stdlib suivants sont désormais des gemmes et sont disponibles sur rubygems.org.
    • abbrev
    • base64
    • English
    • erb
    • find
    • io-nonblock
    • io-wait
    • net-ftp
    • net-http
    • net-imap
    • net-protocol
    • nkf
    • open-uri
    • optparse
    • resolv
    • resolv-replace
    • rinda
    • securerandom
    • set
    • shellwords
    • tempfile
    • time
    • tmpdir
    • tsort
    • weakref

Voir NEWS ou les logs de commit pour plus de détails.

Avec ces changements, 3776 fichiers changés, 181573 insertions(+), 145096 suppressions(-) depuis Ruby 2.7.0!

S’il vous plait, essayez Ruby 3.0.0-preview2 et faites nous des retours !

Téléchargement

  • https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0-preview2.tar.gz

    SIZE: 19378626
    SHA1: 25363b20225850224e7835e99906c52f2ff57792
    SHA256: 9de8661565c2b1007d91a580e9a7e02d23f1e8fc8df371feb15a2727aa05fd9a
    SHA512: 6fa4191425ae71e41894b60bd9c31d483a562ee8216886360ce18238ab48115b95be0367708612c45f634e7584fba8940a524ba0113ce0f36ce4df78a112d0b7
    
  • https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0-preview2.tar.xz

    SIZE: 14244252
    SHA1: 54e4d3892ce480106382bd2d36dd7395e01b0f2a
    SHA256: 03078e82d4fb55c13837c69e56565fc49c451d11b1ca5e1b075d990d0957f181
    SHA512: 8b0e6e3ba7e5f95586b4438d965e7b09187ad599f4ac22dec3db7b176358514fe0c0890dde8912fef1ef92ffcde3f6f1228178eabadcf3a05601e5b6f05881ae
    
  • https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0-preview2.zip

    SIZE: 23907144
    SHA1: 064ee265c94b3df87e737622ba84437ea0d6aeaf
    SHA256: 19e295ae50934ddac2b366f0c7c8de9bd710d596b76eba02152f3641e5ce2b23
    SHA512: 598def50ef9e8ae1f44e05ff2c4e35acf252437286f08644ba5e301ebff2db399140bafa72868877100d6ffa736a4474cb7b99ecea8bdf835ed113ab250bb3d9
    

Ruby, c’est quoi ?

Ruby a été initialement développé par Matz (Yukihiro Matsumoto) en 1993 puis est devenu open source. Il fonctionne sur de nombreuses plates-formes et est utilisé partout dans le monde, en particulier pour le développement web.