Home > Archive > Ruby > August 2005 > Need help with with Binding.of_caller
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Need help with with Binding.of_caller
|
|
| Sascha Ebach 2005-08-04, 10:02 pm |
| Hi,
(hoping that Florian is reading)
I am just in the process of patching ri18n[1] interpolation
functionality. Here is what I a trying to do:
ri18n offers a way to interpolate strings. This is for translation
purposes. The current version of the interpolation method looks like this:
class String
def interpolate(caller)
caller.instance_eval('"' << self.gsub('"', '\"') << '"')
end
...
end
original version is here:
http://svn.berlios.de/viewcvs/ri18n....rb?view=markup
This will correctly interpolate the following:
@color = 'red'
_i('#{@color} whine')
but not this:
color = 'red'
_i('#{color} whine')
So I thought I might try to use the Binding.of_caller technique. I came
as far as this:
class String
def interpolate(caller) # the param is not needed anymore
Binding.of_caller do |binding|
eval('"' << self.gsub('"', '\"') << '"', binding)
end
end
...
end
which will do exactly the opposite. Now I am able to eval local
variables, but not the instance vars.
this doesn't work:
@color = 'red'
_i('#{@color} whine')
but this does:
color = 'red'
_i('#{color} whine')
What do I need to do to capture the whole environment of the originating
_i() call. Is it at all possible?
Sascha Ebach
[1] http://ri18n.berlios.de/
| |
| Florian Groß 2005-08-04, 10:02 pm |
| Sascha Ebach wrote:
> (hoping that Florian is reading)
If in doubt CC, but I try to keep up with ruby-talk. (Not true for the
Rails list, though -- I tried creating a gmane RSS filter for my
identity so I wouldn't miss anything, but so far it seems not to have
worked.)
> So I thought I might try to use the Binding.of_caller technique. I came
> as far as this:
>
> class String
> def interpolate(caller) # the param is not needed anymore
> Binding.of_caller do |binding|
> eval('"' << self.gsub('"', '\"') << '"', binding)
> end
> end
> ...
> end
>
> which will do exactly the opposite. Now I am able to eval local
> variables, but not the instance vars.
Trust me: I'm as shocked as you are.
I think I actually stumbled upon this behavior before but quickly
displaced the knowledge from my memory.
I think this is related to Ruby not setting the .self field of the BLOCK
struct for trace_func bindings. From what I see binding() has some extra
logic which might do exactly this.
Don't take my guess at this too literally -- the code for this is fairly
complex and I will not claim to understand how all parts of it work
together, but I think this might be a bug or a known limitation.
You're only chance of really finding out is if you get lucky and Nobu or
ts or someone else with deeper Ruby knowledge accidently reads all this.
Which would actually be because then I would know if this is by
design or not. Let's wait a bit and see if anyone bites. I will want to
eventually document this so an explanation would be very .
> What do I need to do to capture the whole environment of the originating
> _i() call. Is it at all possible?
It's a good question and I would like to say that coding interpolation
is evil, but it might make sense here.
Perhaps you can make interpolate a method on Kernel -- then you would be
able to do interpolate(@foo) and the self of the interpolate method and
the one of the caller would always be the same thus avoiding the whole
situation. Does this sound reasonable?
| |
| Sascha Ebach 2005-08-05, 9:02 am |
| Thanks for the fast response Florian.
Florian Gro=DF wrote:
> Perhaps you can make interpolate a method on Kernel -- then you would b=
e=20
> able to do interpolate(@foo) and the self of the interpolate method and=
=20
> the one of the caller would always be the same thus avoiding the whole=20
> situation. Does this sound reasonable?
I am not sure anymore if it is worth going through all the trouble. The=20
whole solution is a little evally. First it is a little hard to=20
understand, like you say yourself. Next there is the question of=20
performance. As I understand eval is not very fast. And this is a method=20
which is potentially being called very often. A Binding.of_caller=20
solution would certainly be the most elegant, but faster and more=20
reliable would be if the method would just do some stringfy thing.
_i('%s whine', @color)
or maybe to further simplify
_i(':color_of whine', :color_of =3D> @color)
which should be easier to work with (but less flexible) for the translato=
rs.
_Since I am not the author of the ri18n, he seems to be on a vacation at=20
the moment, I have to wait and talk to him first. But I am going to=20
suggest using the above instead of the eval magic. Unless of course some=20
of the real wizards come up with a magical and fast solution. Chances=20
are slim I guess.
Let's see.
Sascha Ebach
|
|
|
|
|