tutorial sirve rails que para documentacion descargar ruby

sirve - ruby tutorial



ventaja del método de tap en ruby (14)

Estaba leyendo un artículo del blog y me di cuenta de que el autor utilizaba el tap en un fragmento como:

user = User.new.tap do |u| u.username = "foobar" u.save! end

Mi pregunta es, ¿cuál es exactamente el beneficio o la ventaja de usar tap ? No podría simplemente hacer:

user = User.new user.username = "foobar" user.save!

o mejor aún:

user = User.create! username: "foobar"


Cuando los lectores se encuentran:

user = User.new user.username = "foobar" user.save!

Tendrían que seguir todas las tres líneas y luego reconocer que solo está creando una instancia llamada user .

Si fuera:

user = User.new.tap do |u| u.username = "foobar" u.save! end

entonces eso sería inmediatamente claro. Un lector no tendría que leer lo que está dentro del bloque para saber que se creó un user instancia.


En los rieles podemos usar los parámetros de tap para la lista blanca explícitamente:

def client_params params.require(:client).permit(:name).tap do |whitelist| whitelist[:name] = params[:client][:name] end end


Es un ayudante para el encadenamiento de llamadas. Pasa su objeto al bloque dado y, después de que el bloque termina, devuelve el objeto:

an_object.tap do |o| # do stuff with an_object, which is in o # end ===> an_object

El beneficio es que el toque siempre devuelve el objeto al que se llama, incluso si el bloque arroja algún otro resultado. Por lo tanto, puede insertar un bloque de tap en el medio de una tubería de método existente sin interrumpir el flujo.


Esto puede ser útil para depurar una serie de ámbitos encadenados de ActiveRecord .

User .active .tap { |users| puts "Users so far: #{users.size}" } .non_admin .tap { |users| puts "Users so far: #{users.size}" } .at_least_years_old(25) .tap { |users| puts "Users so far: #{users.size}" } .residing_in(''USA'')

Esto hace que sea muy fácil de depurar en cualquier punto de la cadena sin tener que almacenar nada en una variable local ni requiere mucha alteración del código original.

Y, por último, úselo como una forma rápida y discreta de depurar sin alterar la ejecución normal del código :

def rockwell_retro_encabulate provide_inverse_reactive_current synchronize_cardinal_graham_meters @result.tap(&method(:puts)) # Will debug `@result` just before returning it. end


Otro caso para usar el tap es hacer una manipulación en el objeto antes de devolverlo.

Entonces en vez de esto:

def some_method ... some_object.serialize some_object end

podemos ahorrar línea adicional:

def some_method ... some_object.tap{ |o| o.serialize } end

En alguna situación, esta técnica puede guardar más de una línea y hacer que el código sea más compacto.


Podría haber varios usos y lugares donde podamos usar el tap . Hasta ahora solo he encontrado los siguientes 2 usos de tap .

1) El objetivo principal de este método es acceder a una cadena de métodos para realizar operaciones en resultados intermedios dentro de la cadena. es decir

(1..10).tap { |x| puts "original: #{x.inspect}" }.to_a. tap { |x| puts "array: #{x.inspect}" }. select { |x| x%2 == 0 }. tap { |x| puts "evens: #{x.inspect}" }. map { |x| x*x }. tap { |x| puts "squares: #{x.inspect}" }

2) ¿Alguna vez se encontró llamando a un método sobre algún objeto, y el valor de retorno no era el que quería? Tal vez quería agregar un valor arbitrario a un conjunto de parámetros almacenados en un hash. Usted lo actualiza con Hash. [] , Pero obtiene una barra de retorno en lugar del hash de params, por lo que debe devolverlo explícitamente. es decir

def update_params(params) params[:foo] = ''bar'' params end

Para superar esta situación aquí, tap método entra en juego. Solo llámalo al objeto, luego pasa tap a block con el código que querías ejecutar. El objeto será cedido al bloque, luego será devuelto. es decir

def update_params(params) params.tap {|p| p[:foo] = ''bar'' } end

Hay docenas de otros casos de uso, intente encontrarlos usted mismo :)

Fuente:
1) Toque del objeto API Dock
2) five-ruby-methods-you-should-be-using


Puede hacer que sus códigos sean más modulares utilizando tap, y puede lograr una mejor administración de las variables locales. Por ejemplo, en el siguiente código, no necesita asignar una variable local al objeto recién creado, en el alcance del método. Tenga en cuenta que la variable de bloque, u , tiene un ámbito dentro del bloque. En realidad, es una de las bellezas del código ruby.

def a_method ... name = "foobar" ... return User.new.tap do |u| u.username = name u.save! end end


Resulta en un código menos recargado ya que el alcance de la variable está limitado solo a la parte donde realmente se necesita. Además, la sangría dentro del bloque hace que el código sea más legible al mantener juntos el código relevante.

La descripción del tap dice :

Se cede al bloque y luego regresa a sí mismo. El objetivo principal de este método es "aprovechar" una cadena de métodos para realizar operaciones en resultados intermedios dentro de la cadena.

Si buscamos el código fuente de los raíles para tap uso del tap , podemos encontrar algunos usos interesantes. A continuación hay algunos artículos (no una lista exhaustiva) que nos darán pocas ideas sobre cómo usarlos:

  1. Añade un elemento a una matriz según ciertas condiciones

    %w( annotations ... routes tmp ).tap { |arr| arr << ''statistics'' if Rake.application.current_scope.empty? }.each do |task| ... end

  2. Inicializando una matriz y devolviéndola

    [].tap do |msg| msg << "EXPLAIN for: #{sql}" ... msg << connection.explain(sql, bind) end.join("/n")

  3. Como azúcar sintáctico para hacer que el código sea más legible - Se puede decir, en el ejemplo a continuación, el uso del hash de variables y el server hace que la intención del código sea más clara.

    def select(*args, &block) dup.tap { |hash| hash.select!(*args, &block) } end

  4. Inicializar / invocar métodos en objetos recién creados.

    Rails::Server.new.tap do |server| require APP_PATH Dir.chdir(Rails.application.root) server.start end

    A continuación se muestra un ejemplo del archivo de prueba

    @pirate = Pirate.new.tap do |pirate| pirate.catchphrase = "Don''t call me!" pirate.birds_attributes = [{:name => ''Bird1''},{:name => ''Bird2''}] pirate.save! end

  5. Para actuar sobre el resultado de una llamada de yield sin tener que usar una variable temporal.

    yield.tap do |rendered_partial| collection_cache.write(key, rendered_partial, cache_options) end


Si desea devolver al usuario después de configurar el nombre de usuario, deberá hacerlo

user = User.new user.username = ''foobar'' user

Con un tap , podría guardar ese retorno incómodo

User.new.tap do |user| user.username = ''foobar'' end


Tienes razón: el uso del tap en tu ejemplo es un tanto inútil y probablemente menos limpio que tus alternativas.

Como señala Rebitzele, el tap es solo un método de conveniencia, a menudo usado para crear una referencia más corta al objeto actual.

Un buen caso de uso para el tap es la depuración: puede modificar el objeto, imprimir el estado actual y luego continuar modificando el objeto en el mismo bloque. Vea aquí, por ejemplo: http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-expressions .

De vez en cuando me gusta usar los métodos de tap dentro para regresar de manera condicional temprano mientras devuelvo el objeto actual de otra manera.


Una variación de la respuesta de @sawa:

Como ya se mencionó, el uso del tap ayuda a descifrar la intención de su código (aunque no necesariamente lo hace más compacto).

Las dos funciones siguientes son igualmente largas, pero en la primera debes leer hasta el final para descubrir por qué inicialicé una Hash vacía al principio.

def tapping1 # setting up a hash h = {} # working on it h[:one] = 1 h[:two] = 2 # returning the hash h end

Aquí, por otro lado, sabes desde el principio que el hash que se inicializa será la salida del bloque (y, en este caso, el valor de retorno de la función).

def tapping2 # a hash will be returned at the end of this block; # all work will occur inside Hash.new.tap do |h| h[:one] = 1 h[:two] = 2 end end


Usar el tap, como lo hizo el blogger, es simplemente un método de conveniencia. Puede haber sido excesivo en su ejemplo, pero en los casos en los que le gustaría hacer muchas cosas con el usuario, puede proporcionar una interfaz más limpia. Entonces, tal vez sea mejor en un ejemplo de la siguiente manera:

user = User.new.tap do |u| u.build_profile u.process_credit_card u.ship_out_item u.send_email_confirmation u.blahblahyougetmypoint end

El uso de lo anterior hace que sea fácil ver rápidamente que todos esos métodos están agrupados porque todos se refieren al mismo objeto (el usuario en este ejemplo). La alternativa sería:

user = User.new user.build_profile user.process_credit_card user.ship_out_item user.send_email_confirmation user.blahblahyougetmypoint

Una vez más, esto es discutible, pero se puede argumentar que la segunda versión parece un poco más desordenada y requiere un análisis humano más para ver que se están convocando todos los métodos al mismo objeto.


Visualice su ejemplo dentro de una función

def make_user(name) user = User.new user.username = name user.save! end

Hay un gran riesgo de mantenimiento con ese enfoque, básicamente el valor de retorno implícito .

En ese código, ¡sí dependes de save! devolviendo el usuario guardado. Pero si utilizas un pato diferente (o evoluciona tu actual), puedes obtener otras cosas, como un informe de estado de finalización. Por lo tanto, los cambios en el pato podrían romper el código, algo que no sucedería si garantiza el valor de retorno con un user simple o use el tap.

He visto accidentes como este bastante a menudo, especialmente con funciones en las que normalmente no se utiliza el valor de retorno, excepto en una esquina con errores oscuros.

El valor de retorno implícito tiende a ser una de esas cosas en que los novatos tienden a romper cosas agregando un nuevo código después de la última línea sin darse cuenta del efecto. No ven lo que realmente significa el código anterior:

def make_user(name) user = User.new user.username = name return user.save! # notice something different now? end


Yo diría que no hay ninguna ventaja al usar tap . El único beneficio potencial, como señala @sawa, es citar: "Un lector no tendría que leer lo que está dentro del bloque para saber que se creó un usuario de instancia". Sin embargo, en ese punto se puede argumentar que si está haciendo lógica de creación de registros no simplista, su intención sería mejor comunicada extrayendo esa lógica en su propio método.

Sostengo la opinión de que el tap es una carga innecesaria para la legibilidad del código, y podría hacerse sin, o sustituir con una mejor técnica, como el Método Extract .

Si bien el tap es un método de conveniencia, también es una preferencia personal. Dar tap una oportunidad. Luego, escribe un código sin usar el toque, mira si te gusta de una forma u otra.