2014-12-31 2 views
2

это мой Clojure кольцо обработчикИспользуйте параметр ПОЛУЧИТЬ как имя функции

(defn handler [req] 
    (let [distr (get-in req [:query-params "dist"])] 
    (def sortie (describe (eval ((resolve (symbol distr)) 1 3)) 
         0.5 0.25 3)) 
    {:status 200 
    :headers {"Content-Type" "text/html"} 
    :body (str "<p>" (print-str sortie) "<p>")} 
)) 

(def app 
    (-> #'handler 
    (ring.middleware.stacktrace/wrap-stacktrace) 
    (wrap-spy) 
    (wrap-params) 
    )) 

на «Dist» ключевые карты на строку.

:query-params {"dist" "gaussian-dist"} 

Я хочу использовать его как имя функции. Всего

(eval ((resolve (symbol distr)) 1 3)) 

возвращает карту

Когда я заменить на Distr строки, она работает, как требуется.

=> (eval ((resolve (symbol "gaussian-dist")) 1 3)) 
{:Distribution :actuarial.distributions/Gaussian, :Parameters {:sigma 3, :mu 1}} 

Edit:

Это, как я в конечном итоге решить мою проблему: Еще раз спасибо, я новичок в Clojure

я получил через него с помощью макроса

(defmacro get-map [map name] 
    `(get ~map ~name)) 

(defn handler [req] 
    (let [distr-name (get-in req [:query-params "dist"]) 
     distr-map ((get-map distributions-map distr-name) 1 3) 
     sortie (describe distr-map 0.5 0.25 3) 
     ] 

    {:status 200 
    :headers {"Content-Type" "text/html"} 
    :body (str "<p>" sortie "<p>")})) 
+0

Похоже, что значение '' '' '' 'не так, как вы ожидали, можете ли вы поместить в println или иначе проверить его и включить вывод? –

+0

Не используйте функции def внутри. 'sortie' может быть заменен другим запросом, прежде чем вы его используете. – noisesmith

+0

Этот макрос не делает ничего, что вы не могли бы сделать с помощью функции, и более просто: '(defn get-map [имя карты] (получить имя карты))' или действительно '(def get-map get) '. – amalloy

ответ

3

Похоже, что это очень опасное предложение с точки зрения безопасности и обслуживания, позволяющее Интернету использовать любой символ в вашем пространстве имен как функции, поэтому я подумал бы о том, чтобы вместо этого сделать что-то вроде:

Подготовьте белый список функций, которые пользователи должны иметь возможность запрашивать в виде карты из строк параметров запроса в функции.

(def distributions {"gaussian-dist" gaussian-dist}) 

Сделать функцию по умолчанию, которая либо делает сообщение об ошибке, либо просто выбирает распределение по умолчанию.
Когда вы получаете запрос, просто найдите нужную функцию в distributions с помощью get и функцию по умолчанию, чтобы обрабатывать случай строк запроса не найден.

(let [distr (get-in req [:query-params "dist"]) 
     sortie ((get distributions distr default-fn) 1 3)] 

Это также своего рода рискованно def вар как sortie каждый запрос, так как это открывает вас к условиям гонки. Вот почему это было более естественно для let, но это имя тоже, если только обработчик больше, чем я вижу здесь. Вы также можете делать то, что хотите, с (def ^:dynamic *sortie*) и binding, который изолирует привязки разных потоков друг от друга, чтобы предотвратить это.

+1

Не просто «любопытно рискованно» определять символ в обработчике запросов, это просто неправильно. Vars - глобально доступное изменяемое состояние без механизма параллелизма. – noisesmith