edge
Plus sur rubyonrails.org: Plus de Ruby on Rails

Extensions de base d'Active Support

Active Support est le composant Ruby on Rails responsable de fournir des extensions et des utilitaires au langage Ruby.

Il offre une base plus riche au niveau du langage, ciblant à la fois le développement d'applications Rails et le développement de Ruby on Rails lui-même.

Après avoir lu ce guide, vous saurez :

Chapters

  1. Comment charger les extensions de base
  2. Extensions pour tous les objets
  3. Extensions à Module
  4. Extensions à Class
  5. Extensions à String
  6. Extensions à Symbol
  7. Extensions à Numeric
  8. Extensions à Integer
  9. Extensions à BigDecimal
  10. Extensions à Enumerable
  11. Extensions pour Array
  12. Extensions à Hash
  13. Extensions à Regexp
  14. Extensions à Range
  15. Extensions à Date
  16. Extensions pour DateTime
  17. Extensions à Time
  18. Extensions à File
  19. Extensions à NameError
  20. Extensions à LoadError
  21. Extensions à Pathname

1 Comment charger les extensions de base

1.1 Active Support autonome

Afin d'avoir la plus petite empreinte possible par défaut, Active Support charge les dépendances minimales par défaut. Il est divisé en petites parties afin que seules les extensions souhaitées puissent être chargées. Il dispose également de points d'entrée pratiques pour charger des extensions connexes en une seule fois, voire tout.

Ainsi, après un simple require comme :

require "active_support"

seules les extensions requises par le framework Active Support sont chargées.

1.1.1 Sélectionner une définition

Cet exemple montre comment charger Hash#with_indifferent_access. Cette extension permet la conversion d'un Hash en ActiveSupport::HashWithIndifferentAccess qui permet d'accéder aux clés sous forme de chaînes de caractères ou de symboles.

{ a: 1 }.with_indifferent_access["a"] # => 1

Pour chaque méthode définie en tant qu'extension de base, ce guide comporte une note indiquant où cette méthode est définie. Dans le cas de with_indifferent_access, la note indique :

NOTE : Défini dans active_support/core_ext/hash/indifferent_access.rb.

Cela signifie que vous pouvez le requérir comme ceci :

require "active_support"
require "active_support/core_ext/hash/indifferent_access"

Active Support a été soigneusement révisé de manière à ce que la sélection d'un fichier ne charge que les dépendances strictement nécessaires, le cas échéant.

1.1.2 Charger les extensions de base groupées

Le niveau suivant consiste simplement à charger toutes les extensions de Hash. En règle générale, les extensions de SomeClass sont disponibles en une seule fois en chargeant active_support/core_ext/some_class.

Ainsi, pour charger toutes les extensions de Hash (y compris with_indifferent_access) :

require "active_support"
require "active_support/core_ext/hash"

1.1.3 Charger toutes les extensions de base

Vous pouvez préférer simplement charger toutes les extensions de base, il y a un fichier pour cela :

require "active_support"
require "active_support/core_ext"

1.1.4 Charger tout Active Support

Et enfin, si vous souhaitez avoir tout Active Support disponible, il suffit de lancer :

require "active_support/all"

Cela ne met même pas tout Active Support en mémoire à l'avance, en effet, certaines choses sont configurées via autoload, donc elles ne sont chargées que si elles sont utilisées.

1.2 Active Support dans une application Ruby on Rails

Une application Ruby on Rails charge tout Active Support à moins que config.active_support.bare ne soit vrai. Dans ce cas, l'application ne chargera que ce que le framework lui-même sélectionne pour ses propres besoins, et peut toujours se sélectionner elle-même à n'importe quel niveau de granularité, comme expliqué dans la section précédente.

2 Extensions pour tous les objets

2.1 blank? et present?

Les valeurs suivantes sont considérées comme vides dans une application Rails :

  • nil et false,

  • les chaînes de caractères composées uniquement d'espaces (voir la note ci-dessous),

  • les tableaux et les hachages vides, et

  • tout autre objet qui répond à empty? et qui est vide.

INFO : Le prédicat pour les chaînes de caractères utilise la classe de caractères sensible à l'Unicode [:space:], donc par exemple U+2029 (séparateur de paragraphe) est considéré comme un espace. AVERTISSEMENT: Notez que les nombres ne sont pas mentionnés. En particulier, 0 et 0.0 ne sont pas vides.

Par exemple, cette méthode de ActionController::HttpAuthentication::Token::ControllerMethods utilise blank? pour vérifier si un jeton est présent:

def authenticate(controller, &login_procedure)
  token, options = token_and_options(controller.request)
  unless token.blank?
    login_procedure.call(token, options)
  end
end

La méthode present? est équivalente à !blank?. Cet exemple est tiré de ActionDispatch::Http::Cache::Response:

def set_conditional_cache_control!
  return if self["Cache-Control"].present?
  # ...
end

Défini dans active_support/core_ext/object/blank.rb.

2.2 presence

La méthode presence renvoie son receveur s'il est present?, et nil sinon. Elle est utile pour des idiomes comme celui-ci:

host = config[:host].presence || 'localhost'

Défini dans active_support/core_ext/object/blank.rb.

2.3 duplicable?

À partir de Ruby 2.5, la plupart des objets peuvent être dupliqués via dup ou clone:

"foo".dup           # => "foo"
"".dup              # => ""
Rational(1).dup     # => (1/1)
Complex(0).dup      # => (0+0i)
1.method(:+).dup    # => TypeError (allocator undefined for Method)

Active Support fournit duplicable? pour interroger un objet à ce sujet:

"foo".duplicable?           # => true
"".duplicable?              # => true
Rational(1).duplicable?     # => true
Complex(1).duplicable?      # => true
1.method(:+).duplicable?    # => false

AVERTISSEMENT: Toute classe peut interdire la duplication en supprimant dup et clone ou en levant des exceptions à partir d'eux. Ainsi, seul rescue peut dire si un objet arbitraire donné est duplicable. duplicable? dépend de la liste codée en dur ci-dessus, mais il est beaucoup plus rapide que rescue. Utilisez-le uniquement si vous savez que la liste codée en dur est suffisante dans votre cas d'utilisation.

Défini dans active_support/core_ext/object/duplicable.rb.

2.4 deep_dup

La méthode deep_dup renvoie une copie en profondeur d'un objet donné. Normalement, lorsque vous dupliquez un objet qui contient d'autres objets, Ruby ne les duplique pas, il crée donc une copie superficielle de l'objet. Si vous avez un tableau avec une chaîne, par exemple, cela ressemblera à ceci:

array     = ['string']
duplicate = array.dup

duplicate.push 'another-string'

# l'objet a été dupliqué, donc l'élément a été ajouté uniquement à la copie
array     # => ['string']
duplicate # => ['string', 'another-string']

duplicate.first.gsub!('string', 'foo')

# le premier élément n'a pas été dupliqué, il sera modifié dans les deux tableaux
array     # => ['foo']
duplicate # => ['foo', 'another-string']

Comme vous pouvez le voir, après avoir dupliqué l'instance Array, nous avons obtenu un autre objet, donc nous pouvons le modifier et l'objet original restera inchangé. Cependant, cela n'est pas vrai pour les éléments du tableau. Comme dup ne fait pas de copie en profondeur, la chaîne à l'intérieur du tableau est toujours le même objet.

Si vous avez besoin d'une copie en profondeur d'un objet, vous devez utiliser deep_dup. Voici un exemple:

array     = ['string']
duplicate = array.deep_dup

duplicate.first.gsub!('string', 'foo')

array     # => ['string']
duplicate # => ['foo']

Si l'objet n'est pas duplicable, deep_dup le renverra simplement:

number = 1
duplicate = number.deep_dup
number.object_id == duplicate.object_id   # => true

Défini dans active_support/core_ext/object/deep_dup.rb.

2.5 try

Lorsque vous souhaitez appeler une méthode sur un objet uniquement s'il n'est pas nil, la manière la plus simple de le faire est d'utiliser des instructions conditionnelles, ce qui ajoute un encombrement inutile. L'alternative est d'utiliser try. try est comme Object#public_send, sauf qu'il renvoie nil s'il est envoyé à nil. Voici un exemple :

# sans try
unless @number.nil?
  @number.next
end

# avec try
@number.try(:next)

Un autre exemple est ce code de ActiveRecord::ConnectionAdapters::AbstractAdapter@logger pourrait être nil. Vous pouvez voir que le code utilise try et évite une vérification inutile.

def log_info(sql, name, ms)
  if @logger.try(:debug?)
    name = '%s (%.1fms)' % [name || 'SQL', ms]
    @logger.debug(format_log_entry(name, sql.squeeze(' ')))
  end
end

try peut également être appelé sans arguments mais avec un bloc, qui ne sera exécuté que si l'objet n'est pas nul :

@person.try { |p| "#{p.first_name} #{p.last_name}" }

Notez que try va ignorer les erreurs de méthode inexistante, renvoyant à la place nil. Si vous voulez vous protéger contre les fautes de frappe, utilisez try! à la place :

@number.try(:nest)  # => nil
@number.try!(:nest) # NoMethodError: undefined method `nest' for 1:Integer

NOTE : Défini dans active_support/core_ext/object/try.rb.

2.6 class_eval(*args, &block)

Vous pouvez évaluer du code dans le contexte de la classe singleton de n'importe quel objet en utilisant class_eval :

class Proc
  def bind(object)
    block, time = self, Time.current
    object.class_eval do
      method_name = "__bind_#{time.to_i}_#{time.usec}"
      define_method(method_name, &block)
      method = instance_method(method_name)
      remove_method(method_name)
      method
    end.bind(object)
  end
end

NOTE : Défini dans active_support/core_ext/kernel/singleton_class.rb.

2.7 acts_like?(duck)

La méthode acts_like? permet de vérifier si une classe se comporte comme une autre classe en se basant sur une simple convention : une classe qui fournit la même interface que String définit

def acts_like_string?
end

qui est simplement un marqueur, son corps ou sa valeur de retour sont sans importance. Ensuite, le code client peut interroger la conformité au type de canard de cette manière :

some_klass.acts_like?(:string)

Rails possède des classes qui se comportent comme Date ou Time et qui suivent ce contrat.

NOTE : Défini dans active_support/core_ext/object/acts_like.rb.

2.8 to_param

Tous les objets dans Rails répondent à la méthode to_param, qui est censée renvoyer quelque chose qui les représente comme des valeurs dans une chaîne de requête ou comme des fragments d'URL.

Par défaut, to_param appelle simplement to_s :

7.to_param # => "7"

La valeur de retour de to_param ne doit pas être échappée :

"Tom & Jerry".to_param # => "Tom & Jerry"

Plusieurs classes dans Rails redéfinissent cette méthode.

Par exemple, nil, true et false renvoient eux-mêmes. Array#to_param appelle to_param sur les éléments et joint le résultat avec "/":

[0, true, String].to_param # => "0/true/String"

Il est important de noter que le système de routage de Rails appelle to_param sur les modèles pour obtenir une valeur pour le paramètre :id. ActiveRecord::Base#to_param renvoie l'id d'un modèle, mais vous pouvez redéfinir cette méthode dans vos modèles. Par exemple, avec :

class User
  def to_param
    "#{id}-#{name.parameterize}"
  end
end

nous obtenons :

user_path(@user) # => "/users/357-john-smith"

ATTENTION. Les contrôleurs doivent être conscients de toute redéfinition de to_param car lorsque cette requête arrive, "357-john-smith" est la valeur de params[:id].

NOTE : Défini dans active_support/core_ext/object/to_param.rb.

2.9 to_query

La méthode to_query construit une chaîne de requête qui associe une clé donnée à la valeur renvoyée par to_param. Par exemple, avec la définition to_param suivante :

class User
  def to_param
    "#{id}-#{name.parameterize}"
  end
end

nous obtenons :

current_user.to_query('user') # => "user=357-john-smith"

Cette méthode échappe tout ce qui est nécessaire, à la fois pour la clé et pour la valeur :

account.to_query('company[name]')
# => "company%5Bname%5D=Johnson+%26+Johnson"

ainsi sa sortie est prête à être utilisée dans une chaîne de requête. Les tableaux renvoient le résultat de l'application de to_query à chaque élément avec key[] comme clé, et joignent le résultat avec "&":

[3.4, -45.6].to_query('sample')
# => "sample%5B%5D=3.4&sample%5B%5D=-45.6"

Les hachages répondent également à to_query mais avec une signature différente. Si aucun argument n'est passé, un appel génère une série triée d'assignations clé/valeur en appelant to_query(key) sur ses valeurs. Ensuite, il joint le résultat avec "&":

{ c: 3, b: 2, a: 1 }.to_query # => "a=1&b=2&c=3"

La méthode Hash#to_query accepte un espace de noms facultatif pour les clés:

{ id: 89, name: "John Smith" }.to_query('user')
# => "user%5Bid%5D=89&user%5Bname%5D=John+Smith"

NOTE : Défini dans active_support/core_ext/object/to_query.rb.

2.10 with_options

La méthode with_options permet de regrouper des options communes dans une série d'appels de méthode.

Étant donné un hachage d'options par défaut, with_options renvoie un objet proxy à un bloc. Dans le bloc, les méthodes appelées sur le proxy sont transmises au receveur avec leurs options fusionnées. Par exemple, vous pouvez vous débarrasser de la duplication dans :

class Account < ApplicationRecord
  has_many :customers, dependent: :destroy
  has_many :products,  dependent: :destroy
  has_many :invoices,  dependent: :destroy
  has_many :expenses,  dependent: :destroy
end

de cette manière :

class Account < ApplicationRecord
  with_options dependent: :destroy do |assoc|
    assoc.has_many :customers
    assoc.has_many :products
    assoc.has_many :invoices
    assoc.has_many :expenses
  end
end

Cette expression peut également transmettre un regroupement au lecteur. Par exemple, supposons que vous souhaitiez envoyer une newsletter dont la langue dépend de l'utilisateur. Vous pouvez regrouper les éléments dépendant de la langue quelque part dans le mailer de cette manière :

I18n.with_options locale: user.locale, scope: "newsletter" do |i18n|
  subject i18n.t :subject
  body    i18n.t :body, user_name: user.name
end

CONSEIL : Comme with_options transmet les appels à son receveur, ils peuvent être imbriqués. Chaque niveau d'imbrication fusionnera les valeurs par défaut héritées en plus des siennes propres.

NOTE : Défini dans active_support/core_ext/object/with_options.rb.

2.11 Support JSON

Active Support fournit une meilleure implémentation de to_json que la gemme json ne le fait normalement pour les objets Ruby. Cela est dû au fait que certaines classes, comme Hash et Process::Status, nécessitent un traitement spécial pour fournir une représentation JSON appropriée.

NOTE : Défini dans active_support/core_ext/object/json.rb.

2.12 Variables d'instance

Active Support fournit plusieurs méthodes pour faciliter l'accès aux variables d'instance.

2.12.1 instance_values

La méthode instance_values renvoie un hachage qui fait correspondre les noms de variables d'instance sans "@" à leurs valeurs correspondantes. Les clés sont des chaînes de caractères :

class C
  def initialize(x, y)
    @x, @y = x, y
  end
end

C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}

NOTE : Défini dans active_support/core_ext/object/instance_variables.rb.

2.12.2 instance_variable_names

La méthode instance_variable_names renvoie un tableau. Chaque nom inclut le signe "@".

class C
  def initialize(x, y)
    @x, @y = x, y
  end
end

C.new(0, 1).instance_variable_names # => ["@x", "@y"]

NOTE : Défini dans active_support/core_ext/object/instance_variables.rb.

2.13 Suppression des avertissements et des exceptions

Les méthodes silence_warnings et enable_warnings modifient la valeur de $VERBOSE en conséquence pendant la durée de leur bloc, puis la réinitialisent :

silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }

Il est également possible de supprimer les exceptions avec suppress. Cette méthode reçoit un nombre arbitraire de classes d'exceptions. Si une exception est levée pendant l'exécution du bloc et qu'elle est kind_of? l'un des arguments, suppress la capture et la renvoie silencieusement. Sinon, l'exception n'est pas capturée : ```ruby

Si l'utilisateur est verrouillé, l'incrément est perdu, pas de problème majeur.

suppress(ActiveRecord::StaleObjectError) do current_user.increment! :visits end ```

NOTE : Défini dans active_support/core_ext/kernel/reporting.rb.

2.14 in?

Le prédicat in? teste si un objet est inclus dans un autre objet. Une exception ArgumentError sera levée si l'argument passé ne répond pas à include?.

Exemples de in? :

1.in?([1, 2])        # => true
"lo".in?("hello")   # => true
25.in?(30..50)      # => false
1.in?(1)            # => ArgumentError

NOTE : Défini dans active_support/core_ext/object/inclusion.rb.

3 Extensions à Module

3.1 Attributs

3.1.1 alias_attribute

Les attributs du modèle ont un lecteur, un écrivain et un prédicat. Vous pouvez créer un alias pour un attribut du modèle en utilisant alias_attribute, qui définit automatiquement les trois méthodes correspondantes pour vous. Comme pour les autres méthodes d'aliasing, le nouveau nom est le premier argument et l'ancien nom est le deuxième (un moyen mnémotechnique est de les mettre dans le même ordre que si vous faisiez une affectation) :

class User < ApplicationRecord
  # Vous pouvez vous référer à la colonne email en tant que "login".
  # Cela peut être utile pour le code d'authentification.
  alias_attribute :login, :email
end

NOTE : Défini dans active_support/core_ext/module/aliasing.rb.

3.1.2 Attributs internes

Lorsque vous définissez un attribut dans une classe destinée à être sous-classée, les collisions de noms sont un risque. Cela est particulièrement important pour les bibliothèques.

Active Support définit les macros attr_internal_reader, attr_internal_writer et attr_internal_accessor. Elles fonctionnent comme leurs homologues Ruby attr_*, à la différence qu'elles nomment la variable d'instance sous-jacente de manière à réduire les risques de collision.

La macro attr_internal est un synonyme de attr_internal_accessor :

# bibliothèque
class ThirdPartyLibrary::Crawler
  attr_internal :log_level
end

# code client
class MyCrawler < ThirdPartyLibrary::Crawler
  attr_accessor :log_level
end

Dans l'exemple précédent, il se peut que :log_level n'appartienne pas à l'interface publique de la bibliothèque et qu'il ne soit utilisé que pour le développement. Le code client, ignorant le risque de conflit, sous-classe et définit son propre :log_level. Grâce à attr_internal, il n'y a pas de collision.

Par défaut, la variable d'instance interne est nommée avec un tiret bas en préfixe, @_log_level dans l'exemple ci-dessus. Cela peut être configuré via Module.attr_internal_naming_format, vous pouvez passer n'importe quelle chaîne de format sprintf avec un @ en préfixe et un %s quelque part, où le nom sera placé. La valeur par défaut est "@_%s".

Rails utilise des attributs internes à quelques endroits, par exemple pour les vues :

module ActionView
  class Base
    attr_internal :captures
    attr_internal :request, :layout
    attr_internal :controller, :template
  end
end

NOTE : Défini dans active_support/core_ext/module/attr_internal.rb.

3.1.3 Attributs de module

Les macros mattr_reader, mattr_writer et mattr_accessor sont identiques aux macros cattr_* définies pour les classes. En fait, les macros cattr_* ne sont que des alias des macros mattr_*. Voir Attributs de classe.

Par exemple, l'API pour le journal de Active Storage est générée avec mattr_accessor :

module ActiveStorage
  mattr_accessor :logger
end

NOTE : Défini dans active_support/core_ext/module/attribute_accessors.rb.

3.2 Parents

3.2.1 module_parent

La méthode module_parent sur un module nommé imbriqué renvoie le module qui contient sa constante correspondante :

module X
  module Y
    module Z
    end
  end
end
M = X::Y::Z

X::Y::Z.module_parent # => X::Y
M.module_parent       # => X::Y

Si le module est anonyme ou appartient au niveau supérieur, module_parent renvoie Object. AVERTISSEMENT: Notez que dans ce cas, module_parent_name renvoie nil.

Défini dans active_support/core_ext/module/introspection.rb.

3.2.2 module_parent_name

La méthode module_parent_name sur un module nommé imbriqué renvoie le nom entièrement qualifié du module qui contient sa constante correspondante:

module X
  module Y
    module Z
    end
  end
end
M = X::Y::Z

X::Y::Z.module_parent_name # => "X::Y"
M.module_parent_name       # => "X::Y"

Pour les modules de niveau supérieur ou anonymes, module_parent_name renvoie nil.

AVERTISSEMENT: Notez que dans ce cas, module_parent renvoie Object.

Défini dans active_support/core_ext/module/introspection.rb.

3.2.3 module_parents

La méthode module_parents appelle module_parent sur le receveur et remonte jusqu'à ce que Object soit atteint. La chaîne est renvoyée dans un tableau, du bas vers le haut:

module X
  module Y
    module Z
    end
  end
end
M = X::Y::Z

X::Y::Z.module_parents # => [X::Y, X, Object]
M.module_parents       # => [X::Y, X, Object]

Défini dans active_support/core_ext/module/introspection.rb.

3.3 Anonyme

Un module peut avoir ou non un nom:

module M
end
M.name # => "M"

N = Module.new
N.name # => "N"

Module.new.name # => nil

Vous pouvez vérifier si un module a un nom avec le prédicat anonymous?:

module M
end
M.anonymous? # => false

Module.new.anonymous? # => true

Notez que le fait d'être inaccessible n'implique pas d'être anonyme:

module M
end

m = Object.send(:remove_const, :M)

m.anonymous? # => false

bien qu'un module anonyme soit inaccessible par définition.

Défini dans active_support/core_ext/module/anonymous.rb.

3.4 Délégation de méthode

3.4.1 delegate

La macro delegate offre un moyen facile de déléguer des méthodes.

Imaginons que les utilisateurs dans une application aient des informations de connexion dans le modèle User mais un nom et d'autres données dans un modèle séparé Profile:

class User < ApplicationRecord
  has_one :profile
end

Avec cette configuration, vous obtenez le nom d'un utilisateur via son profil, user.profile.name, mais il pourrait être pratique de pouvoir toujours accéder à cet attribut directement:

class User < ApplicationRecord
  has_one :profile

  def name
    profile.name
  end
end

C'est ce que fait delegate pour vous:

class User < ApplicationRecord
  has_one :profile

  delegate :name, to: :profile
end

C'est plus court et l'intention est plus évidente.

La méthode doit être publique dans la cible.

La macro delegate accepte plusieurs méthodes:

delegate :name, :age, :address, :twitter, to: :profile

Lorsqu'elle est interpolée dans une chaîne, l'option :to doit devenir une expression qui s'évalue à l'objet auquel la méthode est déléguée. Typiquement une chaîne de caractères ou un symbole. Une telle expression est évaluée dans le contexte du receveur:

# délègue à la constante Rails
delegate :logger, to: :Rails

# délègue à la classe du receveur
delegate :table_name, to: :class

AVERTISSEMENT: Si l'option :prefix est true, cela est moins générique, voir ci-dessous.

Par défaut, si la délégation génère une NoMethodError et que la cible est nil, l'exception est propagée. Vous pouvez demander que nil soit renvoyé à la place avec l'option :allow_nil:

delegate :name, to: :profile, allow_nil: true

Avec :allow_nil, l'appel user.name renvoie nil si l'utilisateur n'a pas de profil.

L'option :prefix ajoute un préfixe au nom de la méthode générée. Cela peut être pratique, par exemple, pour obtenir un meilleur nom: ruby delegate :street, to: :address, prefix: true

L'exemple précédent génère address_street plutôt que street.

AVERTISSEMENT: Dans ce cas, le nom de la méthode générée est composé des noms de l'objet cible et de la méthode cible, l'option :to doit donc être un nom de méthode.

Un préfixe personnalisé peut également être configuré:

delegate :size, to: :attachment, prefix: :avatar

Dans l'exemple précédent, la macro génère avatar_size plutôt que size.

L'option :private modifie la portée des méthodes:

delegate :date_of_birth, to: :profile, private: true

Les méthodes déléguées sont publiques par défaut. Passez private: true pour changer cela.

Défini dans active_support/core_ext/module/delegation.rb

3.4.2 delegate_missing_to

Imaginez que vous souhaitez déléguer tout ce qui manque à l'objet User à l'objet Profile. La macro delegate_missing_to vous permet de mettre en œuvre cela facilement:

class User < ApplicationRecord
  has_one :profile

  delegate_missing_to :profile
end

La cible peut être n'importe quoi de callable dans l'objet, par exemple des variables d'instance, des méthodes, des constantes, etc. Seules les méthodes publiques de la cible sont déléguées.

Défini dans active_support/core_ext/module/delegation.rb.

3.5 Redéfinition des méthodes

Il existe des cas où vous devez définir une méthode avec define_method, mais vous ne savez pas si une méthode portant ce nom existe déjà. Si c'est le cas, un avertissement est émis s'ils sont activés. Ce n'est pas grave, mais ce n'est pas propre non plus.

La méthode redefine_method évite un tel avertissement potentiel, en supprimant la méthode existante si nécessaire.

Vous pouvez également utiliser silence_redefinition_of_method si vous avez besoin de définir la méthode de remplacement vous-même (parce que vous utilisez delegate, par exemple).

Défini dans active_support/core_ext/module/redefine_method.rb.

4 Extensions à Class

4.1 Attributs de classe

4.1.1 class_attribute

La méthode class_attribute déclare un ou plusieurs attributs de classe héritables qui peuvent être remplacés à n'importe quel niveau de la hiérarchie.

class A
  class_attribute :x
end

class B < A; end

class C < B; end

A.x = :a
B.x # => :a
C.x # => :a

B.x = :b
A.x # => :a
C.x # => :b

C.x = :c
A.x # => :a
B.x # => :b

Par exemple, ActionMailer::Base définit:

class_attribute :default_params
self.default_params = {
  mime_version: "1.0",
  charset: "UTF-8",
  content_type: "text/plain",
  parts_order: [ "text/plain", "text/enriched", "text/html" ]
}.freeze

Ils peuvent également être accédés et remplacés au niveau de l'instance.

A.x = 1

a1 = A.new
a2 = A.new
a2.x = 2

a1.x # => 1, provient de A
a2.x # => 2, remplacé dans a2

La génération de la méthode d'instance writer peut être empêchée en définissant l'option :instance_writer sur false.

module ActiveRecord
  class Base
    class_attribute :table_name_prefix, instance_writer: false, default: "my"
  end
end

Un modèle peut trouver cette option utile comme moyen d'empêcher l'attribution en masse de définir l'attribut.

La génération de la méthode d'instance reader peut être empêchée en définissant l'option :instance_reader sur false.

class A
  class_attribute :x, instance_reader: false
end

A.new.x = 1
A.new.x # NoMethodError

Pour plus de commodité, class_attribute définit également un prédicat d'instance qui est la double négation de ce que renvoie le lecteur d'instance. Dans les exemples ci-dessus, il serait appelé x?. Lorsque :instance_reader est false, le prédicat d'instance renvoie une NoMethodError tout comme la méthode de lecture.

Si vous ne souhaitez pas utiliser le prédicat d'instance, passez instance_predicate: false et il ne sera pas défini.

NOTE : Défini dans active_support/core_ext/class/attribute.rb.

4.1.2 cattr_reader, cattr_writer et cattr_accessor

Les macros cattr_reader, cattr_writer et cattr_accessor sont analogues à leurs homologues attr_* mais pour les classes. Elles initialisent une variable de classe à nil sauf si elle existe déjà, et génèrent les méthodes de classe correspondantes pour y accéder :

class MysqlAdapter < AbstractAdapter
  # Génère les méthodes de classe pour accéder à @@emulate_booleans.
  cattr_accessor :emulate_booleans
end

De plus, vous pouvez passer un bloc à cattr_* pour configurer l'attribut avec une valeur par défaut :

class MysqlAdapter < AbstractAdapter
  # Génère les méthodes de classe pour accéder à @@emulate_booleans avec une valeur par défaut de true.
  cattr_accessor :emulate_booleans, default: true
end

Des méthodes d'instance sont également créées pour plus de commodité, ce sont simplement des proxies vers l'attribut de classe. Ainsi, les instances peuvent modifier l'attribut de classe, mais ne peuvent pas le remplacer comme c'est le cas avec class_attribute (voir ci-dessus). Par exemple, étant donné

module ActionView
  class Base
    cattr_accessor :field_error_proc, default: Proc.new { ... }
  end
end

nous pouvons accéder à field_error_proc dans les vues.

La génération de la méthode de lecture de l'instance peut être empêchée en définissant :instance_reader sur false et la génération de la méthode d'écriture de l'instance peut être empêchée en définissant :instance_writer sur false. La génération des deux méthodes peut être empêchée en définissant :instance_accessor sur false. Dans tous les cas, la valeur doit être exactement false et non une fausse valeur quelconque.

module A
  class B
    # Aucune méthode de lecture de l'instance first_name n'est générée.
    cattr_accessor :first_name, instance_reader: false
    # Aucune méthode d'écriture de l'instance last_name= n'est générée.
    cattr_accessor :last_name, instance_writer: false
    # Aucune méthode de lecture de l'instance surname ou de l'écriture surname= n'est générée.
    cattr_accessor :surname, instance_accessor: false
  end
end

Un modèle peut trouver utile de définir :instance_accessor sur false comme moyen d'empêcher l'assignation en masse de définir l'attribut.

NOTE : Défini dans active_support/core_ext/module/attribute_accessors.rb.

4.2 Sous-classes et descendants

4.2.1 subclasses

La méthode subclasses renvoie les sous-classes du receveur :

class C; end
C.subclasses # => []

class B < C; end
C.subclasses # => [B]

class A < B; end
C.subclasses # => [B]

class D < C; end
C.subclasses # => [B, D]

L'ordre dans lequel ces classes sont renvoyées n'est pas spécifié.

NOTE : Défini dans active_support/core_ext/class/subclasses.rb.

4.2.2 descendants

La méthode descendants renvoie toutes les classes qui sont < que son receveur :

class C; end
C.descendants # => []

class B < C; end
C.descendants # => [B]

class A < B; end
C.descendants # => [B, A]

class D < C; end
C.descendants # => [B, A, D]

L'ordre dans lequel ces classes sont renvoyées n'est pas spécifié.

NOTE : Défini dans active_support/core_ext/class/subclasses.rb.

5 Extensions à String

5.1 Sécurité de la sortie

5.1.1 Motivation

Insérer des données dans des modèles HTML nécessite une attention particulière. Par exemple, vous ne pouvez pas simplement interpoler @review.title tel quel dans une page HTML. Pour une chose, si le titre de la revue est "Flanagan & Matz rules!", la sortie ne sera pas bien formée car un esperluette doit être échappée en "&amp;". De plus, selon l'application, cela peut constituer une grande faille de sécurité car les utilisateurs peuvent injecter du code HTML malveillant en définissant un titre de revue spécialement conçu. Consultez la section sur les attaques de type cross-site scripting dans le guide de sécurité pour plus d'informations sur les risques.

5.1.2 Chaînes de caractères sécurisées

Active Support a le concept de chaînes de caractères (html) sécurisées. Une chaîne de caractères sécurisée est marquée comme pouvant être insérée dans du HTML telle quelle. Elle est considérée comme fiable, que ce soit échappée ou non.

Par défaut, les chaînes de caractères sont considérées comme non sécurisées :

"".html_safe? # => false

Vous pouvez obtenir une chaîne de caractères sécurisée à partir d'une chaîne donnée avec la méthode html_safe :

s = "".html_safe
s.html_safe? # => true

Il est important de comprendre que html_safe ne réalise aucune échappement, c'est simplement une assertion :

s = "<script>...</script>".html_safe
s.html_safe? # => true
s            # => "<script>...</script>"

Il est de votre responsabilité de vous assurer que l'appel à html_safe sur une chaîne particulière est correct.

Si vous ajoutez une chaîne à une chaîne sécurisée, que ce soit en place avec concat/<<, ou avec +, le résultat est une chaîne sécurisée. Les arguments non sécurisés sont échappés :

"".html_safe + "<" # => "&lt;"

Les arguments sécurisés sont directement ajoutés :

"".html_safe + "<".html_safe # => "<"

Ces méthodes ne doivent pas être utilisées dans les vues ordinaires. Les valeurs non sécurisées sont automatiquement échappées :

<%= @review.title %> <%# correct, échappé si nécessaire %>

Pour insérer quelque chose tel quel, utilisez l'aide raw plutôt que d'appeler html_safe :

<%= raw @cms.current_template %> <%# insère @cms.current_template tel quel %>

ou, de manière équivalente, utilisez <%== :

<%== @cms.current_template %> <%# insère @cms.current_template tel quel %>

L'aide raw appelle html_safe pour vous :

def raw(stringish)
  stringish.to_s.html_safe
end

NOTE : Défini dans active_support/core_ext/string/output_safety.rb.

5.1.3 Transformation

En règle générale, à l'exception peut-être de la concaténation comme expliqué ci-dessus, toute méthode qui peut modifier une chaîne de caractères vous donne une chaîne non sécurisée. Il s'agit de downcase, gsub, strip, chomp, underscore, etc.

Dans le cas des transformations en place comme gsub!, le récepteur lui-même devient non sécurisé.

INFO : Le bit de sécurité est toujours perdu, que la transformation ait effectivement changé quelque chose ou non.

5.1.4 Conversion et coercition

Appeler to_s sur une chaîne de caractères sécurisée renvoie une chaîne de caractères sécurisée, mais la coercition avec to_str renvoie une chaîne de caractères non sécurisée.

5.1.5 Copie

Appeler dup ou clone sur des chaînes de caractères sécurisées donne des chaînes de caractères sécurisées.

5.2 remove

La méthode remove supprime toutes les occurrences du motif :

"Hello World".remove(/Hello /) # => "World"

Il existe également la version destructive String#remove!.

NOTE : Défini dans active_support/core_ext/string/filters.rb.

5.3 squish

La méthode squish supprime les espaces vides en début et en fin de chaîne, et remplace les séries d'espaces vides par un seul espace :

" \n  foo\n\r \t bar \n".squish # => "foo bar"

Il existe également la version destructive String#squish!.

Notez qu'elle gère à la fois les espaces vides ASCII et Unicode.

NOTE : Défini dans active_support/core_ext/string/filters.rb.

5.4 truncate

La méthode truncate renvoie une copie de la chaîne de caractères tronquée après une longueur donnée :

"Oh dear! Oh dear! I shall be late!".truncate(20)
# => "Oh dear! Oh dear!..."

L'ellipse peut être personnalisée avec l'option :omission :

"Oh dear! Oh dear! I shall be late!".truncate(20, omission: '&hellip;')
# => "Oh dear! Oh &hellip;"

Notez en particulier que la troncature prend en compte la longueur de la chaîne d'omission.

Passez un :separator pour tronquer la chaîne à une rupture naturelle : ```ruby "Oh dear! Oh dear! I shall be late!".truncate(18)

=> "Oh dear! Oh dea..."

"Oh dear! Oh dear! I shall be late!".truncate(18, separator: ' ')

=> "Oh dear! Oh..."


L'option `:separator` peut être une expression régulière :

```ruby
"Oh dear! Oh dear! I shall be late!".truncate(18, separator: /\s/)
# => "Oh dear! Oh..."

Dans les exemples ci-dessus, "dear" est coupé en premier, mais :separator l'empêche ensuite.

NOTE : Défini dans active_support/core_ext/string/filters.rb.

5.5 truncate_bytes

La méthode truncate_bytes renvoie une copie de son objet tronqué à un maximum de bytesize octets :

"👍👍👍👍".truncate_bytes(15)
# => "👍👍👍…"

L'omission peut être personnalisée avec l'option :omission :

"👍👍👍👍".truncate_bytes(15, omission: "🖖")
# => "👍👍🖖"

NOTE : Défini dans active_support/core_ext/string/filters.rb.

5.6 truncate_words

La méthode truncate_words renvoie une copie de son objet tronqué après un certain nombre de mots :

"Oh dear! Oh dear! I shall be late!".truncate_words(4)
# => "Oh dear! Oh dear!..."

L'omission peut être personnalisée avec l'option :omission :

"Oh dear! Oh dear! I shall be late!".truncate_words(4, omission: '&hellip;')
# => "Oh dear! Oh dear!&hellip;"

Passez un :separator pour tronquer la chaîne à une rupture naturelle :

"Oh dear! Oh dear! I shall be late!".truncate_words(3, separator: '!')
# => "Oh dear! Oh dear! I shall be late..."

L'option :separator peut être une expression régulière :

"Oh dear! Oh dear! I shall be late!".truncate_words(4, separator: /\s/)
# => "Oh dear! Oh dear!..."

NOTE : Défini dans active_support/core_ext/string/filters.rb.

5.7 inquiry

La méthode inquiry convertit une chaîne de caractères en un objet StringInquirer, rendant les comparaisons d'égalité plus jolies.

"production".inquiry.production? # => true
"active".inquiry.inactive?       # => false

NOTE : Défini dans active_support/core_ext/string/inquiry.rb.

5.8 starts_with? et ends_with?

Active Support définit des alias à la troisième personne de String#start_with? et String#end_with? :

"foo".starts_with?("f") # => true
"foo".ends_with?("o")   # => true

NOTE : Défini dans active_support/core_ext/string/starts_ends_with.rb.

5.9 strip_heredoc

La méthode strip_heredoc supprime l'indentation dans les heredocs.

Par exemple, dans

if options[:usage]
  puts <<-USAGE.strip_heredoc
    This command does such and such.

    Supported options are:
      -h         This message
      ...
  USAGE
end

l'utilisateur verra le message d'utilisation aligné contre la marge gauche.

Techniquement, elle recherche la ligne avec le moins d'indentation dans toute la chaîne, et supprime cette quantité d'espaces en début de ligne.

NOTE : Défini dans active_support/core_ext/string/strip.rb.

5.10 indent

La méthode indent indente les lignes de l'objet :

<<EOS.indent(2)
def some_method
  some_code
end
EOS
# =>
  def some_method
    some_code
  end

Le deuxième argument, indent_string, spécifie quelle chaîne d'indentation utiliser. Par défaut, c'est nil, ce qui indique à la méthode de deviner en regardant la première ligne indentée, et de revenir à un espace s'il n'y en a pas.

"  foo".indent(2)        # => "    foo"
"foo\n\t\tbar".indent(2) # => "\t\tfoo\n\t\t\t\tbar"
"foo".indent(2, "\t")    # => "\t\tfoo"

Bien que indent_string soit généralement un espace ou une tabulation, il peut être n'importe quelle chaîne de caractères.

Le troisième argument, indent_empty_lines, est un indicateur qui indique si les lignes vides doivent être indentées. Par défaut, c'est false.

"foo\n\nbar".indent(2)            # => "  foo\n\n  bar"
"foo\n\nbar".indent(2, nil, true) # => "  foo\n  \n  bar"

La méthode indent! effectue l'indentation sur place.

NOTE : Défini dans active_support/core_ext/string/indent.rb.

5.11 Accès

5.11.1 at(position)

La méthode at renvoie le caractère de la chaîne de caractères à la position position :

"hello".at(0)  # => "h"
"hello".at(4)  # => "o"
"hello".at(-1) # => "o"
"hello".at(10) # => nil

NOTE : Défini dans active_support/core_ext/string/access.rb.

5.11.2 from(position)

La méthode from renvoie la sous-chaîne de caractères de la chaîne de caractères à partir de la position position :

"hello".from(0)  # => "hello"
"hello".from(2)  # => "llo"
"hello".from(-2) # => "lo"
"hello".from(10) # => nil

NOTE : Défini dans active_support/core_ext/string/access.rb.

5.11.3 to(position)

La méthode to renvoie la sous-chaîne de caractères de la chaîne de caractères jusqu'à la position position :

"hello".to(0)  # => "h"
"hello".to(2)  # => "hel"
"hello".to(-2) # => "hell"
"hello".to(10) # => "hello"

NOTE : Défini dans active_support/core_ext/string/access.rb.

5.11.4 first(limit = 1)

La méthode first renvoie une sous-chaîne de caractères contenant les limit premiers caractères de la chaîne de caractères.

L'appel str.first(n) est équivalent à str.to(n-1) si n > 0, et renvoie une chaîne vide pour n == 0.

NOTE : Défini dans active_support/core_ext/string/access.rb.

5.11.5 last(limit = 1)

La méthode last renvoie une sous-chaîne de caractères contenant les limit derniers caractères de la chaîne de caractères.

L'appel str.last(n) est équivalent à str.from(-n) si n > 0, et renvoie une chaîne vide pour n == 0.

NOTE : Défini dans active_support/core_ext/string/access.rb.

5.12 Inflections

5.12.1 pluralize

La méthode pluralize renvoie le pluriel de son objet :

"table".pluralize     # => "tables"
"ruby".pluralize      # => "rubies"
"equipment".pluralize # => "equipment"

Comme le montre l'exemple précédent, Active Support connaît certains pluriels irréguliers et des noms non dénombrables. Les règles intégrées peuvent être étendues dans config/initializers/inflections.rb. Ce fichier est généré par défaut par la commande rails new et contient des instructions en commentaires.

pluralize peut également prendre un paramètre optionnel count. Si count == 1, la forme singulière sera renvoyée. Pour toute autre valeur de count, la forme plurielle sera renvoyée :

"dude".pluralize(0) # => "dudes"
"dude".pluralize(1) # => "dude"
"dude".pluralize(2) # => "dudes"

Active Record utilise cette méthode pour calculer le nom de table par défaut correspondant à un modèle :

# active_record/model_schema.rb
def undecorated_table_name(model_name)
  table_name = model_name.to_s.demodulize.underscore
  pluralize_table_names ? table_name.pluralize : table_name
end

NOTE : Défini dans active_support/core_ext/string/inflections.rb.

5.12.2 singularize

La méthode singularize est l'inverse de pluralize :

"tables".singularize    # => "table"
"rubies".singularize    # => "ruby"
"equipment".singularize # => "equipment"

Les associations calculent le nom de la classe associée par défaut en utilisant cette méthode :

# active_record/reflection.rb
def derive_class_name
  class_name = name.to_s.camelize
  class_name = class_name.singularize if collection?
  class_name
end

NOTE : Défini dans active_support/core_ext/string/inflections.rb.

5.12.3 camelize

La méthode camelize renvoie son objet en camel case :

"product".camelize    # => "Product"
"admin_user".camelize # => "AdminUser"

En règle générale, vous pouvez considérer cette méthode comme celle qui transforme les chemins en noms de classes ou de modules Ruby, où les barres obliques séparent les espaces de noms :

"backoffice/session".camelize # => "Backoffice::Session"

Par exemple, Action Pack utilise cette méthode pour charger la classe qui fournit un certain magasin de session :

# action_controller/metal/session_management.rb
def session_store=(store)
  @@session_store = store.is_a?(Symbol) ?
    ActionDispatch::Session.const_get(store.to_s.camelize) :
    store
end

camelize accepte un argument optionnel, qui peut être :upper (par défaut) ou :lower. Avec ce dernier, la première lettre devient en minuscule : ruby "visual_effect".camelize(:lower) # => "visualEffect"

Cela peut être pratique pour calculer des noms de méthodes dans une langue qui suit cette convention, par exemple JavaScript.

En règle générale, vous pouvez considérer camelize comme l'inverse de underscore, bien qu'il existe des cas où cela ne s'applique pas: "SSLError".underscore.camelize renvoie "SslError". Pour prendre en charge des cas comme celui-ci, Active Support vous permet de spécifier des acronymes dans config/initializers/inflections.rb:

ActiveSupport::Inflector.inflections do |inflect|
  inflect.acronym 'SSL'
end

"SSLError".underscore.camelize # => "SSLError"

camelize est un alias de camelcase.

Défini dans active_support/core_ext/string/inflections.rb.

5.12.4 underscore

La méthode underscore fait l'inverse, du camel case aux chemins:

"Product".underscore   # => "product"
"AdminUser".underscore # => "admin_user"

Convertit également "::" en "/":

"Backoffice::Session".underscore # => "backoffice/session"

et comprend les chaînes qui commencent par une minuscule:

"visualEffect".underscore # => "visual_effect"

underscore n'accepte aucun argument.

Rails utilise underscore pour obtenir un nom en minuscules pour les classes de contrôleur:

# actionpack/lib/abstract_controller/base.rb
def controller_path
  @controller_path ||= name.delete_suffix("Controller").underscore
end

Par exemple, cette valeur est celle que vous obtenez dans params[:controller].

En règle générale, vous pouvez considérer underscore comme l'inverse de camelize, bien qu'il existe des cas où cela ne s'applique pas. Par exemple, "SSLError".underscore.camelize renvoie "SslError".

Défini dans active_support/core_ext/string/inflections.rb.

5.12.5 titleize

La méthode titleize met en majuscule les mots dans la chaîne:

"alice in wonderland".titleize # => "Alice In Wonderland"
"fermat's enigma".titleize     # => "Fermat's Enigma"

titleize est un alias de titlecase.

Défini dans active_support/core_ext/string/inflections.rb.

5.12.6 dasherize

La méthode dasherize remplace les underscores dans la chaîne par des tirets:

"name".dasherize         # => "name"
"contact_data".dasherize # => "contact-data"

Le sérialiseur XML des modèles utilise cette méthode pour transformer les noms de nœuds en tirets:

# active_model/serializers/xml.rb
def reformat_name(name)
  name = name.camelize if camelize?
  dasherize? ? name.dasherize : name
end

Défini dans active_support/core_ext/string/inflections.rb.

5.12.7 demodulize

Étant donné une chaîne avec un nom de constante qualifié, demodulize renvoie le nom de la constante lui-même, c'est-à-dire la partie la plus à droite:

"Product".demodulize                        # => "Product"
"Backoffice::UsersController".demodulize    # => "UsersController"
"Admin::Hotel::ReservationUtils".demodulize # => "ReservationUtils"
"::Inflections".demodulize                  # => "Inflections"
"".demodulize                               # => ""

Active Record utilise par exemple cette méthode pour calculer le nom d'une colonne de cache de compteur:

# active_record/reflection.rb
def counter_cache_column
  if options[:counter_cache] == true
    "#{active_record.name.demodulize.underscore.pluralize}_count"
  elsif options[:counter_cache]
    options[:counter_cache]
  end
end

Défini dans active_support/core_ext/string/inflections.rb.

5.12.8 deconstantize

Étant donné une chaîne avec une expression de référence de constante qualifiée, deconstantize supprime le segment le plus à droite, laissant généralement le nom du conteneur de la constante:

"Product".deconstantize                        # => ""
"Backoffice::UsersController".deconstantize    # => "Backoffice"
"Admin::Hotel::ReservationUtils".deconstantize # => "Admin::Hotel"

Défini dans active_support/core_ext/string/inflections.rb.

5.12.9 parameterize

La méthode parameterize normalise la chaîne de manière à pouvoir être utilisée dans les URL conviviales.

"John Smith".parameterize # => "john-smith"
"Kurt Gödel".parameterize # => "kurt-godel"

Pour conserver la casse de la chaîne, définissez l'argument preserve_case sur true. Par défaut, preserve_case est défini sur false.

"John Smith".parameterize(preserve_case: true) # => "John-Smith"
"Kurt Gödel".parameterize(preserve_case: true) # => "Kurt-Godel"

Pour utiliser un séparateur personnalisé, remplacez l'argument separator.

"John Smith".parameterize(separator: "_") # => "john_smith"
"Kurt Gödel".parameterize(separator: "_") # => "kurt_godel"

REMARQUE : Défini dans active_support/core_ext/string/inflections.rb.

5.12.10 tableize

La méthode tableize est underscore suivie de pluralize.

"Personne".tableize      # => "people"
"Facture".tableize     # => "invoices"
"LigneFacture".tableize # => "invoice_lines"

En règle générale, tableize renvoie le nom de la table correspondant à un modèle donné pour les cas simples. L'implémentation réelle dans Active Record n'est pas simplement tableize, car elle démodule également le nom de la classe et vérifie quelques options qui peuvent affecter la chaîne renvoyée.

REMARQUE : Défini dans active_support/core_ext/string/inflections.rb.

5.12.11 classify

La méthode classify est l'inverse de tableize. Elle vous donne le nom de classe correspondant à un nom de table :

"people".classify        # => "Personne"
"invoices".classify      # => "Facture"
"invoice_lines".classify # => "LigneFacture"

La méthode comprend les noms de table qualifiés :

"highrise_production.companies".classify # => "Societe"

Notez que classify renvoie un nom de classe sous forme de chaîne. Vous pouvez obtenir l'objet de classe réel en invoquant constantize dessus, expliqué ensuite.

REMARQUE : Défini dans active_support/core_ext/string/inflections.rb.

5.12.12 constantize

La méthode constantize résout l'expression de référence constante dans son receveur :

"Integer".constantize # => Integer

module M
  X = 1
end
"M::X".constantize # => 1

Si la chaîne ne correspond à aucune constante connue, ou si son contenu n'est même pas un nom de constante valide, constantize génère une NameError.

La résolution du nom de constante par constantize commence toujours au niveau supérieur de Object, même s'il n'y a pas de "::" au début.

X = :in_Object
module M
  X = :in_M

  X                 # => :in_M
  "::X".constantize # => :in_Object
  "X".constantize   # => :in_Object (!)
end

Ainsi, en général, cela n'est pas équivalent à ce que Ruby ferait au même endroit, si une vraie constante était évaluée.

Les cas de test des mailers obtiennent le mailer testé à partir du nom de la classe de test en utilisant constantize :

# action_mailer/test_case.rb
def determine_default_mailer(name)
  name.delete_suffix("Test").constantize
rescue NameError => e
  raise NonInferrableMailerError.new(name)
end

REMARQUE : Défini dans active_support/core_ext/string/inflections.rb.

5.12.13 humanize

La méthode humanize ajuste un nom d'attribut pour l'affichage aux utilisateurs finaux.

Plus précisément, elle effectue ces transformations :

  • Applique les règles d'inflection humaine à l'argument.
  • Supprime les tirets bas initiaux, le cas échéant.
  • Supprime le suffixe "_id" s'il est présent.
  • Remplace les tirets bas par des espaces, le cas échéant.
  • Met en minuscule tous les mots sauf les acronymes.
  • Met en majuscule le premier mot.

La majuscule du premier mot peut être désactivée en définissant l'option :capitalize sur false (par défaut, true).

"name".humanize                         # => "Nom"
"author_id".humanize                    # => "Auteur"
"author_id".humanize(capitalize: false) # => "auteur"
"comments_count".humanize               # => "Nombre de commentaires"
"_id".humanize                          # => "Id"

Si "SSL" est défini comme un acronyme :

'ssl_error'.humanize # => "Erreur SSL"

La méthode d'aide full_messages utilise humanize comme solution de secours pour inclure les noms d'attributs :

def full_messages
  map { |attribute, message| full_message(attribute, message) }
end

def full_message
  # ...
  attr_name = attribute.to_s.tr('.', '_').humanize
  attr_name = @base.class.human_attribute_name(attribute, default: attr_name)
  # ...
end

REMARQUE : Défini dans active_support/core_ext/string/inflections.rb.

5.12.14 foreign_key

La méthode foreign_key donne le nom de la colonne de clé étrangère à partir d'un nom de classe. Pour ce faire, elle démodule, ajoute des tirets bas et ajoute "_id" :

"User".foreign_key           # => "user_id"
"InvoiceLine".foreign_key    # => "invoice_line_id"
"Admin::Session".foreign_key # => "session_id"

Passez un argument faux si vous ne voulez pas de tiret bas dans "_id":

"User".foreign_key(false) # => "userid"

Les associations utilisent cette méthode pour déduire les clés étrangères, par exemple has_one et has_many font cela:

# active_record/associations.rb
foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key

NOTE : Défini dans active_support/core_ext/string/inflections.rb.

5.12.15 upcase_first

La méthode upcase_first met en majuscule la première lettre du récepteur :

"employee salary".upcase_first # => "Employee salary"
"".upcase_first                # => ""

NOTE : Défini dans active_support/core_ext/string/inflections.rb.

5.12.16 downcase_first

La méthode downcase_first convertit la première lettre du récepteur en minuscule :

"If I had read Alice in Wonderland".downcase_first # => "if I had read Alice in Wonderland"
"".downcase_first                                  # => ""

NOTE : Défini dans active_support/core_ext/string/inflections.rb.

5.13 Conversions

5.13.1 to_date, to_time, to_datetime

Les méthodes to_date, to_time et to_datetime sont essentiellement des enveloppes pratiques autour de Date._parse :

"2010-07-27".to_date              # => Tue, 27 Jul 2010
"2010-07-27 23:37:00".to_time     # => 2010-07-27 23:37:00 +0200
"2010-07-27 23:37:00".to_datetime # => Tue, 27 Jul 2010 23:37:00 +0000

to_time reçoit un argument facultatif :utc ou :local, pour indiquer dans quel fuseau horaire vous voulez l'heure :

"2010-07-27 23:42:00".to_time(:utc)   # => 2010-07-27 23:42:00 UTC
"2010-07-27 23:42:00".to_time(:local) # => 2010-07-27 23:42:00 +0200

La valeur par défaut est :local.

Veuillez vous référer à la documentation de Date._parse pour plus de détails.

INFO : Les trois renvoient nil pour les récepteurs vides.

NOTE : Défini dans active_support/core_ext/string/conversions.rb.

6 Extensions à Symbol

6.1 starts_with? et ends_with?

Active Support définit des alias à la troisième personne de Symbol#start_with? et Symbol#end_with? :

:foo.starts_with?("f") # => true
:foo.ends_with?("o")   # => true

NOTE : Défini dans active_support/core_ext/symbol/starts_ends_with.rb.

7 Extensions à Numeric

7.1 Bytes

Tous les nombres répondent à ces méthodes :

Elles renvoient la quantité correspondante d'octets, en utilisant un facteur de conversion de 1024 :

2.kilobytes   # => 2048
3.megabytes   # => 3145728
3.5.gigabytes # => 3758096384.0
-4.exabytes   # => -4611686018427387904

Les formes singulières sont des alias, vous pouvez donc dire :

1.megabyte # => 1048576

NOTE : Défini dans active_support/core_ext/numeric/bytes.rb.

7.2 Time

Les méthodes suivantes :

permettent les déclarations et les calculs de temps, comme 45.minutes + 2.hours + 4.weeks. Leurs valeurs de retour peuvent également être ajoutées ou soustraites des objets Time.

Ces méthodes peuvent être combinées avec from_now, ago, etc, pour des calculs de date précis. Par exemple :

# équivalent à Time.current.advance(days: 1)
1.day.from_now

# équivalent à Time.current.advance(weeks: 2)
2.weeks.from_now

# équivalent à Time.current.advance(days: 4, weeks: 5)
(4.days + 5.weeks).from_now

ATTENTION. Pour d'autres durées, veuillez vous référer aux extensions de temps à Integer.

NOTE : Défini dans active_support/core_ext/numeric/time.rb.

7.3 Formatage

Permet le formatage des nombres de différentes manières.

Produire une représentation sous forme de chaîne d'un nombre en tant que numéro de téléphone :

5551234.to_fs(:phone)
# => 555-1234
1235551234.to_fs(:phone)
# => 123-555-1234
1235551234.to_fs(:phone, area_code: true)
# => (123) 555-1234
1235551234.to_fs(:phone, delimiter: " ")
# => 123 555 1234
1235551234.to_fs(:phone, area_code: true, extension: 555)
# => (123) 555-1234 x 555
1235551234.to_fs(:phone, country_code: 1)
# => +1-123-555-1234

Produire une représentation sous forme de chaîne d'un nombre en tant que devise :

1234567890.50.to_fs(:currency)                 # => $1,234,567,890.50
1234567890.506.to_fs(:currency)                # => $1,234,567,890.51
1234567890.506.to_fs(:currency, precision: 3)  # => $1,234,567,890.506

Produire une représentation sous forme de chaîne d'un nombre en pourcentage:

100.to_fs(:pourcentage)
# => 100.000%
100.to_fs(:pourcentage, precision: 0)
# => 100%
1000.to_fs(:pourcentage, delimiter: '.', separator: ',')
# => 1.000,000%
302.24398923423.to_fs(:pourcentage, precision: 5)
# => 302.24399%

Produire une représentation sous forme de chaîne d'un nombre en forme délimitée:

12345678.to_fs(:délimité)                     # => 12,345,678
12345678.05.to_fs(:délimité)                  # => 12,345,678.05
12345678.to_fs(:délimité, delimiter: ".")     # => 12.345.678
12345678.to_fs(:délimité, delimiter: ",")     # => 12,345,678
12345678.05.to_fs(:délimité, separator: " ")  # => 12,345,678 05

Produire une représentation sous forme de chaîne d'un nombre arrondi à une précision:

111.2345.to_fs(:arrondi)                     # => 111.235
111.2345.to_fs(:arrondi, precision: 2)       # => 111.23
13.to_fs(:arrondi, precision: 5)             # => 13.00000
389.32314.to_fs(:arrondi, precision: 0)      # => 389
111.2345.to_fs(:arrondi, significant: true)  # => 111

Produire une représentation sous forme de chaîne d'un nombre en tant que nombre de bytes lisible par un humain:

123.to_fs(:taille_humaine)                  # => 123 Bytes
1234.to_fs(:taille_humaine)                 # => 1.21 KB
12345.to_fs(:taille_humaine)                # => 12.1 KB
1234567.to_fs(:taille_humaine)              # => 1.18 MB
1234567890.to_fs(:taille_humaine)           # => 1.15 GB
1234567890123.to_fs(:taille_humaine)        # => 1.12 TB
1234567890123456.to_fs(:taille_humaine)     # => 1.1 PB
1234567890123456789.to_fs(:taille_humaine)  # => 1.07 EB

Produire une représentation sous forme de chaîne d'un nombre en mots lisibles par un humain:

123.to_fs(:humain)               # => "123"
1234.to_fs(:humain)              # => "1.23 Thousand"
12345.to_fs(:humain)             # => "12.3 Thousand"
1234567.to_fs(:humain)           # => "1.23 Million"
1234567890.to_fs(:humain)        # => "1.23 Billion"
1234567890123.to_fs(:humain)     # => "1.23 Trillion"
1234567890123456.to_fs(:humain)  # => "1.23 Quadrillion"

Défini dans active_support/core_ext/numeric/conversions.rb.

8 Extensions à Integer

8.1 multiple_of?

La méthode multiple_of? teste si un entier est un multiple de l'argument:

2.multiple_of?(1) # => true
1.multiple_of?(2) # => false

Défini dans active_support/core_ext/integer/multiple.rb.

8.2 ordinal

La méthode ordinal renvoie la chaîne de suffixe ordinal correspondant à l'entier:

1.ordinal    # => "st"
2.ordinal    # => "nd"
53.ordinal   # => "rd"
2009.ordinal # => "th"
-21.ordinal  # => "st"
-134.ordinal # => "th"

Défini dans active_support/core_ext/integer/inflections.rb.

8.3 ordinalize

La méthode ordinalize renvoie la chaîne ordinale correspondant à l'entier. En comparaison, notez que la méthode ordinal renvoie seulement la chaîne de suffixe.

1.ordinalize    # => "1st"
2.ordinalize    # => "2nd"
53.ordinalize   # => "53rd"
2009.ordinalize # => "2009th"
-21.ordinalize  # => "-21st"
-134.ordinalize # => "-134th"

Défini dans active_support/core_ext/integer/inflections.rb.

8.4 Time

Les méthodes suivantes:

permettent les déclarations et les calculs de temps, comme 4.months + 5.years. Leurs valeurs de retour peuvent également être ajoutées ou soustraites des objets Time.

Ces méthodes peuvent être combinées avec from_now, ago, etc, pour des calculs de dates précis. Par exemple:

# équivalent à Time.current.advance(months: 1)
1.month.from_now

# équivalent à Time.current.advance(years: 2)
2.years.from_now

# équivalent à Time.current.advance(months: 4, years: 5)
(4.months + 5.years).from_now

ATTENTION. Pour d'autres durées, veuillez vous référer aux extensions de temps à Numeric.

Défini dans active_support/core_ext/integer/time.rb.

9 Extensions à BigDecimal

9.1 to_s

La méthode to_s fournit un spécificateur par défaut de "F". Cela signifie qu'un simple appel à to_s donnera une représentation en virgule flottante au lieu de la notation scientifique:

BigDecimal(5.00, 6).to_s       # => "5.0"

La notation scientifique est toujours prise en charge:

BigDecimal(5.00, 6).to_s("e")  # => "0.5E1"

10 Extensions à Enumerable

10.1 sum

La méthode sum ajoute les éléments d'un énumérable: ruby [1, 2, 3].sum # => 6 (1..100).sum # => 5050

L'addition suppose seulement que les éléments répondent à +:

[[1, 2], [2, 3], [3, 4]].sum    # => [1, 2, 2, 3, 3, 4]
%w(foo bar baz).sum             # => "foobarbaz"
{ a: 1, b: 2, c: 3 }.sum          # => [:a, 1, :b, 2, :c, 3]

La somme d'une collection vide est zéro par défaut, mais cela peut être personnalisé:

[].sum    # => 0
[].sum(1) # => 1

Si un bloc est donné, sum devient un itérateur qui renvoie les éléments de la collection et additionne les valeurs renvoyées:

(1..5).sum { |n| n * 2 } # => 30
[2, 4, 6, 8, 10].sum    # => 30

La somme d'un récepteur vide peut également être personnalisée sous cette forme:

[].sum(1) { |n| n**3 } # => 1

Défini dans active_support/core_ext/enumerable.rb.

10.2 index_by

La méthode index_by génère un hash avec les éléments d'une énumération indexés par une clé.

Elle itère à travers la collection et passe chaque élément à un bloc. L'élément sera indexé par la valeur renvoyée par le bloc:

invoices.index_by(&:number)
# => {'2009-032' => <Invoice ...>, '2009-008' => <Invoice ...>, ...}

ATTENTION. Les clés devraient normalement être uniques. Si le bloc renvoie la même valeur pour différents éléments, aucune collection n'est construite pour cette clé. Le dernier élément l'emportera.

Défini dans active_support/core_ext/enumerable.rb.

10.3 index_with

La méthode index_with génère un hash avec les éléments d'une énumération comme clés. La valeur est soit une valeur par défaut passée en argument, soit renvoyée par un bloc.

post = Post.new(title: "hey there", body: "what's up?")

%i( title body ).index_with { |attr_name| post.public_send(attr_name) }
# => { title: "hey there", body: "what's up?" }

WEEKDAYS.index_with(Interval.all_day)
# => { monday: [ 0, 1440 ], … }

Défini dans active_support/core_ext/enumerable.rb.

10.4 many?

La méthode many? est une abréviation pour collection.size > 1:

<% if pages.many? %>
  <%= pagination_links %>
<% end %>

Si un bloc optionnel est donné, many? ne prend en compte que les éléments qui renvoient true:

@see_more = videos.many? { |video| video.category == params[:category] }

Défini dans active_support/core_ext/enumerable.rb.

10.5 exclude?

Le prédicat exclude? teste si un objet donné n'appartient pas à la collection. C'est la négation de include? intégré:

to_visit << node if visited.exclude?(node)

Défini dans active_support/core_ext/enumerable.rb.

10.6 including

La méthode including renvoie une nouvelle énumération qui inclut les éléments passés en argument:

[ 1, 2, 3 ].including(4, 5)                    # => [ 1, 2, 3, 4, 5 ]
["David", "Rafael"].including %w[ Aaron Todd ] # => ["David", "Rafael", "Aaron", "Todd"]

Défini dans active_support/core_ext/enumerable.rb.

10.7 excluding

La méthode excluding renvoie une copie d'une énumération avec les éléments spécifiés supprimés:

["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]

excluding est un alias de without.

Défini dans active_support/core_ext/enumerable.rb.

10.8 pluck

La méthode pluck extrait la clé donnée de chaque élément:

[{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name) # => ["David", "Rafael", "Aaron"]
[{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name) # => [[1, "David"], [2, "Rafael"]]

Défini dans active_support/core_ext/enumerable.rb.

10.9 pick

La méthode pick extrait la clé donnée du premier élément :

[{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pick(:name) # => "David"
[{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pick(:id, :name) # => [1, "David"]

Défini dans active_support/core_ext/enumerable.rb.

11 Extensions pour Array

11.1 Accès

Active Support améliore l'API des tableaux pour faciliter certaines façons de les accéder. Par exemple, to renvoie le sous-tableau des éléments jusqu'à celui à l'index passé :

%w(a b c d).to(2) # => ["a", "b", "c"]
[].to(7)          # => []

De même, from renvoie la partie à partir de l'élément à l'index passé jusqu'à la fin. Si l'index est supérieur à la longueur du tableau, il renvoie un tableau vide.

%w(a b c d).from(2)  # => ["c", "d"]
%w(a b c d).from(10) # => []
[].from(0)           # => []

La méthode including renvoie un nouveau tableau qui inclut les éléments passés :

[ 1, 2, 3 ].including(4, 5)          # => [ 1, 2, 3, 4, 5 ]
[ [ 0, 1 ] ].including([ [ 1, 0 ] ]) # => [ [ 0, 1 ], [ 1, 0 ] ]

La méthode excluding renvoie une copie du tableau en excluant les éléments spécifiés. Il s'agit d'une optimisation de Enumerable#excluding qui utilise Array#- au lieu de Array#reject pour des raisons de performance.

["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]
[ [ 0, 1 ], [ 1, 0 ] ].excluding([ [ 1, 0 ] ])                  # => [ [ 0, 1 ] ]

Les méthodes second, third, fourth et fifth renvoient l'élément correspondant, tout comme second_to_last et third_to_last (first et last sont intégrés). Grâce à la sagesse sociale et à la constructivité positive partout, forty_two est également disponible.

%w(a b c d).third # => "c"
%w(a b c d).fifth # => nil

Défini dans active_support/core_ext/array/access.rb.

11.2 Extraction

La méthode extract! supprime et renvoie les éléments pour lesquels le bloc renvoie une valeur vraie. Si aucun bloc n'est donné, un énumérateur est renvoyé à la place.

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
numbers # => [0, 2, 4, 6, 8]

Défini dans active_support/core_ext/array/extract.rb.

11.3 Extraction des options

Lorsque le dernier argument dans un appel de méthode est un hash, à l'exception peut-être d'un argument &block, Ruby vous permet d'omettre les crochets :

User.exists?(email: params[:email])

Ce sucre syntaxique est beaucoup utilisé dans Rails pour éviter les arguments positionnels lorsque cela serait trop nombreux, offrant à la place des interfaces qui émulent les paramètres nommés. En particulier, il est très idiomatique d'utiliser un hash de fin pour les options.

Si une méthode attend un nombre variable d'arguments et utilise * dans sa déclaration, cependant, un hash d'options se retrouve être un élément du tableau d'arguments, où il perd son rôle.

Dans ces cas, vous pouvez donner à un hash d'options un traitement distinct avec extract_options!. Cette méthode vérifie le type du dernier élément d'un tableau. S'il s'agit d'un hash, il le supprime et le renvoie, sinon il renvoie un hash vide. Voyons par exemple la définition de la macro du contrôleur caches_action :

def caches_action(*actions)
  return unless cache_configured?
  options = actions.extract_options!
  # ...
end

Cette méthode reçoit un nombre arbitraire de noms d'actions et un hachage d'options facultatif en dernier argument. Avec l'appel à extract_options!, vous obtenez le hachage d'options et le supprimez de actions de manière simple et explicite.

NOTE : Défini dans active_support/core_ext/array/extract_options.rb.

11.4 Conversions

11.4.1 to_sentence

La méthode to_sentence transforme un tableau en une chaîne de caractères contenant une phrase qui énumère ses éléments :

%w().to_sentence                # => ""
%w(Earth).to_sentence           # => "Earth"
%w(Earth Wind).to_sentence      # => "Earth and Wind"
%w(Earth Wind Fire).to_sentence # => "Earth, Wind, and Fire"

Cette méthode accepte trois options :

  • :two_words_connector : Ce qui est utilisé pour les tableaux de longueur 2. La valeur par défaut est " and ".
  • :words_connector : Ce qui est utilisé pour joindre les éléments des tableaux avec 3 éléments ou plus, sauf les deux derniers. La valeur par défaut est ", ".
  • :last_word_connector : Ce qui est utilisé pour joindre les derniers éléments d'un tableau avec 3 éléments ou plus. La valeur par défaut est ", and ".

Les valeurs par défaut de ces options peuvent être localisées, leurs clés sont :

Option Clé I18n
:two_words_connector support.array.two_words_connector
:words_connector support.array.words_connector
:last_word_connector support.array.last_word_connector

NOTE : Défini dans active_support/core_ext/array/conversions.rb.

11.4.2 to_fs

La méthode to_fs agit comme to_s par défaut.

Si le tableau contient des éléments qui répondent à id, cependant, le symbole :db peut être passé en argument. C'est généralement utilisé avec des collections d'objets Active Record. Les chaînes retournées sont :

[].to_fs(:db)            # => "null"
[user].to_fs(:db)        # => "8456"
invoice.lines.to_fs(:db) # => "23,567,556,12"

Les entiers dans l'exemple ci-dessus sont censés provenir des appels respectifs à id.

NOTE : Défini dans active_support/core_ext/array/conversions.rb.

11.4.3 to_xml

La méthode to_xml renvoie une chaîne de caractères contenant une représentation XML de son objet :

Contributor.limit(2).order(:rank).to_xml
# =>
# <?xml version="1.0" encoding="UTF-8"?>
# <contributors type="array">
#   <contributor>
#     <id type="integer">4356</id>
#     <name>Jeremy Kemper</name>
#     <rank type="integer">1</rank>
#     <url-id>jeremy-kemper</url-id>
#   </contributor>
#   <contributor>
#     <id type="integer">4404</id>
#     <name>David Heinemeier Hansson</name>
#     <rank type="integer">2</rank>
#     <url-id>david-heinemeier-hansson</url-id>
#   </contributor>
# </contributors>

Pour ce faire, elle envoie to_xml à chaque élément à tour de rôle et collecte les résultats sous un nœud racine. Tous les éléments doivent répondre à to_xml, sinon une exception est levée.

Par défaut, le nom de l'élément racine est le pluriel en underscore et en tiret du nom de la classe du premier élément, à condition que le reste des éléments appartiennent à ce type (vérifié avec is_a?) et qu'ils ne soient pas des hachages. Dans l'exemple ci-dessus, il s'agit de "contributors".

S'il y a un élément qui n'appartient pas au type du premier élément, le nœud racine devient "objects" :

[Contributor.first, Commit.first].to_xml
# =>
# <?xml version="1.0" encoding="UTF-8"?>
# <objects type="array">
#   <object>
#     <id type="integer">4583</id>
#     <name>Aaron Batalion</name>
#     <rank type="integer">53</rank>
#     <url-id>aaron-batalion</url-id>
#   </object>
#   <object>
#     <author>Joshua Peek</author>
#     <authored-timestamp type="datetime">2009-09-02T16:44:36Z</authored-timestamp>
#     <branch>origin/master</branch>
#     <committed-timestamp type="datetime">2009-09-02T16:44:36Z</committed-timestamp>
#     <committer>Joshua Peek</committer>
#     <git-show nil="true"></git-show>
#     <id type="integer">190316</id>
#     <imported-from-svn type="boolean">false</imported-from-svn>
#     <message>Kill AMo observing wrap_with_notifications since ARes was only using it</message>
#     <sha1>723a47bfb3708f968821bc969a9a3fc873a3ed58</sha1>
#   </object>
# </objects>

Si le récepteur est un tableau de hachages, l'élément racine est par défaut également "objects":

[{ a: 1, b: 2 }, { c: 3 }].to_xml
# =>
# <?xml version="1.0" encoding="UTF-8"?>
# <objects type="array">
#   <object>
#     <b type="integer">2</b>
#     <a type="integer">1</a>
#   </object>
#   <object>
#     <c type="integer">3</c>
#   </object>
# </objects>

ATTENTION. Si la collection est vide, l'élément racine est par défaut "nil-classes". C'est un piège, par exemple l'élément racine de la liste des contributeurs ci-dessus ne serait pas "contributors" si la collection était vide, mais "nil-classes". Vous pouvez utiliser l'option :root pour garantir un élément racine cohérent.

Le nom des nœuds enfants est par défaut le nom du nœud racine singulier. Dans les exemples ci-dessus, nous avons vu "contributor" et "object". L'option :children vous permet de définir ces noms de nœuds.

Le constructeur XML par défaut est une nouvelle instance de Builder::XmlMarkup. Vous pouvez configurer votre propre constructeur via l'option :builder. La méthode accepte également des options telles que :dasherize et autres, qui sont transmises au constructeur :

Contributor.limit(2).order(:rank).to_xml(skip_types: true)
# =>
# <?xml version="1.0" encoding="UTF-8"?>
# <contributors>
#   <contributor>
#     <id>4356</id>
#     <name>Jeremy Kemper</name>
#     <rank>1</rank>
#     <url-id>jeremy-kemper</url-id>
#   </contributor>
#   <contributor>
#     <id>4404</id>
#     <name>David Heinemeier Hansson</name>
#     <rank>2</rank>
#     <url-id>david-heinemeier-hansson</url-id>
#   </contributor>
# </contributors>

NOTE : Défini dans active_support/core_ext/array/conversions.rb.

11.5 Enveloppement

La méthode Array.wrap enveloppe son argument dans un tableau à moins qu'il ne soit déjà un tableau (ou de type tableau).

Plus précisément :

  • Si l'argument est nil, un tableau vide est renvoyé.
  • Sinon, si l'argument répond à to_ary, il est invoqué, et si la valeur de to_ary n'est pas nil, elle est renvoyée.
  • Sinon, un tableau avec l'argument comme unique élément est renvoyé.
Array.wrap(nil)       # => []
Array.wrap([1, 2, 3]) # => [1, 2, 3]
Array.wrap(0)         # => [0]

Cette méthode est similaire en but à Kernel#Array, mais il y a quelques différences :

  • Si l'argument répond à to_ary, la méthode est invoquée. Kernel#Array passe à to_a si la valeur renvoyée est nil, mais Array.wrap renvoie immédiatement un tableau avec l'argument comme unique élément.
  • Si la valeur renvoyée par to_ary n'est ni nil ni un objet Array, Kernel#Array génère une exception, tandis que Array.wrap ne le fait pas, il renvoie simplement la valeur.
  • Il n'appelle pas to_a sur l'argument, si l'argument ne répond pas à to_ary, il renvoie un tableau avec l'argument comme unique élément.

Le dernier point vaut particulièrement la peine d'être comparé pour certaines énumérables :

Array.wrap(foo: :bar) # => [{:foo=>:bar}]
Array(foo: :bar)      # => [[:foo, :bar]]

Il existe également une expression idiomatique associée qui utilise l'opérateur splat :

[*object]

NOTE : Défini dans active_support/core_ext/array/wrap.rb.

11.6 Duplication

La méthode Array#deep_dup duplique elle-même et tous les objets à l'intérieur de manière récursive avec la méthode Active Support Object#deep_dup. Elle fonctionne comme Array#map, en envoyant la méthode deep_dup à chaque objet à l'intérieur.

array = [1, [2, 3]]
dup = array.deep_dup
dup[1][2] = 4
array[1][2] == nil   # => true

NOTE : Défini dans active_support/core_ext/object/deep_dup.rb.

11.7 Groupement

11.7.1 in_groups_of(nombre, remplir_avec = nil)

La méthode in_groups_of divise un tableau en groupes consécutifs d'une certaine taille. Elle renvoie un tableau avec les groupes :

[1, 2, 3].in_groups_of(2) # => [[1, 2], [3, nil]]

ou les renvoie un par un si un bloc est passé :

<% sample.in_groups_of(3) do |a, b, c| %>
  <tr>
    <td><%= a %></td>
    <td><%= b %></td>
    <td><%= c %></td>
  </tr>
<% end %>

Le premier exemple montre comment in_groups_of remplit le dernier groupe avec autant d'éléments nil que nécessaire pour obtenir la taille demandée. Vous pouvez changer cette valeur de remplissage en utilisant le deuxième argument optionnel :

[1, 2, 3].in_groups_of(2, 0) # => [[1, 2], [3, 0]]

Et vous pouvez indiquer à la méthode de ne pas remplir le dernier groupe en passant false :

[1, 2, 3].in_groups_of(2, false) # => [[1, 2], [3]]

En conséquence, false ne peut pas être utilisé comme valeur de remplissage.

NOTE : Défini dans active_support/core_ext/array/grouping.rb.

11.7.2 in_groups(nombre, remplir_avec = nil)

La méthode in_groups divise un tableau en un certain nombre de groupes. La méthode renvoie un tableau avec les groupes :

%w(1 2 3 4 5 6 7).in_groups(3)
# => [["1", "2", "3"], ["4", "5", nil], ["6", "7", nil]]

ou les renvoie un par un si un bloc est passé :

%w(1 2 3 4 5 6 7).in_groups(3) { |group| p group }
["1", "2", "3"]
["4", "5", nil]
["6", "7", nil]

Les exemples ci-dessus montrent que in_groups remplit certains groupes avec un élément nil supplémentaire si nécessaire. Un groupe peut avoir au plus un de ces éléments supplémentaires, le dernier à droite s'il y en a. Et les groupes qui les ont sont toujours les derniers.

Vous pouvez changer cette valeur de remplissage en utilisant le deuxième argument optionnel :

%w(1 2 3 4 5 6 7).in_groups(3, "0")
# => [["1", "2", "3"], ["4", "5", "0"], ["6", "7", "0"]]

Et vous pouvez indiquer à la méthode de ne pas remplir les groupes plus petits en passant false :

%w(1 2 3 4 5 6 7).in_groups(3, false)
# => [["1", "2", "3"], ["4", "5"], ["6", "7"]]

En conséquence, false ne peut pas être utilisé comme valeur de remplissage.

NOTE : Défini dans active_support/core_ext/array/grouping.rb.

11.7.3 split(valeur = nil)

La méthode split divise un tableau par un séparateur et renvoie les morceaux résultants.

Si un bloc est passé, les séparateurs sont les éléments du tableau pour lesquels le bloc renvoie true :

(-5..5).to_a.split { |i| i.multiple_of?(4) }
# => [[-5], [-3, -2, -1], [1, 2, 3], [5]]

Sinon, la valeur reçue en argument, qui est par défaut nil, est le séparateur :

[0, 1, -5, 1, 1, "foo", "bar"].split(1)
# => [[0], [-5], [], ["foo", "bar"]]

ASTUCE : Remarquez dans l'exemple précédent que les séparateurs consécutifs donnent des tableaux vides.

NOTE : Défini dans active_support/core_ext/array/grouping.rb.

12 Extensions à Hash

12.1 Conversions

12.1.1 to_xml

La méthode to_xml renvoie une chaîne de caractères contenant une représentation XML de son objet :

{ foo: 1, bar: 2 }.to_xml
# =>
# <?xml version="1.0" encoding="UTF-8"?>
# <hash>
#   <foo type="integer">1</foo>
#   <bar type="integer">2</bar>
# </hash>

Pour ce faire, la méthode boucle sur les paires et construit des nœuds qui dépendent des valeurs. Étant donné une paire clé, valeur :

  • Si valeur est un hash, il y a un appel récursif avec clé en tant que :root.

  • Si valeur est un tableau, il y a un appel récursif avec clé en tant que :root, et clé singulier en tant que :children.

  • Si valeur est un objet appelable, il doit s'attendre à un ou deux arguments. Selon l'arité, l'appelable est invoqué avec le hash options comme premier argument avec clé en tant que :root, et clé singulier en tant que deuxième argument. Sa valeur de retour devient un nouveau nœud.

  • Si valeur répond à to_xml, la méthode est invoquée avec clé en tant que :root.

  • Sinon, un nœud avec clé en tant qu'étiquette est créé avec une représentation sous forme de chaîne de caractères de valeur en tant que nœud de texte. Si valeur est nil, un attribut "nil" défini sur "true" est ajouté. À moins que l'option :skip_types n'existe et soit true, un attribut "type" est également ajouté selon la correspondance suivante :

XML_TYPE_NAMES = {
  "Symbol"     => "symbol",
  "Integer"    => "integer",
  "BigDecimal" => "decimal",
  "Float"      => "float",
  "TrueClass"  => "boolean",
  "FalseClass" => "boolean",
  "Date"       => "date",
  "DateTime"   => "datetime",
  "Time"       => "datetime"
}

Par défaut, le nœud racine est "hash", mais cela peut être configuré via l'option :root.

Le constructeur XML par défaut est une nouvelle instance de Builder::XmlMarkup. Vous pouvez configurer votre propre constructeur avec l'option :builder. La méthode accepte également des options telles que :dasherize et autres, qui sont transmises au constructeur.

NOTE : Défini dans active_support/core_ext/hash/conversions.rb.

12.2 Fusion

Ruby dispose d'une méthode intégrée Hash#merge qui fusionne deux hashes :

{ a: 1, b: 1 }.merge(a: 0, c: 2)
# => {:a=>0, :b=>1, :c=>2}

Active Support définit quelques autres façons de fusionner des hashes qui peuvent être pratiques.

12.2.1 reverse_merge et reverse_merge!

En cas de collision, la clé dans le hash de l'argument l'emporte dans merge. Vous pouvez prendre en charge des hashes d'options avec des valeurs par défaut de manière compacte avec cette expression :

options = { length: 30, omission: "..." }.merge(options)

Active Support définit reverse_merge au cas où vous préférez cette notation alternative :

options = options.reverse_merge(length: 30, omission: "...")

Et une version avec un point d'exclamation reverse_merge! qui effectue la fusion sur place :

options.reverse_merge!(length: 30, omission: "...")

ATTENTION. Prenez en compte que reverse_merge! peut modifier le hash dans l'appelant, ce qui peut être une bonne ou une mauvaise idée.

NOTE : Défini dans active_support/core_ext/hash/reverse_merge.rb.

12.2.2 reverse_update

La méthode reverse_update est un alias de reverse_merge!, expliqué ci-dessus.

ATTENTION. Notez que reverse_update n'a pas de point d'exclamation.

NOTE : Défini dans active_support/core_ext/hash/reverse_merge.rb.

12.2.3 deep_merge et deep_merge!

Comme vous pouvez le voir dans l'exemple précédent, si une clé est présente dans les deux hashes, la valeur dans celui de l'argument l'emporte.

Active Support définit Hash#deep_merge. Dans une fusion profonde, si une clé est présente dans les deux hashes et que leurs valeurs sont elles-mêmes des hashes, alors leur fusion devient la valeur dans le hash résultant :

{ a: { b: 1 } }.deep_merge(a: { c: 2 })
# => {:a=>{:b=>1, :c=>2}}

La méthode deep_merge! effectue une fusion profonde sur place.

NOTE : Défini dans active_support/core_ext/hash/deep_merge.rb.

12.3 Duplication profonde

La méthode Hash#deep_dup se duplique elle-même ainsi que toutes les clés et valeurs à l'intérieur de manière récursive avec la méthode Active Support Object#deep_dup. Elle fonctionne comme Enumerator#each_with_object en envoyant la méthode deep_dup à chaque paire à l'intérieur.

hash = { a: 1, b: { c: 2, d: [3, 4] } }

dup = hash.deep_dup
dup[:b][:e] = 5
dup[:b][:d] << 5

hash[:b][:e] == nil      # => true
hash[:b][:d] == [3, 4]   # => true

NOTE : Défini dans active_support/core_ext/object/deep_dup.rb.

12.4 Travailler avec les clés

12.4.1 except et except!

La méthode except renvoie un hash avec les clés de la liste d'arguments supprimées, si elles sont présentes :

{ a: 1, b: 2 }.except(:a) # => {:b=>2}

Si le receveur répond à convert_key, la méthode est appelée sur chacun des arguments. Cela permet à except de fonctionner correctement avec des hashes à accès indifférent, par exemple :

{ a: 1 }.with_indifferent_access.except(:a)  # => {}
{ a: 1 }.with_indifferent_access.except("a") # => {}

Il existe également la variante except! qui supprime les clés sur place.

NOTE : Défini dans active_support/core_ext/hash/except.rb.

12.4.2 stringify_keys et stringify_keys!

La méthode stringify_keys renvoie un hash dont les clés du receveur sont converties en chaînes de caractères. Elle le fait en envoyant to_s à chaque clé :

{ nil => nil, 1 => 1, a: :a }.stringify_keys
# => {"" => nil, "1" => 1, "a" => :a}

En cas de collision de clés, la valeur sera celle qui a été insérée le plus récemment dans le hash :

{ "a" => 1, a: 2 }.stringify_keys
# Le résultat sera
# => {"a"=>2}

Cette méthode peut être utile, par exemple, pour accepter facilement à la fois des symboles et des chaînes de caractères en tant qu'options. Par exemple, ActionView::Helpers::FormHelper définit :

def to_check_box_tag(options = {}, checked_value = "1", unchecked_value = "0")
  options = options.stringify_keys
  options["type"] = "checkbox"
  # ...
end

La deuxième ligne peut accéder en toute sécurité à la clé "type" et permettre à l'utilisateur de passer soit :type, soit "type".

Il existe également la variante stringify_keys! qui convertit les clés en chaînes de caractères sur place.

En plus de cela, on peut utiliser deep_stringify_keys et deep_stringify_keys! pour convertir en chaînes de caractères toutes les clés du hash donné et de tous les hashes imbriqués. Un exemple du résultat est :

{ nil => nil, 1 => 1, nested: { a: 3, 5 => 5 } }.deep_stringify_keys
# => {""=>nil, "1"=>1, "nested"=>{"a"=>3, "5"=>5}}

NOTE : Défini dans active_support/core_ext/hash/keys.rb.

12.4.3 symbolize_keys et symbolize_keys!

La méthode symbolize_keys renvoie un hash dont les clés du receveur sont symbolisées, dans la mesure du possible. Elle le fait en envoyant to_sym à chaque clé :

{ nil => nil, 1 => 1, "a" => "a" }.symbolize_keys
# => {nil=>nil, 1=>1, :a=>"a"}

ATTENTION. Notez que dans l'exemple précédent, une seule clé a été symbolisée.

En cas de collision de clés, la valeur sera celle qui a été insérée le plus récemment dans le hash :

{ "a" => 1, a: 2 }.symbolize_keys
# => {:a=>2}

Cette méthode peut être utile, par exemple, pour accepter facilement à la fois des symboles et des chaînes de caractères en tant qu'options. Par exemple, ActionText::TagHelper définit ```ruby def rich_text_area_tag(name, value = nil, options = {}) options = options.symbolize_keys

options[:input] ||= "trix_input_#{ActionText::TagHelper.id += 1}" # ... end ```

La troisième ligne peut accéder en toute sécurité à la clé :input et permet à l'utilisateur de passer soit :input soit "input".

Il existe également la variante avec point d'exclamation symbolize_keys! qui symbolise les clés sur place.

En plus de cela, on peut utiliser deep_symbolize_keys et deep_symbolize_keys! pour symboliser toutes les clés du hash donné et tous les hashes imbriqués. Un exemple du résultat est :

{ nil => nil, 1 => 1, "nested" => { "a" => 3, 5 => 5 } }.deep_symbolize_keys
# => {nil=>nil, 1=>1, nested:{a:3, 5=>5}}

NOTE : Défini dans active_support/core_ext/hash/keys.rb.

12.4.4 to_options et to_options!

Les méthodes to_options et to_options! sont des alias de symbolize_keys et symbolize_keys!, respectivement.

NOTE : Défini dans active_support/core_ext/hash/keys.rb.

12.4.5 assert_valid_keys

La méthode assert_valid_keys reçoit un nombre arbitraire d'arguments et vérifie si le récepteur a une clé en dehors de cette liste. Si c'est le cas, une ArgumentError est levée.

{ a: 1 }.assert_valid_keys(:a)  # passe
{ a: 1 }.assert_valid_keys("a") # ArgumentError

Active Record n'accepte pas les options inconnues lors de la construction d'associations, par exemple. Il implémente ce contrôle via assert_valid_keys.

NOTE : Défini dans active_support/core_ext/hash/keys.rb.

12.5 Travailler avec les valeurs

12.5.1 deep_transform_values et deep_transform_values!

La méthode deep_transform_values renvoie un nouveau hash avec toutes les valeurs converties par l'opération de bloc. Cela inclut les valeurs du hash racine et de tous les hashes et tableaux imbriqués.

hash = { person: { name: 'Rob', age: '28' } }

hash.deep_transform_values { |value| value.to_s.upcase }
# => {person: {name: "ROB", age: "28"}}

Il existe également la variante avec point d'exclamation deep_transform_values! qui convertit de manière destructive toutes les valeurs en utilisant l'opération de bloc.

NOTE : Défini dans active_support/core_ext/hash/deep_transform_values.rb.

12.6 Découpage

La méthode slice! remplace le hash par les seules clés données et renvoie un hash contenant les paires clé/valeur supprimées.

hash = { a: 1, b: 2 }
rest = hash.slice!(:a) # => {:b=>2}
hash                   # => {:a=>1}

NOTE : Défini dans active_support/core_ext/hash/slice.rb.

12.7 Extraction

La méthode extract! supprime et renvoie les paires clé/valeur correspondant aux clés données.

hash = { a: 1, b: 2 }
rest = hash.extract!(:a) # => {:a=>1}
hash                     # => {:b=>2}

La méthode extract! renvoie la même sous-classe de Hash que le récepteur.

hash = { a: 1, b: 2 }.with_indifferent_access
rest = hash.extract!(:a).class
# => ActiveSupport::HashWithIndifferentAccess

NOTE : Défini dans active_support/core_ext/hash/slice.rb.

12.8 Accès indifférent

La méthode with_indifferent_access renvoie un ActiveSupport::HashWithIndifferentAccess à partir de son récepteur :

{ a: 1 }.with_indifferent_access["a"] # => 1

NOTE : Défini dans active_support/core_ext/hash/indifferent_access.rb.

13 Extensions à Regexp

13.1 multiline?

La méthode multiline? indique si une expression régulière a le drapeau /m défini, c'est-à-dire si le point correspond aux sauts de ligne.

%r{.}.multiline?  # => false
%r{.}m.multiline? # => true

Regexp.new('.').multiline?                    # => false
Regexp.new('.', Regexp::MULTILINE).multiline? # => true

Rails utilise cette méthode à un seul endroit, également dans le code de routage. Les expressions régulières multilignes sont interdites pour les exigences de route et ce drapeau facilite l'application de cette contrainte.

def verify_regexp_requirements(requirements)
  # ...
  if requirement.multiline?
    raise ArgumentError, "Regexp multiline option is not allowed in routing requirements: #{requirement.inspect}"
  end
  # ...
end

Défini dans active_support/core_ext/regexp.rb.

14 Extensions à Range

14.1 to_fs

Active Support définit Range#to_fs comme une alternative à to_s qui comprend un argument de format optionnel. Au moment de la rédaction de cet article, le seul format non par défaut pris en charge est :db:

(Date.today..Date.tomorrow).to_fs
# => "2009-10-25..2009-10-26"

(Date.today..Date.tomorrow).to_fs(:db)
# => "BETWEEN '2009-10-25' AND '2009-10-26'"

Comme l'exemple le montre, le format :db génère une clause SQL BETWEEN. Cela est utilisé par Active Record dans son support des valeurs de plage dans les conditions.

Défini dans active_support/core_ext/range/conversions.rb.

14.2 === et include?

Les méthodes Range#=== et Range#include? indiquent si une valeur se situe entre les extrémités d'une instance donnée:

(2..3).include?(Math::E) # => true

Active Support étend ces méthodes de sorte que l'argument puisse être à son tour une autre plage. Dans ce cas, nous testons si les extrémités de la plage d'argument appartiennent elles-mêmes au receveur:

(1..10) === (3..7)  # => true
(1..10) === (0..7)  # => false
(1..10) === (3..11) # => false
(1...9) === (3..9)  # => false

(1..10).include?(3..7)  # => true
(1..10).include?(0..7)  # => false
(1..10).include?(3..11) # => false
(1...9).include?(3..9)  # => false

Défini dans active_support/core_ext/range/compare_range.rb.

14.3 overlap?

La méthode Range#overlap? indique si deux plages données ont une intersection non vide:

(1..10).overlap?(7..11)  # => true
(1..10).overlap?(0..7)   # => true
(1..10).overlap?(11..27) # => false

Défini dans active_support/core_ext/range/overlap.rb.

15 Extensions à Date

15.1 Calculs

Les méthodes de calcul suivantes ont des cas particuliers en octobre 1582, car les jours 5 à 14 n'existent tout simplement pas. Ce guide ne documente pas leur comportement autour de ces jours pour des raisons de concision, mais il suffit de dire qu'ils font ce que vous attendez. C'est-à-dire que Date.new(1582, 10, 4).tomorrow renvoie Date.new(1582, 10, 15) et ainsi de suite. Veuillez consulter test/core_ext/date_ext_test.rb dans la suite de tests Active Support pour connaître le comportement attendu.

15.1.1 Date.current

Active Support définit Date.current comme étant aujourd'hui dans le fuseau horaire actuel. C'est comme Date.today, sauf qu'il respecte le fuseau horaire de l'utilisateur, s'il est défini. Il définit également Date.yesterday et Date.tomorrow, ainsi que les prédicats d'instance past?, today?, tomorrow?, next_day?, yesterday?, prev_day?, future?, on_weekday? et on_weekend?, tous relatifs à Date.current.

Lorsque vous effectuez des comparaisons de dates en utilisant des méthodes qui respectent le fuseau horaire de l'utilisateur, assurez-vous d'utiliser Date.current et non Date.today. Il existe des cas où le fuseau horaire de l'utilisateur peut être dans le futur par rapport au fuseau horaire du système, que Date.today utilise par défaut. Cela signifie que Date.today peut être égal à Date.yesterday.

Défini dans active_support/core_ext/date/calculations.rb.

15.1.2 Dates nommées

15.1.2.1 beginning_of_week, end_of_week

Les méthodes beginning_of_week et end_of_week renvoient les dates du début et de la fin de la semaine, respectivement. On suppose que les semaines commencent le lundi, mais cela peut être modifié en passant un argument, en définissant Date.beginning_of_week en tant que variable locale ou config.beginning_of_week.

d = Date.new(2010, 5, 8)     # => Sat, 08 May 2010
d.beginning_of_week          # => Mon, 03 May 2010
d.beginning_of_week(:sunday) # => Sun, 02 May 2010
d.end_of_week                # => Sun, 09 May 2010
d.end_of_week(:sunday)       # => Sat, 08 May 2010

beginning_of_week est un alias de at_beginning_of_week et end_of_week est un alias de at_end_of_week.

Défini dans active_support/core_ext/date_and_time/calculations.rb.

15.1.2.2 monday, sunday

Les méthodes monday et sunday renvoient les dates du lundi précédent et du dimanche suivant, respectivement. ruby date = Date.new(2010, 6, 7) date.months_ago(3) # => Mon, 07 Mar 2010 date.months_since(3) # => Thu, 07 Sep 2010

If such a day does not exist, the last day of the corresponding month is returned:

Date.new(2012, 3, 31).months_ago(1)     # => Thu, 29 Feb 2012
Date.new(2012, 1, 31).months_since(1)   # => Wed, 29 Feb 2012

last_month is short-hand for #months_ago(1).

15.1.2.3 weeks_ago, weeks_since

The methods weeks_ago and [weeks_since][DateAndTime::Calculations#weeks_since] work analogously for weeks:

date = Date.new(2010, 6, 7)
date.weeks_ago(2)   # => Mon, 24 May 2010
date.weeks_since(2) # => Mon, 21 Jun 2010

last_week is short-hand for #weeks_ago(1).

15.1.2.4 days_ago, days_since

The methods [days_ago][DateAndTime::Calculations#days_ago] and [days_since][DateAndTime::Calculations#days_since] work analogously for days:

date = Date.new(2010, 6, 7)
date.days_ago(5)   # => Wed, 02 Jun 2010
date.days_since(5) # => Sat, 12 Jun 2010

[yesterday][DateAndTime::Calculations#yesterday] is short-hand for #days_ago(1), and [tomorrow][DateAndTime::Calculations#tomorrow] is short-hand for #days_since(1).

The method end_of_minute returns a timestamp at the end of the minute (hh:mm:59):

date = DateTime.new(2010, 6, 7, 19, 55, 25)
date.end_of_minute # => Mon Jun 07 19:55:59 +0200 2010

beginning_of_minute is aliased to at_beginning_of_minute.

La méthode end_of_minute renvoie un horodatage à la fin de la minute (hh:mm:59):

date = DateTime.new(2010, 6, 7, 19, 55, 25)
date.end_of_minute # => Lun Jun 07 19:55:59 +0200 2010

beginning_of_minute est un alias de at_beginning_of_minute.

beginning_of_hour, end_of_hour, beginning_of_minute et end_of_minute sont implémentés pour Time et DateTime mais pas pour Date car il n'a pas de sens de demander le début ou la fin d'une heure ou d'une minute sur une instance de Date.

Défini dans active_support/core_ext/date_time/calculations.rb.

15.1.2.5 ago, since

La méthode ago reçoit un nombre de secondes en argument et renvoie un horodatage correspondant à il y a autant de secondes depuis minuit :

date = Date.current # => Ven, 11 Jun 2010
date.ago(1)         # => Jeu, 10 Jun 2010 23:59:59 EDT -04:00

De même, since avance dans le temps :

date = Date.current # => Ven, 11 Jun 2010
date.since(1)       # => Ven, 11 Jun 2010 00:00:01 EDT -04:00

Défini dans active_support/core_ext/date/calculations.rb.

16 Extensions pour DateTime

AVERTISSEMENT : DateTime ne tient pas compte des règles relatives à l'heure d'été, de sorte que certaines de ces méthodes ont des cas particuliers lorsqu'un changement d'heure d'été est en cours. Par exemple, seconds_since_midnight peut ne pas renvoyer la véritable quantité dans un tel jour.

16.1 Calculs

La classe DateTime est une sous-classe de Date, donc en chargeant active_support/core_ext/date/calculations.rb, vous héritez de ces méthodes et de leurs alias, à l'exception qu'elles renverront toujours des datetimes.

Les méthodes suivantes sont réimplémentées afin que vous n'ayez pas besoin de charger active_support/core_ext/date/calculations.rb pour celles-ci :

En revanche, advance et change sont également définis et prennent en charge plus d'options, ils sont documentés ci-dessous.

Les méthodes suivantes sont uniquement implémentées dans active_support/core_ext/date_time/calculations.rb, car elles n'ont de sens que lorsqu'elles sont utilisées avec une instance de DateTime :

16.1.1 Datetimes nommés

16.1.1.1 DateTime.current

Active Support définit DateTime.current pour être similaire à Time.now.to_datetime, à l'exception qu'il respecte le fuseau horaire de l'utilisateur, s'il est défini. Les prédicats d'instance past? et future? sont définis par rapport à DateTime.current.

Défini dans active_support/core_ext/date_time/calculations.rb.

16.1.2 Autres extensions

16.1.2.1 seconds_since_midnight

La méthode seconds_since_midnight renvoie le nombre de secondes depuis minuit :

now = DateTime.current     # => Lun, 07 Jun 2010 20:26:36 +0000
now.seconds_since_midnight # => 73596

Défini dans active_support/core_ext/date_time/calculations.rb.

16.1.2.2 utc

La méthode utc vous donne le même datetime dans le récepteur exprimé en UTC.

now = DateTime.current # => Lun, 07 Jun 2010 19:27:52 -0400
now.utc                # => Lun, 07 Jun 2010 23:27:52 +0000

Cette méthode est également un alias de getutc.

Défini dans active_support/core_ext/date_time/calculations.rb.

16.1.2.3 utc?

Le prédicat utc? indique si le récepteur a UTC comme fuseau horaire :

now = DateTime.now # => Lun, 07 Jun 2010 19:30:47 -0400
now.utc?           # => false
now.utc.utc?       # => true

Défini dans active_support/core_ext/date_time/calculations.rb.

16.1.2.4 advance

La façon la plus générique de passer à un autre datetime est advance. Cette méthode reçoit un hash avec les clés :years, :months, :weeks, :days, :hours, :minutes et :seconds, et renvoie un datetime avancé autant que les clés actuelles l'indiquent. ```ruby d = DateTime.current

=> Jeu, 05 Août 2010 11:33:31 +0000

d.advance(years: 1, months: 1, days: 1, hours: 1, minutes: 1, seconds: 1)

=> Mar, 06 Septembre 2011 12:34:32 +0000


Cette méthode calcule d'abord la date de destination en passant `:years`, `:months`, `:weeks` et `:days` à `Date#advance` documenté ci-dessus. Ensuite, elle ajuste l'heure en appelant [`since`][DateTime#since] avec le nombre de secondes à avancer. Cet ordre est important, un ordre différent donnerait des datetimes différents dans certains cas particuliers. L'exemple dans `Date#advance` s'applique, et nous pouvons l'étendre pour montrer l'importance de l'ordre par rapport aux bits de temps.

Si nous déplaçons d'abord les bits de date (qui ont également un ordre relatif de traitement, comme documenté précédemment), puis les bits de temps, nous obtenons par exemple le calcul suivant :

```ruby
d = DateTime.new(2010, 2, 28, 23, 59, 59)
# => Dim, 28 Février 2010 23:59:59 +0000
d.advance(months: 1, seconds: 1)
# => Lun, 29 Mars 2010 00:00:00 +0000

mais si nous les calculons dans l'autre sens, le résultat serait différent :

d.advance(seconds: 1).advance(months: 1)
# => Jeu, 01 Avril 2010 00:00:00 +0000

AVERTISSEMENT : Étant donné que DateTime ne tient pas compte de l'heure d'été, vous pouvez vous retrouver à un moment qui n'existe pas sans aucun avertissement ou erreur vous le signalant.

REMARQUE : Défini dans active_support/core_ext/date_time/calculations.rb.

16.1.3 Modification des composants

La méthode change vous permet d'obtenir un nouveau datetime qui est identique au récepteur à l'exception des options données, qui peuvent inclure :year, :month, :day, :hour, :min, :sec, :offset, :start :

now = DateTime.current
# => Mar, 08 Juin 2010 01:56:22 +0000
now.change(year: 2011, offset: Rational(-6, 24))
# => Mer, 08 Juin 2011 01:56:22 -0600

Si les heures sont mises à zéro, les minutes et les secondes le sont aussi (sauf si elles ont des valeurs données) :

now.change(hour: 0)
# => Mar, 08 Juin 2010 00:00:00 +0000

De même, si les minutes sont mises à zéro, les secondes le sont aussi (sauf si une valeur est donnée) :

now.change(min: 0)
# => Mar, 08 Juin 2010 01:00:00 +0000

Cette méthode ne tolère pas les dates inexistantes, si le changement est invalide, une ArgumentError est levée :

DateTime.current.change(month: 2, day: 30)
# => ArgumentError: date invalide

REMARQUE : Défini dans active_support/core_ext/date_time/calculations.rb.

16.1.4 Durées

Les objets Duration peuvent être ajoutés et soustraits des datetimes :

now = DateTime.current
# => Lun, 09 Août 2010 23:15:17 +0000
now + 1.year
# => Mar, 09 Août 2011 23:15:17 +0000
now - 1.week
# => Lun, 02 Août 2010 23:15:17 +0000

Ils se traduisent par des appels à since ou advance. Par exemple, ici nous obtenons le bon saut dans la réforme du calendrier :

DateTime.new(1582, 10, 4, 23) + 1.hour
# => Ven, 15 Octobre 1582 00:00:00 +0000

17 Extensions à Time

17.1 Calculs

Ils sont analogues. Veuillez vous référer à leur documentation ci-dessus et prendre en compte les différences suivantes :

  • change accepte une option supplémentaire :usec.
  • Time comprend l'heure d'été, vous obtenez donc des calculs d'heure d'été corrects comme dans l'exemple suivant :
Time.zone_default
# => #<ActiveSupport::TimeZone:0x7f73654d4f38 @utc_offset=nil, @name="Madrid", ...>

# À Barcelone, le 28/03/2010 02:00 +0100 devient le 28/03/2010 03:00 +0200 en raison de l'heure d'été.
t = Time.local(2010, 3, 28, 1, 59, 59)
# => Dim Mar 28 01:59:59 +0100 2010
t.advance(seconds: 1)
# => Dim Mar 28 03:00:00 +0200 2010
  • Si since ou ago saute à un moment qui ne peut pas être exprimé avec Time, un objet DateTime est renvoyé à la place.

17.1.1 Time.current

Active Support définit Time.current pour être aujourd'hui dans le fuseau horaire actuel. C'est comme Time.now, sauf qu'il respecte le fuseau horaire de l'utilisateur, s'il est défini. Il définit également les prédicats d'instance past?, today?, tomorrow?, next_day?, yesterday?, prev_day? et future?, tous relatifs à Time.current.

Lorsque vous effectuez des comparaisons de temps en utilisant des méthodes qui respectent le fuseau horaire de l'utilisateur, assurez-vous d'utiliser Time.current au lieu de Time.now. Il y a des cas où le fuseau horaire de l'utilisateur peut être dans le futur par rapport au fuseau horaire du système, que Time.now utilise par défaut. Cela signifie que Time.now.to_date peut être égal à Date.yesterday.

NOTE : Défini dans active_support/core_ext/time/calculations.rb.

17.1.2 all_day, all_week, all_month, all_quarter et all_year

La méthode all_day renvoie une plage représentant toute la journée du moment actuel.

now = Time.current
# => Mon, 09 Aug 2010 23:20:05 UTC +00:00
now.all_day
# => Mon, 09 Aug 2010 00:00:00 UTC +00:00..Mon, 09 Aug 2010 23:59:59 UTC +00:00

De manière analogue, all_week, all_month, all_quarter et all_year servent tous à générer des plages de temps.

now = Time.current
# => Mon, 09 Aug 2010 23:20:05 UTC +00:00
now.all_week
# => Mon, 09 Aug 2010 00:00:00 UTC +00:00..Sun, 15 Aug 2010 23:59:59 UTC +00:00
now.all_week(:sunday)
# => Sun, 16 Sep 2012 00:00:00 UTC +00:00..Sat, 22 Sep 2012 23:59:59 UTC +00:00
now.all_month
# => Sat, 01 Aug 2010 00:00:00 UTC +00:00..Tue, 31 Aug 2010 23:59:59 UTC +00:00
now.all_quarter
# => Thu, 01 Jul 2010 00:00:00 UTC +00:00..Thu, 30 Sep 2010 23:59:59 UTC +00:00
now.all_year
# => Fri, 01 Jan 2010 00:00:00 UTC +00:00..Fri, 31 Dec 2010 23:59:59 UTC +00:00

NOTE : Défini dans active_support/core_ext/date_and_time/calculations.rb.

17.1.3 prev_day, next_day

prev_day et next_day renvoient le moment du jour précédent ou suivant :

t = Time.new(2010, 5, 8) # => 2010-05-08 00:00:00 +0900
t.prev_day               # => 2010-05-07 00:00:00 +0900
t.next_day               # => 2010-05-09 00:00:00 +0900

NOTE : Défini dans active_support/core_ext/time/calculations.rb.

17.1.4 prev_month, next_month

prev_month et next_month renvoient le moment avec le même jour dans le mois précédent ou suivant :

t = Time.new(2010, 5, 8) # => 2010-05-08 00:00:00 +0900
t.prev_month             # => 2010-04-08 00:00:00 +0900
t.next_month             # => 2010-06-08 00:00:00 +0900

Si un tel jour n'existe pas, le dernier jour du mois correspondant est renvoyé :

Time.new(2000, 5, 31).prev_month # => 2000-04-30 00:00:00 +0900
Time.new(2000, 3, 31).prev_month # => 2000-02-29 00:00:00 +0900
Time.new(2000, 5, 31).next_month # => 2000-06-30 00:00:00 +0900
Time.new(2000, 1, 31).next_month # => 2000-02-29 00:00:00 +0900

NOTE : Défini dans active_support/core_ext/time/calculations.rb.

17.1.5 prev_year, next_year

prev_year et next_year renvoient un moment avec le même jour/mois dans l'année précédente ou suivante :

t = Time.new(2010, 5, 8) # => 2010-05-08 00:00:00 +0900
t.prev_year              # => 2009-05-08 00:00:00 +0900
t.next_year              # => 2011-05-08 00:00:00 +0900

Si la date est le 29 février d'une année bissextile, vous obtenez le 28 :

t = Time.new(2000, 2, 29) # => 2000-02-29 00:00:00 +0900
t.prev_year               # => 1999-02-28 00:00:00 +0900
t.next_year               # => 2001-02-28 00:00:00 +0900

Défini dans active_support/core_ext/time/calculations.rb.

17.1.6 prev_quarter, next_quarter

prev_quarter et next_quarter renvoient la date avec le même jour du trimestre précédent ou suivant:

t = Time.local(2010, 5, 8) # => 2010-05-08 00:00:00 +0300
t.prev_quarter             # => 2010-02-08 00:00:00 +0200
t.next_quarter             # => 2010-08-08 00:00:00 +0300

Si un tel jour n'existe pas, le dernier jour du mois correspondant est renvoyé:

Time.local(2000, 7, 31).prev_quarter  # => 2000-04-30 00:00:00 +0300
Time.local(2000, 5, 31).prev_quarter  # => 2000-02-29 00:00:00 +0200
Time.local(2000, 10, 31).prev_quarter # => 2000-07-31 00:00:00 +0300
Time.local(2000, 11, 31).next_quarter # => 2001-03-01 00:00:00 +0200

prev_quarter est un alias de last_quarter.

Défini dans active_support/core_ext/date_and_time/calculations.rb.

17.2 Constructeurs de temps

Active Support définit Time.current comme Time.zone.now s'il existe un fuseau horaire utilisateur défini, avec une fallback à Time.now:

Time.zone_default
# => #<ActiveSupport::TimeZone:0x7f73654d4f38 @utc_offset=nil, @name="Madrid", ...>
Time.current
# => Fri, 06 Aug 2010 17:11:58 CEST +02:00

De manière analogue à DateTime, les prédicats past? et future? sont relatifs à Time.current.

Si le temps à construire se situe en dehors de la plage supportée par Time dans la plateforme d'exécution, les microsecondes sont ignorées et un objet DateTime est renvoyé à la place.

17.2.1 Durées

Les objets Duration peuvent être ajoutés et soustraits des objets temps:

now = Time.current
# => Mon, 09 Aug 2010 23:20:05 UTC +00:00
now + 1.year
# => Tue, 09 Aug 2011 23:21:11 UTC +00:00
now - 1.week
# => Mon, 02 Aug 2010 23:21:11 UTC +00:00

Ils se traduisent par des appels à since ou advance. Par exemple, ici nous obtenons le bon saut dans la réforme du calendrier:

Time.utc(1582, 10, 3) + 5.days
# => Mon Oct 18 00:00:00 UTC 1582

18 Extensions à File

18.1 atomic_write

Avec la méthode de classe File.atomic_write, vous pouvez écrire dans un fichier d'une manière qui empêchera tout lecteur de voir un contenu partiellement écrit.

Le nom du fichier est passé en argument, et la méthode renvoie une poignée de fichier ouverte en écriture. Une fois que le bloc est terminé, atomic_write ferme la poignée de fichier et termine son travail.

Par exemple, Action Pack utilise cette méthode pour écrire des fichiers de cache d'actifs comme all.css:

File.atomic_write(joined_asset_path) do |cache|
  cache.write(join_asset_file_contents(asset_paths))
end

Pour accomplir cela, atomic_write crée un fichier temporaire. C'est le fichier sur lequel le code dans le bloc écrit réellement. À la fin, le fichier temporaire est renommé, ce qui est une opération atomique sur les systèmes POSIX. Si le fichier cible existe, atomic_write le remplace et conserve les propriétaires et les permissions. Cependant, il existe quelques cas où atomic_write ne peut pas modifier la propriété ou les permissions du fichier, cette erreur est capturée et ignorée en faisant confiance à l'utilisateur/système de fichiers pour s'assurer que le fichier est accessible aux processus qui en ont besoin.

En raison de l'opération chmod que atomic_write effectue, si le fichier cible a un ACL défini dessus, cet ACL sera recalculé/modifié.

AVERTISSEMENT. Notez que vous ne pouvez pas ajouter avec atomic_write.

Le fichier auxiliaire est écrit dans un répertoire standard pour les fichiers temporaires, mais vous pouvez passer un répertoire de votre choix en deuxième argument.

Défini dans active_support/core_ext/file/atomic.rb.

19 Extensions à NameError

Active Support ajoute missing_name? à NameError, qui teste si l'exception a été levée en raison du nom passé en argument.

Le nom peut être donné sous forme de symbole ou de chaîne de caractères. Un symbole est testé par rapport au nom de constante nu, une chaîne de caractères est testée par rapport au nom de constante entièrement qualifié.

CONSEIL : Un symbole peut représenter un nom de constante entièrement qualifié comme dans :"ActiveRecord::Base", donc le comportement pour les symboles est défini pour plus de commodité, et non parce que cela doit être ainsi techniquement.

Par exemple, lorsque l'action d'un ArticlesController est appelée, Rails essaie de manière optimiste d'utiliser ArticlesHelper. Il est normal que le module d'aide n'existe pas, donc si une exception est levée pour ce nom de constante, elle doit être ignorée. Mais il se peut que articles_helper.rb lève une NameError en raison d'une constante inconnue réelle. Dans ce cas, elle doit être relancée. La méthode missing_name? permet de distinguer ces deux cas :

def default_helper_module!
  module_name = name.delete_suffix("Controller")
  module_path = module_name.underscore
  helper module_path
rescue LoadError => e
  raise e unless e.is_missing? "helpers/#{module_path}_helper"
rescue NameError => e
  raise e unless e.missing_name? "#{module_name}Helper"
end

NOTE : Défini dans active_support/core_ext/name_error.rb.

20 Extensions à LoadError

Active Support ajoute is_missing? à LoadError.

Étant donné un nom de chemin, is_missing? teste si l'exception a été levée en raison de ce fichier particulier (sauf peut-être pour l'extension ".rb").

Par exemple, lorsque l'action d'un ArticlesController est appelée, Rails essaie de charger articles_helper.rb, mais ce fichier peut ne pas exister. C'est normal, le module d'aide n'est pas obligatoire, donc Rails ignore une erreur de chargement. Mais il se peut que le module d'aide existe et nécessite à son tour une autre bibliothèque qui est manquante. Dans ce cas, Rails doit relancer l'exception. La méthode is_missing? permet de distinguer ces deux cas :

def default_helper_module!
  module_name = name.delete_suffix("Controller")
  module_path = module_name.underscore
  helper module_path
rescue LoadError => e
  raise e unless e.is_missing? "helpers/#{module_path}_helper"
rescue NameError => e
  raise e unless e.missing_name? "#{module_name}Helper"
end

NOTE : Défini dans active_support/core_ext/load_error.rb.

21 Extensions à Pathname

21.1 existence

La méthode existence renvoie le récepteur si le fichier nommé existe, sinon elle renvoie nil. Elle est utile pour des idiomes comme celui-ci :

content = Pathname.new("file").existence&.read

NOTE : Défini dans active_support/core_ext/pathname/existence.rb.

Retour d'information

Vous êtes encouragé à contribuer à l'amélioration de la qualité de ce guide.

Veuillez contribuer si vous trouvez des fautes de frappe ou des erreurs factuelles. Pour commencer, vous pouvez lire notre contribution à la documentation section.

Vous pouvez également trouver du contenu incomplet ou des informations qui ne sont pas à jour. Veuillez ajouter toute documentation manquante pour la version principale. Assurez-vous de vérifier Edge Guides d'abord pour vérifier si les problèmes ont déjà été résolus ou non sur la branche principale. Consultez les Directives des guides Ruby on Rails pour le style et les conventions.

Si pour une raison quelconque vous repérez quelque chose à corriger mais ne pouvez pas le faire vous-même, veuillez ouvrir un problème.

Et enfin, toute discussion concernant la documentation de Ruby on Rails est la bienvenue sur le Forum officiel de Ruby on Rails.