新しくオープンした日本語版stack overflowを見ていたらこんな質問がありました。
http://ja.stackoverflow.com/questions/1606/rubyで文字列の式展開を後から行うには
読んでいた所、文字列内での変数展開(#{hogehoge}
)を遅延評価するようにできるかな?と、気になったので、ちょっと試しに作ってみました。
本来の質問とは離れた気がするけど、気にしない。
使用例
str = LazyString.new 'Curent Time: #{Time.now}'
puts str # => Curent Time: 2014-12-16 22:56:02 +0900
sleep 1
puts str # => Curent Time: 2014-12-16 22:56:03 +0900
クラス定義
class LazyString
def initialize str
@str = str
end
def to_s
eval %Q("#{@str}")
end
def to_str
to_s
end
def inspect
%Q("#{@str}")
end
def +(opponent)
to_str + opponent.to_str
end
end
問題点
Stringクラスを継承するとputs時にto_sが呼ばれなくなる
class LazyString < String
def initialize str
super
end
def to_s
puts 'LazyString#to_s'
'dummy'
end
end
puts LazyString.new('test')
# => test
puts LazyString.new('test').to_s
# => LazyString#to_s
# => dummy
予想外。
Stringクラスを継承していないので、色々な演算子を定義する必要あり
とりあえず+
だけ定義してみた。
str = LazyString.new 'Curent Time: #{Time.now}'
str + ' is fixed'
# => "Curent Time: 2014-12-16 23:09:40 +0900 fixed"
評価しない+
も欲しくなってくる。
スコープはあくまでLazyString
str = LazyString.new 'Hello, #{name}'
name = 'Sheile'
puts str
# => NameError: undefined local variable or method `name' for "Hello, #{name}":LazyString
まとめ
副作用が大きいので、実際に何かに使うことは無さそうですがStringを継承した場合の予期せぬ挙動とかも見れたので、なかなか面白い挑戦でした。