😎
Ruby で pp の出力結果を文字列として取得する
たまに欲しくなるので覚書。
Ruby では pp で出力することでいい感じに複数行に改行して標準出力してくれます。
result = (1..3).map {
{ value: _1, twice: "#{_1}#{_1}", double: _1 + _1 }
}
# p の場合は1行で出力される
p result
# => [{value: 1, twice: "11", double: 2}, {value: 2, twice: "22", double: 4}, {value: 3, twice: "33", double: 6}]
# pp の場合は複数行にいい感じに改行されて出力される
pp result
# => [{value: 1, twice: "11", double: 2},
# {value: 2, twice: "22", double: 4},
# {value: 3, twice: "33", double: 6}]
このときに p と同様の結果になるような文字列は #inspect で取得することができます。
一方で pp と同様の結果になるような文字列は #pretty_print_inspect で取得することができる…と思ってたんですがどうやら改行された状態では取得できないみたい。
require "pp"
result = (1..3).map {
{ value: _1, twice: "#{_1}#{_1}", double: _1 + _1 }
}
# #inspect は p の結果の文字列が取得できる
p result.inspect
# => "[{value: 1, twice: \"11\", double: 2}, {value: 2, twice: \"22\", double: 4}, {value: 3, twice: \"33\", double: 6}]"
# 同様に pp の結果は #pretty_print_inspect で取得できると思っていたが #inspect と同じで改行コードは存在しない
p result.pretty_print_inspect
# => "[{value: 1, twice: \"11\", double: 2}, {value: 2, twice: \"22\", double: 4}, {value: 3, twice: \"33\", double: 6}]"
Object#pretty_print_inspect (Ruby 3.4 リファレンスマニュアル) を見ると
Object#pretty_print を使って Object#inspect と同様にオブジェクトを人間が読める形式に変換した文字列を返します。
と書いてあったんでてっきり pp の出力と同じ文字列が返ってくるのかと思ったけど改行コードは含まれていないみたいですね。
実際に #pretty_print_inspect の実装は pp-0.6.3 (Ruby 3.4 相当) 時点で以下のような形になっており内部で #singleline_pp を呼ぶようになっているみたいですね。
# Is #inspect implementation using #pretty_print.
# If you implement #pretty_print, it can be used as follows.
#
# alias inspect pretty_print_inspect
#
# However, doing this requires that every class that #inspect is called on
# implement #pretty_print, or a RuntimeError will be raised.
def pretty_print_inspect
if Object.instance_method(:method).bind_call(self, :pretty_print).owner == PP::ObjectMixin
raise "pretty_print is not overridden for #{self.class}"
end
PP.singleline_pp(self, ''.dup)
end
じゃあ、結局改行コードも含んだ pp の出力結果を文字列でどうやって取得するのかというと単純に PP.pp で取得するとよさそうですかねー。
require "pp"
result = (1..3).map {
{ value: _1, twice: "#{_1}#{_1}", double: _1 + _1 }
}
# 第一引数が出力したいオブジェクト
# 第二引数が出力結果を割り当てる元のオブジェクト
# 今回は文字列で結果を取得したいので第二引数が文字列になる
p PP.pp(result, "".dup)
# => "[{value: 1, twice: \"11\", double: 2},\n {value: 2, twice: \"22\", double: 4},\n {value: 3, twice: \"33\", double: 6}]\n"
ちょっと分かりづらいですがこれで pp で出力される値を文字列として取得することができました。
Discussion