Last active
March 8, 2023 04:58
-
-
Save labocho/4e106cbd04423f7f4e71821ec4a8eb9c to your computer and use it in GitHub Desktop.
Plain text template helper for Rails
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# メール文面向けにプレーンテキストを生成する | |
# | |
# t = TextBuilder.new | |
# | |
# t << "Variables" | |
# t.indent { | |
# t.map(["foo", "bar", "baz"]) {|v| | |
# t << v | |
# } | |
# } | |
# | |
# makes | |
# | |
# Variables | |
# | |
# foo | |
# | |
# bar | |
# | |
# baz | |
# | |
class TextBuilder | |
attr_reader :delimiter, :indent_string | |
def initialize(delimiter: "\n", indent_string: " ") | |
@lines = [] | |
@delimiter = delimiter | |
@indent_string = indent_string | |
@depth = 0 | |
end | |
def to_s | |
@lines.join(delimiter) | |
end | |
def indent | |
if block_given? | |
@depth += 1 | |
yield | |
@depth -= 1 | |
else | |
@depth += 1 | |
end | |
end | |
# 空行を追加 | |
def br | |
self << "" | |
end | |
def hr | |
self << "------------------------------------------" | |
end | |
def outdent! | |
@depth -= 1 | |
end | |
# line を出力に追加する | |
# line は delimiter で区切られた複数行の文字列でもよい | |
# 出力時は各 line のあとに自動で delimiter がつく | |
# indent が 0 でなければ indent する | |
def add(line, indented: false) | |
lines = line.to_s.split(delimiter) | |
lines << "" if lines.empty? | |
# 最初の行のインデントを元にインデントを解除する | |
if indented | |
lines.first =~ /\A( *)/ | |
depth = ::Regexp.last_match(1).size | |
pattern = Regexp.compile("^ {,#{depth}}") | |
lines.each {|l| l.gsub!(pattern, "") } | |
end | |
@lines << lines.map {|s| ((indent_string * @depth) + s).gsub(/^ +$/, "") }.join(delimiter) | |
end | |
alias_method :<<, :add | |
# collection の要素ごとに TextBuilder を渡して block を実行し、TextBuilder の内容を self に追加する。 | |
# collection が空でなく、insert_before が truthy なら insert_before のみの行を最初に追加する。 | |
# insert_after_item が truthy なら要素ごとの出力のあとに insert_after_item のみの行を追加する | |
# TextBuilder.new.map(["foo", "bar"]){|t, e| t << e } #=> "\nfoo\n\nbar\n\n" | |
# TextBuilder.new.map(["foo", "bar"], insert_before: false){|t, e| t << e } #=> "foo\n\nbar\n\n" | |
# TextBuilder.new.map(["foo", "bar"], insert_after_item: false){|t, e| t << e } #=> "\nfoo\nbar\n" | |
# TextBuilder.new.map([]){|t, e| t << e } #=> "" | |
def map(collection, insert_before: nil, insert_after_item: nil) | |
return if collection.empty? | |
self << insert_before if insert_before | |
t = TextBuilder.new(delimiter:, indent_string:) | |
collection.each do |e| | |
yield t, e | |
t << insert_after_item if insert_after_item | |
end | |
self << t | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment