33 votes

Méthode combinatoire comme tap, mais capable de retourner une valeur différente?

Je traverse une phase où j'essaie d'éviter les variables temporaires et l'abus de conditions là où je peux utiliser un style de codage plus fluide. J'ai beaucoup aimé utiliser #tap dans les cas où je veux obtenir la valeur dont j'ai besoin pour la retourner, mais faire quelque chose avec avant de la retourner.

def méthode_fluide
  quelque_chose_de_compliqué(a, b, c).tap do |obj|
    obj.update(:x => y)
  end

Par rapport à la méthode procédurale:

def méthode_non_fluide
  obj = quelque_chose_de_compliqué(a, b, c)
  obj.update(:x => y)
  obj # <= Je n'aime pas ça, si c'est évitable

De toute évidence, les exemples ci-dessus sont simples, mais c'est un style de codage assez courant dans la communauté ruby. Parfois, j'utiliserai #inject pour passer un objet à travers une série de filtres également:

choses.inject(quelque_chose) do |obj, chose|
  chose.filtre(obj)

Par rapport à la méthode procédurale:

obj = quelque_chose
choses.each do |chose|
  obj = chose.filter(obj)

Maintenant, je suis confronté à une utilisation répétée d'une condition comme celle-ci, et je cherche une approche plus fluide pour la gérer:

def méthode_pas_sympa
  obj = quelque_chose_de_complexe(a, b, c)
  if a_predicate_check?
    obj.one_more_method_call
  else
    obj
  end

La solution (légèrement) plus propre est d'éviter la variable temporaire au détriment de la duplication:

def méthode_pas_sympa
  if a_predicate_check?
    quelque_chose_de_complexe(a, b, c).one_more_method_call
  else
    quelque_chose_de_complexe(a, b, c)
  end

Je ne peux m'empêcher de ressentir le désir d'utiliser quelque chose presque comme #tap ici cependant.

Quels autres motifs pourrais-je suivre ici. Je réalise que tout cela n'est que du sucre absurde pour certaines personnes et que je devrais passer à des problèmes plus intéressants, mais j'essaie d'apprendre à écrire dans un style plus fonctionnel, donc je suis juste curieux de savoir ce que les rubyistes de longue date ont déterminé être de bonnes façons de traiter des situations comme celle-ci. Ces exemples sont très simplifiés.

0voto

smendola Points 851
class Object
  def apply_if(pred)
    if pred
      yield self
    else
      self
    end
  end
end

Utilisation typique :

      def rlrs_usage_by_group(group_id, date_range = nil)
        views = ContentView.joins(user: [:groups])
                           .where(groups: { id: group_id })
                           .where(viewable_type: 'RealStory')
                           .apply_if(date_range) {
                             _1.where(viewed_at: date_range)
                           }
      end

Votre cas :

def nice_method
  something_complex(a, b, c)
    .apply_if(a_predicate_check?) { 
      _1.one_more_method_call
    }

ou même

  something_complex(a, b, c)
     .apply_if(a_predicate_check, &:one_more_method_call)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X