Existe-t-il un Ruby ou un Ruby-ism pour not_nil? l'opposé de nul? méthode?

87

Je n'ai pas d'expérience en Ruby, donc mon code est "moche" et non idiomatique:

def logged_in?
  !user.nil?
end

Je préfère avoir quelque chose comme

def logged_in?
  user.not_nil?
end

Mais ne peut pas trouver une telle méthode qui s'oppose nil?

berkes
la source

Réponses:

51

lorsque vous utilisez ActiveSupport, il y a user.present? http://api.rubyonrails.org/classes/Object.html#method-i-present%3F , pour vérifier uniquement les non-nil, pourquoi ne pas utiliser

def logged_in?
  user # or !!user if you really want boolean's
end
lwe
la source
48
Attention: present?nécessite une chaîne non vide. ! "".nil?renvoie vrai, mais "".present?renvoie faux.
lambshaanxy
9
Attention 2: je noterai également que !! user ne fait PAS la distinction entre user étant nul et user étant faux; l'utilisation à double bang confond ces deux. Donc, si vous voulez vraiment déterminer si un objet n'est pas nul (c'est-à-dire: vrai, faux, 0, "", autre chose que nil), vous devez utiliser l'approche "moche" que les berkes n'aiment pas ou le monkeypatch que @Tempus propose ci-dessous . Bien sûr dans ce cas où pas nil n'est pas nécessaire (un utilisateur dans Rails), l'approche adoptée par Samo est la moins moche, imo.
likethesky
12
false.present? == false !false.nil? == true
Dudo
3
Cette réponse ne répond pas du tout à la question posée. C'est une réponse à ce problème particulier de mise en œuvre.
Ekkstein
3
Cette réponse n'est pas correcte. false.nil? est faux, alors que faux.présent? est AUSSI faux!
Mike
49

Vous semblez trop préoccupé par les booléens.

def logged_in?
  user
end

Si l'utilisateur est nul, alors connecté_in? renverra une valeur "falsey". Sinon, il renverra un objet. Dans Ruby, nous n'avons pas besoin de renvoyer true ou false, car nous avons des valeurs "true" et "falsey" comme en JavaScript.

Mettre à jour

Si vous utilisez Rails, vous pouvez rendre cela plus agréable en utilisant la present?méthode:

def logged_in?
  user.present?
end
Samo
la source
1
L'espérance avec une méthode se terminant par a ?est qu'elle renvoie un booléen. !!valueest le moyen classique de convertir quoi que ce soit en booléen. Pas exactement la même chose, mais dans ce cas, Object#present?RoR est également bon.
tokland
cela casse réellement dans Ruby 2.4 avec Path! [43] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.blank? true [44] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.to_s "/ var / folders / rp / _k99k0pn0rsb4d3lm9l3dnjh0000gn / T / d20170603-96466-zk7ctdi7" [45] (pryRecnecnets :: ReactRails) >: 0> assets_path.present? false [46] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.nil? false
justingordon
23

Méfiez-vous des autres réponses présentées present?comme une réponse à votre question.

present?est l'opposé de blank?in rails.

present?vérifie s'il existe une valeur significative. Ces choses peuvent échouer à un present?contrôle:

"".present? # false
"    ".present? # false
[].present? # false
false.present? # false
YourActiveRecordModel.where("false = true").present? # false

Alors qu'un !nil?chèque donne:

!"".nil? # true
!"    ".nil? # true
![].nil? # true
!false.nil? # true
!YourActiveRecordModel.where("false = true").nil? # true

nil?vérifie si un objet est réellement nil. Rien d' autre: une chaîne vide, 0, false, peu importe, n'est pas nil.

present?est très utile, mais certainement pas le contraire de nil?. La confusion des deux peut conduire à des erreurs inattendues.

Pour votre cas d'utilisation present?fonctionnera, mais il est toujours sage d'être conscient de la différence.

Un fader sombre
la source
Doit être inclus dans la réponse acceptée. false.blank?n'est pas la même chose quefalse.nil?
Yason
17

Peut-être que cela pourrait être une approche:

class Object
  def not_nil?
    !nil?
  end
end
Géo
la source
Bonne idée. Je fais de cela qu'il n'y a pas de not_nil? en Ruby. Mais cela ne devrait-il pas être !self.nil?plutôt alors !nil?, ou est-ce selfimplicite?
berkes
3
Vous n'avez pas besoin de vous-même. Ce sera implicite.
Geo
Self est impliqué lors de la lecture à partir de méthodes d'instance (ou d'accesseurs, qui ne sont en réalité que des méthodes). Lors de la définition des valeurs, une variable locale à la méthode sera créée avant que Ruby vérifie l'instance de classe pour une méthode setter du même nom. Règle générale: si vous avez un attr_accessor appelé xxx, utilisez "self.xxx = 3" (définition d'une valeur) ou "temp = xxx" (lecture de la valeur). L'utilisation de "xxx = 3" ne mettra pas à jour l'accesseur, créez simplement une nouvelle variable dans la portée de la méthode.
A Fader Darkly
4

Vous pouvez simplement utiliser ce qui suit:

if object
  p "object exists"
else
  p "object does not exist"
end

Cela ne fonctionne pas seulement pour nil mais aussi pour false, etc., vous devez donc tester pour voir si cela fonctionne dans votre cas d'utilisation.

Bitterzoet
la source
4

Puis-je offrir la !méthode Ruby-esque sur le résultat de la nil?méthode.

def logged_in?
  user.nil?.!
end

Tellement ésotérique que RubyMine IDE le signalera comme une erreur. ;-)

Christopher Oezbek
la source
2

Je suis arrivé à cette question à la recherche d'une méthode objet, afin que je puisse utiliser le Symbol#to_procraccourci au lieu d'un bloc; Je trouve arr.find(&:not_nil?)un peu plus lisible que arr.find { |e| !e.nil? }.

La méthode que j'ai trouvée est Object#itself. Dans mon utilisation, je voulais trouver la valeur dans un hachage pour la clé name, où, dans certains cas, cette clé était accidentellement capitalisée en tant que Name. Ce one-liner est le suivant:

# Extract values for several possible keys 
#   and find the first non-nil one
["Name", "name"].map { |k| my_hash[k] }.find(&:itself)

Comme indiqué dans d' autres réponses , cela échouera de façon spectaculaire dans les cas où vous testez un booléen.

Ian
la source
En quoi est-ce différent my_hash.values_at("Name", "name").find?
berkes
C'est exactement la même chose. J'avais une autre logique dans mon original mapque j'ai supprimée pour plus de simplicité dans cet exemple, donc comme écrit ici, c'est interchangeable avec values_at. L'important est ce à quoi on passe find.
Ian