静的言語のコンパイルや動的言語の処理実行の前に行われる単純なテキスト置換
パーサ実行前に行われるテキスト置換。
3 hours ago => 3.hours.ago
ファウラー自身は動的言語で多く見てきた。
静的言語の場合はコンパイル前のビルドプロセスで実行。
内部DSLのテクニックであるが、外部DSLでも有用なケースがある。
字句解析前などで見つけづらいもの(インデントや改行)を研磨する場合など。
ファウラー自身は慎重派。
ちょっとしたものでは大げさすぎで、たくさん使うものではとても複雑になるということなので。
また、正規表現は間違えやすいので注意。
内部DSLのノイズキャラクタに対する代替案として、構文の色分けをサポートするエディタを使える。
背景色に近い色にして目立たなくすると。
多くの研磨をやっているなら、いっそのこと外部DSLを使ったほうがよい。
学習曲線が上がってしまえばそっちの方が楽、とのこと。
シンプルな割引ルールで、3000ドルを超える注文の場合は 3% 割り引くといったものを考える。
rule = DiscountBuilder.percent(3).when.minimum(30000).content
これを別ファイルとして分割すると次のようになる。
processing code... input = File.readlines("rules.rb") rules = [] input.each do |line| builder = DiscountBuilder.new builder.instance_eval(line) rules << builder.content if builder.has_rule? end rules.rb... percent(3).when.minimum(30000) # more rules....
コメントなどのようにルールがない場合は無視する必要があるので、builder.has_rule?によるチェックは必須。
続いてドメインエキスパートが次のようなものを好んだ場合。
3% if value at least $30000
次のようになる。
class DiscountRulePolisher... def polish aString @buffer = aString process_percent process_value_at_least process_if replace_spaces return @buffer end
class DiscountRulePolisher... def process_percent @buffer = @buffer.gsub(/\b(\d+)%\s+/, 'percent(\1) ') end&br;エクスプレッションの境界は \b だが、 "%" は単語の境界ではないので定義に注意。
class DiscountRulePolisher... def process_value_at_least @buffer = @buffer.gsub(/\bvalue\s+at\s+least\s+\$?(\d+)\b/, 'minimum(\1)') end
class DiscountRulePolisher... def process_if @buffer = @buffer.gsub(/\bif\b/, 'when') end&br;"when"に限らず"my_if"や"_if"でもよい。
class DiscountRulePolisher... def replace_spaces @buffer = @buffer.strip.gsub(/ +/, ".") end
翻訳難しいっす。。。