LispマクロでLispコードをCSSに変換するようにしてみた
2014.9.16
覚えたてのマクロの練習がてらつくってみた。500バイト程度で実装。ファイル出力がなければ400バイトくらい?
(defmacro css (name elems)
(with-open-file
(*standard-output* (string-downcase name) :direction :output :if-exists :supersede)
`(progn
,@(mapc
(lambda (style)
(let ((elem (car style))
(attrs (cadr style)))
(format t "~a {~%" elem)
(loop for i in attrs do
(format t "~2T~a: ~a;~%" (string-downcase (car i)) (cadr i)))
(format t "}~%~%"))) elems)) t))
引数には名前と要素のリストを取るようにしよう。要素のリストは CSSの構造が以下のコードのようにネストされているようにする。
2行目で with-open-file関数を呼び出し、3行目では標準出力の使用、アウトプット先などのオプションの指定。
あとは 要素 { … } が 各要素毎にひと固まりとして生成されるように mapをかけてあげる。ここでmapは直接ファイル出力として作用しており、リストを返す必要が無いのでmapcarではなくmapcを使用している。
そんでもって変換用のLispコードを用意する。
; Macro Sample 1
(css
test.css
((".hoge"
((background "#F00")
(border-radius "5px")))
("#fuga"
((background "#009")
(color "#FFF")))))
; Macro Sample 2
(css
test2.css
(("body"
((background "#CCC")))
("p"
((font-size "10px")
(margin "3px 0")
(padding "5px 0")))))
これを先ほどのマクロと共に実行すると、「test.css」「test2.css」という二つのCSSファイルが作成される。
/* test.css */
.hoge {
background: #F00;
border-radius: 5px;
}
#fuga {
background: #009;
color: #FFF;
}
/* test2.css */
body {
background: #CCC;
}
p {
font-size: 10px;
margin: 3px 0;
padding: 5px 0;
}
もう少し厳密に書けばファイル出力のあたり関数に分けられるだろうし そもそももっと賢い書き方ができそうな気がするので、「ここはこうした方が良い」という部分がございましたら そっとマサカリを投げて頂ければ幸いです。
Written by Nisei Kimura ( 木村 仁星 )
