Fitur tersembunyi Ruby


160

Melanjutkan meme "Fitur tersembunyi ...", mari berbagi fitur bahasa pemrograman Ruby yang kurang dikenal namun bermanfaat.

Cobalah batasi diskusi ini dengan Ruby inti, tanpa Ruby apa pun.

Lihat juga:

(Tolong, hanya satu fitur tersembunyi per jawaban.)

Terima kasih


seharusnya menjadi komunitas wiki
SilentGhost

Jawaban:


80

Dari Ruby 1.9 Proc # === adalah alias untuk panggilan Proc #, yang berarti objek Proc dapat digunakan dalam pernyataan kasus seperti:

def multiple_of(factor)
  Proc.new{|product| product.modulo(factor).zero?}
end

case number
  when multiple_of(3)
    puts "Multiple of 3"
  when multiple_of(7)
    puts "Multiple of 7"
end

1
Saya benar-benar menulis permata pada satu titik untuk melakukan ini, tetapi kode saya (a) berantakan, dan (b) lambat. Saya sangat senang bahwa fungsinya telah menjadikannya inti.
James A. Rosen

76

Peter Cooper memiliki daftar trik Ruby yang bagus. Mungkin favorit saya miliknya adalah memungkinkan item tunggal dan koleksi untuk disebutkan. (Yaitu, perlakukan objek non-koleksi sebagai koleksi yang berisi objek itu saja.) Kelihatannya seperti ini:

[*items].each do |item|
  # ...
end

38
A (dan dengan demikian lebih bagus) bentuk yang lebih eksplisit ini adalah Array (item) .each
mislav

Jika itemsadalah string, Anda tidak harus melampirkannya dengan [* ...] String.each tidak mengulangi karakter seperti yang diharapkan beberapa orang. Itu hanya mengembalikan dirinya ke blok.
mxcl

Apa gunanya ini melayani? Hanya penasaran.
Ed S.

1
@ Ed: senang jika Anda sedang menulis metode dan ingin mengizinkan pengguna metode untuk melewati daftar varargs atau Array.
James A. Rosen

64

Tidak tahu seberapa tersembunyi ini, tapi saya merasa berguna ketika perlu membuat Hash dari array satu dimensi:

fruit = ["apple","red","banana","yellow"]
=> ["apple", "red", "banana", "yellow"]

Hash[*fruit]    
=> {"apple"=>"red", "banana"=>"yellow"}

Catatan yang Hash[ [["apple","red"], ["banana","yellow"] ]menghasilkan hasil yang sama.
Marc-André Lafortune

54

Salah satu trik yang saya suka adalah dengan menggunakan splat ( *) expander pada objek selain Array. Berikut ini contoh pada pencocokan ekspresi reguler:

match, text, number = *"Something 981".match(/([A-z]*) ([0-9]*)/)

Contoh lain termasuk:

a, b, c = *('A'..'Z')

Job = Struct.new(:name, :occupation)
tom = Job.new("Tom", "Developer")
name, occupation = *tom

13
Kebetulan, bagi yang penasaran, ini bekerja dengan secara implisit memanggil to_a pada target percikan.
Bob Aman

1
Jika Anda tidak tertarik pada pertandingan, Anda bisa melakukannya text, number = *"text 555".match(/regexp/)[1..-1].
Andrew Grimm

text, number = "Something 981".scan(/([A-z]*) ([0-9]*)/).flatten.map{|m| Integer(m) rescue m}
Jonas Elfström

7
Keduanya trik yang bagus, tapi pasti ada titik di mana itu terlalu banyak sihir, kan ?!
tomafro

1
@Andrew, apakah Anda menganggap, bahwa pertandingan dapat mengembalikan nol? nil tidak punya metode []
Alexey

52

Wow, tidak ada yang menyebut operator flip flop:

1.upto(100) do |i|
  puts i if (i == 3)..(i == 15)
end

11
Benar ... seseorang harus menjelaskan yang ini padaku. Ini berhasil, tetapi saya tidak tahu mengapa.
Bob Aman

12
Operator flip flop adalah statefull if. Keadaannya beralih ke true segera i == 3dan beralih ke false setelah i != 3 dan i == 15. Mirip dengan flip-flop: en.wikipedia.org/wiki/Flip-flop_%28electronics%29
Konstantin Haase

1
Saya tidak akan menyebut ini sebagai fitur tersembunyi, sangat menyebalkan. Saya ingat pertama kali saya diperkenalkan di #Ruby on Freenode, tahun lalu; Saya pada dasarnya telah menggunakan setiap fitur Ruby di beberapa titik kecuali yang ini.
DAPAT DITERBITKAN

1
Saya tidak akan menyebutnya gangguan, itu hanya sesuatu yang belum Anda gunakan. Saya menggunakannya dan itu dapat mengurangi kode dengan baik, terutama ketika saya mengambil blok dari file berdasarkan beberapa kriteria.
the Tin Man

49

Salah satu hal keren tentang ruby ​​adalah Anda dapat memanggil metode dan menjalankan kode di tempat yang disukai oleh bahasa lain, seperti dalam metode atau definisi kelas.

Misalnya, untuk membuat kelas yang memiliki superclass yang tidak diketahui sampai waktu berjalan, yaitu acak, Anda bisa melakukan hal berikut:

class RandomSubclass < [Array, Hash, String, Fixnum, Float, TrueClass].sample

end

RandomSubclass.superclass # could output one of 6 different classes.

Ini menggunakan Array#samplemetode 1.9 (hanya 1.8.7, lihat Array#choice), dan contohnya cukup dibuat tetapi Anda dapat melihat kekuatannya di sini.

Contoh keren lainnya adalah kemampuan untuk menempatkan nilai parameter default yang tidak tetap (seperti bahasa lain yang sering diminta):

def do_something_at(something, at = Time.now)
   # ...
end

Tentu saja masalah dengan contoh pertama adalah bahwa ia dievaluasi pada waktu definisi, bukan waktu panggilan. Jadi, sekali superclass telah dipilih, ia tetap superclass itu untuk sisa program.

Namun, dalam contoh kedua, setiap kali Anda menelepon do_something_at, atvariabel akan menjadi waktu metode dipanggil (well, sangat sangat dekat dengannya)


2
Catatan: Array # rand disediakan oleh ActiveSupport yang dapat Anda gunakan di luar Rails semudahrequire 'activesupport'
rfunduk

Array # choice ada di 1.8.7
Josh Lee

24
Pilihan # array hanya 1,8.7 ! Jangan gunakan itu, sudah hilang di 1.9 dan akan hilang di 1.8.8. Gunakan #sample
Marc-André Lafortune

python: class DictList ([dict, list] [random.randint (0,1)]): pass
Anurag Uniyal

def do_something_at (sesuatu, at = lambda {Time.now}) at.call #sekarang secara dinamis menetapkan waktu akhir
Jack Kinsella

47

Fitur mungil lainnya - konversikan Fixnummenjadi basis apa saja hingga 36:

>> 1234567890.to_s(2)
=> "1001001100101100000001011010010"

>> 1234567890.to_s(8)
=> "11145401322"

>> 1234567890.to_s(16)
=> "499602d2"

>> 1234567890.to_s(24)
=> "6b1230i"

>> 1234567890.to_s(36)
=> "kf12oi"

Dan seperti komentar Huw Walters, mengonversi dengan cara lain sama mudahnya:

>> "kf12oi".to_i(36)
=> 1234567890

1
Dan untuk kelengkapannya, String#to_s(base)dapat digunakan untuk mengkonversi kembali ke integer; "1001001100101100000001011010010".to_i(2), "499602d2".to_i(16)dll semua mengembalikan yang asli Fixnum.
Huw Walters

40

Hash dengan nilai default! Array dalam hal ini.

parties = Hash.new {|hash, key| hash[key] = [] }
parties["Summer party"]
# => []

parties["Summer party"] << "Joe"
parties["Other party"] << "Jane"

Sangat berguna dalam metaprogramming.


1
ya benar. Hash Ruby dapat menerima operator '<<' jika sudah ada penetapan nilai default dengan '=' (tidak peduli meskipun itu tugas kosong) jika tidak, hash tidak akan menerima '<<'. CMIIW
mhd

39

Unduh sumber Ruby 1.9, dan terbitkan make golf, maka Anda dapat melakukan hal-hal seperti ini:

make golf

./goruby -e 'h'
# => Hello, world!

./goruby -e 'p St'
# => StandardError

./goruby -e 'p 1.tf'
# => 1.0

./goruby19 -e 'p Fil.exp(".")'
"/home/manveru/pkgbuilds/ruby-svn/src/trunk"

Baca golf_prelude.cuntuk hal-hal yang lebih rapi bersembunyi.


38

Tambahan menyenangkan lainnya dalam fungsi 1.9 Proc adalah Proc # curry yang memungkinkan Anda untuk mengubah argumen yang menerima Proc menjadi argumen yang menerima n-1. Ini dikombinasikan dengan tips Proc # === yang saya sebutkan di atas:

it_is_day_of_week = lambda{ |day_of_week, date| date.wday == day_of_week }
it_is_saturday = it_is_day_of_week.curry[6]
it_is_sunday = it_is_day_of_week.curry[0]

case Time.now
when it_is_saturday
  puts "Saturday!"
when it_is_sunday
  puts "Sunday!"
else
  puts "Not the weekend"
end

35

Operator Boolean pada nilai non boolean.

&& dan ||

Keduanya mengembalikan nilai ekspresi terakhir yang dievaluasi.

Itu sebabnya ||=akan memperbarui variabel dengan nilai yang dikembalikan ekspresi di sisi kanan jika variabel tidak terdefinisi. Ini tidak didokumentasikan secara eksplisit, tetapi pengetahuan umum.

Namun &&=tidak begitu banyak diketahui tentang.

string &&= string + "suffix"

setara dengan

if string
  string = string + "suffix"
end

Ini sangat berguna untuk operasi destruktif yang tidak boleh dilanjutkan jika variabel tidak terdefinisi.


2
Lebih tepatnya, string &&= string + "suffix" setara dengan string = string && string + "suffix". Itu &&dan ||mengembalikan argumen kedua mereka dibahas dalam PickAx, hal. 154 (Bagian I - Aspek Ruby, Ekspresi, Eksekusi Bersyarat).
Richard Michael

29

Fungsi Symbol # to_proc yang disediakan Rails benar-benar keren.

Dari pada

Employee.collect { |emp| emp.name }

Kamu bisa menulis:

Employee.collect(&:name)

Ini, tampaknya, "urutan besarnya lebih lambat" daripada menggunakan blok. igvita.com/2008/07/08/6-optimization-tips-for-ruby-mri
Charles Roper

Saya hanya mencobanya, dan menemukan tidak ada perbedaan yang signifikan antara keduanya. Saya tidak yakin dari mana barang "urutan besarnya" ini berasal. (Menggunakan Ruby 1.8.7)
Matt Grande

1
Melakukan ini di luar Rails juga berguna dan dapat dilakukan require 'activesupport'karena di situlah sebagian besar pembantu ini berasal.
rfunduk

8
ini dulunya lambat karena implemenetasi active_support, yaitu ia menerima beberapa argumen sehingga Anda bisa melakukan hal-hal keren seperti (1..10) .inject &: *, tetapi kasus penggunaan utama sering hanya memanggil metode pada setiap anggota dari suatu koleksi mis.% w (rubah coklat cepat) .map &: huruf besar. pada 1.8.7 itu adalah inti ruby ​​dan kinerjanya masuk akal.
Steve Graham

4
@ thenduks: Dan itu bisa dilakukan tanpa bantuan activesupport di ruby ​​1.8.7 dan 1.9.
Andrew Grimm

28

Satu yang terakhir - di ruby ​​Anda dapat menggunakan karakter apa pun yang ingin Anda batasi string. Ambil kode berikut:

message = "My message"
contrived_example = "<div id=\"contrived\">#{message}</div>"

Jika Anda tidak ingin lepas dari tanda kutip ganda dalam string, Anda dapat menggunakan pembatas yang berbeda:

contrived_example = %{<div id="contrived-example">#{message}</div>}
contrived_example = %[<div id="contrived-example">#{message}</div>]

Selain menghindari pelarian pembatas, Anda dapat menggunakan pembatas ini untuk string multiline yang lebih bagus:

sql = %{
    SELECT strings 
    FROM complicated_table
    WHERE complicated_condition = '1'
}

19
bukan sembarang karakter, tapi itu masih cukup keren. Ini juga berfungsi dengan literal lain:% () /% {} /% [] /% <> /% || % r () /% r {} /% r [] /% r <> /% r || % w () /% w {} /% w [] /% w <> /% w ||
Bo Jeanes

Ada juga sintaks doc saat ini: << BLOCK ... BLOCK, yang saya suka gunakan untuk hal-hal seperti pernyataan SQL multiline dll.
Martin T.

26

Saya menemukan menggunakan perintah define_method untuk secara dinamis menghasilkan metode yang cukup menarik dan tidak terlalu dikenal. Sebagai contoh:

((0..9).each do |n|
    define_method "press_#{n}" do
      @number = @number.to_i * 10 + n
    end
  end

Kode di atas menggunakan perintah 'define_method' untuk secara dinamis membuat metode "press1" melalui "press9." Alih-alih mengetik semua 10 metode yang essentailly berisi kode yang sama, perintah metode define digunakan untuk menghasilkan metode ini dengan cepat sesuai kebutuhan.


4
Satu-satunya masalah dengan define_method adalah bahwa ia tidak mengizinkan blok untuk dilewatkan sebagai parameter dalam ruby ​​1.8. Lihat posting blog ini untuk solusinya.
Andrew Grimm

26

Gunakan objek Range sebagai daftar malas tak terbatas:

Inf = 1.0 / 0

(1..Inf).take(5) #=> [1, 2, 3, 4, 5]

Info lebih lanjut di sini: http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-ruby/


The lazy_select dalam artikel tertaut sangat rapi.
Joseph Weissman

Ini sangat mengagumkan. Saya suka bagaimana Infinity adalah float, seperti itu ketika saya mencoba ini: (-Inf..Inf) .take (4) ia memunculkan (konsisten secara logis) tidak dapat beralih dari kesalahan float. : D
zachaysan

23

module_function

Metode modul yang dideklarasikan sebagai module_function akan membuat salinan dirinya sebagai metode turunan pribadi di kelas yang menyertakan Modul:

module M
  def not!
    'not!'
  end
  module_function :not!
end

class C
  include M

  def fun
    not!
  end
end

M.not!     # => 'not!
C.new.fun  # => 'not!'
C.new.not! # => NoMethodError: private method `not!' called for #<C:0x1261a00>

Jika Anda menggunakan fungsi module_ tanpa argumen, maka metode modul apa pun yang muncul setelah pernyataan module_function akan secara otomatis menjadi fungsi module_functions sendiri.

module M
  module_function

  def not!
    'not!'
  end

  def yea!
    'yea!'
  end
end


class C
  include M

  def fun
    not! + ' ' + yea!
  end
end
M.not!     # => 'not!'
M.yea!     # => 'yea!'
C.new.fun  # => 'not! yea!'

4
Jika Anda hanya ingin mendeklarasikan metode pribadi dalam modul, cukup gunakan kata kunci pribadi. Selain membuat metode pribadi di kelas yang menyertakan modul, module_function menyalin metode ke instance modul. Dalam kebanyakan kasus, ini bukan yang Anda inginkan.
tomafro

Saya tahu Anda bisa menggunakan pribadi. Tapi ini pertanyaan tentang fitur tersembunyi Ruby. Dan, saya pikir kebanyakan orang belum pernah mendengar tentang module_function (termasuk saya sendiri) sampai mereka melihatnya di doc dan mulai mempermainkannya.
newtonapple

Alternatif untuk menggunakan module_function(cara 2) adalah dengan hanya menggunakan extend self(yang terlihat cukup bagus: D)
J -_- L


21

Peringatan: item ini terpilih sebagai # 1 Hack Paling Menghebohkan tahun 2008 , jadi gunakan dengan hati-hati. Sebenarnya, hindarilah seperti wabah, tetapi itu pasti Ruby Tersembunyi.

Superator Tambahkan Operator Baru ke Ruby

Pernah menginginkan operator jabat tangan super-rahasia untuk beberapa operasi unik dalam kode Anda? Suka bermain golf kode? Coba operator seperti - ~ + ~ - atau <--- Yang terakhir digunakan dalam contoh untuk membalik urutan item.

Saya tidak ada hubungannya dengan Proyek Superators selain mengaguminya.


19

Saya terlambat ke pesta, tetapi:

Anda dapat dengan mudah mengambil dua array dengan panjang yang sama dan mengubahnya menjadi hash dengan satu array memasok kunci dan yang lainnya nilainya:

a = [:x, :y, :z]
b = [123, 456, 789]

Hash[a.zip(b)]
# => { :x => 123, :y => 456, :z => 789 }

(Ini berfungsi karena Array # zip "zip" nilai-nilai dari dua array:

a.zip(b)  # => [[:x, 123], [:y, 456], [:z, 789]]

Dan Hash [] dapat mengambil array seperti itu. Saya telah melihat orang melakukan ini juga:

Hash[*a.zip(b).flatten]  # unnecessary!

Yang menghasilkan hasil yang sama, tetapi percikan dan ratakan sama sekali tidak perlu - mungkin mereka tidak di masa lalu?)


3
Ini memang tidak terdokumentasi untuk waktu yang lama (lihat redmine.ruby-lang.org/issues/show/1385 ). Perhatikan bahwa formulir baru ini baru untuk Ruby 1.8.7
Marc-André Lafortune

19

Hash vivifying otomatis di Ruby

def cnh # silly name "create nested hash"
  Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}
end
my_hash = cnh
my_hash[1][2][3] = 4
my_hash # => { 1 => { 2 => { 3 =>4 } } }

Ini bisa sangat berguna.


1
Saya akan membungkusnya dalam modul untuk memiliki perasaan yang sama seperti module InfHash; def self.new; Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}; end; end
hasit

16

Merusak Array

(a, b), c, d = [ [:a, :b ], :c, [:d1, :d2] ]

Dimana:

a #=> :a
b #=> :b
c #=> :c
d #=> [:d1, :d2]

Dengan menggunakan teknik ini kita dapat menggunakan penugasan sederhana untuk mendapatkan nilai tepat yang kita inginkan dari array bersarang dari kedalaman apa pun.


15

Class.new()

Buat kelas baru saat run time. Argumennya bisa berupa kelas untuk diturunkan, dan bloknya adalah badan kelas. Anda mungkin juga ingin melihat const_set/const_get/const_defined?agar kelas baru Anda terdaftar dengan benar, jadiinspect mencetak nama dan bukan nomor.

Bukan sesuatu yang Anda butuhkan setiap hari, tetapi cukup berguna saat Anda melakukannya.


1
MyClass = Class.new Array do; def hi; 'hi'; end; endtampaknya setara dengan class MyClass < Array; def hi; 'hi'; end; end.
yfeldblum

1
Mungkin lebih benar daripada yang saya pikirkan. Bahkan tampaknya Anda dapat mewarisi dari variabel daripada hanya konstanta. Namun, versi bergula (kedua) tampaknya tidak berfungsi jika Anda perlu membuat nama kelas pada waktu berjalan. (Baring eval, tentu saja.)
Justin Love

Teknik ini dijelaskan dengan cukup baik dalam buku Metaprogramming Ruby .
Paul Pladijs

13

buat array angka berurutan:

x = [*0..5]

set x ke [0, 1, 2, 3, 4, 5]


Yap, tapi tidak sesingkat dan manis;)
horseyguy

2
kesederhanaan adalah tujuan, keterbacaan adalah masalah selera dan pengalaman
Alexey

Operator percikan ( *) pada dasarnya to_atetap menelepon .
Matheus Moreira

13

Banyak keajaiban yang Anda lihat di Rubyland ada hubungannya dengan metaprogramming, yang hanya menulis kode yang menulis kode untuk Anda. Ruby attr_accessor, attr_readerdan attr_writersemua metaprogramming sederhana, dalam arti bahwa mereka membuat dua metode dalam satu baris, mengikuti pola standar. Rails melakukan banyak metaprogramming dengan metode manajemen hubungan seperti has_onedan belongs_to.

Tapi cukup mudah untuk membuat trik metaprogramming Anda sendiri menggunakan class_evaluntuk mengeksekusi kode yang ditulis secara dinamis.

Contoh berikut memungkinkan objek wrapper untuk meneruskan metode tertentu ke objek internal:

class Wrapper
  attr_accessor :internal

  def self.forwards(*methods)
    methods.each do |method|
      define_method method do |*arguments, &block|
        internal.send method, *arguments, &block
      end
    end
  end

  forwards :to_i, :length, :split
end

w = Wrapper.new
w.internal = "12 13 14"
w.to_i        # => 12
w.length      # => 8
w.split('1')  # => ["", "2 ", "3 ", "4"]

Metode ini Wrapper.forwardsmengambil simbol untuk nama-nama metode dan menyimpannya dalam methodsarray. Kemudian, untuk masing-masing yang diberikan, kita gunakandefine_method untuk membuat metode baru yang tugasnya mengirim pesan, termasuk semua argumen dan blok.

Sumber yang bagus untuk masalah metaprogramming adalah Why the Lucky Stiff's "Seeing Metaprogramming Clearly" .


Saya ingin terjun lebih dulu ke metaprogramming di ruby. Bisakah Anda memberikan beberapa referensi untuk memulainya (Selain tautan yang diberikan)? Buku juga bisa. Terima kasih.
Chirantan

Serie videocasting PragProg "The Ruby Object Model and Metaprogramming" merupakan pengantar yang bagus untuk pemrograman meta menggunakan ruby: pragprog.com/screencasts/v-dtrubyom/…
caffo

@ Cirantan, lihat Metaprogramming Ruby .
Paul Pladijs

12

menggunakan apa pun yang menanggapi ===(obj)perbandingan kasus:

case foo
when /baz/
  do_something_with_the_string_matching_baz
when 12..15
  do_something_with_the_integer_between_12_and_15
when lambda { |x| x % 5 == 0 }
  # only works in Ruby 1.9 or if you alias Proc#call as Proc#===
  do_something_with_the_integer_that_is_a_multiple_of_5
when Bar
  do_something_with_the_instance_of_Bar
when some_object
  do_something_with_the_thing_that_matches_some_object
end

Module(dan dengan demikian Class) Regexp,Date , dan banyak kelas-kelas lain mendefinisikan metode contoh: === (lainnya), dan semua bisa digunakan.

Terima kasih kepada Farrel untuk pengingat Proc#callakan alias seperti Proc#===di Ruby 1.9.


11

Biner "ruby" (setidaknya MRI) mendukung banyak switch yang membuat perl one-liner cukup populer.

Yang signifikan:

  • -n Mengatur loop luar hanya dengan "mendapat" - yang secara ajaib bekerja dengan nama file atau STDIN yang diberikan, mengatur setiap baris baca dalam $ _
  • -p Mirip dengan -n tetapi dengan puts otomatis di akhir setiap iterasi loop
  • -Panggilan otomatis ke .split pada setiap jalur input, disimpan dalam $ F
  • -i Di tempat mengedit file input
  • -l Panggilan otomatis ke .chomp on input
  • -E Menjalankan sepotong kode
  • -c Periksa kode sumber
  • -w Dengan peringatan

Beberapa contoh:

# Print each line with its number:
ruby -ne 'print($., ": ", $_)' < /etc/irbrc

# Print each line reversed:
ruby -lne 'puts $_.reverse' < /etc/irbrc

# Print the second column from an input CSV (dumb - no balanced quote support etc):
ruby -F, -ane 'puts $F[1]' < /etc/irbrc

# Print lines that contain "eat"
ruby -ne 'puts $_ if /eat/i' < /etc/irbrc

# Same as above:
ruby -pe 'next unless /eat/i' < /etc/irbrc

# Pass-through (like cat, but with possible line-end munging):
ruby -p -e '' < /etc/irbrc

# Uppercase all input:
ruby -p -e '$_.upcase!' < /etc/irbrc

# Same as above, but actually write to the input file, and make a backup first with extension .bak - Notice that inplace edit REQUIRES input files, not an input STDIN:
ruby -i.bak -p -e '$_.upcase!' /etc/irbrc

Jangan ragu untuk google "ruby one-liners" dan "perl one-liners" untuk banyak contoh yang lebih bermanfaat dan praktis. Ini pada dasarnya memungkinkan Anda untuk menggunakan ruby ​​sebagai pengganti yang cukup kuat untuk awk dan sed.


10

Metode send () adalah metode tujuan umum yang dapat digunakan pada Kelas atau Objek apa pun di Ruby. Jika tidak diganti, kirim () menerima string dan memanggil nama metode yang stringnya dilewatkan. Misalnya, jika pengguna mengklik tombol "Clr", string 'press_clear' akan dikirim ke metode send () dan metode 'press_clear' akan dipanggil. Metode send () memungkinkan cara yang dinamis dan menyenangkan untuk memanggil fungsi di Ruby.

 %w(7 8 9 / 4 5 6 * 1 2 3 - 0 Clr = +).each do |btn|
    button btn, :width => 46, :height => 46 do
      method = case btn
        when /[0-9]/: 'press_'+btn
        when 'Clr': 'press_clear'
        when '=': 'press_equals'
        when '+': 'press_add'
        when '-': 'press_sub'
        when '*': 'press_times'
        when '/': 'press_div'
      end

      number.send(method)
      number_field.replace strong(number)
    end
  end

Saya berbicara lebih banyak tentang fitur ini di Blogging Shoes: The Simple-Calc Application


Kedengarannya seperti cara yang bagus untuk membuka lubang keamanan.
mP.

4
Saya akan menggunakan simbol sedapat mungkin.
reto

9

Menipu beberapa kelas atau modul yang mengatakan itu membutuhkan sesuatu yang sebenarnya tidak diperlukan:

$" << "something"

Ini berguna misalnya ketika membutuhkan A yang pada gilirannya membutuhkan B tetapi kami tidak membutuhkan B dalam kode kami (dan A tidak akan menggunakannya baik melalui kode kami):

Misalnya, Backgroundrb bdrb_test_helper requires 'test/spec', tetapi Anda tidak menggunakannya sama sekali, jadi dalam kode Anda:

$" << "test/spec"
require File.join(File.dirname(__FILE__) + "/../bdrb_test_helper")

Apakah ini memperbaiki masalah di mana permata A membutuhkan foo-1.0.0, dan permata B membutuhkan foo-1.0.1?
Andrew Grimm

Tidak karena "sesuatu" kode tidak akan tersedia: ini hanya mensimulasikan bahwa "sesuatu" diperlukan, tetapi sebenarnya tidak memerlukannya. $ "adalah larik yang berisi nama-nama modul yang dimuat oleh keharusan (ini digunakan oleh keharusan untuk mencegah memuat modul dua kali). Jadi, jika Anda menggunakan ini untuk mengelabui permata, itu akan menghasilkan kerusakan ketika permata mencoba menggunakan" sesuatu "yang sebenarnya. kode, karena tidak akan ada. Anda mungkin ingin memaksakan laoding versi konkret permata (misalnya foo-1.0.0), bukan yang terbaru: docs.rubygems.org/read/chapter/4#page71
olegueret

9

Fixnum#to_s(base)dalam beberapa kasus bisa sangat berguna. Salah satu kasus tersebut adalah menghasilkan token acak (semu) dengan mengubah angka acak menjadi string menggunakan basis 36.

Token dengan panjang 8:

rand(36**8).to_s(36) => "fmhpjfao"
rand(36**8).to_s(36) => "gcer9ecu"
rand(36**8).to_s(36) => "krpm0h9r"

Token dengan panjang 6:

rand(36**6).to_s(36) => "bvhl8d"
rand(36**6).to_s(36) => "lb7tis"
rand(36**6).to_s(36) => "ibwgeh"

9

Menentukan metode yang menerima sejumlah parameter dan hanya membuang semuanya

def hello(*)
    super
    puts "hello!"
end

helloMetode di atas hanya perlu puts "hello"di layar dan panggilan super- tetapi karena superclass hellomenentukan parameternya juga - namun karena sebenarnya tidak perlu menggunakan parameter itu sendiri - itu tidak harus memberi mereka nama.

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.