it-swarm-eu.dev

Versteckte Funktionen von Ruby

Lassen Sie uns die weniger bekannten, aber nützlichen Funktionen der Programmiersprache Ruby) mit anderen teilen, indem wir das Mem "Versteckte Funktionen von ..." fortsetzen.

Versuchen Sie, diese Diskussion mit Core Ruby einzuschränken, ohne Ruby on Rails stuff.

Siehe auch:

(Bitte nur ein verstecktes Merkmal pro Antwort.)

Vielen Dank

160
squadette

From Ruby 1.9 Proc # === ist ein Alias ​​für 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
80
Farrel

Peter Cooper hat eine gute Liste von Ruby Tricks. Vielleicht ist es mein Favorit, sowohl einzelne Gegenstände als auch Sammlungen aufzählen zu lassen. Sammlungsobjekt als Sammlung, die nur dieses Objekt enthält.) Es sieht so aus:

[*items].each do |item|
  # ...
end
76
James A. Rosen

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

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

Hash[*fruit]    
=> {"Apple"=>"red", "banana"=>"yellow"}
64
astronautism

Ein Trick, den ich mag, ist das Verwenden des splat (*) Expander auf 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
54
tomafro

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

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

Eine der coolen Sachen 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 Superklasse hat, d. H. 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#sample Methode (nur in 1.8.7, siehe Array#choice), und das Beispiel ist ziemlich ausgedacht, aber Sie können die Macht hier sehen.

Ein weiteres cooles Beispiel ist die Möglichkeit, Standardparameterwerte einzugeben, die nicht fest vorgegeben sind (wie es andere Sprachen häufig verlangen):

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

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

Im zweiten Beispiel rufen Sie jedoch jedes Mal do_something_at, die Variable at ist die Zeit, zu der die Methode aufgerufen wurde (na ja, sehr, sehr nah dran)

49
Bo Jeanes

Ein weiteres kleines Feature - konvertiere ein Fixnum in 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 die Umstellung genauso einfach:

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

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.

40
August Lilleaas

Laden Sie Ruby 1.9 source herunter und geben Sie make golf 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"

Lesen Sie den golf_prelude.c, Um weitere hübsche Dinge zu finden, die sich verstecken.

39
manveru

Eine weitere unterhaltsame Erweiterung der 1.9 Proc-Funktionalität ist Proc # curry, mit der Sie ein Proc, das n Argumente akzeptiert, in ein Proc umwandeln können, das 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
38
Farrel

Boolesche Operatoren für nicht-boolesche Werte.

&& und ||

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

Welches ist, warum die ||= aktualisiert die Variable mit dem zurückgegebenen Wert auf der rechten Seite, wenn die Variable nicht definiert ist. Dies ist nicht explizit dokumentiert, aber allgemein bekannt.

Das &&= ist 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 ausgeführt werden sollten, wenn die Variable undefiniert ist.

35
EmFi

Die Symbol # to_proc-Funktion, die Rails zur Verfügung stellt, ist wirklich cool.

Anstatt

Employee.collect { |emp| emp.name }

Du kannst schreiben:

Employee.collect(&:name)
29
hoyhoy

Eine letzte - in Ruby können Sie ein beliebiges Zeichen verwenden, um Zeichenfolgen abzugrenzen. 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 müssen nicht nur Trennzeichen umgehen, sondern können diese Trennzeichen auch für schönere mehrzeilige Zeichenfolgen verwenden:

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

Ich finde die Verwendung des Befehls define_method zum dynamischen Generieren von Methoden sehr interessant und weniger bekannt. 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.

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/

26
horseyguy

module_function

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 folgen, 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!'
23
newtonapple

Kurz spritzen, wie zB:

Summe des Bereichs:

(1..10).inject(:+)
=> 55
23
user130730

Achtung: Dieser Artikel wurde zur Nummer 1 gewählt Most Horrendous Hack of 2008. Eigentlich meide es wie die Pest, aber es ist mit Sicherheit Hidden Ruby.

Superatoren Fügen Sie Ruby neue Operatoren hinzu

Wünschen Sie sich schon immer einen geheimen Handshake-Operator für einen einzigartigen Vorgang in Ihrem Code? Lust auf Code Golf? Versuchen Sie es mit Operatoren wie - ~ + ~ - oder <--- Dieser letzte wird in den Beispielen zum Umkehren der Reihenfolge eines Elements verwendet.

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

21
Captain Hammer

Ich bin zu spät zur Party, aber:

Sie können leicht zwei gleichlange Arrays nehmen und sie 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 annehmen. Ich habe auch Leute gesehen, die das gemacht haben:

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

Was das gleiche Ergebnis liefert, aber das Aufschlagen und Abflachen ist völlig unnötig - vielleicht waren sie nicht in der Vergangenheit?)

19
Jordan Running

Selbstbelebende 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.

19
Trevoke

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 mithilfe einer einfachen Zuweisung die genauen Werte aus verschachtelten Arrays beliebiger Tiefe abrufen.

16
horseyguy

Class.new()

Erstellen Sie zur Laufzeit eine neue Klasse. Das Argument kann eine abzuleitende Klasse sein, und der Block ist der Klassenhauptteil. Vielleicht möchten Sie auch const_set/const_get/const_defined?, um Ihre neue Klasse ordnungsgemäß zu registrieren, sodass inspect anstelle einer Zahl einen Namen ausgibt.

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

15
Justin Love

erstellen Sie ein Array von fortlaufenden Nummern:

x = [*0..5]

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

13
horseyguy

Ein Großteil der Magie, die Sie in Rubyland sehen, hat mit der Metaprogrammierung zu tun, bei der einfach Code geschrieben wird, der Code für Sie schreibt. Rubys attr_accessor, attr_reader Und attr_writer Sind alles einfache Metaprogrammierungen, indem sie nach einem Standardmuster zwei Methoden in einer Zeile erstellen. Rails macht eine Menge Metaprogramme mit ihren Beziehungsmanagementmethoden wie has_one Und belongs_to.

Es ist jedoch ziemlich einfach, eigene Metaprogrammier-Tricks mit class_eval Zu erstellen, um dynamisch geschriebenen Code auszuführen.

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 Verwendet Symbole für die Namen von Methoden und speichert sie im Array methods. Anschließend erstellen wir für jede der angegebenen Methoden mit define_method Eine neue Methode, deren Aufgabe es ist, die Nachricht einschließlich aller Argumente und Blöcke zu senden.

Eine großartige Ressource für Fragen der Metaprogrammierung ist Warum der Lucky Stiff die Metaprogrammierung klar sieht .

13
TALlama

verwenden Sie für Fallvergleiche alles, was auf ===(obj) antwortet:

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

Danke an Farrel für die Erinnerung an Proc#call Alias ​​als Proc#=== in Ruby 1.9.

12
James A. Rosen

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

Bedeutende:

  • -n Richtet eine äußere Schleife mit nur "gets" ein - dies funktioniert auf magische Weise mit dem angegebenen Dateinamen oder STDIN, wobei jede gelesene Zeile in $ _ gesetzt wird.
  • -p Ähnlich wie -n, jedoch mit einem automatischen puts 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 der Eingabe
  • -e Führe einen Code aus
  • -c Überprüfe den Quellcode
  • -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

Sie können auch "Ruby One-Liner" und "Perl One-Liner" googeln, um weitere nützliche und praktische Beispiele zu finden. Grundsätzlich können Sie Ruby als ziemlich mächtigen Ersatz für awk und sed verwenden.

11
minaguib

Die send () -Methode ist eine universelle Methode, 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 send () -Methode gesendet und die "press_clear" -Methode aufgerufen. Die send () -Methode bietet 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: Die Simple-Calc-Anwendung

10
private unless Rails.env == 'test'
# e.g. a bundle of methods you want to test directly

Sieht aus wie ein cooles und (in einigen Fällen) nettes/nützliches Hack/Feature von Ruby.

9
Szymon Jeż

Fixnum#to_s(base) kann in manchen Fällen sehr nützlich sein. In einem solchen Fall werden zufällige (pseudo) eindeutige Token generiert, indem eine Zufallszahl mit der Basis 36 in eine Zeichenfolge konvertiert wird.

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"
9
sickill

Täuschen Sie eine Klasse oder ein Modul, die/das erzählt, dass sie etwas benötigt hat, was sie wirklich nicht benötigt:

$" << "something"

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

Zum Beispiel: Backgroundrbs bdrb_test_helper requires'test/spec', aber du verwendest es überhaupt nicht, also in deinem Code:

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

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

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

Die obige hello Methode muss nur puts"hello" auf dem Bildschirm und rufen super auf - aber da die Oberklasse hello Parameter definiert, muss sie dies auch tun - da sie die Parameter selbst jedoch nicht wirklich verwenden muss - tut sie dies nicht müssen ihnen einen Namen geben.

9
horseyguy

So kombinieren Sie mehrere reguläre Ausdrücke mit | können Sie verwenden

Regexp.union /Ruby\d/, /test/i, "cheat"

so erstellen Sie eine Regexp ähnlich der folgenden:

/(Ruby\d|[tT][eE][sS][tT]|cheat)/
8
J-_-L

Ich finde das in einigen Skripten nützlich. Es ermöglicht die direkte Verwendung von Umgebungsvariablen wie in Shell-Skripten und Makefiles. Umgebungsvariablen werden als Ersatz für undefinierte Ruby Konstanten verwendet.

>> class <<Object
>>  alias :old_const_missing :const_missing
>>  def const_missing(sym)
>>   ENV[sym.to_s] || old_const_missing(sym)
>>  end
>> end
=> nil

>> puts Shell
/bin/zsh
=> nil
>> TERM == 'xterm'
=> true
8
Ropez

Wie wäre es mit dem Öffnen einer Datei basierend auf ARGV [0]?

readfile.rb:

$<.each_line{|l| puts l}

Ruby readfile.rb testfile.txt

Es ist eine großartige Abkürzung zum Schreiben von einmaligen Skripten. Es gibt eine ganze Menge vordefinierter Variablen, von denen die meisten Menschen nichts wissen. Verwenden Sie sie mit Bedacht (lesen Sie: Verunreinigen Sie keine Codebasis, die Sie pflegen möchten, da dies zu Problemen führen kann).

8
Scott Holden

Ich bin ein Fan von:

%w{An Array of strings} #=> ["An", "Array", "of", "Strings"]

Es ist schon komisch, wie oft das nützlich ist.

5
Judson

Mehrere Rückgabewerte

def getCostAndMpg
    cost = 30000  # some fancy db calls go here
    mpg = 30
    return cost,mpg
end
AltimaCost, AltimaMpg = getCostAndMpg
puts "AltimaCost = #{AltimaCost}, AltimaMpg = #{AltimaMpg}"

Parallele Zuordnung

i = 0
j = 1
puts "i = #{i}, j=#{j}"
i,j = j,i
puts "i = #{i}, j=#{j}"

Virtuelle Attribute

class Employee < Person
  def initialize(fname, lname, position)
    super(fname,lname)
    @position = position
  end
  def to_s
     super + ", #@position"
  end
  attr_writer :position
  def etype
     if @position == "CEO" || @position == "CFO"
         "executive"
     else
         "staff"
     end
  end
end
employee = Employee.new("Augustus","Bondi","CFO")
employee.position = "CEO"
puts employee.etype    =>  executive
employee.position = "Engineer"
puts employee.etype    =>  staff

method_missing - eine wunderbare idee

(In den meisten Sprachen, wenn eine Methode nicht gefunden werden kann und ein Fehler ausgegeben wird und Ihr Programm stoppt. In Ruby können Sie diese Fehler tatsächlich abfangen und möglicherweise etwas Intelligentes mit der Situation tun)

class MathWiz
  def add(a,b) 
    return a+b
  end
  def method_missing(name, *args)
    puts "I don't know the method #{name}"
  end
end
mathwiz = MathWiz.new
puts mathwiz.add(1,4)
puts mathwiz.subtract(4,2)

5

Ich kenne die Methode nicht subtrahieren

null

5
Ramiz Uddin

James A. Rosens Tipp ist cool ([* items] .each), aber ich finde, dass er Hashes zerstört:

irb(main):001:0> h = {:name => "Bob"}
=> {:name=>"Bob"}
irb(main):002:0> [*h]
=> [[:name, "Bob"]]

Ich bevorzuge diese Vorgehensweise, wenn ich eine Liste der zu verarbeitenden Dinge akzeptiere, aber nachsichtig bin und dem Anrufer erlaube, eine zu liefern:

irb(main):003:0> h = {:name => "Bob"}
=> {:name=>"Bob"}
irb(main):004:0> [h].flatten
=> [{:name=>"Bob"}]

Dies kann mit einer Methodensignatur wie folgt kombiniert werden:

def process(*entries)
  [entries].flatten.each do |e|
    # do something with e
  end
end
4
minaguib

Ich mag nur das Inline-Schlüsselwort rescue so:
BEARBEITETES BEISPIEL:

@user #=> nil (but I did't know)
@user.name rescue "Unknown"
link_to( d.user.name, url_user( d.user.id, d.user.name)) rescue 'Account removed'

Dies verhindert, dass meine App kaputt geht, und ist weitaus besser als die Funktion, die unter Rails veröffentlicht wurde. Try ()

4
Fabiano Soriani

Aufrufen einer Methode, die an einer beliebigen Stelle in der Vererbungskette definiert ist, auch wenn sie überschrieben wird

ActiveSupports Objekte maskieren sich manchmal als eingebaute Objekte.

 erfordern 'active_support' 
 Tage = 5.Tage 
 Tage.Klasse # => Fixnum 
 Tage.ist_a? (Fixnum) # => Wahr 
 Fixnum === days # => false (nicht wahr? Was sind Sie wirklich?) 
 Object.instance_method (: class) .bind (days) .call # => ActiveSupport :: Duration (aha!) 
 ActiveSupport :: Duration === days # => true 

Das obige beruht natürlich auf der Tatsache, dass active_support Object # instance_method nicht neu definiert. In diesem Fall wären wir wirklich einen Bach hoch. Andererseits können wir den Rückgabewert von Object.instance_method (: class) immer speichern, bevor eine Bibliothek eines Drittanbieters geladen wird.

Object.instance_method (...) gibt eine UnboundMethod zurück, die Sie dann an eine Instanz dieser Klasse binden können. In diesem Fall können Sie es an jede Instanz von Object binden (einschließlich Unterklassen).

Wenn die Klasse eines Objekts Module enthält, können Sie auch die UnboundMethod aus diesen Modulen verwenden.

 Modul Mod 
 def var_add (more); @ var + more; end 
 end 
 class Cla 
 include Mod 
 def initialize (var); @ var = var; end 
 # override 
 def var_add (more); @ var + more + more; end 
 end 
 cla = Cla.new ('abcdef') 
 cla.var_add ('ghi') # => "abcdefghighi" 
 Mod.instance_method ( : var_add) .bind (cla) .call ('ghi') # => "abcdefghi" 

Dies funktioniert sogar für Singleton-Methoden, die eine Instanzmethode der Klasse überschreiben, zu der das Objekt gehört.

 class Foo 
 def mymethod; 'Original'; end 
 end 
 foo = Foo. new 
 foo.mymethod # => 'original' 
 def foo.mymethod; 'singleton'; end 
 foo.mymethod # => 'singleton' 
 Foo.instance_method (: mymethod) .bind (foo) .call # => 'original' 
 
 # Sie können die Methode #instance auch für Singleton-Klassen aufrufen: 
 Class << foo; selbst; end.instance_method (: mymethod) .bind (foo) .call # => 'singleton' 
4
Kelvin

Es gibt einige Aspekte von Symbol-Literalen, die die Leute kennen sollten. Ein Fall, der durch spezielle Symbol-Literale gelöst wird, ist, wenn Sie ein Symbol erstellen müssen, dessen Name aus irgendeinem Grund einen Syntaxfehler mit der normalen Symbol-Literal-Syntax verursacht:

:'class'

Sie können auch eine Symbolinterpolation durchführen. Im Kontext eines Accessors zum Beispiel:

define_method :"#{name}=" do |value|
  instance_variable_set :"@#{name}", value
end
3
Tom

each_with_index Methode für jedes enumarable Objekt (Array, Hash, etc.) vielleicht?

myarray = ["la", "li", "lu"]
myarray.each_with_index{|v,idx| puts "#{idx} -> #{v}"}

#result:
#0 -> la
#1 -> li
#2 -> lu

Vielleicht ist es bekannter als andere Antworten, aber nicht so bekannt für alle Ruby Programmierer :)

3
mhd
class A

  private

  def my_private_method
    puts 'private method called'
  end
end

a = A.new
a.my_private_method # Raises exception saying private method was called
a.send :my_private_method # Calls my_private_method and prints private method called'
2
Chirantan

Ruby hat einen call/cc Mechanismus, der es einem erlaubt, frei im Stapel auf und ab zu hüpfen.

Ein einfaches Beispiel folgt. Dies ist sicherlich nicht die Art und Weise, wie man eine Sequenz in Ruby multipliziert, aber es zeigt, wie man mit call/cc den Stack erreichen kann, um einen Algorithmus kurzzuschließen. In diesem Fall multiplizieren wir rekursiv eine Liste von Zahlen, bis wir entweder jede Zahl gesehen haben oder Null sehen (die beiden Fälle, in denen wir die Antwort kennen). Im Nullfall können wir beliebig tief in der Liste stehen und enden.

#!/usr/bin/env Ruby

def rprod(k, rv, current, *nums)
  puts "#{rv} * #{current}"
  k.call(0) if current == 0 || rv == 0
  nums.empty? ? (rv * current) : rprod(k, rv * current, *nums)
end

def prod(first, *rest)
  callcc { |k| rprod(k, first, *rest) }
end

puts "Seq 1:  #{prod(1, 2, 3, 4, 5, 6)}"
puts ""
puts "Seq 2:  #{prod(1, 2, 0, 3, 4, 5, 6)}"

Sie können die Ausgabe hier sehen:

http://codepad.org/Oh8ddh9e

Für ein komplexeres Beispiel mit Fortsetzungen, die auf dem Stapel in die andere Richtung verschoben werden, lesen Sie die Quelle unter Generator .

2
Dustin

Ich habe gerade alle Antworten gelesen ... eine bemerkenswerte Lücke war die Aufgabe der Destrukturierung:

> (a,b),c = [[1,2],3]
=> [[1,2],3]
> a
=> 1

Es funktioniert auch für Blockparameter. Dies ist nützlich, wenn Sie geschachtelte Arrays haben, von denen jedes Element etwas anderes darstellt. Anstatt Code wie "array [0] [1]" zu schreiben, können Sie dieses verschachtelte Array aufteilen und jedem Element einen beschreibenden Namen in einer einzigen Codezeile geben.

2
Alex D
@user #=> nil (but I did't know)
@user.name rescue "Unknown"
2
haoqi

Die Sprintf-Verknüpfung

Meine Lieblingsfunktion Ruby. Syntax ist format_string % argument

"%04d"  % 1         # => "0001"
"%0.2f" % Math::PI  # => "3.14"

Funktioniert auch für Arrays (format_string % array_of_arguments)

"%.2f %.3f %.4f" % ([Math::PI]*3) 
# => "3.14 3.142 3.1416"
1
iblue