Skip to content

Instantly share code, notes, and snippets.

@bouzuya
Created January 14, 2013 13:03
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bouzuya/4529917 to your computer and use it in GitHub Desktop.
Save bouzuya/4529917 to your computer and use it in GitHub Desktop.
(use 'clojure.test)
(with-test
(defn f
[& {:as options}]
options)
(is (nil? (f)))
(is (thrown? IllegalArgumentException (f nil)))
(is (thrown? IllegalArgumentException (f :a)))
(is (= (f nil nil) {nil nil}))
(is (= (f :a \a) {:a \a}))
(is (= (f :a \a :b \b) {:a \a :b \b}))
(is (= (f :a \a :b \b :c \c) {:a \a :b \b :c \c})))
(with-test
(defn g
[& {:as options :or {a \0 b \1}}]
options)
(is (nil? (g))) ; oh...
(is (thrown? IllegalArgumentException (g nil)))
(is (thrown? IllegalArgumentException (g :a)))
(is (= (g nil nil) {nil nil}))
(is (= (g :a \a) {:a \a}))
(is (= (g :a \a :b \b) {:a \a :b \b}))
(is (= (g :a \a :b \b :c \c) {:a \a :b \b :c \c}))) ; oh...
(with-test
(defn h
[& {:keys [a b] :or {a \0 b \1}}] ; oh...
{:a a :b b})
(is (= (h) {:a \0 :b \1}))
(is (thrown? IllegalArgumentException (h nil)))
(is (thrown? IllegalArgumentException (h :a)))
(is (= (h nil nil) {:a \0 :b \1}))
(is (= (h :a \a) {:a \a :b \1}))
(is (= (h :a \a :b \b) {:a \a :b \b}))
(is (= (h :a \a :b \b :c \c) {:a \a :b \b})))
(with-test
(defn i
[& {:as options}]
(merge {:a \0 :b \1}
options))
(is (= (i) {:a \0 :b \1}))
(is (thrown? IllegalArgumentException (i nil)))
(is (thrown? IllegalArgumentException (i :a)))
(is (= (i nil nil) {nil nil :a \0 :b \1})) ; oh...
(is (= (i :a \a) {:a \a :b \1}))
(is (= (i :a \a :b \b) {:a \a :b \b}))
(is (= (i :a \a :b \b :c \c) {:a \a :b \b :c \c}))) ; oh...
(with-test
(defn j
[& {:as options}]
(let [default {:a \0 :b \1}]
(into {} (filter (comp (set (keys default)) key)
(merge default options)))))
(is (= (j) {:a \0 :b \1}))
(is (thrown? IllegalArgumentException (j nil)))
(is (thrown? IllegalArgumentException (j :a)))
(is (= (j nil nil) {:a \0 :b \1}))
(is (= (j :a \a) {:a \a :b \1}))
(is (= (j :a \a :b \b) {:a \a :b \b}))
(is (= (j :a \a :b \b :c \c) {:a \a :b \b})))
(with-test
(defn apply-defaults
[values defaults]
(->>
(apply hash-map values)
(merge defaults)
(filter (comp (set (keys defaults)) key))
(remove (comp nil? val))
(into {})))
(is (thrown? IllegalArgumentException (apply-defaults [nil] {:a \0 :b \1})))
(are [values expected]
(= (apply-defaults values {:a \0 :b \1}) expected)
nil {:a \0 :b \1}
[] {:a \0 :b \1}
[nil nil] {:a \0 :b \1}
[:a \a] {:a \a :b \1}
[:a \a :b \b] {:a \a :b \b}
[:a \a :b \b :c \c] {:a \a :b \b})
(are [values expected]
(= (apply-defaults values {:a \0 :b \1 :c nil}) expected)
[:a \a] {:a \a :b \1}
[:a \a :b \b] {:a \a :b \b}
[:a \a :c \c] {:a \a :b \1 :c \c}
[:a \a :b \b :c nil] {:a \a :b \b}
[:a \a :b \b :d \d] {:a \a :b \b}
[:a \a :b \b :c \c] {:a \a :b \b :c \c}))
(with-test
(defn k
[& options]
(apply-defaults options {:a \0 :b \1})) ; ok!
(is (= (k) {:a \0 :b \1}))
(is (thrown? IllegalArgumentException (k nil)))
(is (thrown? IllegalArgumentException (k :a)))
(is (= (k nil nil) {:a \0 :b \1}))
(is (= (k :a \a) {:a \a :b \1}))
(is (= (k :a \a :b \b) {:a \a :b \b}))
(is (= (k :a \a :b \b :c \c) {:a \a :b \b})))
@bouzuya
Copy link
Author

bouzuya commented Jan 14, 2013

Clojure での省略可能引数の書き方について考えてみた。

最終的には apply-defaults を定義して、それに処理させる k に落ち着いた。

apply-defaults は指定可能な引数の制限と、val が nil のものの削除と、デフォルト値の設定を行う。色々やりすぎているが、これくらいの方が使いやすいと思う。良い名前が思い浮かばないので、ひとまず apply-defaults にしている。

引数の制限や nil 値の削除が不要なら i(merge defaults options) で十分で、これなら関数も不要だと思う。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment