infinity_test
This is my test suite setup:
For a rather large Rails project:
Looking at the Gemfile, I feel the need to clean it up. But this works pretty good at the moment :)
Setting up infinity test was soooo easy and well documented, it really was fun: https://github.com/tomas-stefano/infinity_test
Thanks to watchr, and rvm, who made this project possible!
A problem with the way we declare private methods in Ruby is the fact that when a class gets larger and more private methods are added to it, we lose sight of whether we are looking at a private, protected or public method. This is because the private declaration is a few hundred lines…
This is why I miss a private do ... end block sometimes. But I’ll be the repeating private declaration in future.
I like the modular approach too, especially when you have huge classes. I like this post :)
Ruby eval, dynamischer geht es nicht
Ruby macht es möglich, dass man zur Laufzeit Methoden hinzufügt. Ob man das nutzen sollte, es rein stilistisch gesehen klar geht oder nicht, ist dem Anwender überlassen. Und ich find es eigentlich cool, von ner Programmiersprache nicht wie nen Kind behandelt zu werden. Es gibt auf jeden Fall Use-Cases wo man solch ein Verhalten will (wie ActiveRecord in Rails und die sexy dynamischen find-Methoden).
eval
eval fuehrt den uebergebenen String aus
eval "13+37" # => 50
Damit ist es also unproblematisch code, den ich hier in einem Textfeld eingebe, irgendwo in meinem Programm ausfuehrbar zu machen (bis nen %x{ rm -rf /* kommt}).
Also: aus grosser Macht, folgt grosse Verantwortung :)
instance_eval
instance_eval ist der kleine Bruder von Eval: Sehr geile Eigenschaft: es wird der String oder der Block den du uebergibst ausgefuehrt, self wird aber auf den Empfaenger des Methoden-Aufrufs gesetzt. Boah, ok Bahnhof. Hier kommt nen Beispiel:
class Secret private def psst puts "ey psst, darf keiner wissen" end end s = Secret.new s.psst # => NoMethodError: private method `psst' called for #<Secret:0x10137bd18> s.instance_eval { psst } # => "ey psst, darf keiner wissen"
Also ist self der Empfaenger und darf damit auf psst zugreifen. Ganz schoen hackisch mal eben self veraendern zu duerfen ;)
class_eval
Und das leckerste zum Schluss: mit class_eval kann man auf den class-definition body zugreifen.
str = "test" # => "test" str.class.class_eval do def to_turkish "#{self.gsub(/[ou]/,'ü').gsub(/[OU]/,'Ü')}, ya" end end str.to_turkish # => "test, ya" foo = "foo" # => "foo" foo.to_turkish # => "füü, ya" # arkadaslar tuerk, ya, Kreuzberg geliorum!
Zugriff auf Variablen im uebergeordneten Scope
Man kann mit class_eval auch den Scope erweitern:
# in der irb >> draussen = "du kommst hier nicht rein" >> class Club >> puts draussen >> end => NameError: undefined local variable or method 'draussen' for Club:Class # wobei das hier geht >> Club.class_eval { puts draussen } => "du kommst hier nicht rein" # das hier wiederum nicht, da 'def' nen eigenen Scope oeffnet >> Club.class_eval {def mach_ansage; puts draussen; end; } => NameError: undefined local variable or method 'draussen' for Club:Class # das hier aber wieder funzt: >> Club.class_eval { define_method("mach_ansage") { puts draussen } } => #<Proc:0x0133723@(irb):42> >> _.call => "du kommst hier nicht rein" >> Club.new.mach_ansage => "du kommst hier nicht rein"
Ist doch mal der absolute Kracher, oder? Ich finds sooo geil :)
Ruby singleton klassen
Ich mache mal ne kleine Serie über Ruby, insbesondere über dynamische Aspekte. Ich stelle mal die Singleton-Klassen an den Anfang.
Singleton
Ein singleton ist nen Design-Pattern, bei dem die Kernaussage wohl kurz und knapp wie folgt definiert werden kann Eine Klasse, deren Anzahl an Instanzen zu jeder Zeit maximal 1 beträgt, ist ein Singleton.
In Ruby ist alles Objekt. Jedes Objekt hat eigentlich zwei Klassen:
- Die Klasse von der sie instanziiert wird
- seine Singleton-Klasse
Beispiel: singleton-Methoden auf Objekten definieren
Bevor ich hier gross anfange zu erklären, zeig ich erstmal bisserl Code:
# ist das gleiche wie # str = "test" str = String.new "test" # => "test" # hier wird eine singleton-Methode definiert # oder anders ausgedrueckt: der singleton-Klasse von str wird die Methode length # hinzugefuegt def str.length "#{super} Zeichen" end str.length # => "4 Zeichen" str.class # => String foo = String.new # => "" foo.length # => 0
die Methode length existiert also lediglich fuer das Objekt str.
Beispiel: Singleton-Context oeffnen
Man kann Methoden auch im Singleton-Context eines Objektes definieren.
str = "test" # den singleton-context oeffnet man dann mit diesem Konstrukt: class << test def zweimal "#{self} #{self}" end end str.zweimal # => "test test"
Beispiel Klassenmethoden
Es gibt unterschiedliche Varianten Singleton-Methoden zu definieren. Da alles Objekt ist, kannst du auch den Singleton-Kontext einer Klasse beschreiben:
# oeffnen des Definitions-contextes der Klasse Array class Array class << self def say puts "hi from array" end end end # ist dasselbe wie def Array.say puts "hi from array" end # ist dasselbe wie class Array def self.say puts "hi from array" end end
