元ネタは Homebrew の String#undent メソッドです.
ここで紹介するものはそれを少し賢くしています.
class String
def undent
min_space_num = self.split("\n").delete_if{|s| s=~ /^\s*$/ }.map{|s| s[/^\s*/].length }.min
self.gsub(/^[ \t]{,#{min_space_num}}/, '')
end
end
Ruby のヒアドキュメントでは,
class Notifier
def warning
<<-EOS
*** WARNING ***
your action is invalid!
check your input.
EOS
end
end
という風に,インデントを無視して書かなければなりません.
なぜなら,<<-EOS と EOS で囲まれている部分すべてが文字列になるので,インデントも文字列の一部に入ってしまうからです.
しかし,String#undent メソッドを使うと,次のように自然に書けます.
class Notifier
def warning
<<-EOS.undent
*** WARNING ***
your action is invalid!
check your input.
EOS
end
end
Homebrew の String#undent はヒアドキュメントの1行目のスペース数だけを見て undent していますが,ここに書いたものは
- 各行の行頭のスペースの中で一番スペース数が少ないものをインデント数と判断して,全行のインデントを削除
- ただし,空行やスペースのみの行は除く
というふうに,もう少し賢くインデント数を判断して undent します.