Ukryte funkcje Rubiego

160

Kontynuując mem "Ukryte cechy ...", podzielmy się mniej znanymi, ale użytecznymi cechami języka programowania Ruby.

Spróbuj ograniczyć tę dyskusję do rdzenia Rubiego, bez żadnych rzeczy związanych z Ruby on Rails.

Zobacz też:

(Proszę, tylko jedna ukryta funkcja na odpowiedź.)

Dziękuję Ci

składu
źródło
powinno być wiki społeczności
SilentGhost

Odpowiedzi:

80

Od Ruby 1.9 Proc # === jest aliasem do wywołania Proc #, co oznacza, że ​​obiekty Proc mogą być używane w instrukcjach case, takich jak:

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
Farrel
źródło
1
Właściwie w pewnym momencie napisałem klejnot, aby to zrobić, ale mój kod był (a) bałagan i (b) wolny. Bardzo się cieszę, że ta funkcjonalność stała się rdzeniem.
James A. Rosen
76

Peter Cooper ma dobrą listę sztuczek Ruby. Być może moim ulubionym z jego dzieł jest umożliwienie wyliczenia zarówno pojedynczych przedmiotów, jak i kolekcji. (To znaczy traktuj obiekt niebędący kolekcją jako kolekcję zawierającą tylko ten obiekt). Wygląda to tak:

[*items].each do |item|
  # ...
end
James A. Rosen
źródło
38
Bardziej wyraźną (a przez to ładniejszą) formą tego jest Array (items). Każdy
Mislav
Jeśli itemsjest łańcuchem, nie musisz go otaczać [*…]. String.each nie wykonuje iteracji po znakach, jak niektórzy mogą się spodziewać. Po prostu wraca do bloku.
mxcl
Jaki pożytek miałoby to kiedykolwiek służyć? Po prostu ciekawy.
Ed S.
1
@Ed: to miłe, jeśli piszesz metodę i chcesz pozwolić użytkownikowi metody na przekazanie listy varargs lub Array.
James A. Rosen
64

Nie wiem, jak to jest ukryte, ale uznałem to za przydatne, gdy potrzebowałem zrobić hasz z jednowymiarowej tablicy:

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

Hash[*fruit]    
=> {"apple"=>"red", "banana"=>"yellow"}
astronautyzm
źródło
Zauważ, że Hash[ [["apple","red"], ["banana","yellow"] ]daje ten sam wynik.
Marc-André Lafortune
54

Jedną ze sztuczek, które lubię, jest użycie *ekspandera splat ( ) na obiektach innych niż Arrays. Oto przykład dopasowania wyrażenia regularnego:

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

Inne przykłady obejmują:

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

Job = Struct.new(:name, :occupation)
tom = Job.new("Tom", "Developer")
name, occupation = *tom
tomafro
źródło
13
Nawiasem mówiąc, dla ciekawskich działa to przez niejawne wywołanie to_a na celu ikony.
Bob Aman
1
Jeśli nie jesteś zainteresowany meczem, możesz to zrobić 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
Obie są dobre, ale musi być taki moment, w którym jest za dużo magii, prawda ?!
tomafro
1
@Andrew, czy zastanawiałeś się, czy dopasowanie może zwrócić zero? zero nie ma metody []
Alexey
52

Wow, nikt nie wspomniał o operatorze flip flop:

1.upto(100) do |i|
  puts i if (i == 3)..(i == 15)
end
Konstantin Haase
źródło
11
Racja ... ktoś będzie musiał mi to wyjaśnić. Działa, ale nie wiem, dlaczego.
Bob Aman
12
Operator przerzutnika jest stanowym jeśli. Jego stan zmienia się na prawda, gdy tylko i == 3i zmienia się na fałsz po i != 3 i i == 15. Podobny do flip-flop: en.wikipedia.org/wiki/Flip-flop_%28electronics%29
Konstantin Haase,
1
Nie nazwałbym tego dokładnie ukrytą funkcją, tak bardzo irytujące. Pamiętam, jak po raz pierwszy zostałem przedstawiony w #Ruby na Freenode, lata temu; W pewnym momencie użyłem praktycznie każdej funkcji Rubiego, z wyjątkiem tej.
ELLIOTTCABLE
1
Nie nazwałbym tego irytacją, to po prostu coś, czego nie używałeś. Używam go i może ładnie zredukować kod, zwłaszcza gdy pobieram bloki wierszy z plików na podstawie pewnych kryteriów.
Tin Man
49

Jedną z fajnych rzeczy w Ruby jest to, że możesz wywoływać metody i uruchamiać kod w miejscach, na które inne języki by się nie podobały, na przykład w definicjach metod lub klas.

Na przykład, aby utworzyć klasę, która ma nieznaną nadklasę do czasu uruchomienia, tj. Jest losowa, możesz wykonać następujące czynności:

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

end

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

Używa Array#samplemetody 1.9 (tylko w 1.8.7, zobacz Array#choice), a przykład jest dość wymyślony, ale możesz zobaczyć tutaj moc.

Innym fajnym przykładem jest możliwość umieszczenia domyślnych wartości parametrów, które nie są stałe (jak często wymagają inne języki):

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

Oczywiście problem z pierwszym przykładem polega na tym, że jest on oceniany w czasie definicji, a nie w czasie połączenia. Tak więc, po wybraniu superklasy, pozostaje nią do końca programu.

Jednak w drugim przykładzie, za każdym razem, gdy wywołasz do_something_at, atzmienną będzie czas wywołania metody (cóż, bardzo, bardzo blisko)

bjeanes
źródło
2
Uwaga: Tablica # rand jest dostarczana przez ActiveSupport, z której można korzystać poza Railsami tak łatwo, jakrequire 'activesupport'
rfunduk
Wybór tablicy # jest dostępny w wersji 1.8.7
Josh Lee
24
Wybór tablicy # to tylko 1.8.7 ! Nie używaj go, zniknął w 1.9 i zniknie w 1.8.8. Użyj #sample
Marc-André Lafortune
python: class DictList ([dict, list] [random.randint (0,1)]): pass
Anurag Uniyal
def do_something_at (something, at = lambda {Time.now}) at.call #now dynamically assign time end
Jack Kinsella
47

Kolejna mała funkcja - zamień a Fixnumna dowolną bazę do 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"

Jak skomentował Huw Walters, konwersja w drugą stronę jest równie prosta:

>> "kf12oi".to_i(36)
=> 1234567890
tomafro
źródło
1
I dla kompletności, String#to_s(base)może służyć do konwersji z powrotem na liczbę całkowitą; "1001001100101100000001011010010".to_i(2), "499602d2".to_i(16)Etc wszystkim zwraca oryginał Fixnum.
Huw Walters
40

Hashe z wartościami domyślnymi! Tablica w tym przypadku.

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

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

Bardzo przydatne w metaprogramowaniu.

August Lilleaas
źródło
1
tak prawda. Skrót Ruby może akceptować operator „<<”, jeśli istnieje już przypisana wartość domyślna z „=” (nie przejmuj się, nawet jeśli jest to puste przypisanie), w przeciwnym razie hash nie zaakceptuje „<<”. CMIIW
mhd
39

Pobierz źródło Ruby 1.9 i wydaj make golf, a następnie możesz zrobić takie rzeczy:

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"

Przeczytaj golf_prelude.cwięcej schludnych rzeczy, które się ukrywają.

manveru
źródło
38

Kolejnym fajnym dodatkiem do funkcjonalności 1.9 Proc jest Proc # curry, który pozwala zamienić Proc przyjmujący n argumentów na taki, który akceptuje n-1. Tutaj jest połączony z poradą Proc # ===, o której wspomniałem powyżej:

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
Farrel
źródło
35

Operatory logiczne na wartościach innych niż boolowskie.

&& i ||

Oba zwracają wartość ostatniego ocenianego wyrażenia.

Dlatego też ||=zaktualizuje zmienną z wyrażeniem zwracanej wartości po prawej stronie, jeśli zmienna jest niezdefiniowana. Nie jest to wyraźnie udokumentowane, ale powszechnie wiadomo.

Jednak &&=nie jest to tak powszechnie znane.

string &&= string + "suffix"

jest równa

if string
  string = string + "suffix"
end

Jest to bardzo przydatne w przypadku destrukcyjnych operacji, które nie powinny być kontynuowane, jeśli zmienna jest niezdefiniowana.

EmFi
źródło
2
Dokładniej, string &&= string + "suffix" jest równoważne string = string && string + "suffix". To &&i ||zwrot ich drugiego argumentu omówiono w PickAx, str. 154 (Część I - Aspekty języka Ruby, wyrażenia, wykonywanie warunkowe).
Richard Michael,
29

Funkcja Symbol # to_proc dostarczana przez Railsy jest naprawdę fajna.

Zamiast

Employee.collect { |emp| emp.name }

Możesz pisać:

Employee.collect(&:name)
hoyhoy
źródło
Jest to najwyraźniej „o rząd wielkości wolniejsze” niż użycie bloku. igvita.com/2008/07/08/6-optimization-tips-for-ruby-mri
Charles Roper
Właśnie go wypróbowałem i stwierdziłem, że nie ma między nimi znaczącej różnicy. Nie jestem pewien, skąd się wzięły te rzeczy z „rzędu wielkości”. (Korzystanie z Ruby 1.8.7)
Matt Grande
1
Robienie tego poza Railsami jest również przydatne i można to zrobić, require 'activesupport'ponieważ tak naprawdę pochodzi większość tych pomocników.
rfunduk
8
to było powolne z powodu implementacji active_support, tj. akceptowało wiele argumentów, więc można było robić fajne rzeczy, takie jak (1..10) .inject &: *, ale głównym przypadkiem użycia było często wywoływanie metody tylko na każdym elemencie elementu kolekcja, np.% w (szybki brązowy lis) .map &: upcase. od 1.8.7 jego rdzeń rubinowy, a wydajność jest rozsądna.
Steve Graham
4
@thenduks: I można to zrobić bez pomocy activesupport w Rubim 1.8.7 i 1.9.
Andrew Grimm
28

I ostatnia - w ruby ​​możesz użyć dowolnego znaku, który chcesz oddzielić ciągi. Weź następujący kod:

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

Jeśli nie chcesz usuwać podwójnych cudzysłowów w ciągu, możesz po prostu użyć innego separatora:

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

Oprócz uniknięcia konieczności zmiany miejsca na separatory, możesz użyć tych separatorów dla ładniejszych ciągów wielowierszowych:

sql = %{
    SELECT strings 
    FROM complicated_table
    WHERE complicated_condition = '1'
}
tomafro
źródło
19
nie żadną postacią, ale nadal jest całkiem fajna. Działa również z innymi literałami:% () /% {} /% [] /% <> /% || % r () /% r {} /% r [] /% r <> /% r || % w () /% w {} /% w [] /% w <> /% w ||
Bo Jeanes
Jest też obecna składnia doc: << BLOCK ... BLOCK, której lubię używać do takich rzeczy, jak wielowierszowe instrukcje SQL itp.
Martin T.
26

Uważam, że użycie polecenia define_method do dynamicznego generowania metod jest dość interesujące i niezbyt dobrze znane. Na przykład:

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

Powyższy kod używa polecenia „define_method” do dynamicznego tworzenia metod od „press1” do „press9”. Zamiast wpisywać wszystkie 10 metod, które zasadniczo zawierają ten sam kod, do generowania tych metod w locie w razie potrzeby używane jest polecenie define method.

Kodowanie bez komentarzy
źródło
4
Jedyny problem z define_method polega na tym, że nie pozwala ona na przekazywanie bloków jako parametrów w Ruby 1.8. Zobacz ten post na blogu, aby poznać obejście.
Andrew Grimm,
26

Użyj obiektu Range jako nieskończonej leniwej listy:

Inf = 1.0 / 0

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

Więcej informacji tutaj: http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-ruby/

koński
źródło
Lazy_select w połączonym artykule jest bardzo zgrabna.
Joseph Weissman,
To jest naprawdę niesamowite. Podoba mi się, że Infinity jest zmiennoprzecinkową, w ten sposób, gdy próbowałem tego: (-Inf..Inf) .take (4) wywołało (logicznie spójne) nie można iterować z błędu float. : D
zachaysan
23

moduł_funkcja

Metody modułu, które są zadeklarowane jako module_function utworzą swoje kopie jako metody wystąpienia prywatnego w klasie zawierającej Module:

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>

Jeśli użyjesz module_function bez żadnych argumentów, wówczas wszelkie metody modułu, które pojawią się po instrukcji module_function, same staną się automatycznie module_functions.

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!'
niutonapple
źródło
4
Jeśli chcesz tylko zadeklarować metody prywatne w modułach, użyj słowa kluczowego private. Oprócz uczynienia metody prywatną w klasach zawierających moduł, module_function kopiuje metodę do instancji modułu. W większości przypadków tego nie chcesz.
tomafro
Wiem, że możesz po prostu użyć prywatnego. Ale to jest kwestia ukrytych funkcji Rubiego. I myślę, że większość ludzi nigdy nie słyszała o module_function (łącznie ze mną), dopóki nie zobaczą go w dokumencie i nie zaczną się nim bawić.
newtonapple
Alternatywą dla module_function(drugi sposób) jest po prostu użycie extend self(co wygląda całkiem nieźle: D)
J -_- L
23

Krótkie wstrzyknięcie, takie jak:

Suma zakresu:

(1..10).inject(:+)
=> 55
user130730
źródło
2
Warto zauważyć, że potrzebujesz Ruby 1.9 lub Rails z Ruby 1.8, aby to zadziałało.
mxcl
1
@Max Howell: lub require 'backports':-)
Marc-André Lafortune
1
Czy to nie jest duplikat odpowiedzi Hoyhoy?
Andrew Grimm,
21

Uwaga: ten przedmiot został uznany za # 1 najbardziej przerażającego hacka 2008 roku , więc używaj go ostrożnie. Właściwie unikaj tego jak zarazy, ale z pewnością jest to Ukryty Rubin.

Superators Dodają nowych operatorów do Rubiego

Czy kiedykolwiek chciałeś mieć super tajnego operatora uzgadniania do jakiejś unikalnej operacji w swoim kodzie? Lubisz grać w code-golfa? Wypróbuj operatory, takie jak - ~ + ~ - lub <--- Ten ostatni jest używany w przykładach do odwracania kolejności elementów.

Nie mam nic wspólnego z projektem Superators poza podziwianiem go.

Kapitanie Hammer
źródło
19

Spóźniłem się na imprezę, ale:

Możesz łatwo wziąć dwie tablice o równej długości i przekształcić je w skrót, w którym jedna tablica dostarcza klucze, a druga wartości:

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

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

(Działa to, ponieważ Array # zip „spakuje” wartości z dwóch tablic:

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

Hash [] może przyjąć właśnie taką tablicę. Widziałem, jak ludzie też to robią:

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

Co daje ten sam wynik, ale splatanie i spłaszczanie są całkowicie niepotrzebne - być może nie były w przeszłości?)

Jordan Running
źródło
3
To było rzeczywiście nieudokumentowane przez długi czas (patrz redmine.ruby-lang.org/issues/show/1385 ). Zauważ, że ta nowa forma jest nowością w Rubim 1.8.7
Marc-André Lafortune
19

Automatyczne ożywianie skrótów w Rubim

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 } } }

To może być po prostu cholernie przydatne.

Trevoke
źródło
1
module InfHash; def self.new; Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}; end; end
Owinąłbym
16

Destrukturyzacja tablicy

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

Gdzie:

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

Używając tej techniki, możemy użyć prostego przypisania, aby uzyskać dokładne wartości, które chcemy z zagnieżdżonej tablicy o dowolnej głębokości.

koński
źródło
15

Class.new()

Utwórz nową klasę w czasie wykonywania. Argumentem może być klasa, z której ma pochodzić, a blok jest treścią klasy. Możesz również sprawdzić, czy const_set/const_get/const_defined?twoja nowa klasa została poprawnie zarejestrowana, tak aby inspectwypisała nazwę zamiast numeru.

Nie jest to coś, czego potrzebujesz na co dzień, ale całkiem przydatne, kiedy to robisz.

Po prostu zakochany
źródło
1
MyClass = Class.new Array do; def hi; 'hi'; end; endwydaje się być równoważne class MyClass < Array; def hi; 'hi'; end; end.
yfeldblum
1
Prawdopodobnie bardziej prawdziwe niż myślałem. Wygląda nawet na to, że można dziedziczyć ze zmiennej, a nie tylko ze stałej. Jednak sugerowana wersja (druga) nie działa, jeśli musisz utworzyć nazwę klasy w czasie wykonywania. (Oczywiście z wyjątkiem ewaluacji.)
Justin Love
Ta technika jest dość dobrze opisana w książce Metaprogramming Ruby .
Paul Pladijs
13

utwórz tablicę kolejnych liczb:

x = [*0..5]

ustawia x na [0, 1, 2, 3, 4, 5]

koński
źródło
Tak, ale nie jest tak krótko i słodko;)
horseyguy
2
zwięzłość jest obiektywna, czytelność to kwestia gustu i doświadczenia
Alexey
Operator splat ( *) w zasadzie i to_atak wywołuje .
Matheus Moreira,
13

Wiele magii, które widzisz w Rubyland, ma związek z metaprogramowaniem, czyli po prostu pisaniem kodu, który pisze kod za Ciebie. Ruby's attr_accessor, attr_readeri attr_writersą prostym metaprogramowaniem, ponieważ tworzą dwie metody w jednej linii, według standardowego wzorca. Railsy wykonują bardzo dużo metaprogramowania za pomocą metod zarządzania relacjami, takich jak has_onei belongs_to.

Ale tworzenie własnych sztuczek metaprogramowania za pomocą class_evaldo wykonywania dynamicznie napisanego kodu jest całkiem proste .

Poniższy przykład umożliwia obiektowi opakowania przekazywanie pewnych metod do obiektu wewnętrznego:

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"]

Metoda Wrapper.forwardsprzyjmuje symbole dla nazw metod i przechowuje je w methodstablicy. Następnie, dla każdego z podanych, define_methodtworzymy nową metodę, której zadaniem jest przesłanie wiadomości wraz ze wszystkimi argumentami i blokami.

Świetnym źródłem informacji na temat zagadnień związanych z metaprogramowaniem jest „ Why the Lucky Stiff” „Seeing Metaprogramming Clearly” .

TALlama
źródło
Chciałbym najpierw zagłębić się w metaprogramowanie w rubinie. Czy możesz podać jakieś odniesienia, aby zacząć z nim korzystać (inne niż podany link)? Książki też się nadadzą. Dzięki.
Chirantan
Seria wideokastry PragProg "The Ruby Object Model and Metaprogramming" to dobre wprowadzenie do metaprogramowania
caffo
@Chirantan, spójrz na Metaprogramowanie w Rubim .
Paul Pladijs,
12

użyj wszystkiego, na co odpowiada, do ===(obj)porównań przypadków:

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(a więc Class) Regexp, Datei wiele innych klas określić metodą przykład: === (drugiego), i wszystkie mogą być użyte.

Podziękowania dla Farrela za przypomnienie o Proc#callaliasie jak Proc#===w Rubim 1.9.

Jamesa A. Rosena
źródło
11

Binarny "ruby" (przynajmniej MRI) obsługuje wiele przełączników, które sprawiły, że jednolinijkowe perl stały się dość popularne.

Istotne:

  • -n Ustawia zewnętrzną pętlę tylko z „pobieraniem” - co magicznie działa z podaną nazwą pliku lub STDIN, ustawiając każdą linię odczytu w $ _
  • -p Podobne do -n, ale z automatycznym puts na końcu każdej iteracji pętli
  • -a Automatyczne wywołanie .split w każdej linii wejściowej, przechowywane w $ F
  • -i Edycja plików wejściowych w miejscu
  • -l Automatyczne wywołanie .chomp na wejściu
  • -e Wykonaj fragment kodu
  • -c Sprawdź kod źródłowy
  • -w Z ostrzeżeniami

Kilka przykładów:

# 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

Zapraszam do wygooglowania „ruby one-liners” i „perl one-liners”, aby uzyskać więcej użytecznych i praktycznych przykładów. Zasadniczo pozwala ci używać ruby ​​jako dość potężnego zamiennika awk i sed.

minaguib
źródło
10

Metoda send () jest metodą ogólnego przeznaczenia, której można użyć w dowolnej klasie lub obiekcie w Rubim. Jeśli nie jest zastępowany, funkcja send () akceptuje ciąg znaków i wywołuje nazwę metody, której ciąg jest przekazywany. Na przykład, jeśli użytkownik kliknie przycisk „Clr”, ciąg „press_clear” zostanie wysłany do metody send () i zostanie wywołana metoda „press_clear”. Metoda send () pozwala na przyjemny i dynamiczny sposób wywoływania funkcji w Rubim.

 %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

Więcej o tej funkcji mówię w Blogging Shoes: The Simple-Calc Application

Kodowanie bez komentarzy
źródło
Brzmi jak świetny sposób na otwarcie luki w zabezpieczeniach.
mP.
4
Tam, gdzie to możliwe, używałbym symboli
powrót
9

Oszukać jakąś klasę lub moduł, mówiąc, że wymagał czegoś, czego tak naprawdę nie wymagał:

$" << "something"

Jest to przydatne na przykład, gdy wymagamy A, które z kolei wymaga B, ale nie potrzebujemy B w naszym kodzie (a A nie użyje go również w naszym kodzie):

Na przykład Backgroundrb bdrb_test_helper requires 'test/spec', ale w ogóle go nie używasz, więc w swoim kodzie:

$" << "test/spec"
require File.join(File.dirname(__FILE__) + "/../bdrb_test_helper")
olegueret
źródło
Czy to rozwiązuje problemy, gdy klejnot A wymaga foo-1.0.0, a klejnot B wymaga foo-1.0.1?
Andrew Grimm,
Nie, ponieważ kod „czegoś” nie będzie dostępny: to tylko symuluje, że „coś” jest wymagane, ale tak naprawdę tego nie wymaga. $ "to tablica zawierająca nazwy modułów ładowane przez require (jest używana przez require, aby zapobiec dwukrotnemu ładowaniu modułów). Więc jeśli użyjesz tego do oszukania klejnotów, spowoduje to awarię, gdy klejnoty spróbują użyć rzeczywistego" czegoś " ponieważ nie będzie istniał. Zamiast tego możesz wymusić laoding konkretną wersję klejnotu (np. foo-1.0.0) zamiast najnowszej: docs.rubygems.org/read/chapter/4#page71
olegueret
9

Fixnum#to_s(base)może być naprawdę przydatna w niektórych przypadkach. Jednym z takich przypadków jest generowanie losowych (pseudo) unikalnych tokenów poprzez konwersję liczby losowej na ciąg przy użyciu podstawy 36.

Żeton o długości 8:

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

Żeton o długości 6:

rand(36**6).to_s(36) => "bvhl8d"
rand(36**6).to_s(36) => "lb7tis"
rand(36**6).to_s(36) => "ibwgeh"
chory
źródło
9

Zdefiniowanie metody, która akceptuje dowolną liczbę parametrów i po prostu odrzuca je wszystkie

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

Powyższa hellometoda musi tylko pojawić się puts "hello"na ekranie i wywołać super- ale ponieważ nadklasa hellodefiniuje również parametry - jednak ponieważ w rzeczywistości nie musi używać samych parametrów - nie musi nadawać im nazwy.

koński
źródło