Más en rubyonrails.org: Más Ruby on Rails

NO LEA ESTE ARCHIVO EN GITHUB, LAS GUÍAS SE PUBLICAN EN https://guides.rubyonrails.org.

Extensiones de Núcleo de Active Support

Active Support es el componente Ruby on Rails responsable de proporcionar extensiones de lenguaje Ruby, utilidades y otras cosas transversales.

Ofrece un resultado final más rico a nivel de lenguaje, dirigido tanto al desarrollo de aplicaciones Rails como al desarrollo de Ruby on Rails.

Después de leer esta guía, sabrá:

1 How to Load Core Extensions

1.1 Stand-Alone Active Support

Para tener una huella predeterminada cercana a cero, Active Support no carga nada de forma predeterminada. Está dividido en pedazos pequeños para que pueda cargar justo lo que necesita, y también tiene algunos puntos de entrada convenientes para cargar extensiones relacionadas de una sola vez, incluso todo.

Por lo tanto, después de un simple requerimiento como:

require "active_support"

objects do not even respond to blank?. Let's see how to load its definition.

1.1.1 Cherry-picking a Definition

La forma más ligera de dejar blank? es seleccionar el archivo que lo define.

Para cada método definido como una extensión principal, esta guía tiene una nota que dice dónde se define dicho método. En el caso de blank?, La nota dice:

Definido en active_support/core_ext/object/blank.rb.

Eso significa que puede solicitarlo así:

require "active_support"
require "active_support/core_ext/object/blank"

Active Support se ha revisado cuidadosamente para que la selección de un archivo solo cargue las dependencias estrictamente necesarias, si las hubiera.

1.1.2 Loading Grouped Core Extensions

El siguiente nivel es simplemente cargar todas las extensiones en Object. Como regla general, las extensiones de SomeClass están disponibles de una sola vez cargando active_support/core_ext/some_class.

Por lo tanto, para cargar todas las extensiones a Object (incluyendo blank?):

require "active_support"
require "active_support/core_ext/object"
1.1.3 Loading All Core Extensions

Es posible que prefiera cargar todas las extensiones principales, hay un archivo para eso:

require "active_support"
require "active_support/core_ext"
1.1.4 Loading All Active Support

Y finalmente, si desea tener disponible todo el Soporte activo, simplemente emita:

require "active_support/all"

Eso ni siquiera pone todo el Active Support en la memoria por adelantado, de hecho, algunas cosas se configuran mediante autoload, por lo que solo se carga si se usa.

1.2 Active Support Within a Ruby on Rails Application

Una aplicación Ruby on Rails carga todo el soporte activo a menos que config.active_support.bare sea verdadero. En ese caso, la aplicación solo cargará lo que el propio marco elija para sus propias necesidades, y aún puede hacerlo en cualquier nivel de granularidad, como se explicó en la sección anterior.

2 Extensions to All Objects

2.1 blank? and present?

The following values are considered to be blank in a Rails application:

  • nil yfalse,

  • cadenas compuestas solo de espacios en blanco (ver nota a continuación),

  • matrices y hashes vacíos, y

  • cualquier otro objeto que responda a "¿vacío?" y esté vacío.

El predicado para cadenas utiliza la clase de caracteres compatible con Unicode [:space:], por lo que, por ejemplo, U + 2029 (separador de párrafo) se considera un espacio en blanco.

Tenga en cuenta que no se mencionan los números. En particular, 0 y 0.0 son ** no ** en blanco.

Por ejemplo, este método de ActionController::HttpAuthentication::Token::ControllerMethods usa blank? Para verificar si un token está presente:

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

El método present? Es equivalente a !blank?. Este ejemplo está tomado de ActionDispatch::Http::Cache::Response:

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

Definido en active_support/core_ext/object/blank.rb.

2.2 presence

El método presence devuelve su receptor si present? y nil en caso contrario. Es útil para modismos como este:

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

Definido en active_support/core_ext/object/blank.rb.

2.3 duplicable?

A partir de Ruby 2.5, la mayoría de los objetos se pueden duplicar mediante dup o 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 proporciona duplicable? Para consultar un objeto sobre esto:

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

Cualquier clase puede prohibir la duplicación eliminando dup y clone o generando excepciones. Por lo tanto, solo "rescue" puede decir si un objeto arbitrario dado es duplicable. duplicable? depende de la lista codificada anterior, pero es mucho más rápido que rescue. Úselo solo si sabe que la lista codificada es suficiente en su caso de uso.

Definido en active_support/core_ext/object/duplicable.rb.

3 deep_dup

The deep_dup El método devuelve una copia profunda de un objeto dado. Normalmente, cuando dup un objeto que contiene otros objetos, Ruby no los "duplica", por lo que crea una copia superficial del objeto. Si tiene una matriz con una cadena, por ejemplo, se verá así:

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

duplicate.push 'another-string'

# the object was duplicated, so the element was added only to the duplicate
array     # => ['string']
duplicate # => ['string', 'another-string']

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

# first element was not duplicated, it will be changed in both arrays
array     # => ['foo']
duplicate # => ['foo', 'another-string']

Como puede ver, después de duplicar la instancia de Array, obtuvimos otro objeto, por lo tanto, podemos modificarlo y el objeto original permanecerá sin cambios. Sin embargo, esto no es cierto para los elementos de la matriz. Dado que dup no hace una copia profunda, la cadena dentro de la matriz sigue siendo el mismo objeto.

Si necesita una copia profunda de un objeto, debe usar deep_dup. Aquí hay un ejemplo:

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

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

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

Si el objeto no es duplicable, deep_dup simplemente lo devolverá:

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

Definido en active_support/core_ext/object/deep_dup.rb.

3.1 try

Cuando desea llamar a un método en un objeto solo si no es nil, la forma más sencilla de lograrlo es con declaraciones condicionales, agregando desorden innecesario. La alternativa es usar try. try es comoObject # send excepto que devuelve nil si se envía anil.

Aquí hay un ejemplo:

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

# with try
@number.try(:next)

Otro ejemplo es este código de ActiveRecord::ConnectionAdapters::AbstractAdapter donde @logger podría sernil. Puede ver que el código usa try y evita una verificación innecesaria.

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 también se puede llamar sin argumentos pero un bloque, que solo se ejecutará si el objeto no es nil:

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

Tenga en cuenta que try se tragará los errores sin método, devolviendo nil en su lugar. Si desea protegerse contra errores tipográficos, utilice try! En su lugar:

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

Definido en active_support/core_ext/object/try.rb.

3.2 class_eval(*args, &block)

Puede evaluar código en el contexto de la clase singleton de cualquier objeto usando 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

Definido en active_support/core_ext/kernel/singleton_class.rb.

3.3 acts_like?(duck)

El método acts_libe? Proporciona una manera de comprobar si alguna clase actúa como otra clase basándose en una convención simple: una clase que proporciona la misma interfaz que define String

def acts_like_string?
end

que es solo un marcador, su cuerpo o valor de retorno son irrelevantes. Luego, el código del cliente puede consultar la seguridad del tipo pato de esta manera:

some_klass.acts_like?(:string)

Rails tiene clases que actúan como Date o Time y siguen este contrato.

Definido en active_support/core_ext/object/acts_like.rb.

3.4 to_param

Todos los objetos en Rails responden al método to_param, que está destinado a devolver algo que los represente como valores en una cadena de consulta o como fragmentos de URL.

Por defecto, to_param solo llama a to_s:

7.to_param # => "7"

El valor de retorno de to_param no debe escaparse:

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

Varias clases de Rails sobrescriben este método.

Por ejemplo, nil,true y false se devuelven ellos mismos. Array#to_param llama a to_param en los elementos y une el resultado con "/":

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

En particular, el sistema de enrutamiento Rails llama a to_param en los modelos para obtener un valor para el marcador de posición: id. ActiveRecord :: Base # to_param devuelve el id de un modelo, pero puedes redefinir ese método en tus modelos. Por ejemplo, dado

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

Nosotras obtenemos:

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

ADVERTENCIA. Los controladores deben estar al tanto de cualquier redefinición de to_param porque cuando una solicitud como esa viene en "357-john-smith" es el valor de params[:id].

NOTA: Definido en active_support/core_ext/object/to_param.rb.

3.5 to_query

A excepción de los hash, dada una key sin escape, este método construye la parte de una cadena de consulta que mapeará dicha clave a lo que devuelve to_param. Por ejemplo, dado

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

Nosotras obtenemos:

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

Este método escapa a lo que sea necesario, tanto para la clave como para el valor:

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

por lo que su salida está lista para usarse en una cadena de consulta.

Las matrices devuelven el resultado de aplicar to_query a cada elemento con key[] como clave, y unen el resultado con "&":

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

Los hash también responden a to_query pero con una firma diferente. Si no se pasa ningún argumento, una llamada genera una serie ordenada de asignaciones de clave / valor que llaman a to_query(key) en sus valores. Luego une el resultado con "&":

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

El método Hash#to_query acepta un espacio de nombre opcional para las claves:

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

NOTA: Definido en active_support/core_ext/object/to_query.rb.

3.6 with_options

El método with_options proporciona una manera de descartar opciones comunes en una serie de llamadas a métodos.

Dado un hash de opciones predeterminado, with_options cede un objeto proxy a un bloque. Dentro del bloque, los métodos llamados en el proxy se envían al receptor con sus opciones fusionadas. Por ejemplo, se deshace de la duplicación en:

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 esta manera:

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

Ese idioma también puede transmitir grouping al lector. Por ejemplo, digamos que desea enviar un boletín cuyo idioma depende del usuario. En algún lugar del correo, podría agrupar bits dependientes de la configuración regional como este:

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

Since with_options forwards calls to its receiver they can be nested. Each nesting level will merge inherited defaults in addition to their own.

Definido en active_support/core_ext/object/with_options.rb.

3.7 JSON support

Active Support proporciona una mejor implementación de to_json que la gem json que normalmente proporciona para los objetos Ruby. Esto se debe a que algunas clases, como Hash, OrderedHash y Process::Status necesitan un manejo especial para proporcionar una representación JSON adecuada.

NOTA: Definido en active_support/core_ext/object/json.rb.

3.8 Instance Variables

Active Support proporciona varios métodos para facilitar el acceso a las variables de instancia.

3.8.1 instance_values

El método instance_values devuelve un hash que asigna los nombres de las variables de instancia sin" @ "a su valores correspondientes. Las claves son cadenas:

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

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

Definido en active_support/core_ext/object/instance_variables.rb.

3.8.2 instance_variable_names

El método instance_variable_names devuelve una matriz. Cada nombre incluye el signo "@".

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

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

Definido en active_support/core_ext/object/instance_variables.rb.

3.9 Silencing Warnings and Exceptions

Los métodos silent_warnings y enable_warnings cambian el valor de $VERBOSE en consecuencia durante la duración de su bloqueo, y lo restablecen después:

silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }

También es posible silenciar las excepciones con suppress. Este método recibe un número arbitrario de clases de excepción. Si se genera una excepción durante la ejecución del bloque y es kind_of? Cualquiera de los argumentos, suppress la captura y regresa silenciosamente. De lo contrario, la excepción no se captura:

# If the user is locked, the increment is lost, no big deal.
suppress(ActiveRecord::StaleObjectError) do
  current_user.increment! :visits
end

Definido en active_support/core_ext/kernel/reporting.rb.

3.10 in?

El predicado in? Prueba si un objeto está incluido en otro objeto. Se generará una excepción ArgumentError si el argumento pasado no responde a include?.

Ejemplos de in?:

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

Definido en active_support/core_ext/object/inclusion.rb.

4 Extensions to Module

4.1 Attributes

4.1.1 alias_attribute
class User < ApplicationRecord
  # You can refer to the email column as "login".
  # This can be meaningful for authentication code.
  alias_attribute :login, :email
end

Definido en active_support/core_ext/module/aliasing.rb.

4.1.2 Internal Attributes

Cuando está definiendo un atributo en una clase que está destinado a ser subclasificado, las colisiones de nombres son un riesgo. Eso es muy importante para las bibliotecas.

Active Support define las macros attr_internal_reader, attr_internal_writer y attr_internal_accessor. Se comportan como sus contrapartes attr_ * incorporadas en Ruby, excepto que nombran la variable de instancia subyacente de una manera que hace que las colisiones sean menos probables.

La macro attr_internal es sinónimo de attr_internal_accessor:

# library
class ThirdPartyLibrary::Crawler
  attr_internal :log_level
end

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

En el ejemplo anterior podría darse el caso de que :log_level no pertenezca a la interfaz pública de la biblioteca y solo se utilice para desarrollo. El código del cliente, inconsciente del posible conflicto, subclasifica y define su propio : log_level. Gracias a attr_internal no hay colisión.

De forma predeterminada, la variable de instancia interna se nombra con un guión bajo inicial, @ _log_level en el ejemplo anterior. Eso se puede configurar a través de Module.attr_internal_naming_format, sin embargo, puede pasar cualquier cadena de formato similar asprintf con una @ inicial y un % s en algún lugar, que es donde se colocará el nombre. El valor predeterminado es " @ _% s ".

Rails usa atributos internos en algunos puntos, como ejemplos de vistas:

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

Definido en active_support/core_ext/module/attr_internal.rb.

4.1.3 Module Attributes

Las macros mattr_reader, mattr_writer y mattr_accessor son las mismas que las macros cattr_ *definidas para la clase. De hecho, las macros cattr_ * son solo alias para las macros mattr_ *. Marque Class Attributes.

Por ejemplo, el mecanismo de dependencias las usa:

module ActiveSupport
  module Dependencies
    mattr_accessor :warnings_on_first_load
    mattr_accessor :history
    mattr_accessor :loaded
    mattr_accessor :mechanism
    mattr_accessor :load_paths
    mattr_accessor :load_once_paths
    mattr_accessor :autoloaded_constants
    mattr_accessor :explicitly_unloadable_constants
    mattr_accessor :constant_watch_stack
    mattr_accessor :constant_watch_stack_mutex
  end
end

active_support/core_ext/module/attribute_accessors.rb.

4.2 Parents

4.2.1 module_parent

El método module_parent en un módulo con nombre anidado devuelve el módulo que contiene su constante correspondiente:

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 el módulo es anónimo o pertenece al nivel superior, module_parent devuelve Object.

Tenga en cuenta que en ese caso module_parent_name devuelve nil.

Definido en active_support/core_ext/module/introspection.rb.

4.2.2 module_parent_name

El método module_parent_name en un módulo con nombre anidado devuelve el nombre completo del módulo que contiene su constante correspondiente:

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"

Para módulos anónimos o de nivel superior, module_parent_name devuelve nil.

Tenga en cuenta que en ese caso module_parent devuelve Object.

Definido en active_support/core_ext/module/introspection.rb.

4.2.3 module_parents

El método module_parents llama a module_parent en el receptor y hacia arriba hasta que se alcanza el Object. La cadena se devuelve en una matriz, de abajo hacia arriba:

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]

Definido en active_support/core_ext/module/introspection.rb.

4.3 Anonymous

Un módulo puede tener o no un nombre:

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

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

Module.new.name # => nil

Puede comprobar si un módulo tiene un nombre con el predicado anonymous?:

module M
end
M.anonymous? # => false

Module.new.anonymous? # => true

Tenga en cuenta que ser inalcanzable no implica ser anónimo:

module M
end

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

m.anonymous? # => false

aunque un módulo anónimo es inalcanzable por definición.

Definido en active_support/core_ext/module/anonymous.rb.

4.4 Method Delegation

4.4.1 delegate

La macro delegate ofrece una manera fácil de reenviar métodos.

Imaginemos que los usuarios de alguna aplicación tienen información de inicio de sesión en el modelo User, pero el nombre y otros datos en un modelo Profile separado:

class User < ApplicationRecord
  has_one :profile
end

Con esa configuración, obtienes el nombre de un usuario a través de su perfil, user.profile.name, pero podría ser útil poder acceder a dicho atributo directamente:

class User < ApplicationRecord
  has_one :profile

  def name
    profile.name
  end
end

Eso es lo que delegate hace por ti:

class User < ApplicationRecord
  has_one :profile

  delegate :name, to: :profile
end

Es más corto y la intención más obvia.

El método debe ser público en el destino.

La macro delegate acepta varios métodos:

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

Cuando se interpola en una cadena, la opción :to debería convertirse en una expresión que evalúe el objeto al que se delega el método. Normalmente una cadena o un símbolo. Tal expresión se evalúa en el contexto del receptor:

# delegates to the Rails constant
delegate :logger, to: :Rails

# delegates to the receiver's class
delegate :table_name, to: :class

Si la opción :prefix es true, esto es menos genérico, ver más abajo.

De forma predeterminada, si la delegación genera "NoMethodError" y el objetivo es "nil", la excepción se propaga. Puede pedir que se devuelva nil en su lugar con la opción :allow_nil:

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

Con :allow_nil la llamada user.name devuelve nil si el usuario no tiene perfil.

La opción :prefix agrega un prefijo al nombre del método generado. Esto puede ser útil, por ejemplo, para obtener un mejor nombre:

delegate :street, to: :address, prefix: true

El ejemplo anterior genera address_street en lugar de street.

Dado que en este caso el nombre del método generado está compuesto por el objeto de destino y los nombres del método de destino, la opción : to debe ser un nombre de método.

También se puede configurar un prefijo personalizado:

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

En el ejemplo anterior, la macro genera avatar_size en lugar de size.

La opción :private cambia el alcance de los métodos:

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

Los métodos delegados son públicos de forma predeterminada. Pase private: true para cambiar eso.

Definido en active_support/core_ext/module/delegation.rb

4.4.2 delegate_missing_to

Imagina que te gustaría delegar todo lo que falta en el objeto User, al de Profile. La macro delegate_missing_to le permite implementar esto en una brisa:

class User < ApplicationRecord
  has_one :profile

  delegate_missing_to :profile
end

El objetivo puede ser cualquier cosa invocable dentro del objeto, p. Ej. variables de instancia, métodos, constantes, etc. Sólo se delegan los métodos públicos del objetivo.

Definido en active_support/core_ext/module/delegation.rb.

4.5 Redefining Methods

Hay casos en los que necesitas definir un método con define_method, pero no sabes si ya existe un método con ese nombre. Si es así, se emite una advertencia si están habilitados. No es gran cosa, pero tampoco limpia.

El método redefine_method previene tal advertencia potencial, eliminando el método existente antes si es necesario.

También puede usar silent_redefinition_of_method si necesita definir el método de reemplazo usted mismo (porque está usando delegate, para ejemplo).

Definido en active_support/core_ext/module/redefine_method.rb.

5 Extensions to Class

5.1 Class Attributes

5.1.1 class_attribute

El método class_attribute declara uno o más atributos de clase heredables que pueden anularse en cualquier nivel de la jerarquía.

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

Por ejemplo, ActionMailer::Base define:

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

También se puede acceder a ellos y anularlos a nivel de instancia.

A.x = 1

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

a1.x # => 1, comes from A
a2.x # => 2, overridden in a2

La generación del método de instancia de escritor se puede evitar configurando la opción :instance_writer en false.

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

Un modelo puede encontrar esa opción útil como una forma de evitar que la asignación masiva establezca el atributo.

La generación del método de la instancia del lector puede evitarse configurando la opción :instance_reader en false.

class A
  class_attribute :x, instance_reader: false
end

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

Por conveniencia, class_attribute también define un predicado de instancia que es la doble negación de lo que devuelve el lector de instancias. En los ejemplos anteriores se llamaría x?.

Cuando :instance_reader es false, el predicado de instancia devuelve un NoMethodError al igual que el método reader.

Si no desea el predicado de instancia, pase instance_predicate: false y no se definirá.

Definido en active_support/core_ext/class/attribute.rb.

5.1.2 cattr_reader, cattr_writer, and cattr_accessor

Las macros cattr_reader,cattr_writer y cattr_accessor son análogas a sus contrapartesattr_ *pero para clases. Inicializan una variable de clase en nil a menos que ya exista, y generan los métodos de clase correspondientes para acceder a ella:

class MysqlAdapter < AbstractAdapter
  # Generates class methods to access @@emulate_booleans.
  cattr_accessor :emulate_booleans
end

Además, puede pasar un bloque a cattr_ * para configurar el atributo con un valor predeterminado:

class MysqlAdapter < AbstractAdapter
  # Generates class methods to access @@emulate_booleans with default value of true.
  cattr_accessor :emulate_booleans, default: true
end

Los métodos de instancia también se crean por conveniencia, son solo sustitutos del atributo de clase. Por lo tanto, las instancias pueden cambiar el atributo de clase, pero no pueden anularlo como sucede con class_attribute (ver más arriba). Por ejemplo dado

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

podemos acceder a field_error_proc en las vistas.

La generación del método de instancia del lector se puede evitar configurando :instance_reader en false y la generación del método de instancia del escritor se puede evitar configurando :instance_writer en false. La generación de ambos métodos se puede evitar configurando :instance_accessor en false. En todos los casos, el valor debe ser exactamente false y no ningún valor falso.

module A
  class B
    # No first_name instance reader is generated.
    cattr_accessor :first_name, instance_reader: false
    # No last_name= instance writer is generated.
    cattr_accessor :last_name, instance_writer: false
    # No surname instance reader or surname= writer is generated.
    cattr_accessor :surname, instance_accessor: false
  end
end

Un modelo puede encontrar útil establecer :instance_accessor en false como una forma de evitar que la asignación masiva establezca el atributo.

Definido en active_support/core_ext/module/attribute_accessors.rb.

5.2 Subclasses & Descendants

5.2.1 subclasses

El método subclasses devuelve las subclases del receptor:

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]

El orden en el que se devuelven estas clases no se especifica.

Definido en active_support/core_ext/class/subclasses.rb.

5.2.2 descendants

El método descendants devuelve todas las clases que son<que su receptor:

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]

El orden en el que se devuelven estas clases no se especifica.

Definido en active_support/core_ext/class/subclasses.rb.

6 Extensions to String

6.1 Output Safety

6.1.1 Motivation

Insertar datos en plantillas HTML requiere un cuidado especial. Por ejemplo, no puede simplemente interpolar @review.title literalmente en una página HTML. Por un lado, si el título de la reseña es "Flanagan & Matz rules!" la salida no estará bien formada porque un ampersand debe escaparse como "&amp;". Además, dependiendo de la aplicación, eso puede ser un gran agujero de seguridad porque los usuarios pueden inyectar HTML malicioso configurando un título de revisión hecho a mano. Consulte la sección sobre secuencias de comandos entre sitios en la Security guide para obtener más información sobre los riesgos.

6.1.2 Safe Strings

Active Support tiene el concepto de (html) safe strings. Una cadena segura es aquella que está marcada como insertable en HTML tal cual. Es de confianza, sin importar si se ha escapado o no.

Las cadenas se consideran inseguras por defecto:

"".html_safe? # => false

Puede obtener una cadena segura de una determinada con el método html_safe:

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

Es importante entender que html_safe no realiza ningún tipo de escape, es solo una afirmación:

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

Es su responsabilidad asegurarse de que llamar a html_safe en una cadena en particular esté bien.

Si agrega una cadena segura, ya sea en el lugar con concat/<<, o con +, el resultado es una cadena segura. Se escapan los argumentos inseguros:

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

Los argumentos seguros se añaden directamente:

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

Estos métodos no deben utilizarse en vistas normales. Los valores no seguros se escapan automáticamente:

<%= @review.title %> <%# fine, escaped if needed %>

Para insertar algo textualmente use el ayudante raw en lugar de llamar a html_safe:

<%= raw @cms.current_template %> <%# inserts @cms.current_template as is %>

o, de manera equivalente, use <%==:

<%== @cms.current_template %> <%# inserts @cms.current_template as is %>

El ayudante raw llama a html_safe para usted:

def raw(stringish)
  stringish.to_s.html_safe
end

Definido en active_support/core_ext/string/output_safety.rb.

6.2 Transformation

Como regla general, excepto quizás para la concatenación como se explicó anteriormente, cualquier método que pueda cambiar una cadena le da una cadena insegura. Estos son downcase,gsub, strip,chomp, underscore, etc.

En el caso de transformaciones in situ como gsub!, El receptor en sí se vuelve inseguro.

El bit de seguridad se pierde siempre, sin importar si la transformación realmente cambió algo.

6.2.1 Conversion and Coercion

Llamar a to_s en una cadena segura devuelve una cadena segura, pero la coerción con to_str devuelve una cadena insegura.

6.2.2 Copying

Llamar a dup o clone en cadenas seguras produce cadenas seguras.

6.3 remove

El método remove eliminará todas las apariciones del patrón:

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

También existe la versión destructiva String#remove!.

Definido en active_support/core_ext/string/filters.rb.

6.4 squish

El método squish elimina los espacios en blanco iniciales y finales, y sustituye los espacios en blanco con un solo espacio cada uno:

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

También existe la versión destructiva String#squish!.

Tenga en cuenta que maneja espacios en blanco ASCII y Unicode.

Definido en active_support/core_ext/string/filters.rb.

6.5 truncate

El método truncate devuelve una copia de su receptor truncado después de una length dada:

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

La elipsis se puede personalizar con la opción :omission:

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

Tenga en cuenta en particular que el truncamiento tiene en cuenta la longitud de la cadena de omisión.

Pase un :separator para truncar la cadena en un salto natural:

"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..."

La opción :separator puede ser una expresión regular:

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

En los ejemplos anteriores, "dear" se corta primero, pero luego :separator lo impide.

6.6 truncate_bytes

El método truncate_bytes devuelve una copia de su receptor truncado como máximo en bytes de bytesize:

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

La elipsis se puede personalizar con la opción : omission:

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

Definido en active_support/core_ext/string/filters.rb.

6.7 truncate_words

El método truncate_words devuelve una copia de su receptor truncado después de un número determinado de palabras:

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

La elipsis se puede personalizar con la opción :omission:

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

Pase un :separator para truncar la cadena en un salto natural:

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

La opción :separator puede ser una expresión regular:

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

Definido en active_support/core_ext/string/filters.rb.

6.8 inquiry

El método query convierte una cadena en un objeto StringInquirer haciendo más bonitas las verificaciones de igualdad.

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

Definido en active_support/core_ext/string/query.rb.

6.9 starts_with? and ends_with?

Active Support define los alias en tercera persona de String#start_with? y String#end_with?:

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

Definido en active_support/core_ext/string/starts_ends_with.rb.

6.10 strip_heredoc

El método strip_heredoc elimina la sangría en heredocs.

Por ejemplo en

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

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

el usuario vería el mensaje de uso alineado con el margen izquierdo.

Técnicamente, busca la línea con menos sangría en toda la cadena y elimina esa cantidad de espacios en blanco iniciales.

Definido en active_support/core_ext/string/strip.rb.

### indent

Sangra las líneas en el receptor:

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

El segundo argumento, indent_string, especifica qué cadena de sangría usar. El valor predeterminado es nil, que le dice al método que haga una conjetura educada mirando la primera línea con sangría, y retroceda a un espacio si no hay ninguno.

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

Si bien indent_string suele ser un espacio o tabulación, puede ser cualquier cadena.

El tercer argumento, indent_empty_lines, es una bandera que indica si las líneas vacías deben tener sangría. El valor predeterminado es falso.

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

El método indent! Realiza la sangría en el lugar.

Definido en active_support/core_ext/string/indent.rb.

6.11 Access

6.11.1 at(position)

Devuelve el carácter de la cadena en la posición position:

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

Definido en active_support/core_ext/string/access.rb.

6.11.2 from(position)

Devuelve la subcadena de la cadena que comienza en la posición position:

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

Definido en active_support/core_ext/string/access.rb.

#### to(position)

Devuelve la subcadena de la cadena hasta la posición position:

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

Definido en active_support/core_ext/string/access.rb.

6.11.3 first(limit = 1)

La llamada str.first(n) es equivalente a str.to(n-1) si n > 0, y devuelve una cadena vacía paran == 0.

NOTA: Definido en active_support/core_ext/string/access.rb.

6.11.4 last(limit = 1)

La llamada str.last (n) es equivalente a str.from (-n) si n> 0, y devuelve una cadena vacía paran == 0.

Definido en active_support/core_ext/string/access.rb.

6.12 Inflections

6.12.1 pluralize

El método pluralize devuelve el plural de su receptor:

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

Como muestra el ejemplo anterior, Active Support conoce algunos plurales irregulares y sustantivos incontables. Las reglas integradas se pueden ampliar en config/initializers/inflections.rb. Este archivo es generado por defecto por el comando rails new y tiene instrucciones en los comentarios.

pluralize también puede tomar un parámetro opcional count. Si count == 1 se devolverá la forma singular. Para cualquier otro valor de count se devolverá la forma plural:

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

Active Record utiliza este método para calcular el nombre de tabla predeterminado que corresponde a un modelo:

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

Definido en active_support/core_ext/string/inflections.rb.

6.12.2 singularize

El inverso de pluralize:

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

Las asociaciones calculan el nombre de la clase asociada predeterminada correspondiente utilizando este método:

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

Definido en active_support/core_ext/string/inflections.rb.

6.12.3 camelize

El método camelize devuelve su receptor en caso de camello:

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

Como regla general, puede pensar en este método como el que transforma las rutas en nombres de módulos o clases Ruby, donde se cortan espacios de nombres separados:

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

Por ejemplo, Action Pack usa este método para cargar la clase que proporciona una determinada tienda de sesión:

# 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 acepta un argumento opcional, que puede ser:upper (predeterminado) o :lower. Con este último la primera letra se vuelve minúscula:

"visual_effect".camelize(:lower) # => "visualEffect"

Eso puede ser útil para calcular nombres de métodos en un lenguaje que siga esa convención, por ejemplo JavaScript.

Como regla general, puede pensar en camelize como el inverso de undercore, aunque hay casos en los que eso no se cumple: " SSLError ".underscore.camelize devuelve"SslError". Para apoyar casos como este, Active Support le permite especificar acrónimos en config/initializers/inflections.rb:

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

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

camelize tiene el alias de camelcase.

Definido en active_support/core_ext/string/inflections.rb.

6.12.4 underscore

El método underscore va al revés, desde el caso del camello hasta las rutas:

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

También convierte "::" a "/":

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

y entiende cadenas que comienzan con minúsculas:

"visualEffect".underscore # => "visual_effect"

Sin embargo, el underscore no acepta ningún argumento.

La carga automática de módulos y clases de Rails utiliza un guión bajo para inferir la ruta relativa sin extensión de un archivo que definiría una constante faltante dada:

# active_support/dependencies.rb
def load_missing_constant(from_mod, const_name)
  ...
  qualified_name = qualified_name_for from_mod, const_name
  path_suffix = qualified_name.underscore
  ...
end

Como regla general, puede pensar en underscore como el inverso de camelize, aunque hay casos en los que eso no se cumple. Por ejemplo, " SSLError ".underscore.camelize devuelve"SslError".

NOTA: Definido enactive_support/core_ext/string/inflections.rb.

6.12.5 titleize

El método titleize capitaliza las palabras en el receptor:

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

titleize tiene el alias de titlecase.

Definido en active_support/core_ext/string/inflections.rb.

6.12.6 dasherize

El método dasherize reemplaza los guiones bajos en el receptor con guiones:

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

El serializador XML de modelos utiliza este método para dividir los nombres de los nodos:

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

Definido en active_support/core_ext/string/inflections.rb.

6.12.7 demodulize

Given a string with a qualified constant name, demodulize returns the very constant name, that is, the rightmost part of it:

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

Active Record, por ejemplo, utiliza este método para calcular el nombre de una columna de caché de contador:

# 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

Definido en active_support/core_ext/string/inflections.rb.

6.12.8 deconstantize

Dada una cadena con una expresión de referencia constante calificada, deconstantize elimina el segmento más a la derecha, generalmente dejando el nombre del contenedor de la constante:

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

Definido en active_support/core_ext/string/inflections.rb.

6.12.9 parameterize

El método parameterize normaliza su receptor de una forma que se puede utilizar en URL bonitas.

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

Para preservar el caso de la cadena, establezca el argumento preserve_case en verdadero. De forma predeterminada, preserve_case se establece en falso.

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

Para usar un separador personalizado, anule el argumento separator.

"John Smith".parameterize(separator: "_") # => "john\_smith"
"Kurt Gödel".parameterize(separator: "_") # => "kurt\_godel"

Definido en active_support/core_ext/string/inflections.rb.

6.12.10 tableize

El método tableize esunderscore seguido de pluralize.

"Person".tableize      # => "people"
"Invoice".tableize     # => "invoices"
"InvoiceLine".tableize # => "invoice_lines"

Como regla general, tableize devuelve el nombre de la tabla que corresponde a un modelo dado para casos simples. De hecho, la implementación real en Active Record no es un "tableize" directo, porque también demoduliza el nombre de la clase y verifica algunas opciones que pueden afectar la cadena devuelta.

Definido en active_support/core_ext/string/inflections.rb.

6.12.11 classify

El método classify es el inverso de tableize. Te da el nombre de clase correspondiente al nombre de una tabla:

"people".classify        # => "Person"
"invoices".classify      # => "Invoice"
"invoice_lines".classify # => "InvoiceLine"

El método comprende tabla calificada

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

Tenga en cuenta que classify devuelve un nombre de clase como una cadena. Puede obtener el objeto de clase real invocando constantize, explicado a continuación.

Definido en active_support/core_ext/string/inflections.rb.

6.12.12 constantize~

El método constantize resuelve la expresión de referencia constante en su receptor:

"Integer".constantize # => Integer

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

Si la cadena no se evalúa como una constante conocida, o su contenido ni siquiera es un nombre de constante válido, constantize genera NameError.

La resolución constante de nombres por constantize comienza siempre en el Object de nivel superior, incluso si no hay un "::" inicial.

X = :in_Object
module M
  X = :in_M

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

Entonces, en general, no es equivalente a lo que haría Ruby en el mismo lugar, si se evaluara una constante real.

Los casos de prueba de mailer obtienen el mailer que se está probando a partir del nombre de la clase de prueba usando constantize:

# action_mailer/test_case.rb
def determine_default_mailer(name)
  name.sub(/Test$/, '').constantize
rescue NameError => e
  raise NonInferrableMailerError.new(name)
end

Definido en active_support/core_ext/string/inflections.rb.

6.12.13 humanize

El método humanize modifica un nombre de atributo para mostrarlo a los usuarios finales.

Específicamente realiza estas transformaciones:

  • Aplica reglas de inflexión humana al argumento.
  • Elimina los guiones bajos iniciales, si los hay.
  • Elimina un sufijo "_id" si está presente.
  • Reemplaza los guiones bajos con espacios, si los hubiera.
  • Reduce todas las palabras excepto los acrónimos.
  • Capitaliza la primera palabra.

La mayúscula de la primera palabra se puede desactivar configurando la opción :capitalize en falso (el valor predeterminado es verdadero).

"name".humanize                         # => "Name"
"author_id".humanize                    # => "Author"
"author_id".humanize(capitalize: false) # => "author"
"comments_count".humanize               # => "Comments count"
"_id".humanize                          # => "Id"

Si "SSL" se definió como un acrónimo:

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

El método auxiliar full_messages usa humanize como alternativa para incluir nombres de atributos:

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

Definido en active_support/core_ext/string/inflections.rb.

6.12.14 foreign_key

El método foreign_key da un nombre de columna de clave externa de un nombre de clase. Para hacerlo, demoduliza, subraya y agrega "_id":

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

Pase un argumento falso si no desea el guión bajo en "_id":

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

Las asociaciones usan este método para inferir claves externas, por ejemplo, has_one y has_many hacen esto:

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

Definido en active_support/core_ext/string/inflections.rb.

6.13 Conversions

6.13.1 to_date, to_time, to_datetime

Los métodos to_date, to_time y to_datetime son básicamente envoltorios de conveniencia alrededor 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 recibe un argumento opcional:utc o :local, para indicar en qué zona horaria quieres la hora:

"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

El valor predeterminado es :local.

Consulte la documentación de Date._parse para obtener más detalles.

Los tres devuelven nil para los receptores en blanco.

Definido en active_support/core_ext/string/conversions.rb.

7 Extensions to Symbol

7.1 starts_with? and ends_with?

Active Support define los alias en tercera persona de Symbol#start_with? y Symbol#end_with?:

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

Definido en active_support/core_ext/symbol/starts_ends_with.rb.

8 Extensions to Numeric

8.1 Bytes

Todos los números responden a estos métodos:

bytes
kilobytes
megabytes
gigabytes
terabytes
petabytes
exabytes

Devuelven la cantidad correspondiente de bytes, usando un factor de conversión de 1024:

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

Las formas singulares tienen un alias para que pueda decir:

1.megabyte # => 1048576

Definido en active_support/core_ext/numeric/bytes.rb.

8.2 Time

Permite el uso de cálculos y declaraciones de tiempo, como 45.minutes + 2.hours + 4.weeks.

Estos métodos usan Time # advance para cálculos de fecha precisos cuando se usa from_now, ago, etc. así como sumar o restar sus resultados de un objeto Time. Por ejemplo:

# equivalent to Time.current.advance(months: 1)
1.month.from_now

# equivalent to Time.current.advance(weeks: 2)
2.weeks.from_now

# equivalent to Time.current.advance(months: 4, weeks: 5)
(4.months + 5.weeks).from_now

Para otras duraciones, consulte las extensiones de tiempo para Integer.

Definido en active_support/core_ext/numeric/time.rb.

8.3 Formatting

Habilita el formateo de números de varias formas.

Producir una representación de cadena de un número como un número de teléfono:

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

Produzca una representación de cadena de un número como moneda:

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

Produzca una representación de cadena de un número como porcentaje:

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

Produce una representación de cadena de un número en forma delimitada:

12345678.to_s(:delimited)                     # => 12,345,678
12345678.05.to_s(:delimited)                  # => 12,345,678.05
12345678.to_s(:delimited, delimiter: ".")     # => 12.345.678
12345678.to_s(:delimited, delimiter: ",")     # => 12,345,678
12345678.05.to_s(:delimited, separator: " ")  # => 12,345,678 05

Produce una representación de cadena de un número redondeado con una precisión:

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

Produzca una representación de cadena de un número en palabras legibles por humanos:

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

Definido en active_support/core_ext/numeric/conversions.rb.

9 Extensions to Integer

9.1 multiple_of?

El método multiple_of? Prueba si un número entero es múltiplo del argumento:

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

Definido en active_support/core_ext/integer/multiple.rb.

9.2 ordinal

El método ordinal devuelve la cadena de sufijo ordinal correspondiente al entero receptor:

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

Definido en active_support/core_ext/integer/inflections.rb.

9.3 ordinalize

El método ordinalize devuelve la cadena ordinal correspondiente al entero receptor. En comparación, tenga en cuenta que el método ordinal devuelve ** solo ** la cadena de sufijo.

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

Definido en active_support/core_ext/integer/inflections.rb.

9.4 Time

Habilita el uso de declaraciones y cálculos de tiempo, como 4.months + 5.years.

Estos métodos usan Time # advance para cálculos de fecha precisos cuando se usa from_now, ago, etc. así como sumar o restar sus resultados de un objeto Time. Por ejemplo:

# equivalent to Time.current.advance(months: 1)
1.month.from_now

# equivalent to Time.current.advance(years: 2)
2.years.from_now

# equivalent to Time.current.advance(months: 4, years: 5)
(4.months + 5.years).from_now

Para otras duraciones, consulte las extensiones de tiempo para Numeric.

Definido en active_support/core_ext/integer/time.rb.

10 Extensions to BigDecimal

10.1 to_s

El método to_s proporciona un especificador predeterminado de" F ". Esto significa que una simple llamada a to_s dará como resultado una representación de punto flotante en lugar de una notación de ingeniería:

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

y que también se admiten especificadores de símbolos:

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

Aún se admite la notación de ingeniería:

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

11 Extensions to Enumerable

11.1 sum

El método sum agrega los elementos de un enumerable:

[1, 2, 3].sum # => 6
(1..100).sum  # => 5050

La adición solo asume que los elementos responden a '+':

[[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 suma de una colección vacía es cero de forma predeterminada, pero es personalizable:

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

Si se proporciona un bloque, sum se convierte en un iterador que produce los elementos de la colección y suma los valores devueltos:

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

La suma de un receptor vacío también se puede personalizar en este formulario:

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

Definido en active_support/core_ext/enumerable.rb.

11.2 index_by

El método index_by genera un hash con los elementos de un enumerable indexado por alguna clave.

Repite la colección y pasa cada elemento a un bloque. El elemento estará codificado por el valor devuelto por el bloque:

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

Las claves normalmente deberían ser únicas. Si el bloque devuelve el mismo valor para diferentes elementos, no se crea una colección para esa clave. El último artículo ganará.

Definido en active_support/core_ext/enumerable.rb.

11.3 index_with

El método index_with genera un hash con los elementos de un enumerable como claves. El valor es un valor predeterminado pasado o devuelto en un bloque.

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 ], … }

Definido en active_support/core_ext/enumerable.rb.

11.4 many?

El método many? Es una abreviatura de collection.size > 1:

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

Si se da un bloque opcional, many? Solo tiene en cuenta aquellos elementos que devuelven verdadero:

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

Definido en active_support/core_ext/enumerable.rb.

11.5 exclude?

El predicado exclude? Comprueba si un objeto dado ** no ** pertenece a la colección. Es la negación del include? incorporado:

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

Definido en active_support/core_ext/enumerable.rb.

11.6 including

El método including devuelve un nuevo enumerable que incluye los elementos pasados:

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

Definido en active_support/core_ext/enumerable.rb.

11.7 excluding

El método excluding devuelve una copia de un enumerable con los elementos especificados remoto:

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

excluding tiene el alias dewithout.

Definido en active_support/core_ext/enumerable.rb.

11.8 pluck

El método pluck extrae la clave dada de cada elemento:

[{ 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"]]

Definido en active_support/core_ext/enumerable.rb.

11.9 pick

El método pick extrae la clave dada del primer elemento:

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

Definido en active_support/core_ext/enumerable.rb.

12 Extensions to Array

12.1 Accessing

Active Support aumenta la API de matrices para facilitar ciertas formas de acceder a ellas. Por ejemplo, to devuelve el subarreglo de elementos hasta el del índice pasado:

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

De manera similar, from devuelve la cola del elemento en el índice pasado hasta el final. Si el índice es mayor que la longitud de la matriz, devuelve una matriz vacía.

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

El método including devuelve una nueva matriz que incluye los elementos pasados:

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

El método including devuelve una copia del Array excluyendo los elementos especificados. Esta es una optimización de Enumerable#excluding que usaArray#- en lugar de "Array # rechazar" por motivos de rendimiento.

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

Los métodos second, third, fourth y fifth devuelven el elemento correspondiente, al igual que second_to_last y third_to_last (first y last están integrados). Gracias a la sabiduría social y a la constructividad positiva en todos lados, forty_two también está disponible.

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

Definido en active_support/core_ext/array/access.rb.

12.2 Extracting

El método extract! Elimina y devuelve los elementos para los que el bloque devuelve un valor verdadero. Si no se proporciona ningún bloque, se devuelve un enumerador en su lugar.

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]

Definido en active_support/core_ext/array/extract.rb.

12.3 Options Extraction

Cuando el último argumento en una llamada a un método es un hash, excepto quizás por un argumento &block, Ruby le permite omitir los corchetes:

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

Ese azúcar sintáctico se usa mucho en Rails para evitar argumentos posicionales donde habría demasiados, ofreciendo en su lugar interfaces que emulan parámetros con nombre. En particular, es muy idiomático usar un hash final para las opciones.

Sin embargo, si un método espera un número variable de argumentos y usa * en su declaración, dicho hash de opciones termina siendo un elemento de la matriz de argumentos, donde pierde su función.

En esos casos, puede darle a un hash de opciones un tratamiento distinguido con extract_options!. Este método verifica el tipo del último elemento de una matriz. Si es un hash, lo abre y lo devuelve; de ​​lo contrario, devuelve un hash vacío.

Veamos, por ejemplo, la definición de la macro del controlador caches_action:

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

Este método recibe un número arbitrario de nombres de acción y un hash opcional de opciones como último argumento. Con la llamada a extract_options! Obtienes el hash de opciones y lo eliminas de actions de una manera simple y explícita.

Definido en active_support/core_ext/array/extract_options.rb.

12.4 Conversions

12.4.1 to_sentence

El método to_sentence convierte una matriz en una cadena que contiene una oración que enumera sus elementos:

%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"

Este método acepta tres opciones:

  • :two_words_connector: Lo que se utiliza para matrices de longitud 2. El valor predeterminado es "y".
  • :words_connector: Lo que se usa para unir los elementos de arreglos con 3 o más elementos, excepto los dos últimos. El valor predeterminado es ",".
  • :last_word_connector: Qué se usa para unir los últimos elementos de una matriz con 3 o más elementos. El valor predeterminado es "y".

Los valores predeterminados para estas opciones se pueden localizar, sus claves son:

Option I18n key
:two_words_connector support.array.two_words_connector
:words_connector support.array.words_connector
:last_word_connector support.array.last_word_connector

Definido en active_support/core_ext/array/conversions.rb.

12.4.2 to_formatted_s

El método to_formatted_s actúa comoto_s por defecto.

Sin embargo, si la matriz contiene elementos que responden a id, el símbolo :db se puede pasar como argumento. Eso se usa típicamente con colecciones de objetos Active Record. Las cadenas devueltas son:

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

Se supone que los números enteros en el ejemplo anterior provienen de las respectivas llamadas a id.

Definido en active_support/core_ext/array/conversions.rb.

12.4.3 to_xml

El método to_xml devuelve una cadena que contiene una representación XML de su receptor:

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>

Para hacerlo, envía to_xml a cada elemento por turno y recopila los resultados en un nodo raíz. Todos los elementos deben responder a to_xml; de lo contrario, se genera una excepción.

Por defecto, el nombre del elemento raíz es el plural subrayado y discontinuo del nombre de la clase del primer elemento, siempre que el resto de elementos pertenezcan a ese tipo (marcados con is_a?) Y no sean hashes. En el ejemplo anterior, eso es "contribuyentes".

Si hay algún elemento que no pertenece al tipo del primero, el nodo raíz se convierte en "objetos":

[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 el receptor es una matriz de hashes, el elemento raíz por defecto también es "objetos":

[{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>

Si la colección está vacía, el elemento raíz es por defecto "nil-classes". Eso es un problema, por ejemplo, el elemento raíz de la lista de contribuyentes anterior no sería "contribuyentes" si la colección estuviera vacía, sino "nil-classes". Puede usar la opción :root para asegurar un elemento raíz consistente.

El nombre de los nodos hijos es por defecto el nombre del nodo raíz singularizado. En los ejemplos anteriores, hemos visto "contribuyente" y "objeto". La opción :children le permite establecer estos nombres de nodo.

El constructor XML predeterminado es una instancia nueva de Builder::XmlMarkup. Puede configurar su propio constructor a través de la opción :builder. El método también acepta opciones como :dasherize y amigos, se reenvían al constructor:

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>

Definido en active_support/core_ext/array/conversions.rb.

12.5 Wrapping

El método Array.wrap envuelve su argumento en una matriz a menos que ya sea una matriz (o similar a una matriz).

Específicamente:

  • Si el argumento es nil, se devuelve una matriz vacía.
  • De lo contrario, si el argumento responde a to_ary se invoca, y si el valor deto_ary no es nil, se devuelve.
  • De lo contrario, se devuelve una matriz con el argumento como elemento único.
Array.wrap(nil)       # => []
Array.wrap([1, 2, 3]) # => [1, 2, 3]
Array.wrap(0)         # => [0]

Este método tiene un propósito similar al de Kernel#Array, pero hay algunas diferencias:

  • Si el argumento responde a to_ary, se invoca el método. Kernel#Array pasa a intentar to_a si el valor devuelto es nil, pero Array.wrap devuelve una matriz con el argumento como su único elemento de inmediato.
  • Si el valor devuelto de to_ary no es ninil ni un objeto Array, Kernel#Array genera una excepción, mientras que Array.wrap no lo hace, simplemente devuelve el valor.
  • No llama a to_a en el argumento, si el argumento no responde ato_ary, devuelve una matriz con el argumento como su único elemento.

El último punto es particularmente digno de comparar para algunos enumerables:

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

También hay un modismo relacionado que usa el operador splat:

[*object]

Definido en active_support/core_ext/array/wrap.rb.

12.6 Duplicating

El método Array#deep_dup se duplica a sí mismo y a todos los objetos dentro de forma recursiva con el método de soporte activo Object#deep_dup. Funciona como Array#map con el envío del método deep_dup a cada objeto dentro.

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

Definido en active_support/core_ext/object/deep_dup.rb.

12.7 Grouping

12.7.1 in_groups_of(number, fill_with = nil)

El método in_groups_of divide una matriz en grupos consecutivos de cierto tamaño. Devuelve una matriz con los grupos:

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

O los cede a su vez si se pasa un bloque:

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

El primer ejemplo muestra que in_groups_of llena el último grupo con tantos elementosnil como sea necesario para tener el tamaño solicitado. Puede cambiar este valor de relleno utilizando el segundo argumento opcional:

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

Y puede decirle al método que no complete el último grupo pasando false:

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

Como consecuencia, false no se puede utilizar como valor de relleno.

Definido en active_support/core_ext/array/grouping.rb.

12.7.2 in_groups(number, fill_with = nil)

El método in_groups divide una matriz en un cierto número de grupos. El método devuelve una matriz con los grupos:

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

o los cede a su vez si se pasa un bloque:

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

Los ejemplos anteriores muestran que in_groups llena algunos grupos con un elemento nil final según sea necesario. Un grupo puede obtener como máximo uno de estos elementos adicionales, el más a la derecha si lo hay. Y los grupos que los tienen son siempre los últimos.

Puede cambiar este valor de relleno utilizando el segundo argumento opcional:

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

Y puede decirle al método que no complete los grupos más pequeños pasando false:

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

Como consecuencia, "false" no se puede utilizar como valor de relleno.

Definido en active_support/core_ext/array/grouping.rb.

12.7.3 split(value = nil)

El método split divide una matriz por un separador y devuelve los fragmentos resultantes.

Si se pasa un bloque, los separadores son aquellos elementos de la matriz para los que el bloque devuelve verdadero:

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

De lo contrario, el valor recibido como argumento, cuyo valor predeterminado es nil, es el separador:

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

Observe en el ejemplo anterior que los separadores consecutivos dan como resultado matrices vacías.

NOTA: Definido en active_support/core_ext/array/grouping.rb.

13 Extensions to Hash

13.1 Conversions

13.1.1 to_xml

El método to_xml devuelve una cadena que contiene una representación XML de su receptor:

{"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>

Para hacerlo, el método recorre los pares y construye nodos que dependen de los valores. Dado un par de clave,valor:

  • Si value es un hash, hay una llamada recursiva con key como :root.

  • Si value es una matriz, hay una llamada recursiva con key como :root, ykey singularizada como : children.

  • Si valor es un objeto invocable, debe esperar uno o dos argumentos. Dependiendo de la aridad, el invocable se invoca con el hash options como primer argumento con key como :root, ykey singularizado como segundo argumento. Su valor de retorno se convierte en un nuevo nodo.

  • Si value responde ato_xml, el método se invoca con key como :root.

  • De lo contrario, se crea un nodo con key como etiqueta con una representación de cadena de value como nodo de texto. Si value esnil, se agrega un atributo "nil" establecido en "true". A menos que la opción :skip_types exista y sea verdadera, también se agrega un atributo "tipo" de acuerdo con la siguiente asignación:

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

Por defecto, el nodo raíz es "hash", pero eso se puede configurar a través de la opción :root.

El constructor XML predeterminado es una instancia nueva de Builder::XmlMarkup. Puede configurar su propio constructor con la opción :constructor. El método también acepta opciones como :dasherize y amigos, se reenvían al constructor.

NOTA: Definido en active_support/core_ext/hash/conversions.rb.

13.2 Merging

Ruby tiene un método incorporado Hash#merge que fusiona dos hashes:

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

Active Support define algunas formas más de fusionar hashes que pueden ser convenientes.

13.2.1 reverse_merge and reverse_merge!

En caso de colisión, la clave en el hash del argumento gana en merge. Puede admitir hash de opciones con valores predeterminados de una manera compacta con este modismo:

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

Active Support define reverse_merge en caso de que prefiera esta notación alternativa:

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

Y una versión explosiva reverse_merge! Que realiza la fusión en su lugar:

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

Tenga en cuenta que reverse_merge! Puede cambiar el hash en la persona que llama, lo que puede ser una buena idea o no.

Definido en active_support/core_ext/hash/reverse_merge.rb.

13.2.2 reverse_update

El método reverse_update es un alias dereverse_merge!, Explicado anteriormente.

Tenga en cuenta que "reverse_update" no tiene explosión.

Definido en active_support/core_ext/hash/reverse_merge.rb.

13.2.3 deep_merge and deep_merge!

Como puede ver en el ejemplo anterior, si se encuentra una clave en ambos hashes, gana el valor del que está en el argumento.

Active Support define Hash#deep_merge. En una fusión profunda, si se encuentra una clave en ambos hashes y sus valores son hashes a su vez, su merge se convierte en el valor del hash resultante:

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

El método deep_merge! Realiza una fusión profunda en su lugar.

Definido en active_support/core_ext/hash/deep_merge.rb.

13.3 Deep duplicating

El método Hash # deep_dup se duplica a sí mismo y a todas las claves y valores dentro de forma recursiva con el método de soporte activo Object#deep_dup. Funciona como Enumerator#each_with_object con el envío del método deep_dup a cada par dentro.

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

Definido en active_support/core_ext/object/deep_dup.rb.

13.4 Working with Keys

13.4.1 except and except!

El método except devuelve un hash con las claves de la lista de argumentos eliminadas, si están presentes:

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

Si el receptor responde a convert_key, se llama al método en cada uno de los argumentos. Esto permite que except juegue bien con hashes con acceso indiferente, por ejemplo:

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

There's also the bang variant except! that removes keys in the very receiver.

Definido en active_support/core_ext/hash/except.rb.

13.4.2 stringify_keys and stringify_keys!

El método stringify_keys devuelve un hash que tiene una versión en cadena de las claves en el receptor. Lo hace enviándoles to_s:

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

En caso de colisión de claves, el valor será el que se haya insertado más recientemente en el hash:

{"a" => 1, a: 2}.stringify_keys
# The result will be
# => {"a"=>2}

This method may be useful for example to easily accept both symbols and strings as options. For instance ActionView::Helpers::FormHelper defines:

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

La segunda línea puede acceder de forma segura a la tecla "tipo" y permitir que el usuario pase ": tipo" o "tipo".

También existe la variante bang stringify_keys! Que secuencia las claves en el mismo receptor.

Además de eso, uno puede usar deep_stringify_keys y deep_stringify_keys! para secuenciar todas las claves en el hash dado y todos los hash anidados en él. Un ejemplo del resultado es:

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

Definido en active_support/core_ext/hash/keys.rb.

13.4.3 symbolize_keys and symbolize_keys!

El método symbolize_keys devuelve un hash que tiene una versión simbolizada de las claves en el receptor, cuando es posible. Lo hace enviándoles to_sym:

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

Tenga en cuenta que en el ejemplo anterior solo se simbolizó una tecla.

En caso de colisión de claves, el valor será el que se haya insertado más recientemente en el hash:

{"a" => 1, a: 2}.symbolize_keys
# The result will be
# => {:a=>2}

Este método puede ser útil, por ejemplo, para aceptar fácilmente símbolos y cadenas como opciones. Por ejemplo, ActionText::TagHelper define

def rich_text_area_tag(name, value = nil, options = {})
  options = options.symbolize_keys

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

La tercera línea puede acceder de forma segura a la tecla :input, y permitir que el usuario pase: input o "input".

También existe la variante bang symbolize_keys! Que simboliza las teclas en el mismo receptor.

Además de eso, uno puede usar deep_symbolize_keys y deep_symbolize_keys! para simbolizar todas las claves en el hash dado y todos los hashes anidados en él. Un ejemplo del resultado es:

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

Definido en active_support/core_ext/hash/keys.rb.

13.4.4 to_options and to_options!

Los métodos to_options yto_options!Son, respectivamente, alias de symbolize_keys y symbolize_keys!.

Definido en active_support/core_ext/hash/keys.rb.

13.4.5 assert_valid_keys

El método assert_valid_keys recibe un número arbitrario de argumentos y comprueba si el receptor tiene alguna clave fuera de esa lista blanca. Si lo hace, se genera ArgumentError.

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

Active Record no acepta opciones desconocidas al crear asociaciones, por ejemplo. Implementa ese control a través de assert_valid_keys.

Definido en active_support/core_ext/hash/keys.rb.

13.5 Working with Values

13.5.1 deep_transform_values and deep_transform_values!

El método deep_transform_values devuelve un nuevo hash con todos los valores convertidos por la operación de bloque. Esto incluye los valores del hash raíz y de todos los hash y matrices anidados.

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

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

También existe la variante bang deep_transform_values! Que convierte destructivamente todos los valores mediante la operación de bloque.

Definido en active_support/core_ext/hash/deep_transform_values.rb.

13.6 Slicing

El método slice! Reemplaza el hash solo con las claves dadas y devuelve un hash que contiene los pares clave/valor eliminados.

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

Definido en active_support/core_ext/hash/slice.rb.

13.7 Extracting

El método extract! Elimina y devuelve los pares clave/valor que coinciden con las claves dadas.

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

El método extract! Devuelve la misma subclase de Hash que el receptor.

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

Definido en active_support/core_ext/hash/slice.rb.

13.8 Indifferent Access`

El método with_indifferent_access devuelve unActiveSupport::HashWithIndifferentAccess de su receptor:

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

Definido en active_support/core_ext/hash/indifferent_access.rb.

14 Extensions to Regexp

14.1 multiline?

El método multiline? Dice si una expresión regular tiene el indicador / m establecido, es decir, si el punto coincide con las nuevas líneas.

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

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

Rails utiliza este método en un solo lugar, también en el código de enrutamiento. Las expresiones regulares multilínea no están permitidas para los requisitos de ruta y este indicador facilita la aplicación de esa restricción.

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

Definido en active_support/core_ext/regexp.rb.

15 Extensions to Range

15.1 to_s

Active Support extiende el método Range#to_s para que comprenda un argumento de formato opcional. En el momento de escribir estas líneas, el único formato no predeterminado admitido es :db: ```ruby (Date.today..Date.tomorrow).to_s

=> "2009-10-25..2009-10-26"

(Date.today..Date.tomorrow).to_s(:db)

=> "BETWEEN '2009-10-25' AND '2009-10-26'"


Como muestra el ejemplo, el formato `:db` genera una cláusula SQL` BETWEEN`. Eso lo utiliza Active Record en su apoyo a valores de rango en condiciones.

NOTE: Definido en `active_support/core_ext/range/conversions.rb`.

### `===`, `include?`, and `cover?`

Los métodos `Range#===`, `Range#include?` y `Range#cover?` Dicen si algún valor se encuentra entre los extremos de una instancia determinada:

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

Active Support amplía estos métodos para que el argumento pueda ser otro rango a su vez. En ese caso, probamos si los extremos del rango del argumento pertenecen al receptor mismo:

(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

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

Definido en active_support/core_ext/range/compare_range.rb.

15.2 overlaps?

El método Range#overlaps? dice si dos rangos dados tienen una intersección no nula:

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

Definido en active_support/core_ext/range/overlaps.rb.

16 Extensions to Date

16.1 Calculations

Los siguientes métodos de cálculo tienen casos extremos en octubre de 1582, ya que los días 5..14 simplemente no existen. Esta guía no documenta su comportamiento en esos días por brevedad, pero basta con decir que hacen lo que cabría esperar. Es decir, Date.new(1582, 10, 4).Tomorrow devuelveDate.new (1582, 10, 15)y así sucesivamente. Compruebe test/core_ext/date_ext_test.rb en el conjunto de pruebas de Active Support para conocer el comportamiento esperado.

16.1.1 Date.current

Active Support define "Date.current" como hoy en la zona horaria actual. Eso es como Date.today, excepto que respeta la zona horaria del usuario, si está definida. También define Date.yesterday y Date.tomorrow, y la instancia predica past?, today?, tomorrow?, next_day?, yesterday?, prev_day?, future?, on_weekday? y on_weekend?, todos ellos relativos a Date.current.

Cuando realice comparaciones de fechas utilizando métodos que respeten la zona horaria del usuario, asegúrese de utilizar Date.current y no Date.today. Hay casos en los que la zona horaria del usuario podría estar en el futuro en comparación con la zona horaria del sistema, que Date.today usa de forma predeterminada. Esto significa que Date.today puede ser igual a Date.yesterday.

Definido en active_support/core_ext/date/calculations.rb.

16.1.2 Named dates
16.1.2.1 beginning_of_week, end_of_week

Los métodos begin_of_week y end_of_week devuelven las fechas para principio y fin de semana, respectivamente. Se supone que las semanas comienzan en Lunes, pero eso se puede cambiar pasando un argumento, configurando el hilo local Date.beginning_of_week o 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 tiene el alias de at_beginning_of_week y end_of_week tiene el alias deat_end_of_week.

Definido en active_support/core_ext/date_and_time/calculations.rb.

16.1.2.2 monday, sunday

Los métodos monday y sunday devuelven las fechas del lunes anterior y el próximo domingo, respectivamente.

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

d = Date.new(2012, 9, 10)    # => Mon, 10 Sep 2012
d.monday                     # => Mon, 10 Sep 2012

d = Date.new(2012, 9, 16)    # => Sun, 16 Sep 2012
d.sunday                     # => Sun, 16 Sep 2012

Definido en active_support/core_ext/date_and_time/calculations.rb.

16.1.2.3 prev_week, next_week

El método next_week recibe un símbolo con un nombre de día en inglés (por defecto es el hilo local Date.beginning_of_week, o config.beginning_of_week, o :monday) y devuelve la fecha correspondiente a ese día.

d = Date.new(2010, 5, 9) # => Sun, 09 May 2010
d.next_week              # => Mon, 10 May 2010
d.next_week(:saturday)   # => Sat, 15 May 2010

El método prev_week es análogo:

d.prev_week              # => Mon, 26 Apr 2010
d.prev_week(:saturday)   # => Sat, 01 May 2010
d.prev_week(:friday)     # => Fri, 30 Apr 2010

prev_week tiene el alias de last_week.

Tanto next_week como prev_week funcionan como se esperaba cuando se configuran Date.beginning_of_week o config.beginning_of_week.

Definido en active_support/core_ext/date_and_time/calculations.rb.

16.1.2.4 beginning_of_month, end_of_month

Los métodos begin_of_month y end_of_month devuelven las fechas para el comienzo y el final del mes:

d = Date.new(2010, 5, 9) # => Sun, 09 May 2010
d.beginning_of_month     # => Sat, 01 May 2010
d.end_of_month           # => Mon, 31 May 2010

begin_of_month tiene un alias de at_beginning_of_month, y end_of_month tiene un alias de at_end_of_month.

Definido en active_support/core_ext/date_and_time/calculations.rb.

16.1.2.5 beginning_of_quarter, end_of_quarter

Los métodos begin_of_quarter y end_of_quarter devuelven las fechas para el inicio y el final del trimestre del año calendario del receptor:

d = Date.new(2010, 5, 9) # => Sun, 09 May 2010
d.beginning_of_quarter   # => Thu, 01 Apr 2010
d.end_of_quarter         # => Wed, 30 Jun 2010

begin_of_quarter tiene el alias de at_beginning_of_quarter, y end_of_quarter tiene el alias de at_end_of_quarter.

Definido en active_support/core_ext/date_and_time/calculations.rb.

16.1.2.6 beginning_of_year, end_of_year

Los métodos begin_of_year y end_of_year devuelven las fechas para el comienzo y el final del año:

d = Date.new(2010, 5, 9) # => Sun, 09 May 2010
d.beginning_of_year      # => Fri, 01 Jan 2010
d.end_of_year            # => Fri, 31 Dec 2010

beginning_of_year is aliased to at_beginning_of_year, and end_of_year is aliased to at_end_of_year.

Definido en active_support/core_ext/date_and_time/calculations.rb.

16.1.3 Other Date Computations
16.1.3.1 years_ago, years_since

El método years_ago recibe un número de años y devuelve la misma fecha que hace muchos años:

date = Date.new(2010, 6, 7)
date.years_ago(10) # => Wed, 07 Jun 2000

years_since moves forward in time:

date = Date.new(2010, 6, 7)
date.years_since(10) # => Sun, 07 Jun 2020

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

Date.new(2012, 2, 29).years_ago(3)     # => Sat, 28 Feb 2009
Date.new(2012, 2, 29).years_since(3)   # => Sat, 28 Feb 2015

last_year is short-hand for #years_ago(1).

Definido en active_support/core_ext/date_and_time/calculations.rb.

16.1.3.2 months_ago, months_since

Los métodos months_ago y months_since funcionan de manera análoga durante meses:

Date.new(2010, 4, 30).months_ago(2)   # => Sun, 28 Feb 2010
Date.new(2010, 4, 30).months_since(2) # => Wed, 30 Jun 2010

Si ese día no existe, se devuelve el último día del mes correspondiente:

Date.new(2010, 4, 30).months_ago(2)    # => Sun, 28 Feb 2010
Date.new(2009, 12, 31).months_since(2) # => Sun, 28 Feb 2010

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

Definido en active_support/core_ext/date_and_time/calculations.rb.

16.1.3.3 weeks_ago

The method weeks_ago works analogously for weeks:

Date.new(2010, 5, 24).weeks_ago(1)    # => Mon, 17 May 2010
Date.new(2010, 5, 24).weeks_ago(2)    # => Mon, 10 May 2010

Definido en active_support/core_ext/date_and_time/calculations.rb.

16.1.3.4 advance

La forma más genérica de saltar a otros días es "avance". Este método recibe un hash con las claves : años,: meses, : semanas,: días, y devuelve una fecha avanzada tanto como las claves presentes indican:

date = Date.new(2010, 6, 6)
date.advance(years: 1, weeks: 2)  # => Mon, 20 Jun 2011
date.advance(months: 2, days: -2) # => Wed, 04 Aug 2010

Tenga en cuenta en el ejemplo anterior que los incrementos pueden ser negativos.

Para realizar el cálculo, el método primero incrementa años, luego meses, luego semanas y finalmente días. Este orden es importante hacia finales de meses. Digamos, por ejemplo, que estamos a finales de febrero de 2010 y queremos avanzar un mes y un día.

El método advance avanza primero un mes, y luego un día, el resultado es:

Date.new(2010, 2, 28).advance(months: 1, days: 1)
# => Sun, 29 Mar 2010

Mientras que si lo hiciera al revés el resultado sería diferente:

Date.new(2010, 2, 28).advance(days: 1).advance(months: 1)
# => Thu, 01 Apr 2010

Definido en active_support/core_ext/date/calculations.rb.

16.1.4 Changing Components

El método change le permite obtener una nueva fecha que es la misma que la del receptor, excepto para el año, mes o día dado:

Date.new(2010, 12, 23).change(year: 2011, month: 11)
# => Wed, 23 Nov 2011

Este método no es tolerante con fechas inexistentes, si el cambio no es válido, se genera un error de argumento:

Date.new(2010, 1, 31).change(month: 2)
# => ArgumentError: invalid date

Definido en active_support/core_ext/date/calculations.rb.

16.1.5 Durations

Las duraciones se pueden sumar y restar de las fechas:

d = Date.current
# => Mon, 09 Aug 2010
d + 1.year
# => Tue, 09 Aug 2011
d - 3.hours
# => Sun, 08 Aug 2010 21:00:00 UTC +00:00

Se traducen en llamadas a since o advance. Por ejemplo aquí obtenemos el salto correcto en la reforma del calendario:

Date.new(1582, 10, 4) + 1.day
# => Fri, 15 Oct 1582
16.1.6 Timestamps

Los siguientes métodos devuelven un objeto Time si es posible, de lo contrario unDateTime. Si se configura, respetan la zona horaria del usuario.

16.1.6.1 beginning_of_day, end_of_day

El método begin_of_day devuelve una marca de tiempo al comienzo del día (00:00:00):

date = Date.new(2010, 6, 7)
date.beginning_of_day # => Mon Jun 07 00:00:00 +0200 2010

The method end_of_day returns a timestamp at the end of the day (23:59:59):

date = Date.new(2010, 6, 7)
date.end_of_day # => Mon Jun 07 23:59:59 +0200 2010

begin_of_day tiene el alias de at_beginning_of_day, midnight, at_midnight.

Definido en active_support/core_ext/date/calculations.rb.

16.1.6.2 beginning_of_hour, end_of_hour

El método begin_of_hour devuelve una marca de tiempo al comienzo de la hora (hh: 00: 00):

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

El método end_of_hour devuelve una marca de tiempo al final de la hora (hh: 59: 59):

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

begin_of_hour tiene el alias de at_beginning_of_hour.

Definido en active_support/core_ext/date_time/calculations.rb.

16.1.6.3 beginning_of_minute, end_of_minute

The method beginning_of_minute returns a timestamp at the beginning of the minute (hh:mm:00):

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

El método end_of_minute devuelve una marca de tiempo al final del minuto (hh: mm: 59):

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

begin_of_minute tiene el alias de at_beginning_of_minute.

begin_of_hour, end_of_hour, begin_of_minute yend_of_minute se implementan para Time y DateTime pero no Date ya que no tiene sentido solicitar el comienzo o el final de un hora o minuto en una instancia de Date.

16.1.6.4 ago, since

El método ago recibe una cantidad de segundos como argumento y devuelve una marca de tiempo de hace muchos segundos desde la medianoche:

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

Del mismo modo, since avanza:

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

Definido en active_support/core_ext/date/calculations.rb.

16.1.7 Other Time Computations

16.2 Conversions

17 Extensions to DateTime

DateTime no conoce las reglas de DST, por lo que algunos de estos métodos tienen casos extremos cuando se produce un cambio de DST. Por ejemplo, seconds_since_midnight podría no devolver la cantidad real en ese día.

17.1 Calculations

La clase DateTime es una subclase de Date por lo que al cargar active_support/core_ext/date/calculations.rb hereda estos métodos y sus alias, excepto que siempre devolverán fechas y horas.

Los siguientes métodos se han vuelto a implementar para que ** no ** necesite cargar active_support/core_ext/date/calculations.rb para estos:

beginning_of_day (midnight, at_midnight, at_beginning_of_day)
end_of_day
ago
since (in)

Por otro lado, advance y change también se definen y admiten más opciones, que se documentan a continuación.

Los siguientes métodos solo se implementan en active_support / core_ext / date_time / calculations.rb ya que solo tienen sentido cuando se usan con una instancia de DateTime:

beginning_of_hour (at_beginning_of_hour)
end_of_hour
17.1.1 Named Datetimes
17.1.1.1 DateTime.current

Active Support define DateTime.current como Time.now.to_datetime, excepto que respeta la zona horaria del usuario, si está definida. También define DateTime.yesterday yDateTime.tomorrow, y la instancia predica past? y future? relativo a DateTime.current.

Definido en active_support/core_ext/date_time/calculations.rb.

17.1.2 Other Extensions
17.1.2.1 seconds_since_midnight

El método seconds_since_midnight devuelve el número de segundos desde la medianoche:

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

Definido en active_support/core_ext/date_time/calculations.rb.

17.1.2.2 utc

El método utc le da la misma fecha y hora en el receptor expresada en UTC.

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

Este método también tiene un alias como "getutc".

Definido active_support/core_ext/date_time/calculations.rb.

17.1.2.3 utc?

El predicado utc? dice si el receptor tiene UTC como zona horaria:

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

Definido en active_support/core_ext/date_time/calculations.rb.

17.1.2.4 advance

La forma más genérica de saltar a otros días es advance. Este método recibe un hash con las claves :years, :months, :weeks, :days, y devuelve una fecha avanzada tanto como las claves presentes indican:

d = DateTime.current
# => Thu, 05 Aug 2010 11:33:31 +0000
d.advance(years: 1, months: 1, days: 1, hours: 1, minutes: 1, seconds: 1)
# => Tue, 06 Sep 2011 12:34:32 +0000

Este método primero calcula la fecha de destino pasando :years, :months, :weeks, y :days hasta la Date#advance documentada anteriormente. Después de eso, ajusta el tiempo llamando "desde" con el número de segundos para avanzar. Este orden es relevante, un orden diferente daría diferentes fechas y horas en algunos casos extremos. Se aplica el ejemplo de Date # advance, y podemos ampliarlo para mostrar la relevancia del orden relacionada con los bits de tiempo.

Si primero movemos los bits de fecha (que también tienen un orden relativo de procesamiento, como se documentó anteriormente), y luego los bits de tiempo obtenemos, por ejemplo, el siguiente cálculo:

d = DateTime.new(2010, 2, 28, 23, 59, 59)
# => Sun, 28 Feb 2010 23:59:59 +0000
d.advance(months: 1, seconds: 1)
# => Mon, 29 Mar 2010 00:00:00 +0000

pero si los calculamos al revés, el resultado sería diferente:

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

Dado que "DateTime" no tiene en cuenta el horario de verano, puede terminar en un punto no existente en el tiempo sin ninguna advertencia o error que se lo indique.

Definido en active_support/core_ext/date_time/calculations.rb.

17.1.3 Changing Components

El método change le permite obtener una nueva fecha y hora que es la misma que la del receptor excepto por las opciones dadas, que pueden incluir :year, :month, :day, :hour, :min, :sec, :offset, :start:

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

Si las horas se ponen a cero, los minutos y los segundos también (a menos que hayan dado valores):

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

Del mismo modo, si los minutos se ponen a cero, los segundos también (a menos que se haya dado un valor):

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

Este método no es tolerante con fechas inexistentes, si el cambio no es válido, se genera un error de argumento:

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

Definido en active_support/core_ext/date_time/calculations.rb`.

17.1.4 Durations

Las duraciones se pueden sumar y restar de las fechas y horas:

now = DateTime.current
# => Mon, 09 Aug 2010 23:15:17 +0000
now + 1.year
# => Tue, 09 Aug 2011 23:15:17 +0000
now - 1.week
# => Mon, 02 Aug 2010 23:15:17 +0000

Se traducen en llamadas a since o advance. Por ejemplo aquí obtenemos el salto correcto en la reforma del calendario:

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

18 Extensions to Time

18.1 Calculations

Son análogos. Consulte la documentación anterior y tenga en cuenta las siguientes diferencias:

  • change acepta una opción adicional :usec.
  • Time comprende el horario de verano, por lo que obtiene los cálculos correctos de DST como en
Time.zone_default
# => #<ActiveSupport::TimeZone:0x7f73654d4f38 @utc_offset=nil, @name="Madrid", ...>

# In Barcelona, 2010/03/28 02:00 +0100 becomes 2010/03/28 03:00 +0200 due to DST.
t = Time.local(2010, 3, 28, 1, 59, 59)
# => Sun Mar 28 01:59:59 +0100 2010
t.advance(seconds: 1)
# => Sun Mar 28 03:00:00 +0200 2010
  • Si since oago salta a una hora que no se puede expresar con Time, se devuelve un objetoDateTime en su lugar.
18.1.1 Time.current

Active Support define "Time.current" como hoy en la zona horaria actual. Eso es como "Time.now", excepto que respeta la zona horaria del usuario, si está definida. También define los predicados de instancia past?, today?, tomorrow?, next_day?, yesterday?, prev_day? y future?, Todos ellos relativos a Time.current.

Al hacer comparaciones de tiempo utilizando métodos que respeten la zona horaria del usuario, asegúrese de utilizar Time.current en lugar deTime.now. Hay casos en los que la zona horaria del usuario podría estar en el futuro en comparación con la zona horaria del sistema, que Time.now utiliza de forma predeterminada. Esto significa que "Time.now.to_date" puede ser igual a "Date.yesterday".

Definido en active_support/core_ext/time/calculations.rb.

18.1.2 all_day, all_week, all_month, all_quarter and all_year

El método all_day devuelve un rango que representa el día completo de la hora actual.

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 manera análoga, all_week,all_month, all_quarter y all_year sirven para generar rangos de tiempo.

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
18.1.3 prev_day, next_day

prev_day y next_day devuelven la hora del último día o del día siguiente:

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

Definido en active_support/core_ext/time/calculations.rb.

18.1.4 prev_month, next_month

prev_month y next_month devuelven la hora con el mismo día en el último o el próximo mes:

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 ese día no existe, se devuelve el último día del mes correspondiente:

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

Definido en active_support/core_ext/time/calculations.rb.

18.1.5 prev_year, next_year

prev_year y next_year devuelven una hora con el mismo día / mes en el último o el próximo año:

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 fecha es el 29 de febrero de un año bisiesto, obtiene el 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

Definido en active_support/core_ext/time/calculations.rb.

18.1.6 prev_quarter, next_quarter

prev_quarter and next_quarter return the date with the same day in the previous or next quarter:

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 ese día no existe, se devuelve el último día del mes correspondiente:

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 is aliased to last_quarter.

Definido en active_support/core_ext/date_and_time/calculations.rb.

18.2 Time Constructors

Active Support define Time.current como Time.zone.now si hay una zona horaria definida por el usuario, con un retorno a 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 manera análoga a DateTime, los predicados past? y future? Son relativos a Time.current.

18.2.1 Durations

Las duraciones se pueden sumar y restar de los objetos de tiempo:

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

Se traducen en llamadas a since o advance. Por ejemplo aquí obtenemos el salto correcto en la reforma del calendario:

Time.utc(1582, 10, 3) + 5.days
# => Mon Oct 18 00:00:00 UTC 1582

19 Extensions to File

19.1 atomic_write

Con el método de clase File.atomic_write puedes escribir en un archivo de una manera que evitará que cualquier lector vea contenido a medio escribir.

El nombre del archivo se pasa como argumento y el método produce un identificador de archivo abierto para escritura. Una vez que el bloque está hecho, atomic_write cierra el identificador del archivo y completa su trabajo.

For example, Action Pack uses this method to write asset cache files like all.css:

File.atomic_write(joined_asset_path) do |cache|
  cache.write(join_asset_file_contents(asset_paths))
end

Para lograr esto, atomic_write crea un archivo temporal. Ese es el archivo en el que realmente escribe el código del bloque. Al finalizar, se cambia el nombre del archivo temporal, que es una operación atómica en los sistemas POSIX. Si el archivo de destino existe, atomic_write lo sobrescribe y conserva los propietarios y los permisos. Sin embargo, hay algunos casos en los que atomic_write no puede cambiar la propiedad o los permisos del archivo, este error se detecta y se omite confiando en el usuario/sistema de archivos para garantizar que el archivo sea accesible para los procesos que lo necesitan.

Debido a la operación chmod que realiza atomic_write, si el archivo de destino tiene una ACL configurada, esta ACL será recalculada / modificada.

Tenga en cuenta que no puede agregar con atomic_write.

El archivo auxiliar está escrito en un directorio estándar para archivos temporales, pero puede pasar un directorio de su elección como segundo argumento.

Definido en active_support/core_ext/file/atomic.rb.

20 Extensions to Marshal

20.1 load

Active Support agrega soporte constante de carga automática a load.

Por ejemplo, el almacén de caché de archivos se deserializa de esta manera:

File.open(file_name) { |f| Marshal.load(f) }

Si los datos almacenados en caché hacen referencia a una constante desconocida en ese momento, se activa el mecanismo de carga automática y, si tiene éxito, la deserialización se vuelve a intentar de forma transparente.

ADVERTENCIA. Si el argumento es un IO, debe responder a rewind para poder volver a intentarlo. Los archivos normales responden a rewind.

Definido en active_support/core_ext/marshal.rb.

21 Extensions to NameError

Active Support agrega missing_name? a NameError, que prueba si la excepción se generó debido al nombre pasado como argumento.

El nombre puede darse como símbolo o cadena. Un símbolo se compara con el nombre de constante simple, una cadena se compara con el nombre de constante completo.

Un símbolo puede representar un nombre de constante totalmente calificado como en :" ActiveRecord :: Base ", por lo que el comportamiento de los símbolos se define por conveniencia, no porque tenga que ser así técnicamente.

Por ejemplo, cuando una acción de ArticlesController se llama, Rails intenta de forma optimista usar ArticlesHelper. Está bien que el módulo auxiliar no exista, por lo que si se genera una excepción para ese nombre constante, se debe silenciar. Pero podría darse el caso de que articles_helper.rb genere unNameError debido a una constante desconocida real. Eso debería volver a plantearse. El método missing_name? Proporciona una forma de distinguir ambos casos:

def default_helper_module!
  module_name = name.sub(/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

Definido en active_support/core_ext/name_error.rb`.

22 Extensions to LoadError

Active Support agrega is_missing? a LoadError.

Dado un nombre de ruta, is_missing? Prueba si la excepción se generó debido a ese archivo en particular (excepto quizás por la extensión ".rb").

Por ejemplo, cuando una acción de ArticlesController se llama, Rails intenta cargar articles_helper.rb, pero es posible que ese archivo no exista. Está bien, el módulo de ayuda no es obligatorio, por lo que Rails silencia un error de carga. Pero podría darse el caso de que el módulo auxiliar exista y, a su vez, requiera otra biblioteca que falte. En ese caso, Rails debe volver a generar la excepción. El método is_missing? Proporciona una forma de distinguir ambos casos:

def default_helper_module!
  module_name = name.sub(/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

Definido en active_support/core_ext/load_error.rb.

Comentarios Sobre el Contenido

Las guías de rieles se administran y publican en latinadeveloper/railsguides.es en GitHub.

Si lee esta guía y encuentra algún texto o código incorrecto que le interese, no dude en enviar una solicitud de extracción en el repositorio anterior. Consulte el archivo README en GitHub para saber cómo enviar una solicitud de extracción. Please contribute if you see any typos or factual errors.