Ruby 2.0, 65 76 164 karakter
eval r="gets p;$<.pos=0;`ruby -c 2>&0`;p$?==0&&$_!='eval r=%p'%r"
Ini menggunakan checker sintaks bawaan Ruby ( ruby -c
) untuk memeriksa sintaks input, yang berarti kode tidak akan dievaluasi.
Contoh penggunaan dasar:
ruby syntax.rb <<< foo
true
ruby syntax.rb <<< "'"
false
ruby syntax.rb < synxtax.rb # assumes the file was saved without trailing newline
false
Penjelasan
Solusi ini didasarkan pada standar Ruby quine:
q="q=%p;puts q%%q";puts q%q
%p
adalah penentu format untuk arg.inspect
, yang dapat dibandingkan dengan uneval
: ketika eval
string dikembalikan oleh arg.inspect
, Anda (biasanya) mendapatkan nilai asli lagi. Jadi, ketika memformat q
string dengan dirinya sendiri sebagai argumen, bagian %p
dalam string akan diganti dengan string yang dikutip itu sendiri (yaitu kita mendapatkan sesuatu seperti "q=\"q=%p;puts q%%q\";puts q%q"
).
Generalisasi jenis quine ini mengarah ke sesuatu seperti berikut:
prelude;q="prelude;q=%p;postlude";postlude
Pendekatan ini memiliki satu kelemahan besar (setidaknya dalam kode-golf ): Semua kode harus diduplikasi. Untungnya, eval
bisa digunakan untuk menyiasati ini:
eval r="some code;'eval r=%p'%r"
Apa yang terjadi di sini adalah bahwa kode yang dikirimkan ke eval disimpan di dalam r
sebelum eval
dipanggil. Akibatnya, kode sumber lengkap dari eval
pernyataan tersebut dapat diperoleh dengan 'eval r=%p'%r
. Jika kita melakukan ini di dalam eval
kode d dan memastikan bahwa level teratas dari kita hanya terdiri dari satu eval
pernyataan, ekspresi itu benar-benar memberi kita kode sumber penuh dari program kita, karena kode tambahan yang diteruskan ke eval
sudah tersimpan di dalamnya r
.
Catatan: Pendekatan ini sebenarnya memungkinkan kita untuk menulis Ruby quine dalam 26 karakter: eval r="puts'eval r=%p'%r"
Sekarang, dalam solusi ini kode tambahan yang dijalankan di dalam eval
terdiri dari empat pernyataan:
gets p
Pertama, kami membaca semua input dari STDIN dan secara implisit menyimpannya $_
.
$<.pos=0
Kemudian, kami memundurkan STDIN sehingga input tersedia lagi untuk subproses yang kami mulai pada langkah berikutnya.
`ruby -c 2>&0`
Ini memulai Ruby dalam mode pemeriksaan sintaks bawaannya, membaca kode sumber dari stdin. Jika sintaks skrip yang disediakan (nama file atau stdin) ok, ia mencetak Syntax OK
ke stdout (yang ditangkap oleh proses induk), tetapi dalam kasus kesalahan sintaks, deskripsi kesalahan dicetak ke stderr - yang akan menjadi terlihat, jadi kami mengarahkan itu ke nirwana ( 2>&0
) sebagai gantinya.
p$?==0&&$_!='eval r=%p'%r
Setelah itu, kami memeriksa kode keluar subproses $?
, yaitu 0 jika sintaksnya ok. Terakhir, input yang kita baca sebelumnya ( $_
) dibandingkan dengan kode sumber kita sendiri (yang, seperti yang saya jelaskan sebelumnya, dapat diperoleh dengan 'eval r=%p'%r
).
Sunting: Disimpan 14 karakter berkat @ histokrat!