Apakah ada Ruby, atau Ruby-ism untuk not_nil? kebalikan dari nihil? metode?


87

Saya tidak berpengalaman dalam Ruby, jadi kode saya terasa "jelek" dan tidak idiomatis:

def logged_in?
  !user.nil?
end

Saya lebih memilih sesuatu seperti

def logged_in?
  user.not_nil?
end

Tetapi tidak dapat menemukan metode yang berlawanan nil?

Jawaban:


50

ketika Anda menggunakan ActiveSupport, ada user.present? http://api.rubyonrails.org/classes/Object.html#method-i-present%3F , untuk memeriksa non-nil saja, mengapa tidak menggunakan

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

48
Hati-hati: present?membutuhkan string yang tidak kosong. ! "".nil?mengembalikan nilai benar, tetapi "".present?mengembalikan salah.
lambshaanxy

9
Hati-hati 2: Saya juga akan mencatat bahwa !! pengguna TIDAK membedakan antara pengguna nil dan pengguna salah; penggunaan double-bang menggabungkan keduanya. Jadi jika Anda benar-benar ingin menentukan apakah suatu objek tidak nihil (artinya: benar, salah, 0, "", apa pun selain nihil), Anda perlu menggunakan pendekatan 'jelek' yang tidak disukai berkes. atau monkeypatch yang diusulkan @Tempus di bawah ini . Tentu saja dalam kasus ini di mana tidak nil tidak diperlukan (pengguna di Rails), pendekatan yang diambil oleh Samo adalah yang paling jelek, imo.
likethesky

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

3
Jawaban ini sama sekali tidak menjawab pertanyaan yang diajukan. Ini adalah jawaban untuk masalah implementasi khusus ini.
Ekkstein

3
Jawaban ini tidak benar. false.nil? salah, sedangkan false.present? JUGA salah!
Mike

49

Anda tampaknya terlalu khawatir dengan boolean.

def logged_in?
  user
end

Jika pengguna nihil, lalu login_in? akan mengembalikan nilai "falsey". Jika tidak, itu akan mengembalikan objek. Di Ruby kita tidak perlu mengembalikan true atau false, karena kita memiliki nilai "truthy" dan "falsey" seperti di JavaScript.

Memperbarui

Jika Anda menggunakan Rails, Anda dapat membuat pembacaan ini lebih baik dengan menggunakan present?metode:

def logged_in?
  user.present?
end

1
Harapan dengan metode yang diakhiri dengan a ?adalah mengembalikan boolean. !!valueadalah cara klasik untuk mengonversi apa pun menjadi boolean. Tidak persis sama, tapi dalam hal ini Object#present?RoR juga bagus.
tokland

ini benar-benar rusak di Ruby 2.4 dengan Path! [43] (membongkar) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.blank? true [44] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.to_s "/ var / folder / rp / _k99k0pn0rsb4d3lm9l3dnjh0000gn / T / d20170603-96466-zk7di7" [45] (pry) # <ReactOnRompails >: 0> assets_path.present? false [46] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.nil? false
justingordon pada

26

Waspadai jawaban lain yang muncul present?sebagai jawaban atas pertanyaan Anda.

present?adalah kebalikan dari blank?in rails.

present?memeriksa apakah ada nilai yang berarti. Hal-hal ini dapat gagal dalam present?pemeriksaan:

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

Sedangkan !nil?cek memberikan:

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

nil?memeriksa apakah suatu objek sebenarnya nil. Ada lagi: string kosong, 0, false, apa pun, tidak nil.

present?sangat berguna, tapi jelas bukan kebalikan dari nil?. Membingungkan keduanya dapat menyebabkan kesalahan yang tidak terduga.

Untuk kasus penggunaan Anda present?akan berfungsi, tetapi selalu bijaksana untuk menyadari perbedaannya.


Harus dimasukkan dalam jawaban yang diterima. false.blank?tidak sama denganfalse.nil?
Yason

present?akan menanyakan database Anda, nil?tidak akan, berhati-hatilah dengan itu
Tony

17

Mungkin ini bisa menjadi pendekatan:

class Object
  def not_nil?
    !nil?
  end
end

Ide bagus. Saya membuat dari ini bahwa tidak ada not_nil? di Ruby. Tetapi bukankah ini seharusnya !self.nil?lebih dari itu !nil?, atau selfimplisit?
berkes

3
Anda tidak membutuhkan diri sendiri. Ini akan tersirat.
Geo

Self tersirat ketika membaca dari metode contoh (atau pengakses, yang sebenarnya hanya metode). Saat mengatur nilai, variabel lokal ke metode akan dibuat sebelum Ruby memeriksa instance kelas untuk metode penyetel dengan nama yang sama. Aturan umum: jika Anda memiliki attr_accessor yang disebut xxx, gunakan "self.xxx = 3" (menyetel nilai) atau "temp = xxx" (membaca nilainya). Menggunakan "xxx = 3" tidak akan memperbarui pengakses, cukup buat variabel baru dalam cakupan metode.
A Fader Darkly

5

Izinkan saya menawarkan metode Ruby-esque !pada hasil dari nil?metode tersebut.

def logged_in?
  user.nil?.!
end

Sangat esoteris sehingga RubyMine IDE akan menandainya sebagai kesalahan. ;-)


4

Anda bisa menggunakan yang berikut ini:

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

Ini tidak hanya bekerja untuk nil tetapi juga false dll, jadi Anda harus menguji untuk melihat apakah itu berhasil dalam usecase Anda.


2

Saya sampai pada pertanyaan ini mencari metode objek, sehingga saya bisa menggunakan Symbol#to_procsingkatan alih-alih blok; Saya merasa arr.find(&:not_nil?)agak lebih mudah dibaca daripada arr.find { |e| !e.nil? }.

Metode yang saya temukan adalah Object#itself. Dalam penggunaan saya, saya ingin menemukan nilai dalam hash untuk kunci tersebut name, di mana dalam beberapa kasus kunci tersebut secara tidak sengaja dikapitalisasi sebagai Name. Satu baris itu adalah sebagai berikut:

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

Seperti disebutkan dalam jawaban lain , ini akan gagal secara spektakuler jika Anda menguji boolean.


Apa bedanya dengan my_hash.values_at("Name", "name").find?
berkes

Itu persis sama. Saya memiliki beberapa logika lain dalam aslinya mapyang saya hapus untuk kesederhanaan dalam contoh ini, jadi seperti yang tertulis di sini itu dapat dipertukarkan dengan values_at. Bagian terpenting adalah apa yang diteruskan find.
Ian
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.