четверг, 16 января 2014 г.
Webclojure и android браузеры
понедельник, 23 сентября 2013 г.
Использование JNA в Clojure.
(defproject jna "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.4.0"]]
:plugins [[lein-swank "1.4.5"]]
:resource-paths ["resources/jna-4.0.0.jar"])
После чего необходимо добавить импорт в ns:
(ns jna.core
(:import (com.sun.jna Library Function)))
Следующий шаг это создание нативной библиотеки:
#ifndef FOO_H
#define FOO_H
extern int foo(int a, int b);
#endif
#include "foo.h"
int foo(int a, int b)
{
return a + b;
}
gcc -c -Wall -Werror -fpic foo.c
gcc -shared -o libfoo.so foo.o
Один из вариантов вызова нативных функций это использование интерфейса:
(def foo-interface (gen-interface
:name foo-test
:extends [com.sun.jna.Library]
:methods [[foo [Integer Integer] Integer]]))
Второй этап этой процедуры это загрузка самой библиотеки:
(def native-lib (Native/loadLibrary "clib/libfoo.so" foo-interface))
И последний этап это определение самой функции:
(defn native-foo [a b]
(.foo native-lib (Integer. a) (Integer. b)))
Преобразование входных переменных к типу Integer необходимо из-за того, что при вызове функции с целыми числами они являются типом Long.
Еще одним вариантом вызова нативных функций - это использование класса Function. На просторах интернета я нашел достаточно интересный макрос:
(defmacro jna-call [lib func ret & args]
`(let [library# (name ~lib)
function# (Function/getFunction library# ~func)]
(.invoke function# ~ret (to-array [~@args]))))
Но опять же необходимо не забывать, что при передаче простых чисел они имеют тип Long.
Подключение локальных библиотек в Clojure
(defproject test-project "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.4.0"]]
:plugins [[lein-swank "1.4.5"]]
:resource-paths ["path-to-resource"])
Причем можно указывать как отдельные файлы, так и полностью всю директорию, если использовать wildcards:
:resource-paths ["path-to-resource1/example.jar" "path-to-resource2/*"] .
понедельник, 24 июня 2013 г.
Модуль для работы с конфиг-файлом в clojure с помощью Properties
(ns somens
(:use [clojure.java.io])
(:import (java.util Properties)
(java.io FileOutputStream FileInputStream)))
(defn load-properties [config-file]
(with-open [f (java.io.FileInputStream. (file config-file))]
(doto (Properties.)
(.load f))))
(defn save-properties [#^Properties properties #^String config-file]
(with-open [#^FileOutputStream f (FileOutputStream. (file config-file))]
(.store properties f nil)))
(defn get-property [properties name]
(.getProperty properties name ))
(defn set-property [properties name value]
(.setProperty properties name (str value)))
Пример использования:
конфигурационный файл имеет вид:
$cat conf.prop
a=20
b="test"
Считаем данный файл и выведем параметры:
user> (def conf (load-properties "/home/home/conf.prop"))
#'user/conf
user> (get-property conf "a")
"20"
user> (get-property conf "b")
"test"
А теперь изменим параметры и сохраним:
user> (let [conf (load-properties "/home/home/conf.prop")]
(set-property conf "a" "200")
(set-property conf "b" "600")
(save-properties conf "/home/home/conf.prop"))
nil
$cat conf.prop
#Mon Jun 23 11:18:25 UTC 2013
b=600
a=200
понедельник, 10 июня 2013 г.
Исходники WebClojure
вторник, 23 апреля 2013 г.
Webclojure project
- Eval функций из редактора с возможностью вызова их из repl
- Обработка и отображение ошибок
- Полноценный repl пока без возможности изменения ns(использую sandbox)
- Сохранение исходного кода на сервере
- Загрузка файла с кодом с сервера
понедельник, 15 апреля 2013 г.
clojure-compile-project.el
(defun walk-path (dir action)
"walk DIR executing ACTION with (dir file)"
(cond ((file-directory-p dir)
(or (char-equal ?/ (aref dir(1- (length dir))))
(setq dir (file-name-as-directory dir)))
(let ((lst (directory-files dir nil nil t))
fullname file)
(while lst
(setq file (car lst))
(setq lst (cdr lst))
(cond ((member file '("." "..")))
(t
(and (funcall action dir file)
(setq fullname (concat dir file))
(file-directory-p fullname)
(walk-path fullname action)))))))
(t
(funcall action
(file-name-directory dir)
(file-name-nondirectory dir)))))
(defun walk-path-visitor (dir file)
"Called by walk-path for each file found"
(if (string-match "\\.clj\\'" file)
(slime-load-file (concat dir file)))
(concat dir file))
(defvar start-path nil)
(defun compile-project (start-path)
(interactive "D" (list (read-from-minibuffer "Start path:" start-path)))
(walk-path start-path 'walk-path-visitor))
Конечно, возможно есть более красивое решение, но похоже я слишком плохо искал.
вторник, 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
понедельник, 12 декабря 2011 г.
Настойка IntelliJ IDEA для clojure.
Меня заинтересовал язык clojure, поэтому решил попробовать новую для себя ide IntelliJ IDEA. Версию community edition можно скачать на официальном сайте. Для сборки проектов я использую leiningen . В этом топике я покажу какие необходимо сделать настройки.
Для начала необходимо установить два плагина: La Clojure и Leiningen с помощью Plugin Manager.
Далее нужно настроить плагин Leiningen. Для этого открываем настройки File->Settings(Ctrl+Alt+S), находим строку с данным плагином и устанавливаем путь до утилиты lein.
После чего создадим проект с помощью lein из консоли:
lein new example
Откроем созданный проект в ide, используя Open Project, и выберем файл project.clj. Далее IntelliJ IDEA сгенерит все необходимые для нее файлы.Следующий шаг это добавление необходимых зависимостей для проекта. На данном примере я добавлю clojure-contrib и sqlitejdbc. Файл project.clj примет вид:
(defproject sqlite-example "1.0.0-SNAPSHOT"
:description "sqlite example"
:dependencies [[org.clojure/clojure "1.2.1"]
[org.clojure/clojure-contrib "1.2.0"]
[sqlitejdbc "0.5.6"]])
После чего нажимаем на вкладку Leiningen, выбираем deps и запускаем загрузку необходимых библиотек.Осталось лишь добавить установленные библиотеки в проект idea. Это необходимо сделать, потому что мы не создавали новый проект, а открыли уже существующий, сгенерированный с помощью утилиты lein. Выбираем File->Project Structure (или Ctrl+Alt+Shift+S), далее Modules и выбираем закладку Dependencies, затем нажимаем кнопку Add -> Libraries.
Теперь запускаем REPL - Tools->Start Clojure Console(Ctrl+Shift+F10). На этом настройка ide закончена.