понедельник, 23 сентября 2013 г.

Использование JNA в Clojure.

Разберем использование Java Native Access на простом примере в Clojure. Для начала необходимо скачать jna.jar с github.com и добавить в новый проект clojure, созданный через утилиту lein:

(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

В качестве одного из вариантов подключения своих локальных jar-файлов в проект является использование опции resource-paths в project.clj . Таким образом файл проекта, сгенерированный утилитой lein, примет вид:

(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

В Clojure 1.5 появилась возможность работы с конфигами в формате edn(extensible data notation), но я пока использую версию 1.4, поэтому для себя сделал модуль с использованием класса 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

Появилось время продолжить заниматься веб-редактором для clojure и я выложил исходники прототипа на BitBucket.org. Большая часть кода написана на JavaScript и так как до этого я на нем не писал, то здравая критика приветствуется. Конечно можно было попробовать ClojureScript, но я решил изначально использовать JavaScript. В ближайшее время хотелось исправить возможность сохранять файл по любому пути, а так же неудобство прокрутки textarea.

вторник, 23 апреля 2013 г.

Webclojure project

Решил для себя сделать веб-редактор с repl, так как с планшета нет возможности работать с clojure. Со стороны сервера использую noir framework, со стороны клиента использую javascript. Пока сделан прототип поддерживающий следующие функции:
  • Eval функций из редактора с возможностью вызова их из repl
  • Обработка и отображение ошибок
  • Полноценный repl пока без возможности изменения ns(использую sandbox)
  • Сохранение исходного кода на сервере
  • Загрузка файла с кодом с сервера
На планшете тестировал работу проекта в chrome. Так как у меня это первый проект в web, то как только закончу с рефакторингом javascript выложу проект в свободный доступ. Так же планирую добавить подсветку синтаксиса, табулирование кода и подобие автодополнения кода, так как на планшете все таки не так удобно писать, в отличии от обычной клавиатуры. В планах есть написание статей по использованию noir framework на небольших примерах.

понедельник, 15 апреля 2013 г.

clojure-compile-project.el

При разрастании проекта с использованием clojure надоедает постоянно перекомпилировать весь проект по модулю. Поэтому написал небольшой модуль расширения для emacs, взяв несколько готовых функция с Elisp Cookbook. Работа модуля заключается в следующем: передается отправная точка для рекурсивного обхода директорий и к каждому найденному clojure-файлу применяется функция slime-load-file. До запуска данной функции необходимо выполнить команду clojure-jack-in для запуска repl. Если проект создавался с помощью утилиты lein, то необходимо передавать src директорию.Таким образом, можно без всяких усилий пересобрать проект. Исходный код модуля привожу ниже:

(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))
Конечно, возможно есть более красивое решение, но похоже я слишком плохо искал.

пятница, 12 апреля 2013 г.

Samsung-tools в Ubuntu

Приобрел себе нового коня, хоть и все функ клавиши работают, но на всяк случай сохраню способ установки samsung-tools в ubuntu:

sudo apt-add-repository ppa:voria
sudo apt-get update
sudo apt-get install samsung-tools samsung-backlight

среда, 20 марта 2013 г.

skype в ubuntu x64

Решил для себя сохранить набор команд по установке skype в ubuntu x64:

sudo apt-add-repository "deb http://archive.canonical.com/ $(lsb_release -sc) partner"
sudo apt-get update
sudo apt-get install skype