From: Robert Klemme Date: 2007-05-18T22:55:06+09:00 Subject: Re: Coopting String interpolation On 18.05.2007 14:49, Brian Candler wrote: > On Fri, May 18, 2007 at 05:05:07PM +0900, Robert Klemme wrote: >>> I'm working in a research >>> project and I need to do some "clever stuff" (that's the thing I can't >>> disclose) to all the Strings. This thing is "different" depending on >>> how strings are composed. All the ways I know for string composition >>> but string interpolation (<<, +, concat, gsub, etc.) can be overridden >>> redefining methods in the string class. I'm looking for a way to >>> intercept the string expansion to do my thing. Does ruby internally >>> call some overridable method to compose the strings used in a >>> interpolation? >> Likely but also likely not accessible to pure Ruby code. But in your >> case (research project) it might be ok to hack the interpreter if you >> need to catch all string interpolations. Did you look into this yet? > > Here's a simpler idea. Given that string interpolation calls to_s, you can > use this as your hook if you wrap your objects in a proxy object. You need > to ensure that operations like '+' also return an instance of this proxy > object, so you can do all the operations you want whilst keeping the string > wrapped. Then the only case that to_s is called is when the interpolation > takes place, which gives you the hook you're looking for (as long as you're > not calling to_s in any other context) > > Example: > > class WrapString > def initialize(str) > @str = str > end > > def str > @str > end > protected :str > > def +(other) > self.class.new(str + (other.str rescue other.to_s)) > end > # rinse and repeat > > # Here is your interpolation hook: > def to_s > str.to_s * 2 > end > end > > a = WrapString.new("abc") > b = WrapString.new("def") > > puts "Answer is #{a + b}" > > a = WrapString.new("abc") > b = "def" > > puts "Answer is #{a + b}" > > The result of a + b is , and then the > interpolation calls to_s which in this case just doubles it to > "abcdefabcdef" > > There's probably a neater implementation of the above using method_missing > or a delegation pattern rather than enumerating all the methods of String, > but you get the idea. > > Just a thought? Not bad! Question is: what does it do to the rest of the code? Just think about using obj.to_s for Hash keys. Also, I am not sure what happens in core code if to_s returns something other than a string: 15:51:07 [~]: irb irb(main):001:0> o=Object.new => # irb(main):002:0> puts o # => nil irb(main):003:0> def o.to_s() "foo" end => nil irb(main):004:0> puts o foo => nil irb(main):005:0> def o.to_s() 123 end => nil irb(main):006:0> puts o # => nil Seems to be there could be wired effects... Kind regards robert