Schrift
[thread]13001[/thread]

Wirksamkeit von perl -CSD

Leser: 2


<< >> 5 Einträge, 1 Seite
jonboy
 2009-01-14 18:35
#117992 #117992
User since
2009-01-14
2 Artikel
BenutzerIn
[default_avatar]
Hallo liebe Community,

vielleicht ist die Sache ja ganz einfach, aber ich stehe hier ein bisschen wie die Kuh vorm Berg. Es geht darum, dass ich Dateien einlesen und dabei automatisch durch den :utf8-Layer geschickt haben will. An sich kein Problem - solange ich selbst die fraglichen Dateien öffne, denn sobald ich das durch ein anderes Modul lasse (konkret mittels slurp() aus IO::Util), wirkt der Layer offensichtlich nicht mehr.

So wie ich das verstanden habe, greift die Definition per "use open ':utf8';" nur innerhalb des aktuellen lexical scope, der maximal die eigene Scriptdatei umfasst, sich aber nicht auf andere Module auswirkt. Aus diesem Grund schalte ich den :utf8-Layer mittels "perl -CSD" ein, weil das das "globalste" ist, was mir dazu eingefallen ist.

Nun habe ich das Problem mal auf minimalen Beispielcode reduziert. Erstens habe ich eine Datei mit dem String "äöüÄÖÜ߀" in UTF-8-kodierter Form, wie man nicht zuletzt an der Dateigröße leicht erkennen kann, die nicht 8, sondern 17 Bytes beträgt:

Code: (dl )
1
2
$ ls -l unicodetest 
-rw-rw-r-- 1 jonas jonas 17 2009-01-14 17:22 unicodetest


Das Testscript sieht so aus:

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/perl -w -CSD

use strict;
use TestUnicodeModule;

print "unicode pragma in test-unicode: " . ${^UNICODE} . "\n";

open (F, 'unicodetest');
my $out = <F>;
close (F);

print "out: " . $out . "\n";
print "out is_utf8: " . ( utf8::is_utf8($out) ? 1 : 0 ) . "\n";
print "out length: " . length($out) . "\n";


Wie man sieht, binde ich noch das Modul TestUnicodeModule mit ein. Das macht eigentlich genau das gleiche, nur eben halt in einem ausgelagerten Modul. Der Vollständigkeit halber:

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
package TestUnicodeModule;

print STDERR "unicode pragma in TestUnicodeModule: " . ${^UNICODE} . "\n";

open (F, 'unicodetest');
my $out = <F>;
close (F);

print "out: " . $out . "\n";
print "out is_utf8: " . ( utf8::is_utf8($out) ? 1 : 0 ) . "\n";
print "out length: " . length($out) . "\n";


Nun führe ich das Script aus und versteh's einfach nicht:

Code: (dl )
1
2
3
4
5
6
7
8
9
$ ./test-unicode 
unicode pragma in TestUnicodeModule: 31
out: äöüÃ&#132;Ã&#150;Ã&#156;Ã&#159;â&#130;¬
out is_utf8: 0
out length: 17
unicode pragma in test-unicode: 31
out: äöüÄÖÜ߀
out is_utf8: 1
out length: 8


Laut man perlvar gibt ${^UNICODE} die derzeitigen Unicode-Einstellungen von Perl wieder, und man sieht, dass diese auch im TestUnicodeModule gelten. Trotzdem (und obwohl ich dem open keinerlei Layer mitgebe, die den Default überschreiben könnten) wird die Datei nur im Script mit korrektem Layer eingelesen, im Modul aber nicht, obwohl doch (für mein Empfinden) perl -CSD diese Einstellung doch eigentlich global ändern sollte.

Der springende Punkt ist, dass ich das Modul selbst idealerweise nicht ändern will (weil es hier um fertige CPAN-Module geht - wie gesagt, konkret um IO::Util) und hierfür sozusagen die sauberste, "richtigste" Lösung suche.

Über Hilfestellungen oder Fingerzeige auf Dokumentation, die mir bisher dann offenkundig verborgen geblieben ist, freue ich mich sehr.

Viele Grüße,
Jonas
renee
 2009-01-15 09:15
#118008 #118008
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
Den -C-Switch in der Shebang ist nutzlos (im Gegensatz zum -C in der Kommandozeile), weil er bisher nicht richtig funktioniert hat und in Perl 5.10 rausgeworfen wurde.

Am geschicktesten wäre es wohl, IO::Util zu patchen und den Patch auch an den Autor schicken. Oder ein eigenes Wrappermodul drumbauen, das eine eigene slurp-Funktion bereitstellt, in der Du den Filehandle erstellst und den Filehandle mittels "binmode $filehande, ':encoding(utf-8)'" auf UTF-8 umstellst. Oder Du schreibst gleich eine eigene slurp-Funktion.
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
moritz
 2009-01-15 10:27
#118011 #118011
User since
2007-05-11
923 Artikel
HausmeisterIn
[Homepage]
user image
Dein Versuch, ein Modul "von aussen" Unicode-tauglich zu machen ist genauso verständlich, wie es zum Scheitern verurteilt ist. Spätestens wenn das Modul explizit IO-Layer angibt (was ich bei Module, die selbst mit IO anfangen, für recht wahrscheinlich halte) kann das gar nicht mehr gehen, selbst wenn es ansonsten einen Mechanismus gäbe.
jonboy
 2009-01-15 12:32
#118014 #118014
User since
2009-01-14
2 Artikel
BenutzerIn
[default_avatar]
Hallo,

danke für die informativen Antworten!

renee+2009-01-15 08:15:47--
Den -C-Switch in der Shebang ist nutzlos (im Gegensatz zum -C in der Kommandozeile), weil er bisher nicht richtig funktioniert hat und in Perl 5.10 rausgeworfen wurde.


Auch beim Aufruf von "perl -w -CSD test-unicode" ergibt sich keine Änderung am Verhalten des Scripts; eine Änderung z.B. auf "-C0" im Shebang wirkt sich aber durchaus aus (und sorgt dafür, dass auch mein open() kein utf8 mehr liefert). Das Perl, das hier zum Einsatz kommt, ist auch noch ein 5.8.5 (auf einem CentOS 4.5), auch wenn das Script natürlich auch mal unter Perl 5.10 laufen sollte. Aber das erscheint mir im Moment eher als sekundäres Problem; perl -CSD tut ja auch jetzt schon nicht, was ich meine, was es tun sollte.

renee+2009-01-15 08:15:47--
Am geschicktesten wäre es wohl, IO::Util zu patchen und den Patch auch an den Autor schicken. Oder ein eigenes Wrappermodul drumbauen, das eine eigene slurp-Funktion bereitstellt, in der Du den Filehandle erstellst und den Filehandle mittels "binmode $filehande, ':encoding(utf-8)'" auf UTF-8 umstellst. Oder Du schreibst gleich eine eigene slurp-Funktion.


Okay, ich hatte bewusst gesagt, dass ich IO::Util idealerweise nicht patchen müssen will, weil das letztlich nur ein Beispiel war und ich nach einer generalisierten Lösung suche - deshalb habe ich die Problemstellung ja auch derart zu abstrahieren versucht, dass gar kein externes Modul (außer meinem eigenen zur Demonstration der Problemstellung) zum Einsatz kommt. Denn der Einsatz von Modulen ist in meinem ganz konkreten Fall noch deutlich komplexer, weil IO::Util nur indirekt zum Einsatz kommt: Genaugenommen benutze ich CGI::Builder mit dem Modul CGI::Builder::Magic, das eine Anbindung zu Template::Magic darstellt, das wiederum die Templates einliest. Es wäre also nicht damit getan, IO::Util zu patchen, sondern ich müsste dann auch den ganzen Rest bis hin zum eigentlichen High-Level-Modul CGI::Builder::Magic patchen. Und zwar dergestalt, dass ich hier nicht einfach ein Filehandle übergebe, sondern schon irgendwie mitteilen müsste, dass die darunterliegenden Module bitte auch bei allen weiteren Dateioperationen den utf8-Layer benutzen sollten. Denn:

Die Variante mit der Übergabe eines fertig gelayerten Filehandles, die ist offiziell vorgesehen und funktioniert auch prima. Templates können aber auch include-Anweisungen enthalten und weitere Templates einbinden, und spätestens dann ist wieder Essig, weil es in diesem Fall ja Template::Magic (mittels IO::Util) ist, das das einzubindende Template öffnet, und nicht ich. Es würde also bei einer sauberen Lösung kein Weg daran vorbeiführen, Template::Magic die gewünschten Layer mitzuteilen, damit es diese an IO::Util übergeben kann, damit jenes sie dann auch bei jedem open() beachtet, das es angeregt durch ein include selbst durchführt.

moritz+2009-01-15 09:27:22--
Dein Versuch, ein Modul "von aussen" Unicode-tauglich zu machen ist genauso verständlich, wie es zum Scheitern verurteilt ist. Spätestens wenn das Modul explizit IO-Layer angibt (was ich bei Module, die selbst mit IO anfangen, für recht wahrscheinlich halte) kann das gar nicht mehr gehen, selbst wenn es ansonsten einen Mechanismus gäbe.


Erstmal freut mich, dass mein Wunsch an sich verständlich zu sein scheint. :-)

Mal etwas flapsig ausgedrückt: Ich will kein Modul Unicode-tauglich machen. Ich will, dass ein Modul das richtige tut, wenn es sich einfach gar nicht um den ganzen Layerkrempel kümmert. Es soll sich zurücklehnen und sagen: "Wenn du willst, dass ich bei einem open() den $utf8_oder_sonstwas-Layer benutze, dann sag das nicht mir: Sag es PerlIO. Ich kümmere mich selber nicht um Layer, sondern benutze einfach die, auf die dein PerlIO eingestellt ist." - Dass ein Modul unabhängig davon natürlich _auch_ selber Layer setzen kann, steht dabei ja außer Frage. Mein Beispielcode gibt nebenbei selber keinerlei IO-Layer an, die den "Default" überschreiben würden - und trotzdem funktioniert's nicht.

Mir erscheint es einfach als wenig sinnvoll, jedem einzelnen Modul beibringen zu müssen, welchen Layer es beim Öffnen von Dateien benutzen soll, wenn Perl "eigentlich" eine Möglichkeit mitbringt, den Default-Layer selbst zu bestimmen (und sowohl man perlrun als auch man perluniintro legen das eigentlich nahe: You can enable automatic UTF-8-ification of your standard file handles, default "open()" layer, and @ARGV by using either the "-C" command line switch or the "PERL_UNICODE" environment variable. Und es erscheint mir auch einfach wie ein Fehler, wenn ich mir in meiner TestUnicodeModule.pm den Wert von ${^UNICODE} anschaue und feststelle, es ist auf utf8 für IO-Operationen eingestellt, aber meine IO-Operationen laufen dann faktisch gar nicht über den utf8-Layer.

Sagt mir "Stimmt, blöd, ist aber so", und ich bin still ... wenngleich unglücklich.

Danke und viele Grüße,
Jonas

PS: Wenn's wirklich so ist, wäre das eine gute Erklärung dafür, wieso Unicode mit Perl einfach keinen Spaß mehr machen will, sobald man Module abseits der ganz verbreiteten einsetzen will, in die die Autoren bereits explizit utf8-Support (oder generalisiert: Layer-Support) eingebaut haben. Dieses Geraffel jedem einzelnen CPAN-Modul separat beibringen zu wollen, scheint mir doch zum Scheitern verurteilt ...
sid burn
 2009-01-17 19:34
#118130 #118130
User since
2006-03-29
1520 Artikel
BenutzerIn

user image
Quote
Mal etwas flapsig ausgedrückt: Ich will kein Modul Unicode-tauglich machen. Ich will, dass ein Modul das richtige tut, wenn es sich einfach gar nicht um den ganzen Layerkrempel kümmert.

Eigentlich ist die Aussage ja falsch du willst ja das es sich um den layer krempel kümmert. Den sich nicht darum kümmern das hast du ja derzeit. ;)

Quote
Es soll sich zurücklehnen und sagen: "Wenn du willst, dass ich bei einem open() den $utf8_oder_sonstwas-Layer benutze, dann sag das nicht mir: Sag es PerlIO. Ich kümmere mich selber nicht um Layer, sondern benutze einfach die, auf die dein PerlIO eingestellt ist."

Wäre ehrlich gesagt dumm wenn dies so wäre. Denn damit würdest du mehr kaputt machen als richtig machen.

Stell dir vor du hast ein Modul das nunmal mit Binärdateien umgeht. Nimm ein Modul das mit Bildern umgeht. Image::Magick, Imager etc. Und du würdest jetzt sagen du willst UTF-8 und kein Modul soll sich selber darum kümmern und es wird erzwungen.

Nun dann wären ab sofort alle Module die auf einen anderen layer arbeiten kaputt und würden nicht mehr laufen.

Generell ist es immer eine schlechte Idee wenn ein Modul von ausen beeinflusst werden kann.

Und das was du machst ist für mich eher nur Problemlösung die an der Wurzel des Problems vollständig vorbei gehen.

Das Modul selber muss UTF-8 Support anbieten und sollte in dieser hinsicht gepatcht werden.

Ansonsten wenn du ein fremdes Modul hast das dir keine UTF-8 Kodierten Daten zurück liefert kannst du auch naträglich immer noch "decode()" aus dem Modul "Encode" darauf anwenden.
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de
<< >> 5 Einträge, 1 Seite



View all threads created 2009-01-14 18:35.