metaprogramming String # scan und globals?

8

Mein Ziel ist es, Methoden in der Klasse String durch andere Methoden zu ersetzen, die zusätzliche Arbeit leisten (dies ist für ein Forschungsprojekt). Dies funktioniert für viele Methoden, indem Code in der Klasse String ähnlich wie

geschrieben wird %Vor%

Bei einigen Methoden muss ich auch einen Proc verarbeiten, was kein Problem ist. Für die Methode scan hat das Aufrufen jedoch den Nebeneffekt, dass spezielle globale Variablen aus dem regulären Ausdruck übereinstimmen. Wie dokumentiert, sind diese Variablen lokal für den Thread und die Methode.

Leider ruft ein Teil des Rails-Codes Aufrufe von scan auf, die die Variable $& verwenden. Diese Variable wird in meiner Version der scan -Methode festgelegt, aber da sie lokal ist, wird sie nicht zum ursprünglichen Aufrufer zurückversetzt, der die Variable verwendet.

Kennt jemand einen Weg, um dies zu umgehen? Bitte lassen Sie mich wissen, wenn das Problem geklärt werden muss.

Wenn es überhaupt hilft, sind alle Verwendungen, die ich bisher von der Variable $& gesehen habe, in einem Proc enthalten, der an die Funktion scan übergeben wurde, damit ich die Bindung für diesen Proc erhalten kann. Der Benutzer scheint jedoch $& überhaupt nicht ändern zu können, also weiß ich nicht, wie das viel helfen wird.

Aktueller Code

%Vor%

Natürlich werde ich noch mehr tun, bevor ich r zurückgebe, aber das ist sogar problematisch - aus Gründen der Einfachheit bleiben wir dabei. Betrachten Sie als Testfall:

%Vor%

Dies funktioniert sowohl mit als auch ohne meine Version von scan . Mit der Klasse "vanilla" String erzeugt dies dasselbe wie

%Vor%

Nämlich druckt "ll" und "ld" und gibt "Hallo Welt" zurück. Mit der modifizierten String-Klasse werden zwei leere Zeilen gedruckt (da $& war nil ) und dann "Hallo Welt" zurückgegeben. Ich werde glücklich sein, wenn wir das schaffen können!

    
bchurchill 26.10.2013, 21:38
quelle

2 Antworten

4

Sie können $& nicht festlegen, da es von $~ , dem letzten MatchData, abgeleitet ist. % Co_de% kann jedoch gesetzt werden und das macht tatsächlich, was Sie wollen. Der Trick besteht darin, es in der Blockbindung zu setzen.

Der Code wurde von der alten Ruby-Implementierung von Pathname inspiriert.
(Der neue Code ist in C und muss sich nicht um Ruby frame-local-Variablen kümmern)

%Vor%

Das Speichern der thread-lokalen (naja, tatsächlich faser-lokalen) Variable scheint unnötig zu sein, da sie nur dazu verwendet wird, den Wert zu übergeben und der Thread niemals einen anderen Wert liest als der letzte Satz. Es ist wahrscheinlich da, um den ursprünglichen Wert wiederherzustellen (höchstwahrscheinlich $~ , weil die Variable nicht existierte).

Eine Möglichkeit, Thread-Locals überhaupt zu vermeiden, besteht darin, einen Setter von nil als Lambda zu erstellen (aber für jeden Aufruf wird ein Lambda erstellt):

%Vor%

Mit jedem von diesen funktioniert Ihr Beispiel!

    
eregon 01.11.2013, 15:15
quelle
1

Ich habe einfachen Code geschrieben, der das Problem simuliert:

%Vor%

Und folgendes gefunden. Die Änderung der Eingrenzung der Variablen $& wurde innerhalb einer Funktion :call , d. H. Im 3. Schritt, bevor :call $& einen gültigen Wert enthält, aber innerhalb des Blocks wird sie ungültig. Ich nehme an, dass dies auf den Singularitätsstack und die Variablenwiederherstellung während des Änderungsprozesses / Threadkontexts zurückzuführen ist, da :call function wahrscheinlich nicht auf den lokalen Zustand :scan zugreifen kann.

Ich sehe zwei Varianten: Die erste besteht darin, zu vermeiden, globale Variablen in den spezifischen Funktionsredefinitionen zu verwenden, und zweitens, Quellen von Ruby tiefer zu graben.

    
quelle