Existe um Ruby, ou Ruby-ism para not_nil? oposto de nulo? método?


87

Não tenho experiência em Ruby, então meu código parece "feio" e não idiomático:

def logged_in?
  !user.nil?
end

Eu prefiro ter algo como

def logged_in?
  user.not_nil?
end

Mas não consigo encontrar um método que opõe nil?

Respostas:


51

quando você estiver usando o ActiveSupport, há user.present? http://api.rubyonrails.org/classes/Object.html#method-i-present%3F , para verificar apenas se não for nulo, por que não usar

def logged_in?
  user # or !!user if you really want boolean's
end

48
Cuidado: present?requer uma string não em branco. ! "".nil?retorna verdadeiro, mas "".present?retorna falso.
— lambshaanxy

9
Cuidado 2: também observarei que !! o usuário NÃO distingue entre o usuário ser nulo e o usuário ser falso; o uso de double-bang combina esses dois. Então, se você realmente deseja determinar se um objeto não é nulo (ou seja, é: verdadeiro, falso, 0, "", qualquer coisa diferente de nulo), você precisa usar a abordagem 'feia' que o berkes não gosta ou o monkeypatch que @Tempus propõe abaixo . Claro que neste caso não nulo é não necessário (um usuário em Rails), a abordagem adoptada por Samo é o menos feio, imo.
— likethesky de

12
false.present? == false !false.nil? == true
— Dudo

3
Esta resposta não responde de forma alguma à pergunta feita. É uma resposta a este problema de implementação específico.
— Ekkstein

3
Esta resposta não está correta. false.nil? é falso, enquanto false.present? TAMBÉM é falso!
— Mike

49

Você parece excessivamente preocupado com booleanos.

def logged_in?
  user
end

Se o usuário for nulo, então conectado? retornará um valor "falsey". Caso contrário, ele retornará um objeto. Em Ruby, não precisamos retornar verdadeiro ou falso, uma vez que temos os valores "truthy" e "falsey" como em JavaScript.

Atualizar

Se você estiver usando Rails, você pode fazer isso de forma mais agradável usando o present?método:

def logged_in?
  user.present?
end

1
A expectativa de um método que termina com a ?é que ele retorne um booleano. !!valueé a maneira clássica de converter qualquer coisa em booleano. Não é exatamente o mesmo, mas neste caso Object#present?em RoR também é bom.
— tokland

isso realmente quebra no Ruby 2.4 com o Path! [43] (erguer) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.blank? true [44] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.to_s "/ var / folders / rp / _k99k0pn0rsb4d3lm9l3dnjh0000gn / T / d20170603-96466-zk7di7PrecnO" [45R] (pry) >: 0> assets_path.present? false [46] (erguer) # <ReactOnRails :: AssetsPrecompile>: 0> caminho_de_matos.nil? false
— justingordon

23

Cuidado com as outras respostas apresentadas present?como uma resposta à sua pergunta.

present?é o oposto de blank?em trilhos.

present?verifica se há um valor significativo. Essas coisas podem falhar em uma present?verificação:

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

Considerando que um !nil?cheque dá:

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

nil?verifica se um objeto é realmente nil. Qualquer outra coisa: uma cadeia vazia, 0, false, qualquer que seja, não é nil.

present?é muito útil, mas definitivamente não é o oposto de nil?. Confundir os dois pode levar a erros inesperados.

Pois o seu caso de uso present?funcionará, mas é sempre bom estar ciente da diferença.


Deve ser incluído na resposta aceita. false.blank?não é o mesmo quefalse.nil?
— Yason

17

Talvez esta seja uma abordagem:

class Object
  def not_nil?
    !nil?
  end
end

Boa ideia. Eu concluo que não há not_nil? em Ruby. Mas isso não deveria ser!self.nil? antes !nil?ou está selfimplícito?
— berkes em

3
Você não precisa de si mesmo. Estará implícito.
— Geo

Self está implícito na leitura de métodos de instância (ou acessores, que na verdade são apenas métodos). Ao definir valores, uma variável local para o método será criada antes que Ruby verifique a instância da classe para um método setter com o mesmo nome. Regra geral: se você tiver um attr_accessor chamado xxx, use "self.xxx = 3" (definindo um valor) ou "temp = xxx" (lendo o valor). Usar "xxx = 3" não atualizará o acessador, apenas crie uma nova variável no escopo do método.
— A Fader Darkly

4

Você pode apenas usar o seguinte:

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

Isso não funciona apenas para nil, mas também para false etc., então você deve testar para ver se funciona em seu caso de uso.


4

Posso oferecer o !método Ruby no resultado do nil?método.

def logged_in?
  user.nil?.!
end

Tão esotérico que o IDE RubyMine irá sinalizar como um erro. ;-)


2

Cheguei a esta questão procurando por um método de objeto, para que pudesse usar a Symbol#to_procabreviação em vez de um bloco; Acho arr.find(&:not_nil?)um pouco mais legível do que arr.find { |e| !e.nil? }.

O método que encontrei é Object#itself. No meu uso, eu queria encontrar o valor em um hash para a chave name, onde em alguns casos essa chave foi acidentalmente capitalizada como Name. Esse one-liner é o seguinte:

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

Conforme observado em outras respostas , isso falhará espetacularmente nos casos em que você estiver testando um booleano.


Como isso é diferente de my_hash.values_at("Name", "name").find?
— berkes

É exatamente o mesmo. Eu tinha alguma outra lógica no meu original mapque removi para simplificar neste exemplo, então como está escrito aqui é intercambiável com values_at. A parte importante é o que é passado find.
— Ian
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.