Versteckte Funktionen von Ruby

160

Setzen wir das Mem "Versteckte Funktionen von ..." fort und teilen wir die weniger bekannten, aber nützlichen Funktionen der Programmiersprache Ruby.

Versuchen Sie, diese Diskussion mit Ruby zu begrenzen, ohne Ruby on Rails-Inhalte.

Siehe auch:

(Bitte nur eine versteckte Funktion pro Antwort.)

Danke dir

Squadette
quelle
sollte Community-Wiki sein
SilentGhost

Antworten:

80

Ab Ruby 1.9 ist Proc # === ein Alias ​​für den Proc # -Aufruf, was bedeutet, dass Proc-Objekte in case-Anweisungen wie den folgenden verwendet werden können:

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
quelle
1
Ich habe tatsächlich irgendwann einen Edelstein geschrieben, um dies zu tun, aber mein Code war (a) ein Durcheinander und (b) langsam. Ich bin sehr froh, dass die Funktionalität es in den Kern geschafft hat.
James A. Rosen
76

Peter Cooper hat eine gute Liste von Ruby-Tricks. Vielleicht ist es sein Favorit, sowohl einzelne Gegenstände als auch Sammlungen aufzählen zu lassen. (Das heißt, behandeln Sie ein Nicht-Sammlungsobjekt als eine Sammlung, die nur dieses Objekt enthält.) Es sieht folgendermaßen aus:

[*items].each do |item|
  # ...
end
James A. Rosen
quelle
38
Eine explizitere (und damit schönere) Form davon ist Array (items) .each
mislav
Wenn itemses sich um eine Zeichenfolge handelt, müssen Sie sie nicht mit [*…] einschließen. String.each iteriert nicht wie erwartet über Zeichen. Es kehrt einfach zum Block zurück.
mxcl
Welchen Nutzen würde dies jemals haben? Nur neugierig.
Ed S.
1
@Ed: Es ist schön, wenn Sie eine Methode schreiben und dem Benutzer der Methode erlauben möchten, entweder eine Varargs-Liste oder ein Array zu übergeben.
James A. Rosen
64

Ich weiß nicht, wie versteckt das ist, aber ich fand es nützlich, wenn ich aus einem eindimensionalen Array einen Hash machen muss:

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

Hash[*fruit]    
=> {"apple"=>"red", "banana"=>"yellow"}
Astronautismus
quelle
Beachten Sie, dass Hash[ [["apple","red"], ["banana","yellow"] ]das gleiche Ergebnis erzielt wird.
Marc-André Lafortune
54

Ein Trick, den ich mag, ist die Verwendung des splat ( *) - Expanders für andere Objekte als Arrays. Hier ist ein Beispiel für eine Übereinstimmung mit regulären Ausdrücken:

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

Andere Beispiele sind:

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

Job = Struct.new(:name, :occupation)
tom = Job.new("Tom", "Developer")
name, occupation = *tom
Tomafro
quelle
13
Für Neugierige funktioniert dies übrigens, indem implizit to_a für das Ziel des Splats aufgerufen wird.
Bob Aman
1
Wenn Sie nicht an dem Spiel interessiert sind, können Sie haben 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
Beide guten Tricks, aber es muss einen Punkt geben, an dem es zu viel Magie ist, oder?!
Tomafro
1
@ Andrew, hast du darüber nachgedacht, dass das Match null zurückgeben kann? nil hat keine Methode []
Alexey
52

Wow, niemand hat den Flip-Flop-Operator erwähnt:

1.upto(100) do |i|
  puts i if (i == 3)..(i == 15)
end
Konstantin Haase
quelle
11
Richtig ... jemand muss mir das erklären. Es funktioniert, aber ich kann nicht herausfinden warum.
Bob Aman
12
Der Flip-Flop-Operator ist ein Statefull if. Sein Zustand wechselt sofort zu true i == 3und nach i != 3 und zu false i == 15. Ähnlich wie bei einem Flip-Flop: en.wikipedia.org/wiki/Flip-flop_%28electronics%29
Konstantin Haase
1
Ich würde das nicht gerade als verstecktes Feature bezeichnen, so ärgerlich. Ich erinnere mich an das erste Mal, dass ich es vor Jahren in #Ruby on Freenode kennengelernt habe. Ich habe im Grunde jedes einzelne Feature von Ruby irgendwann außer diesem verwendet.
ELLIOTTCABLE
1
Ich würde es nicht als Ärger bezeichnen, es ist nur etwas, das du nicht benutzt hast. Ich benutze es und es kann Code gut reduzieren, besonders wenn ich Zeilenblöcke aus Dateien greife, die auf bestimmten Kriterien basieren.
der Blechmann
49

Eines der coolen Dinge an Ruby ist, dass Sie Methoden aufrufen und Code an Stellen ausführen können, an denen andere Sprachen die Stirn runzeln würden, z. B. in Methoden- oder Klassendefinitionen.

Um beispielsweise eine Klasse zu erstellen, die bis zur Laufzeit eine unbekannte Oberklasse hat, dh zufällig ist, können Sie Folgendes tun:

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

end

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

Dies verwendet die 1.9- Array#sampleMethode (siehe nur 1.8.7 Array#choice), und das Beispiel ist ziemlich erfunden, aber Sie können die Leistung hier sehen.

Ein weiteres cooles Beispiel ist die Möglichkeit, nicht festgelegte Standardparameterwerte einzugeben (wie dies in anderen Sprachen häufig erforderlich ist):

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

Das Problem mit dem ersten Beispiel ist natürlich, dass es zur Definitionszeit und nicht zur Aufrufzeit ausgewertet wird. Sobald eine Oberklasse ausgewählt wurde, bleibt diese Oberklasse für den Rest des Programms erhalten.

Im zweiten Beispiel ist do_something_atdie atVariable jedoch bei jedem Aufruf die Zeit, zu der die Methode aufgerufen wurde (na ja, sehr, sehr nahe daran).

bjeanes
quelle
2
Hinweis: Array # rand wird von ActiveSupport bereitgestellt, das Sie außerhalb von Rails so einfach verwenden können wierequire 'activesupport'
rfunduk
Array # Wahl ist in 1.8.7
Josh Lee
24
Array # Auswahl ist nur 1.8.7 ! Verwenden Sie es nicht, es ist in 1.9 verschwunden und wird in 1.8.8 verschwunden sein. Verwenden Sie #sample
Marc-André Lafortune
Python: Klasse DictList ([Diktat, Liste] [random.randint (0,1)]): pass
Anurag Uniyal
def do_something_at (etwas, at = lambda {Time.now}) at.call #now dynamisch Zeitende zuweisen
Jack Kinsella
47

Ein weiteres kleines Feature - konvertieren Sie a Fixnumin eine beliebige Basis bis zu 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"

Und wie Huw Walters kommentiert hat, ist das Umwandeln in die andere Richtung genauso einfach:

>> "kf12oi".to_i(36)
=> 1234567890
Tomafro
quelle
1
Und der Vollständigkeit halber String#to_s(base)kann verwendet werden, um zurück in eine Ganzzahl zu konvertieren;"1001001100101100000001011010010".to_i(2), "499602d2".to_i(16)Etc alle Rückkehr des Original Fixnum.
Huw Walters
40

Hashes mit Standardwerten! Ein Array in diesem Fall.

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

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

Sehr nützlich bei der Metaprogrammierung.

August Lilleaas
quelle
1
ja stimmt. Ruby-Hash kann den Operator '<<' akzeptieren, wenn bereits ein Standardwert mit '=' zugewiesen ist (egal, auch wenn es sich um eine leere Zuweisung handelt), andernfalls akzeptiert der Hash '<<' nicht. CMIIW
mhd
39

Laden Sie die Ruby 1.9-Quelle herunter und geben make golfSie ein Problem ein . Dann können Sie Folgendes tun:

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"

Lies das golf_prelude.c für mehr nette Dinge, die sich verstecken.

Manveru
quelle
38

Eine weitere unterhaltsame Ergänzung in der 1.9 Proc-Funktionalität ist Proc # curry, mit der Sie einen Proc, der n Argumente akzeptiert, in einen Proc verwandeln können, der n-1 akzeptiert. Hier wird es mit dem oben erwähnten Proc # === Tipp kombiniert:

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
quelle
35

Boolesche Operatoren für nicht boolesche Werte.

&& und ||

Beide geben den Wert des zuletzt ausgewerteten Ausdrucks zurück.

Aus diesem Grund ||=wird die Variable mit dem Wert aktualisiert, der auf der rechten Seite als Ausdruck zurückgegeben wird, wenn die Variable nicht definiert ist. Dies ist nicht explizit dokumentiert, aber allgemein bekannt.

Allerdings &&=ist das nicht ganz so bekannt.

string &&= string + "suffix"

ist äquivalent zu

if string
  string = string + "suffix"
end

Es ist sehr praktisch für destruktive Operationen, die nicht fortgesetzt werden sollten, wenn die Variable undefiniert ist.

EmFi
quelle
2
Genauer gesagt string &&= string + "suffix" ist gleichbedeutend mit string = string && string + "suffix". Das &&und die ||Rückgabe ihres zweiten Arguments wird in PickAx, S. 22 besprochen. 154 (Teil I - Facetten von Ruby, Ausdrücke, bedingte Ausführung).
Richard Michael
29

Die von Rails bereitgestellte Funktion Symbol # to_proc ist wirklich cool.

Anstatt

Employee.collect { |emp| emp.name }

Du kannst schreiben:

Employee.collect(&:name)
Hoyhoy
quelle
Dies ist anscheinend eine "Größenordnung langsamer" als die Verwendung eines Blocks. igvita.com/2008/07/08/6-optimization-tips-for-ruby-mri
Charles Roper
Ich habe es gerade ausprobiert und festgestellt, dass es keinen signifikanten Unterschied zwischen den beiden gibt. Ich bin mir nicht sicher, woher dieses Zeug in der Größenordnung stammt. (Mit Ruby 1.8.7)
Matt Grande
1
Dies außerhalb von Rails zu tun ist auch praktisch und kann durchgeführt werden, require 'activesupport'da die meisten dieser Helfer tatsächlich von dort stammen.
Rfunduk
8
Früher war dies aufgrund der Implementierung von active_support langsam, dh es wurden mehrere Argumente akzeptiert, sodass Sie coole Scheiße wie (1..10) .inject &: * ausführen konnten. Der Hauptanwendungsfall bestand jedoch häufig darin, nur eine Methode für jedes Mitglied von a aufzurufen Sammlung zB% w (der schnelle braune Fuchs) .map &: upcase. Ab 1.8.7 ist es Core Ruby und die Leistung ist angemessen.
Steve Graham
4
@thenduks: Und es kann ohne die Hilfe von activesupport in Ruby 1.8.7 und 1.9 gemacht werden.
Andrew Grimm
28

Eine letzte - in Ruby können Sie jedes Zeichen verwenden, mit dem Sie Zeichenfolgen abgrenzen möchten. Nehmen Sie den folgenden Code:

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

Wenn Sie die doppelten Anführungszeichen in der Zeichenfolge nicht umgehen möchten, können Sie einfach ein anderes Trennzeichen verwenden:

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

Sie können nicht nur Trennzeichen vermeiden, sondern auch Trennzeichen für schönere mehrzeilige Zeichenfolgen verwenden:

sql = %{
    SELECT strings 
    FROM complicated_table
    WHERE complicated_condition = '1'
}
Tomafro
quelle
19
nicht jeder kühlt immer noch ziemlich Charakter, aber es ist. Es funktioniert auch mit anderen Literalen:% () /% {} /% [] /% <> /% || % r () /% r {} /% r [] /% r <> /% r || % w () /% w {} /% w [] /% w <> /% w ||
Bo Jeanes
Es gibt auch die folgende Doc-Syntax: << BLOCK ... BLOCK, die ich gerne für Dinge wie mehrzeilige SQL-Anweisungen usw. verwende
Martin T.
26

Ich finde es ziemlich interessant und nicht so bekannt , den Befehl define_method zum dynamischen Generieren von Methoden zu verwenden. Beispielsweise:

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

Der obige Code verwendet den Befehl 'define_method', um die Methoden "press1" bis "press9" dynamisch zu erstellen. Anstatt alle 10 Methoden einzugeben, die im Wesentlichen denselben Code enthalten, wird der Befehl define method verwendet, um diese Methoden bei Bedarf im laufenden Betrieb zu generieren.

CodingWithoutComments
quelle
4
Das einzige Problem mit define_method ist, dass keine Blöcke als Parameter in Ruby 1.8 übergeben werden können. In diesem Blogbeitrag finden Sie eine Problemumgehung.
Andrew Grimm
26

Verwenden Sie ein Range-Objekt als unendliche Lazy-Liste:

Inf = 1.0 / 0

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

Weitere Informationen hier: http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-ruby/

horseyguy
quelle
Die lazy_select im verlinkten Artikel ist sehr ordentlich.
Joseph Weissman
Das ist wirklich großartig. Ich mag, wie Infinity ein Float ist, so wie ich es versucht habe: (-Inf..Inf) .take (4) hat es einen (logisch konsistenten) Fehler ausgelöst, der nicht aus dem Float-Fehler iterieren kann. : D
Zachaysan
23

Modulfunktion

Modulmethoden , die als module_function deklariert sind, erstellen Kopien von sich selbst als private Instanzmethoden in der Klasse, die das Modul enthält:

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>

Wenn Sie module_function ohne Argumente verwenden, werden alle Modulmethoden, die nach der Anweisung module_function kommen, automatisch zu 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!'
Newtonapple
quelle
4
Wenn Sie nur private Methoden in Modulen deklarieren möchten, verwenden Sie einfach das Schlüsselwort private. Module_function kopiert die Methode nicht nur in Klassen, die das Modul enthalten, als privat, sondern kopiert sie auch in die Modulinstanz. In den meisten Fällen ist dies nicht das, was Sie wollen.
Tomafro
Ich weiß, dass Sie nur privat verwenden können. Dies ist jedoch eine Frage zu Rubys versteckten Merkmalen. Und ich denke, die meisten Leute haben noch nie von module_function gehört (ich selbst eingeschlossen), bis sie es im Dokument sehen und anfangen, damit herumzuspielen.
Newtonapple
Eine Alternative zur Verwendung module_function(2. Weg) ist die Verwendung extend self(was ziemlich gut aussieht: D)
J -_- L
23

Kurzinjektion wie folgt:

Summe der Reichweite:

(1..10).inject(:+)
=> 55
user130730
quelle
2
Erwähnenswert ist, dass Sie Ruby 1.9 oder Rails mit Ruby 1.8 benötigen, damit dies funktioniert.
mxcl
1
@ Max Howell: oder require 'backports':-)
Marc-André Lafortune
1
Ist das nicht ein Duplikat von Hoyhoys Antwort?
Andrew Grimm
21

Warnung: Dieser Artikel wurde zum # 1 Horrendous Hack des Jahres 2008 gewählt . Verwenden Sie ihn daher mit Vorsicht. Vermeiden Sie es eigentlich wie die Pest, aber es ist mit Sicherheit Hidden Ruby.

Superatoren Fügen Sie Ruby neue Operatoren hinzu

Wollten Sie jemals einen supergeheimen Handshake-Operator für eine einzigartige Operation in Ihrem Code? Wie Code Golf spielen? Versuchen Sie es mit Operatoren wie - ~ + ~ - oder <---. Der letzte wird in den Beispielen zum Umkehren der Reihenfolge eines Elements verwendet.

Ich habe nichts mit dem Superators-Projekt zu tun, außer es zu bewundern.

Kapitän Hammer
quelle
19

Ich bin zu spät zur Party, aber:

Sie können problemlos zwei Arrays gleicher Länge in einen Hash umwandeln, wobei ein Array die Schlüssel und das andere die Werte liefert:

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

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

(Dies funktioniert, weil Array # zip die Werte der beiden Arrays "komprimiert":

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

Und Hash [] kann genau ein solches Array aufnehmen. Ich habe Leute gesehen, die das auch gemacht haben:

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

Was das gleiche Ergebnis liefert, aber Splat und Flatten sind völlig unnötig - vielleicht waren sie nicht in der Vergangenheit?)

Jordan läuft
quelle
3
Dies war in der Tat lange Zeit nicht dokumentiert (siehe redmine.ruby-lang.org/issues/show/1385 ). Beachten Sie, dass dieses neue Formular neu in Ruby 1.8.7 ist
Marc-André Lafortune
19

Automatische Belebung von Hashes in 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 } } }

Das kann verdammt praktisch sein.

Trevoke
quelle
1
Ich würde es in ein Modul einwickeln, um das gleiche Gefühl wie native Hash-Init zu haben:module InfHash; def self.new; Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}; end; end
Asaaki
16

Ein Array zerstören

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

Wo:

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

Mit dieser Technik können wir eine einfache Zuweisung verwenden, um die genauen Werte aus einem verschachtelten Array beliebiger Tiefe zu erhalten.

horseyguy
quelle
15

Class.new()

Erstellen Sie zur Laufzeit eine neue Klasse. Das Argument kann eine Klasse sein, von der abgeleitet werden kann, und der Block ist der Klassenkörper. Vielleicht möchten Sie auch einen Blick darauf werfenconst_set/const_get/const_defined? , ob Ihre neue Klasse ordnungsgemäß registriert ist, damit inspectein Name anstelle einer Nummer ausgedruckt wird.

Nicht etwas, das Sie jeden Tag brauchen, aber sehr praktisch, wenn Sie es tun.

Nur verliebt
quelle
1
MyClass = Class.new Array do; def hi; 'hi'; end; endscheint äquivalent zu sein class MyClass < Array; def hi; 'hi'; end; end.
Yfeldblum
1
Wahrscheinlich wahrer als ich gedacht hatte. Es scheint sogar, dass Sie von einer Variablen und nicht nur von einer Konstanten erben können. Die gezuckerte Version (zweite) scheint jedoch nicht zu funktionieren, wenn Sie den Klassennamen zur Laufzeit erstellen müssen. (Baring eval natürlich.)
Justin Love
Diese Technik ist im Buch Metaprogramming Ruby ziemlich gut beschrieben .
Paul Pladijs
13

Erstellen Sie ein Array von fortlaufenden Zahlen:

x = [*0..5]

setzt x auf [0, 1, 2, 3, 4, 5]

horseyguy
quelle
Ja, aber es ist nicht so kurz und süß;)
horseyguy
2
Knappheit ist objektiv, Lesbarkeit ist eine Frage des Geschmacks und der Erfahrung
Alexey
Der splat ( *) - Operator ruft grundsätzlich to_atrotzdem auf.
Matheus Moreira
13

Ein Großteil der Magie, die Sie in Rubyland sehen, hat mit Metaprogrammierung zu tun, bei der einfach Code geschrieben wird, der Code für Sie schreibt. Ruby's attr_accessor, attr_readerund attr_writersind alle einfache Metaprogrammierungen, da sie zwei Methoden in einer Zeile nach einem Standardmuster erstellen. Rails führt eine Menge Metaprogrammierung mit ihren Beziehungsmanagementmethoden wie has_oneund durchbelongs_to .

Es ist jedoch ziemlich einfach, eigene Metaprogrammier-Tricks zu erstellen class_eval, mit denen dynamisch geschriebener Code ausgeführt wird.

Im folgenden Beispiel kann ein Wrapper-Objekt bestimmte Methoden an ein internes Objekt weiterleiten:

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

Die Methode Wrapper.forwards Symbole für die Namen der Methoden und speichert sie im methodsArray. Dann verwenden wir für jeden der angegebenendefine_method erstellen Methoden eine neue Methode, deren Aufgabe es ist, die Nachricht einschließlich aller Argumente und Blöcke mitzusenden.

Eine großartige Quelle für Metaprogrammierungsprobleme ist, warum der Lucky Stiff "Metaprogrammierung klar sehen" .

TALlama
quelle
Ich möchte mit dem Kopf voran in die Metaprogrammierung in Rubin eintauchen. Könnten Sie einige Referenzen angeben, um damit zu beginnen (außer dem angegebenen Link)? Bücher werden auch tun. Vielen Dank.
Chirantan
PragProgs Videocasting-Serie "The Ruby Object Model and Metaprogramming" ist eine gute Einführung in die Metaprogrammierung mit Ruby: pragprog.com/screencasts/v-dtrubyom/…
caffo
@Chirantan, schauen Sie sich Metaprogramming Ruby an .
Paul Pladijs
12

Verwenden Sie für Fallvergleiche alles, worauf reagiert ===(obj)wird:

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(und damit Class),Regexp , Dateund viele andere Klassen definieren eine Instanzmethode: === (andere), und alle verwendet werden können.

Vielen Dank an Farrel für die Erinnerung an Proc#calldas Aliasing Proc#===in Ruby 1.9.

James A. Rosen
quelle
11

Die "Ruby" -Binärdatei (zumindest MRTs) unterstützt viele der Schalter, die Perl-Einzeiler sehr beliebt gemacht haben.

Bedeutende:

  • -n Richtet eine äußere Schleife mit nur "get" ein - was auf magische Weise mit dem angegebenen Dateinamen oder STDIN funktioniert und jede Lesezeile in $ _ setzt
  • -p Ähnlich wie -n, jedoch mit einer Automatik put s am Ende jeder Schleifeniteration
  • -a Automatischer Aufruf von .split in jeder Eingabezeile, gespeichert in $ F.
  • -i Eingabedateien direkt bearbeiten
  • -l Automatischer Aufruf von .chomp bei Eingabe
  • -e Führe einen Code aus
  • -c Quellcode prüfen
  • -w Mit Warnungen

Einige Beispiele:

# 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

Fühlen Sie sich frei, "Ruby One-Liner" und "Perl One-Liner" für Tonnen mehr brauchbare und praktische Beispiele zu googeln. Es ermöglicht Ihnen im Wesentlichen, Rubin als ziemlich starken Ersatz für awk und sed zu verwenden.

Minaguib
quelle
10

Die send () -Methode ist eine Allzweckmethode, die für jede Klasse oder jedes Objekt in Ruby verwendet werden kann. Wenn nicht überschrieben, akzeptiert send () eine Zeichenfolge und ruft den Namen der Methode auf, deren Zeichenfolge übergeben wird. Wenn der Benutzer beispielsweise auf die Schaltfläche "Clr" klickt, wird die Zeichenfolge "press_clear" an die Methode "send ()" gesendet und die Methode "press_clear" aufgerufen. Die send () -Methode ermöglicht eine unterhaltsame und dynamische Möglichkeit, Funktionen in Ruby aufzurufen.

 %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

Ich spreche mehr über diese Funktion in Blogging Shoes: The Simple-Calc Application

CodingWithoutComments
quelle
Klingt nach einer großartigen Möglichkeit, eine Sicherheitslücke zu öffnen.
mP.
4
Ich würde wo immer möglich Symbole verwenden.
Reto
9

Machen Sie sich eine Klasse oder ein Modul zum Narren und sagen Sie, dass etwas erforderlich ist, das es wirklich nicht benötigt:

$" << "something"

Dies ist zum Beispiel nützlich, wenn A erforderlich ist, für das wiederum B erforderlich ist, wir jedoch kein B in unserem Code benötigen (und A es auch nicht über unseren Code verwendet):

Zum Beispiel Backgroundrb's bdrb_test_helper requires 'test/spec', aber Sie verwenden es überhaupt nicht, also in Ihrem Code:

$" << "test/spec"
require File.join(File.dirname(__FILE__) + "/../bdrb_test_helper")
olegueret
quelle
Behebt dies Probleme, bei denen Edelstein A foo-1.0.0 und Edelstein B foo-1.0.1 benötigt?
Andrew Grimm
Nein, da der Code von "etwas" nicht verfügbar ist: Dies simuliert nur, dass "etwas" erforderlich ist, aber es ist wirklich nicht erforderlich. $ "ist ein Array, das die von require geladenen Modulnamen enthält (es wird von require verwendet, um das zweimalige Laden von Modulen zu verhindern). Wenn Sie dies also verwenden, um Edelsteine ​​zu täuschen, führt dies zu einem Absturz, wenn die Edelsteine ​​versuchen, das tatsächliche" Etwas "zu verwenden. Code, da er nicht vorhanden ist. Möglicherweise möchten Sie stattdessen das Laodieren einer konkreten Version eines Edelsteins (z. B. foo-1.0.0) anstelle der neuesten Version erzwingen: docs.rubygems.org/read/chapter/4#page71
Olegueret
9

Fixnum#to_s(base)kann in manchen Fällen sehr nützlich sein. Ein solcher Fall ist das Erzeugen zufälliger (Pseudo-) eindeutiger Token durch Konvertieren einer Zufallszahl in einen String unter Verwendung der Basis von 36.

Token der Länge 8:

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

Token der Länge 6:

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

Definieren einer Methode, die eine beliebige Anzahl von Parametern akzeptiert und nur alle verwirft

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

Die obige helloMethode muss nur puts "hello"auf dem Bildschirm angezeigt werden, superaber da die Oberklasse auch helloParameter definiert, muss sie dies auch tun. Da sie jedoch die Parameter selbst nicht verwenden muss, muss sie ihnen keinen Namen geben.

horseyguy
quelle