пятница, 3 августа 2012 г.

Git. Создание удаленной ветки. Обновление.

После обновления git заметил что при использовании команды:


git push origin origin:refs/heads/new_branch
git отделяет ветку не от текущей, а от master. Решение проблемы:

git push origin current_branch:refs/heads/new_branch
где current_branch - от какой ветки отделяем.


вторник, 29 мая 2012 г.

Clojure. Метаданные для значений.

В документациии clojure по работе с метаданными написано, что их можно использовать для коллекций или символов(clojure/metadata). Поэтому если вы заходите добавить метаданные к значению, то получите ошибку:


user=> (def a (with-meta 2 {:a "test metadata"}))
java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IObj
user=>

Однако можно добавлять метаданные к var переменным. Это делается так:


user=> (def #^{:a "metadata"} a 2)
#'user/a
user=> (meta #'a)
{:ns #, :name a, :file "NO_SOURCE_PATH", :line 27, :a "metadata"}
user=> ((meta #'a) :a)
"metadata"
user=>

суббота, 5 мая 2012 г.

Параметры по умолчанию в функциях clojure

Один из вариантов параметров по умолчанию в clojure - это использование отображений(maps) в параметрах функции. Пример:


(defn test-add [a & {:keys [b] :or {b 0}}]
    (+ a b))

Использование:


user=>(test-add 1)
=> 1
user=>(test-add 1 :b 5)
=> 6

Разделитель в выражениях clojure

В clojure можно использовать запятую в качестве разделителя для упращения чтения кода:


(+ 1, 2, 3, 4)
(def a {:test1 5, :test2 6})
(def b [1, 2, 4])
;; эквивалентно
(+ 1 2 3 4)
(def a {:test1 5 :test2 6})
(def b [1 2 3])


понедельник, 2 апреля 2012 г.

Отладка в Clojure

В данной статье хочу рассказать о некоторых методах отладки в clojure.

Метод 1. Использование точек останова в slime.

При использовании emacs появляется возможность устранавливать точки останова(breakpoints), что позволяет
просматривать стек вызовов и локальные переменные. Для установки используется функция swank.core/break Рассмотрим небольшой пример:


(defn add [a b]
   (swank.core/break)
   (+ a b))
Вызовем данную функцию из repl: (add 1 2) =>

BREAK:
[Thrown class java.lang.Exception]

Restarts:
0: [QUIT] Quit to the SLIME top level
1: [CONTINUE] Continue from breakpoint

Backtrace:
0: debug.core$add.invoke(core.clj:4)
1: debug.core$eval1851.invoke(NO_SOURCE_FILE:1)
2: clojure.lang.Compiler.eval(Compiler.java:6465)
3: clojure.lang.Compiler.eval(Compiler.java:6431)
4: clojure.core$eval.invoke(core.clj:2795)
--more--

При наведении курсора на строку 0: debug.core$add.invoke(core.clj:4) и нажатии enter, получим:
BREAK:
[Thrown class java.lang.Exception]

Restarts:
0: [QUIT] Quit to the SLIME top level
1: [CONTINUE] Continue from breakpoint

Backtrace:
0: debug.core$add.invoke(core.clj:4)
Locals:
a = 1
b = 2
1: debug.core$eval1851.invoke(NO_SOURCE_FILE:1)
2: clojure.lang.Compiler.eval(Compiler.java:6465)
3: clojure.lang.Compiler.eval(Compiler.java:6431)
4: clojure.core$eval.invoke(core.clj:2795)
--more--
При нажатии enter на локальной переменной запустится инспектор slime.
При нажатии клавиши 1 - функция продолжит свое выполнение.

Метод 2. Трассировка.

В данном методе отладки используется модуль clojure.contrib.trace.
Важно! При использовании версии clojure 1.3 необходимо указывать ^:dynamic при определении функций для трассировки.
Пример:


(use 'clojure.contrib.trace)

(deftrace sub [a b] (- a b))
(deftrace sub-2 [a b] (- b a))

(defn  func [a b]
  (+ (sub a b) (sub-2 a b))
Результат вызова:
(func 1 2)=>
TRACE t1964: (sub 1 2)
TRACE t1964: => -1
TRACE t1965: (sub-2 1 2)
TRACE t1965: => 1
0

Макрос deftrace выводит название функции, ее аргументы и результат выполнения.
Подробнее про данный модуль можно прочитать тут(trace-api)

Метод 3. Использование отладочного вывода.

В данном случае существует множество методик от простого использование функции print до сложных макросов. Одним из вариантов может служить такой пример:


(defmacro debug-do [& body]
  (when *debug*
    `(do ~@body))
Такой способ позволяет включать отладочный режим установкой переменной *debug* в true.
Пример использования:

(def *debug* 1)

(defmacro debug-do [& body]
  (when *debug*
    `(do ~@body))

(defn add-2 [a b]
  (debug-do (printf "a = %d\n" a)
            (printf "b = %d\n" b)
            (flush))
  (+ 1 2))
При вызове этой функции в repl получаем:
(add-2 1 2)=>
a = 1
b = 2
3