This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-06-22
Channels
- # admin-announcements (9)
- # beginners (18)
- # boot (20)
- # cider (32)
- # clojure (108)
- # clojure-berlin (5)
- # clojure-czech (3)
- # clojure-italy (5)
- # clojure-japan (70)
- # clojure-russia (37)
- # clojure-sg (2)
- # clojure-spain (3)
- # clojurescript (89)
- # core-async (5)
- # core-typed (12)
- # datomic (11)
- # dunaj (2)
- # editors (30)
- # euroclojure (33)
- # events (1)
- # jobs (10)
- # ldnclj (18)
- # off-topic (45)
- # reagent (12)
clojailってコードをトラバースしてブラックリストに載ってるシンボルがコード中に出現しないかチェックしてるんですけど、ブラックリストに載ってるシンボルでもメタプログラミング的に生成してしまうと使えてしまう、とか
なので、Clojureの真面目なサンドボックスを作ろうと思った場合、Clojureのコードを見るんじゃなくて、Javaのサンドボックス機能を使うなりして、実行時に「fooクラスのbarメソッドが呼ばれた」みたいなのを検知しないとダメだと思います
ただ、Javaのセキュリティ機能でメソッド呼び出しを禁止するためには、そのクラスがそういう実装になってないとダメなので、「Clojureのコアクラスのこのメソッドを呼び出しちゃいけない」っていうのを後づけで指定できないので、現実的にはさっきの方針はかなり難しいです
もうちょっと現実的な方法としては、自前でクラスローダを用意して、Clojureコアのクラスをロードするときに特定のメソッドにセキュリティチェックを挿入するロードタイムウィービングとかが考えられますけど、まぁこっちにしてもヘビーなことには変わりないですね。
そういえばかなり前に出てた話題ですが、condのインデントが深くなる問題、自分は勝手に cond* という名前のマクロを書いて使ってます。ただこれを他の人もいじるコードでも使うべきかはかなり悩むところ
;;; (cond*
;;; [(very-long-pred? arg1 arg2 arg3)
;;; (very-long-proc! arg4 arg5 arg6)]
;;; [(pred2?) => #(proc2 arg1 arg2 % arg3)]
;;; [(pred3?) (do-aaa!) (do-bbb!) (do-ccc!)]
;;; [:else (proc3! arg1 arg2 arg3)])
(defmacro cond*
"cond came from scheme"
[& clauses]
;; clausesが空の場合はnil(再帰展開時用。ifの第二引数が省略可能なのを利用)
(if (empty? clauses)
nil
(let [current-clause (first clauses)
left-clauses (rest clauses)
pred (first current-clause)
bodies (rest current-clause)
body-fn (when (= '=> (first bodies))
(second bodies))]
(cond
;; => がある場合は、predの結果をbodyに適用(優先順位高)
body-fn `(if-let [r# ~pred]
(~body-fn r#)
(cond* ~@left-clauses))
;; 'else もしくは :else の時はショートカット可能
;; TODO: 数値等の、他の真値にも対応してもよい
(or
(= 'else pred)
(keyword? pred)) `(do ~@bodies)
;; それ以外の場合は普通にifに展開
:else `(if ~pred
(do ~@bodies)
(cond* ~@left-clauses))))))
これまた話が戻るんですが、自分は :pre を使わずに、関数の最初の方で (assert ...) を書くようにしてます。理由は :pre だと例えば、 (defn foo [m] {:pre [(map? m)]} (do-something))
で m がmapじゃなかった時に「じゃあmには何が入っていたのよ?」というのを表示してくれないから…
とは言え (assert (map? m))
でもそれは同様なので、いちいち (assert (map? m) (str "Invalid map " m))
みたいに毎回書く事が多いです。
僕が書いたやつであれですけど、デバッグ周りで悩んでるならこの辺参考になると思いますー。 http://ayato.hateblo.jp/entry/20150419/1429437366 ついでに言うと Cursive ならステップ実行とか普通に出来て便利でした。
ここしばらく、cljsでゲームを作っていました。 http://vnctst.tir.jp/ja/games/op0012-3.html