Skip to content

Instantly share code, notes, and snippets.

@otofu-square
Last active September 4, 2017 05:26
Show Gist options
  • Save otofu-square/e76b9314a5ef0eee3fe8cde06d1c27cf to your computer and use it in GitHub Desktop.
Save otofu-square/e76b9314a5ef0eee3fe8cde06d1c27cf to your computer and use it in GitHub Desktop.
Implementation of Ruby's here document in TypeScript
// 文字列の行頭にあるスペースのサイズを取得する
const getSpaceLengthAtBeginningOfLine = (str: string) =>
str.match(/^(\s*)/)![1].length;
// 末尾の空行を削除する
const trimTailSpaces = (str: string) => str.match(/(.*?)(\s*)$/)![1];
// Number の配列から最小の値を取りだす
// see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min
const getMinOfArray = (arr: number[]) => Math.min.apply(null, arr);
// 改行で区切られたテンプレート文字列の最小の行頭スペースサイズを取得する
const getMinSpaceSize = (template: string) =>
getMinOfArray(
template
.split("\n") // 改行毎の文字列の配列に分割
.filter(str => str !== "") // 空行を除去
.map(str => getSpaceLengthAtBeginningOfLine(str)),
);
// Tagged Template の Literals と Placeholders を結合する
const combineLiteralsAndPlaceholders = (
literals: TemplateStringsArray,
placeholders: any[],
) =>
literals.reduce(
(prev, curr, idx) => `${prev}${placeholders[idx - 1]}${curr}`,
);
// Tagged templates implementation for here document in ruby (<<~EOS ... EOS)
const EOS = (
literals: TemplateStringsArray,
...placeholders: any[],
) => {
const template = combineLiteralsAndPlaceholders(literals, placeholders);
const minSpaceLength = getMinSpaceSize(template);
return template
.split("\n") // 改行毎の文字列の配列に分割
.slice(1) // テンプレートリテラルの頭の改行を除去
.map(str => trimTailSpaces(str.slice(minSpaceLength)))
.join("\n");
};
const doc = EOS`
foo
baz
1 + 1 = ${1 + 1}
1 - 1 = ${1 - 1}
this is foo
foobaz
bazfoo
`;
console.log(doc)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment