Отличная штука. Кручу верчу - остановиться не могу.
вторник, 30 декабря 2008 г.
среда, 24 декабря 2008 г.
среда, 18 июня 2008 г.
суббота, 7 июня 2008 г.
grails 1.0.3
Вышел grails 1.0.3. При попытке заапгрейдтить проект с 1.0.2 до 1.0.3 наткнулся на то, что предыдущий конфиг не совместим с новыми скриптом Package и некоторыми другими.
Заборол конечно. Но осадок остался.
Заборол конечно. Но осадок остался.
среда, 4 июня 2008 г.
speedy racer
Посмотрел Спиди гоншика. Шёл на этот фильм с опаской, но мои опасения были развеяны за первые 15 минут фильма.
Очень хорошее кино.
Очень хорошее кино.
grails: работа с шаблонами
Вот здесь описан способ отправки почтовых сообщений с html форматированием. Всё бы хорошо, но использование groovy шаблонов вместо обычных gsp для задания отображения почтового сообщени я считаю неверным.
Поэтому я чуть-чуть покапался во внутренностях grails и вот результат:
Хочу отметить, что очень большой недостаток доступной документации по grails заключается в отсутствии описания контекстных бинов, которые grails инициализирует и использует. В данном случае такой бин - groovyPagesTemplateEngine.
Поэтому я чуть-чуть покапался во внутренностях grails и вот результат:
import org.codehaus.groovy.grails.web.pages.GroovyPagesTemplateEngine
import org.codehaus.groovy.grails.web.pages.GroovyPageTemplate
import grails.util.GrailsWebUtil
import org.springframework.web.context.request.RequestContextHolder
class TemplateService {
GroovyPagesTemplateEngine groovyPagesTemplateEngine
def createHtml(String templateName, Map model) {
if(!RequestContextHolder.getRequestAttributes())
GrailsWebUtil.bindMockWebRequest()
GroovyPageTemplate tpl = groovyPagesTemplateEngine.createTemplate(templateName)
StringWriter out = new StringWriter()
tpl.make(model).writeTo(out)
return out.toString()
}
}
Хочу отметить, что очень большой недостаток доступной документации по grails заключается в отсутствии описания контекстных бинов, которые grails инициализирует и использует. В данном случае такой бин - groovyPagesTemplateEngine.
вторник, 20 мая 2008 г.
физики шутят
АНГЕЛ: Господи, они синтезировали еще один трансурановый элемент. Как будем реагировать?
БОГ: Добавим еще один нелинейный член в Истинное Уравнение Единого Поля.
БОГ: Добавим еще один нелинейный член в Истинное Уравнение Единого Поля.
четверг, 15 мая 2008 г.
воскресенье, 4 мая 2008 г.
grails: gorm & query by criteria
Есть такая симпатичная штука в hibernate, а как следствие, и в grails. Штука очень хорошая для составления динмаических запросов, в зависимости от того, допустим, по какому набору полей надо искать. И есть в hibernate criteria api такая штука как alias'ы - метод формулировать условия для ассоциаций.
Я очень удивился, когда не нашёл в документации grails ничего об алиасах, ну и полез в гугл - куда ж ещё. Всё оказалось, как обычно, просто. Допустим есть сущность Foo с ассоциацей bar, у которой условие необходимо наложить на поле baz. Пишется это так:
Вот примерно так. bar {...} и является той самой ассоциацией. Вложенность таких вызовов с клозуром может быть какая угодно.
Кстате, пока писал, подумал, как команда grails собирается реализовать gorm на базе JPA текущей (а это планируется в grails 1.1)? В JPA ведь нет никакого criteria api, это чисто hibernate заморочка. Интересно будет посмотреть.
Я очень удивился, когда не нашёл в документации grails ничего об алиасах, ну и полез в гугл - куда ж ещё. Всё оказалось, как обычно, просто. Допустим есть сущность Foo с ассоциацей bar, у которой условие необходимо наложить на поле baz. Пишется это так:
def c = Foo.createCriteria()
def someList = c{
bar {
eq("baz", "some value")
}
}
Вот примерно так. bar {...} и является той самой ассоциацией. Вложенность таких вызовов с клозуром может быть какая угодно.
Кстате, пока писал, подумал, как команда grails собирается реализовать gorm на базе JPA текущей (а это планируется в grails 1.1)? В JPA ведь нет никакого criteria api, это чисто hibernate заморочка. Интересно будет посмотреть.
суббота, 3 мая 2008 г.
А пока были праздники
произошла пара интересных событий:
1. groovy 1.6 beta - заявлено о нехилом росте производительности.
2. SpringSource Application Platform beta - очень интересная штука должна быть, кроме того, grails приложения на неё деплоятся без проблем.
Всех с прошедшими праздниками.
1. groovy 1.6 beta - заявлено о нехилом росте производительности.
2. SpringSource Application Platform beta - очень интересная штука должна быть, кроме того, grails приложения на неё деплоятся без проблем.
Всех с прошедшими праздниками.
вторник, 29 апреля 2008 г.
grails: testing & dbunit
DBUnit plugin для Grails оказался не без изъяна. Две вещи раздражают :
1. Только plain данные можно описать в датасетах. Это очень плохо. Возможно я просто не нашёл как по другому.
2. Почему-то каждый раз при запуске теста происходит полная перекомпиляция, а это очень долго.
Возможно, не стоит использовать DBUnit, потому что, учитывая синатксис Groovy, создание данных для тестиварония простая задача.
1. Только plain данные можно описать в датасетах. Это очень плохо. Возможно я просто не нашёл как по другому.
2. Почему-то каждый раз при запуске теста происходит полная перекомпиляция, а это очень долго.
Возможно, не стоит использовать DBUnit, потому что, учитывая синатксис Groovy, создание данных для тестиварония простая задача.
среда, 23 апреля 2008 г.
пятница, 11 апреля 2008 г.
grails: unit testing
Пришлов время пописать юнит тесты. Юнит тестировал я один из методов сервиса, который проверяет может ли пользователь видеть урл или нет.
Метод вот такой:
Так как я захотел создать именно юнит тест, то все инжекты из grails необходимо было проэмулировать. А это следующее:
Account.get
объект log
attachedAcc.roles.urls - т.е. свойства roles и urls.
И здесь на выручку приходит динамеческая природа groovy, которая позволяет всё необходимое добавить к классам прямо в run-time.
И так:
1. создаём список аккаунтов, назначем аккаунтам роли, ролям паттерны доступных урлов
2. Добавляем к Account метод get()
3. Добавляем к сервису объект log. Ну и конечно же надо создать сам сервис.
здесь SOL - простейщий класс реализующий метод debug()
Собственно всё, среда готова, можно тестировать.
Метод вот такой:
class SecurityService {
static digestAlgo = "MD5"
boolean checkAccess(def acc, def controller, def action) {
def attachedAcc = Account.get(acc.id)
def checkingUrl = controller + "/" + action
def realRes = false
log.debug "let's check it"
log.debug "attachedAcc : ${attachedAcc}"
log.debug "checkingUrl : ${checkingUrl}"
if(attachedAcc) {
attachedAcc.roles.urls*.find { requestmap ->
if(checkingUrl =~ requestmap.url) {
realRes = true
return true
}
}
}
return realRes
}
...
}
Так как я захотел создать именно юнит тест, то все инжекты из grails необходимо было проэмулировать. А это следующее:
Account.get
объект log
attachedAcc.roles.urls - т.е. свойства roles и urls.
И здесь на выручку приходит динамеческая природа groovy, которая позволяет всё необходимое добавить к классам прямо в run-time.
И так:
1. создаём список аккаунтов, назначем аккаунтам роли, ролям паттерны доступных урлов
def adminRole = new Role()
adminRole['urls'] = [
[url: ".*"],
]
def adminAccount = new Account(username : 'admin')
adminAccount['roles'] = [adminRole]
def oneControllerAllRole = new Role()
oneControllerAllRole['urls'] = [
[url: "one/.*"],
]
def restrictedRole = new Role()
restrictedRole['urls'] = [
[url: "two/three"],
[url: "four/five"]
]
def account1 = new Account(username : 'oneAll')
account1['roles'] = [oneControllerAllRole]
def account2 = new Account(username : 'restricted')
account2['roles'] = [restrictedRole]
def account3 = new Account(username : 'oneAllAndRestricted')
account3['roles'] = [oneControllerAllRole, restrictedRole]
def accounts = [
(new Long(1)) : adminAccount,
(new Long(2)) : account1,
(new Long(3)) : account2,
(new Long(4)) : account3
]
2. Добавляем к Account метод get()
Account.metaClass.static.get = { Long id ->
return accounts[(id)]
}
3. Добавляем к сервису объект log. Ну и конечно же надо создать сам сервис.
def sol = new SOL()
SecurityService.metaClass.getLog = { ->
return sol
}
securityService = new SecurityService()
здесь SOL - простейщий класс реализующий метод debug()
Собственно всё, среда готова, можно тестировать.
пятница, 4 апреля 2008 г.
среда, 2 апреля 2008 г.
Бу-ра-ти-но!!!
Отсюда:
Петр Кузнецов, лидер пензенских сектантов, пытался в среду совершить самоубийство. Об этом по телефону из села Никольское Бековского района сообщил вице-губернатор области Олег Мельниченко.
В ходе следствия выяснилось, что открытую черепно-мозговую травму Кузнецов получил не в результате нападения со стороны сектантов, как сообщалось ранее, а «это была попытка суицида».
«Кузнецов положил голову на деревянный чурбан и наносил себе удары другим деревянным чурбаном. В результате он получил открытую черепно-мозговую травму. Кузнецов был доставлен в Бековскую ЦРБ и экстренно прооперирован. В настоящее время он отправлен в больницу в Пензу для дальнейшего хирургического обследования специалистами», - рассказал Мельниченко.
Петр Кузнецов, лидер пензенских сектантов, пытался в среду совершить самоубийство. Об этом по телефону из села Никольское Бековского района сообщил вице-губернатор области Олег Мельниченко.
В ходе следствия выяснилось, что открытую черепно-мозговую травму Кузнецов получил не в результате нападения со стороны сектантов, как сообщалось ранее, а «это была попытка суицида».
«Кузнецов положил голову на деревянный чурбан и наносил себе удары другим деревянным чурбаном. В результате он получил открытую черепно-мозговую травму. Кузнецов был доставлен в Бековскую ЦРБ и экстренно прооперирован. В настоящее время он отправлен в больницу в Пензу для дальнейшего хирургического обследования специалистами», - рассказал Мельниченко.
четверг, 27 марта 2008 г.
среда, 26 марта 2008 г.
grails: mein kampf 1 / опять TagLib
Во время разбирательств с Web Flow я обнаружил, что входящий в поставку тег sortableColumn не поддерживает этот самый Web Flow. Ну что-ж, пора сделать свой тег - сказал я себе. Сказано, сделано. Вот тегова либа.
Несколько кривовато, конечно, но работает. А это, в конце концов самое важное.
class ExtTagLib {
static namespace = "ext"
def sortableColumn = {attrs ->
['sort', 'order'].each { name ->
if(attrs[name] && attrs[name] != '') {
params[name] = attrs[name]
}
}
if(attrs.event) {
if(!attrs.params) attrs.params = [:]
attrs.params['_eventId'] = attrs.event
}
out << g.sortableColumn(attrs)
['sort', 'order'].each { name ->
params.remove(name)
}
}
}
Несколько кривовато, конечно, но работает. А это, в конце концов самое важное.
groovy: маленькие фкусняшечки 1 / работа с датами
Сейчас я решаю задачу: необходимо составить возможное расписание некоторого события, протяжённого во времени, причём, естественно, необходимо знать дату начала и конца данного события.
Простой, понятный и короткий код. И это хорошо.
Магия groovy работы с датами проявляется в 2-х местах.
Первое:
approxEndDate = new Date() + 2
В груви для даты опеределна функция plus(), поэтому к дате можно спокойно добавить дни. Самое смешно, что функция minus() для даты не определена, так что вычитать из даты таким образом нельзя.
Второе:
Здесь используются классы TimeCategory и Duration. Первый позволяет записать Duration в виду duration.minutes, а Duration ползволяет прибавлять и вычитать из даты произвольные периоды времени.
Кстати вместо duration.minutes можно было бы записать 15.minutes или 2.hours, таким образом в этом небольшом куске кода используется DSL для работы с единицами измерения времени.
Такие дела.
import groovy.time.*
// groovy time!
import org.codehaus.groovy.runtime.TimeCategory
approxStartDate = new Date()
// возможная дата начала
approxEndDate = new Date() + 2
// возможная дата конца (импользуем +!)
startHour = 10
//начальный час. число произвольное
endHour = 20
//конечный час. число произвольное
stepsPerHour = 4
//разбивка часа, т.е. событие длится 15 минут. число произвольное
int duration = 7 * 15
//длительность. число произвольное
for(day in approxStartDate..approxEndDate) {
println " $day"
for(hour in startHour..<endHour) {
println " $hour"
for(step in 0..<stepsPerHour) {
use(TimeCategory) {
def dateTimeStart = new Date(
year: day.year,
month: day.month,
hours: hour,
minutes: step * 15,
seconds: 0)
def dateTimeEnd = dateTimeStart + duration.minutes
//прибавляем длительность чтобы получить конечную дату. просто и разумно.
println " $step : $dateTimeStart, $dateTimeEnd"
}
}
}
}
Простой, понятный и короткий код. И это хорошо.
Магия groovy работы с датами проявляется в 2-х местах.
Первое:
approxEndDate = new Date() + 2
В груви для даты опеределна функция plus(), поэтому к дате можно спокойно добавить дни. Самое смешно, что функция minus() для даты не определена, так что вычитать из даты таким образом нельзя.
Второе:
use(TimeCategory) {
def dateTimeStart = new Date(
year: day.year,
month: day.month,
hours: hour,
minutes: step * 15,
seconds: 0)
def dateTimeEnd = dateTimeStart + duration.minutes
//прибавляем длительность чтобы получить конечную дату. просто и разумно.
println " $step : $dateTimeStart, $dateTimeEnd"
Здесь используются классы TimeCategory и Duration. Первый позволяет записать Duration в виду duration.minutes, а Duration ползволяет прибавлять и вычитать из даты произвольные периоды времени.
Кстати вместо duration.minutes можно было бы записать 15.minutes или 2.hours, таким образом в этом небольшом куске кода используется DSL для работы с единицами измерения времени.
Такие дела.
вторник, 25 марта 2008 г.
Биопринтер.
Помнится в 5 элементе Лилу восстанавливали такой хитрой машинкой, у неё ещё ручки так быстро тык-мык тык мык. Так вот, похоже сделали прообраз такой технологии. Охуени!
среда, 19 марта 2008 г.
понедельник, 17 марта 2008 г.
Доброе утро.
Котег сегодня таки заинтересовался движущимися картинками в телеящике. Забавно было то, как он трогал лапой эти самые картинки, и его задумчивый загривок, который как бы говорил мне "OMG! WTF?".
среда, 12 марта 2008 г.
вторник, 11 марта 2008 г.
groovy: маленькие фкусняшечки 0
Допустим, у меня есть некоторый объект (foo), набор полей которого необходимо обработать единообразно.
Java:
groovy:
Вариант на Java не полный - было лень приводить весь код. И не смотря на это, вариант на groovy на мой взгляд несомненно изящнее.
Java:
public void process(String field) {
System.out.println(field)
}
process(foo.getBar());
process(foo.getBaz());
process(foo.getMaz());
groovy:
class Foo {
def bar
def baz
def maz
}
def foo = new Foo(bar : "barrr", baz : "bazzz", maz : "mazzz")
['bar','baz','maz'].each { name ->
println foo[name]
}
Вариант на Java не полный - было лень приводить весь код. И не смотря на это, вариант на groovy на мой взгляд несомненно изящнее.
grails: mein kampf 1 / TagLib
Приступил к разборками с TagLib в grails. В документации обещают, что они будут перегружаться автоматом, как и почти все остальные артефакты проекта.
Однако, как обычно, есть нюанс: если обращаться непосредственно к gsp странице минуя контроллер, то автоматическая перезагрузка не происходит.
Однако, как обычно, есть нюанс: если обращаться непосредственно к gsp странице минуя контроллер, то автоматическая перезагрузка не происходит.
понедельник, 10 марта 2008 г.
JavaService
JavaService - продукт позволяющий использовать java приложения в качестве нативных сервисов (демонов под Unix). Сочетание же java 1.6 и JavaService под Windows даёт замечательный баг: сервис не стартует а в логах виндоуз появляются сообщения о том, что jvm.dll загрузить не было никакой возможности ("can't load jvm.dll").
В результате гуглежа я выяснил, что этот баг не уникален для JavaService, но характерен для jdk 1.6, и что происходит он от того, что приложение пытается запустить java машину через jni, но чего то для этого не хватает. Подробно описано здесь.
Написал я это всё к тому, что я натыкась на эту пердь уже раз в 10-ый, каждый раз как разворачиваю приложение, и каждый раз уходит минут 10-15 поисков.
Решил оставить себе заметку.
В результате гуглежа я выяснил, что этот баг не уникален для JavaService, но характерен для jdk 1.6, и что происходит он от того, что приложение пытается запустить java машину через jni, но чего то для этого не хватает. Подробно описано здесь.
Написал я это всё к тому, что я натыкась на эту пердь уже раз в 10-ый, каждый раз как разворачиваю приложение, и каждый раз уходит минут 10-15 поисков.
Решил оставить себе заметку.
пятница, 7 марта 2008 г.
grails: mein kampf 0 / Web Flow
В Grails есть чудесная штука - называется Web Flow. Хотя, я неверно выразился, Web Flow есть в Spring, а в Grails его "воткнули", как и многое другое. У Web Flow Grails есть чудесная особенность - внутри кода описывающего Web FLow в контроллере нельзя применять Hibernate Criteria, потому как они работают в этом случае очень странно.
Например вот такой код:
даст на выходе запрос в котором отсутствуют всякие упоминания о firstResult и maxResults.
Решение данной проблемы - перенос работы с Criteria в сервис и последующий инжект оного в контроллер.
Такие дела.
Например вот такой код:
def mainFlow = {
...
search {
action {
...
def listCriteria = Client.createCriteria()
def clientList = listCriteria {
like("fname", fname)
like("pname", pname)
like("sname", sname)
firstResult(params.offset)
maxResults(params.max)
}
...
}
}
}
даст на выходе запрос в котором отсутствуют всякие упоминания о firstResult и maxResults.
Решение данной проблемы - перенос работы с Criteria в сервис и последующий инжект оного в контроллер.
Такие дела.
grails: маленькие фкусняшечки 0
А вот код, перетаскивающий параметры POST или GET запроса с именем формата flow.<имя> в контекст Web Flow. Ну напрмер из адресной строки формата http://some.domain/controller/flow?oppa=1&flow.q=obana в Web Flow пробрасывается q (flow.q == "obana").
Нравицца!
params.flow?.each { entry ->
flow.'${entry.key}' = entry.value
}
Нравицца!
четверг, 6 марта 2008 г.
groovy & grails
Два очень интересных и перспективных Java продукта, которые я буду использовать в 2008 году. Постараюсь делать некоторые заметки как о Groovy - в основном в контексте сравнения Java подхода и Groovy, так и о Grails.
Подписаться на:
Сообщения (Atom)

