ruby - globally - how to run rubocop
¿Por qué RuboCop sugiere reemplazar.times.map con Array.new? (3)
RuboCop sugiere:
Use
Array.new
con un bloque en lugar de.times.map.
En los docs para la policía:
Esta policía comprueba las llamadas .times.map. En la mayoría de los casos, dichas llamadas pueden reemplazarse con una creación de matriz explícita.
Ejemplos:
# bad
9.times.map do |i|
i.to_s
end
# good
Array.new(9) do |i|
i.to_s
end
Sé que se puede reemplazar, pero creo que 9.times.map
está más cerca de la gramática inglesa y es más fácil entender lo que hace el código.
¿Por qué debería ser reemplazado?
El último es más eficaz, aquí hay una explicación: Solicitud de extracción donde se agregó esta policía
Comprueba llamadas como esta:
9.times.map { |i| f(i) } 9.times.collect(&foo)
y sugiere usar esto en su lugar:
Array.new(9) { |i| f(i) } Array.new(9, &foo)
El nuevo código tiene aproximadamente el mismo tamaño, pero utiliza menos métodos, consume menos memoria, funciona un poco más rápido y, en mi opinión, es más legible.
He visto muchas veces: {map, collect} en diferentes proyectos conocidos: Rails, GitLab, Rubocop y varias aplicaciones de código cerrado.
Puntos de referencia:
Benchmark.ips do |x| x.report(''times.map'') { 5.times.map{} } x.report(''Array.new'') { Array.new(5){} } x.compare! end __END__ Calculating ------------------------------------- times.map 21.188k i/100ms Array.new 30.449k i/100ms ------------------------------------------------- times.map 311.613k (± 3.5%) i/s - 1.568M Array.new 590.374k (± 1.2%) i/s - 2.954M Comparison: Array.new: 590373.6 i/s times.map: 311612.8 i/s - 1.89x slower
Ahora no estoy seguro de que Lint sea el espacio de nombres correcto para la policía. Avísame si debo moverlo a Performance.
Además, no implementé la corrección automática porque potencialmente puede romper el código existente, por ejemplo, si alguien tiene el método Fixnum # times redefinido para hacer algo sofisticado. Aplicar la autocorrección rompería su código.
Si sientes que es más legible ve con ello.
Esta es una regla de rendimiento y la mayoría de los códigos de ruta en su aplicación probablemente no sean críticos para el rendimiento. Personalmente, siempre estoy abierto a favorecer la legibilidad sobre la optimización prematura.
Que dicho
100.times.map { ... }
-
times
crea un objetoEnumerator
-
map
enumera sobre ese objeto sin poder optimizarlo, por ejemplo, el tamaño de la matriz no se conoce por adelantado y podría tener que reasignar más espacio dinámicamente y tiene que enumerar los valores al llamarEnumerable#each
ya que elmap
se implementa de esa manera
Mientras
Array.new(100) { ... }
-
new
asigna una matriz de tamañoN
- Y luego usa un bucle nativo para completar los valores