ruby - variacion - ¿Método combinatorio como tap, pero capaz de devolver un valor diferente?
probabilidad combinatoria formula (5)
Defina el Object#as
:
class Object
def as
yield self
end
end
Y ahora puedes escribir:
def not_sure_this_is_nice_enough_method1
something_complex(a, b, c).as do |obj|
a_predicate_check? ? obj.one_more_method_call : obj
end
end
Estoy pasando por una fase de tratar de evitar las variables temporales y el uso excesivo de condicionales, donde puedo usar un estilo de codificación más fluido. Me ha gustado mucho usar #tap
en lugares donde quiero obtener el valor que necesito para devolver, pero haz algo con él antes de devolverlo.
def fluid_method
something_complicated(a, b, c).tap do |obj|
obj.update(:x => y)
end
end
Vs. el procedimental:
def non_fluid_method
obj = something_complicated(a, b, c)
obj.update(:x => y)
obj # <= I don''t like this, if it''s avoidable
end
Obviamente, los ejemplos anteriores son simples, pero este es un estilo de codificación bastante común en la comunidad ruby, no obstante. A veces #inject
para pasar un objeto a través de una serie de filtros también:
things.inject(whatever) do |obj, thing|
thing.filter(obj)
end
Vs. el procedimental:
obj = whatever
things.each do |thing|
obj = thing.filter(obj)
end
obj
Ahora enfrento el uso repetido de una condición como la siguiente, y busco un enfoque más fluido para manejarlo:
def not_nice_method
obj = something_complex(a, b, c)
if a_predicate_check?
obj.one_more_method_call
else
obj
end
end
La solución (ligeramente) más limpia es evitar la variable temporal a costa de la duplicación:
def not_nice_method
if a_predicate_check?
something_complex(a, b, c).one_more_method_call
else
something_complex(a, b, c)
end
end
Sin embargo, no puedo evitar sentir el deseo de usar algo como #tap
aquí.
¿Qué otros patrones podría seguir aquí? Me doy cuenta de que esto no es más que una simple falta de sentido para algunas personas y que simplemente debería pasar a problemas más interesantes, pero estoy tratando de aprender a escribir en un estilo más funcional, así que tengo curiosidad por lo que los rubyistas a largo plazo han determinado. Ser buenas maneras de enfrentar situaciones como esta. Estos ejemplos son enormemente simplificados.
Encontré un método en la gema de Facetas que podría ser lo que estabas buscando: Kernel#ergo
Así que tu método original:
def not_nice_method
obj = something_complex(a, b, c)
if a_predicate_check?
obj.one_more_method_call
else
obj
end
end
podría terminar buscando algo como esto:
require ''facets/kernel/ergo''
def nice_method
something_complex(a, b, c).ergo do |_|
a_predicate_check? ? _.one_more_method_call : _
end
end
Necesitaba hacer algo como esto y me gusta la respuesta de tokland, pero no quería contaminar a Object por el pequeño script que estaba escribiendo. En su lugar, hice uso de tap
en una matriz:
[something_complicated].tap { |s| s[0] = new_cool_thing)}.first
instance_eval
puede ser mal usado para este propósito
"this".instance_eval { |test| test + " works" }
Desde 2.5 es posible usar yield_self
"easy".yield_self{ |a| a + " peasy" }
Lee mas:
https://ruby-doc.org/core-1.9.3/BasicObject.html#method-i-instance_eval
https://ruby-doc.org/core-2.5.0/Object.html#method-i-yield_self
def best_nice_method
something_complex(a, b, c).tap |obj|
break obj.one_more_method_call if a_predicate_check?
end
end
La magia es break
in tap
devuelve otro valor.
nuevo
Ruby 2.5 se ha yield_self
que exactamente quieres. https://.com/a/47890832/683157