Re: wie expandiere ich hashvalues in einem string

Pit Capitain <[email protected]> Thu, 24 Feb 2005 21:04:47 +0100
Newsgroups gmane.comp.lang.ruby.german
Message-ID <[email protected]>
robert kuzelj schrieb:
> das ist schon wesentlich besser. hab aber ein paar fragen.

Gerne. Der Code ist leider nicht so leicht zu verstehen.

> 010 def expand(template, values)
> 020    b =3D binding
> 030    v =3D nil
> 040    values.each do |name, value|
> 050      v =3D value
> 060      eval("#{name} =3D v", b)
> 070    end
> 080    eval(%Q{"#{template}"})
> 090 end
> 100
> 110 s =3D expand('Eins: #{eins}, Zwei: #{zwei}', {"eins" =3D> 111, "zwe=
i" =3D>
>  222})
> 120   puts s  # =3D> Eins: 111, Zwei: 222

Zun=C3=A4chst mal nutze ich eval, um die Variablen zu erzeugen. Hierbei i=
st zu=20
beachten, dass man mit eval zwar neue lokale Variablen erzeugen kann, die=
se aber=20
au=C3=9Ferhalb von eval nicht sichtbar sind:

   eval("a =3D 1")
   puts a  # =3D> undefined local variable or method `a'

Man kann allerdings auf diese Variablen auch sp=C3=A4ter noch mit eval zu=
greifen:

   puts(eval("a"))  # =3D> 1

Da das Template am Ende sowieso mit eval ausgewertet werden sollte, hat m=
ir=20
dieses Verhalten gereicht.

Ich habe den Code erst mal ohne Binding und ohne die Variable v ausprobie=
rt.=20
Dabei hat sich gezeigt, dass ich innerhalb des each Blocks zwar auf die n=
euen=20
Variablen zugreifen konnte, diese aber au=C3=9Ferhalb des Blocks nicht me=
hr sichtbar=20
waren. Also gilt auch f=C3=BCr die mit eval angelegten lokalen Variablen =
dasselbe wie=20
bei normalen lokalen Variablen: wenn sie erst in einem Block neu angelegt=
=20
werden, sind sie au=C3=9Ferhalb des Blocks nicht mehr sichtbar:

   1.times do
     a =3D 1
   end
   puts a  # =3D> undefined local variable or method `a'

Daher habe ich dann den zweiten Parameter von eval benutzt, um die Variab=
len im=20
Kontext des =C3=A4u=C3=9Feren Codes zu erzeugen. Daf=C3=BCr brauchte ich =
dann wiederum die=20
Variable v aus dem =C3=A4u=C3=9Feren Kontext, um die Werte setzen zu k=C3=
=B6nnen. So ist dann=20
letztlich dieser Code entstanden.

> soweit ich aus der doku verstanden habe holt sich Kernel::binding
> die variablen bindings zum zeitpunkt des aufrufs um es zb. spaeter
> in einem aufruf von eval nutzen zu koennen. nun ist aber zb. v,
> welches du in eval nutzt noch gar nicht definiert. warum gibt das
> keinen fehler?

Mit binding bekommt man keinen Snapshot der aktuellen Variablen-Bindungen=
,=20
sondern eben nur den Kontext f=C3=BCr die Variablen. Sp=C3=A4tere =C3=84n=
derungen in diesem=20
Kontext sind dann nach wie vor =C3=BCber das vorher erzeugte Binding-Obje=
kt sichtbar.

> und schliesslich was um gottes willen macht %Q ?

Ich wollte das Template ja mit eval auswerten und brauchte daf=C3=BCr ein=
en String,=20
der einen String-Ausdruck enth=C3=A4lt. Ich brauchte also Anf=C3=BChrungs=
zeichen vor und=20
hinter dem Template. Das h=C3=A4tte ich mit

   '"' + template + '"'

machen k=C3=B6nnen, aber normalerweise verwende ich die "...#{wert}..." S=
chreibweise,=20
um Strings zusammenzubauen:

   "\"#{template}\""

Hier haben mich aber die \ vor den Anf=C3=BChrungszeichen etwas gest=C3=B6=
rt, und um ein=20
Konstrukt zu =C3=BCben, das ich bisher nur selten verwendet habe, habe ic=
h den=20
speziellen Quoting-Mechanismus von Ruby verwendet. Siehe hierzu z.B.

   http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_stdtypes.html#S2

Gru=C3=9F,
Pit