Hastache 0.6.0. Новый мейнтейнер

Апрель 01, 2014, 15:30

Вы­шла но­вая вер­сия has­tache 0.6.0. Са­мое за­мет­ное из­ме­не­ние — пе­ре­ход от ис­поль­зо­ва­ния ByteString к ис­поль­зо­ва­нию Text.

А са­мое за­мет­ное из­ме­не­ние для меня са­мо­го в том, что те­перь у has­tache но­вый мейн­тей­нер, ко­то­рый вот эту но­вую вер­сию и вы­пу­стил. Это Dani­il Fru­min. Я ото­шел от раз­ра­бот­ки has­tache про­сто по при­чине от­сут­ствия у меня ак­тив­ных про­ек­тов с его ис­поль­зо­ва­ни­ем, а лю­дям надо, кто-то поль­зу­ет­ся, вот Dani­il и по­про­сил­ся на эту роль. Те­перь у меня та­кое стран­ное чув­ство по это­му по­во­ду. С од­ной сто­ро­ны при­ят­но, что там что-то та­кое на­пи­сал, а вот те­перь оно со­всем сво­ей жиз­нью за­жи­ло. С дру­гой сто­ро­ны, эх вре­ме­ни бы мне немно­го сво­бод­но­го, сесть и пе­ре­пи­сать все со­всем по дру­го­му, по пра­виль­но­му, API мож­но еще немно­го обоб­щить, пар­сер пе­ре­пи­сать...

Новый движок моего блога

Ноябрь 26, 2012, 19:00

В оче­ред­ной раз пе­ре­де­лал дви­жок сво­е­го бло­га. Те­перь у меня чи­сто ста­ти­че­ский блог, ле­жа­щий в Ama­zon S3. Преды­ду­щая вер­сия бла­го­по­луч­но и без еди­но­го на­ре­ка­ния от­ра­бо­та­ла свои год и 9 ме­ся­цев. Те­перь на­ста­ло вре­мя пе­ре­мен.

Мне ка­жет­ся, что сум­мар­ное вре­мя, ко­то­рое я тра­чу на про­грам­ми­ро­ва­ние движ­ков сво­е­го бло­га, уже пре­вы­ша­ет вре­мя на то что­бы что-то сюда пи­сать. И уж во вся­ком слу­чае это явно срав­ни­мые ве­ли­чи­ны.

Окон­ча­тель­ным толч­ком к пе­ре­хо­ду на чи­сто ста­ти­че­ский блог по­слу­жи­ло недав­нее по­яв­ле­ние у Ama­zon S3 функ­ции ре­ди­рек­тов, без ре­ди­рек­тов всё-таки слож­но обой­тись. Та­к­же, для та­ко­го про­сто­го сай­та как лич­ный блог, дер­жать це­лый сер­вер, базу дан­ных, как-то всё это ад­ми­ни­стри­ро­вать — яв­ное пе­ре­услож­не­ние. В по­след­нее вре­мя я боль­ше скло­ня­юсь к про­стым ре­ше­ни­ям.

Для ин­те­ре­су­ю­щих­ся неко­то­рые тех­ни­че­ские по­дроб­но­сти:

Ге­не­ра­тор

Тут для меня без ва­ри­ан­тов — Haskell. Са­мый глав­ный дей­ству­ю­щий пер­со­наж тоже по­ня­тен — Has­tache, не зря же я его пи­сал.

Ор­га­ни­за­ция

Тех­ни­че­ски каж­дая за­пись в бло­ге вы­гля­дит так: от­дель­ная ди­рек­то­рия с име­нем типа «2011-02-28 16:03 new en­gine», внут­ри ле­жит файл def.json с за­го­лов­ком и те­га­ми этой за­пи­си, файл text.html с тек­стом, и ка­кие-ни­будь до­пол­ни­тель­ные фай­лы (если они в этой за­пи­си нуж­ны). Та­кие вот ра­кет­ные тех­но­ло­гии бло­го­стро­е­ния. Text.html — это не про­сто чи­стый html, это ещё и кое-ка­кая до­пол­ни­тель­ная раз­мет­ка, на­при­мер для встав­ки ма­те­ма­ти­че­ских фор­мул ( ру­лит) или ис­ход­но­го кода с под­свет­кой син­так­си­са (high­light­ing-kate). До­пол­ни­тель­ная раз­мет­ка боль­шей ча­стью пред­став­ле­на сек­ци­я­ми Has­tache.

Ти­по­гра­фи­ка

Ммм, это пря­мо моя пре­лесть. Не по­ни­маю чего ни­кто пе­ре­но­сов в вебе не де­ла­ет, на­мно­го ведь при­ят­ней вы­гля­дит, осо­бен­но если текст рас­тя­нут по ши­рине. Тех­ни­че­ски сами пе­ре­но­сы уже сто лет как до­ступ­ны во всех бра­у­зе­рах. У меня те­перь всё с пе­ре­но­са­ми, кра­со­та да и толь­ко. Пе­ре­но­сы рас­став­ля­ет са­мо­пи­сан­ная биб­лио­те­ка (ра­бо­та­ет по ал­го­рит­му Ляна-Кну­та), я её на­пи­сал для qr­ma­nia.ru, и вот опять при­го­ди­лась. Надо бы вы­ло­жить в Hack­age, но пока QA-от­дел в моей го­ло­ве это­го не поз­во­ля­ет.

Ра­бо­та с S3

Сна­ча­ла ду­мал обой­дусь s3cmd, но в ито­ге на­пи­сал соб­ствен­ный син­хро­ни­за­тор для S3, бла­го для Haskell есть биб­лио­те­ка aws. Кста­ти, я в неё за­ком­ми­тил ра­бо­ту с ре­ди­рек­та­ми S3, но эта вер­сия в на­сто­я­щий мо­мент ещё не вы­ло­же­на в Hack­age, кому сроч­но надо бе­ри­те пря­мо с GitHub.

Доступ к элементам списка по номеру в Hastache

Июль 12, 2012, 09:00

Это ко­неч­но очень при­ят­но ко­гда что-то по­лез­ное де­ла­ешь. Поль­зо­ва­те­лей Has­tache в мире мо­жет и не очень мно­го, но они точ­но есть. Вот недав­но Chris­ti­aan Baaij при­слал со­об­ще­ние о функ­ции ко­то­рая есть во мно­гих ре­а­ли­за­ци­ях шаб­ло­ни­за­то­ра Mus­tache, а в Has­tache нет. Это об­ра­ще­ние к эле­мен­там спис­ка по но­ме­ру, т.е. как-то так:

{{heroes.1.name}}
{{heroes.0.name}}

По­лез­ная шту­ка, мне ни разу пока не при­го­ди­лась (по­это­му и не сде­лал), од­на­ко лег­ко мож­но при­ду­мать ей при­ме­не­ние и кому-то та­кое точ­но по­на­до­бит­ся.

Поль­зо­вать­ся так:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/local/bin/runhaskell
{-# LANGUAGE DeriveDataTypeable #-}
import Text.Hastache
import Text.Hastache.Context
import qualified Data.ByteString.Lazy as LZ
import Data.Data
import Data.Generics

main = mapM_ (\(template,context) ->
hastacheStr defaultConfig (encodeStr template) context >>= LZ.putStrLn)
[(template1, mkStrContext context1),
(template1, context2),
(template3, context3)]

names = ["Безымянный","Небо","Сломанный Меч","Летящий Снег","Цинь Шихуанди"]

template1 = concat [
"{{heroes.1.name}}\n",
"{{heroes.0.name}}\n"]

-- Руками написанный контекст в виде функции
context1 "heroes" = MuList $ map (mkStrContext . mkListContext) names where
mkListContext name = \"name" -> MuVariable name
context1 _ = MuNothing

-- Контекст с помощью Generics
data Hero = Hero { name :: String } deriving (Data, Typeable)
data Heroes = Heroes { heroes :: [Hero] } deriving (Data, Typeable)

context2 = mkGenericContext $ Heroes $ map Hero names

-- Контекст с помощью Generics (другой вариант)
template3 = concat [
"{{heroName.3}}\n",
"{{heroName.2}}\n"]

data HeroesStr = HeroesStr { heroName :: [String] } deriving (Data, Typeable)

context3 = mkGenericContext $ HeroesStr names

Ре­зуль­тат:

Небо
Безымянный

Небо
Безымянный

Летящий Снег
Сломанный Меч

Алгоритм Ахо-Корасик на Haskell

Март 15, 2012, 12:05

Вы­ло­жил в open source свою ре­а­ли­за­цию ал­го­рит­ма Ахо-Ко­рас­ик на Haskell. Код на GitHub. Па­кет в Hack­ageDB.

Ал­го­ритм Ахо-Ко­рас­ик — ал­го­ритм по­ис­ка под­строк, со­здан­ный Аль­фре­дом Ахо и Мар­га­рет Ко­рас­ик в 1975 году. Этот ал­го­ритм пред­на­зна­чен для од­но­вре­мен­но­го по­ис­ка сра­зу боль­шо­го ко­ли­че­ства под­строк. Ал­го­ритм со­сто­ит из двух фаз: сна­ча­ла стро­ит­ся ко­неч­ный ав­то­мат по всем под­стро­кам ко­то­рые нуж­но бу­дет ис­кать, и даль­ше че­рез этот по­стро­ен­ный ав­то­мат про­пус­ка­ет­ся текст, в ко­то­ром эти под­стро­ки нуж­но най­ти.

Моя ре­а­ли­за­ция обоб­ще­на для лю­бых по­сле­до­ва­тель­но­стей зна­че­ний, для ко­то­рых ре­а­ли­зо­ван тайп-класс Hash­able (т.е. ис­кать мож­но не толь­ко стро­ки, но и, ска­жем, по­сле­до­ва­тель­ность из чи­сел).

При­ме­ры ис­поль­зо­ва­ния

Са­мый про­стой вы­зов:

example1 = mapM_ print $ findAll simpleSM "ushers" where
simpleSM = makeSimpleStateMachine ["he","she","his","hers"]
Position {pIndex = 1, pLength = 3, pVal = "she"}
Position {pIndex = 2, pLength = 2, pVal = "he"}
Position {pIndex = 2, pLength = 4, pVal = "hers"}

К ис­ко­мым стро­кам мож­но при­вя­зать про­из­воль­ные дан­ные:

example2 = mapM_ print $ findAll sm "ushers" where
sm = makeStateMachine [("he",0),("she",1),("his",2),("hers",3)]
Position {pIndex = 1, pLength = 3, pVal = 1}
Position {pIndex = 2, pLength = 2, pVal = 0}
Position {pIndex = 2, pLength = 4, pVal = 3}

Со­здан­ный ав­то­мат мож­но за­пус­кать по ша­гам (если ну­жен по­иск не по спис­кам, а по чему-ни­будь дру­го­му):

example3 = mapM_ print $ next sm "ushers" where
sm = makeSimpleStateMachine ["he","she","his","hers"]
next _ [] = []
next sm (s:n) = let (SMStepRes match nextSM) = stateMachineStep sm s in
(s, match) : next nextSM n
('u',[])
('s',[])
('h',[])
('e',[(3,"she"),(2,"he")])
('r',[])
('s',[(4,"hers")])

Неко­то­рые по­дроб­но­сти ре­а­ли­за­ции

По­стро­е­ние ко­неч­но­го ав­то­ма­та у меня сде­ла­но в мо­на­де ST. Это мо­на­да ис­поль­зу­ет­ся, ко­гда вам нуж­ны вы­чис­ле­ния с из­ме­ня­е­мы­ми дан­ны­ми, но при этом ни­ка­кой внеш­ний мир не ну­жен (т.е. мо­на­ды IO для вас слиш­ком мно­го), со­от­вет­ствен­но сна­ру­жи мо­на­ды мы име­ем чи­стый ин­тер­фейс, а внут­ри у нас есть му­та­бель­ные пе­ре­мен­ные и мас­си­вы. Там я на­пи­сал про­стей­шую FIFO оче­редь в этой мо­на­де, мож­но по­чи­тать кому ин­те­рес­но.

Сам по­иск с ис­поль­зо­ва­ни­ем со­здан­но­го ав­то­ма­та сде­лан уже в чи­стых функ­ци­ях, это мож­но ви­деть в при­ме­рах выше.

Ссыл­ки по теме

Примеры использования Hastache

Ноябрь 14, 2011, 11:30

Вы­ло­жил при­ме­ров для has­tache: README.md (этот файл, кста­ти, хаста­шем же и со­би­ра­ет­ся — mkReadme.hs). Эти же при­ме­ры рос­сы­пью фай­лов: ex­am­ples.

Libqrencode-js: генерация QR-кодов на JavaScript

Ноябрь 14, 2011, 11:00

А вот ка­кую офи­ген­скую шту­ку я вы­ло­жил!

Это ге­не­ра­тор QR-ко­дов на чи­стом как хру­сталь JavaScript, ни­ка­ких сер­вер­ных ком­по­нен­тов, всё пря­мо в бра­у­зе­ре. Вот сра­зу де­мон­страш­ка для по­ба­ло­вать­ся.

При­чем это не абы что, это порт про­дви­ну­той C-шной биб­лио­те­ки libqren­code, ко­то­рая ра­бо­та­ет в сер­вер­ной ча­сти на по­дав­ля­ю­щем боль­шин­стве сай­тов для ге­не­ра­ции QR-ко­дов, и име­ет бин­дин­ги ко все­му на све­те. Для JavaScript уже есть ге­не­ра­то­ры QR-ко­дов, но все очень сы­рые, в от­ли­чии от libqren­code ко­то­рый уже несколь­ко лет пи­шет­ся и, как я уже го­во­рил, мно­го где ис­поль­зу­ет­ся.

Про­цесс пор­ти­ро­ва­ния C-шной биб­лио­те­ки на JavaScript, это, ска­жу я вам, про­сто пес­ня. Есть со­вер­шен­но за­ме­ча­тель­ный про­ект em­scripten — ком­пи­ля­тор LLVM в JavaScript. Вот с по­мо­щью него вол­шеб­ство и про­изо­шло. Я на­пи­сал неболь­шую C-шную оберт­ку над libqren­code, ском­пи­ли­ро­вал всё вме­сте в LLVM-код с по­мо­щью Clang, пе­ре­дал в em­scripten и на­пи­сал JavaScript оберт­ку над ре­зуль­та­том его ра­бо­ты. По­лу­чи­лось хо­ро­шо.

Ли­цен­зия LGPL (ви­ру­сом от libqren­code). Поль­зуй­тесь!

Hastache растёт и развивается

Ноябрь 08, 2011, 11:20

Но­во­сти хаста­ше­стро­е­ния:

Во-пер­вых, Akaspin при­слал по­лез­ный патч, поз­во­ля­ю­щий с по­мо­щью mk­Gener­ic­Con­text со­зда­вать кон­тек­сты для ти­пов с по­ля­ми Mona­dIO m => (Byte)String -> m (Byte)String, за что ему вы­да­ёт­ся оче­ред­ной плюс в кар­му. Сам я о та­кой воз­мож­но­сти ду­мал, но не оси­лил, ура опен­сор­су. При­мер ис­поль­зо­ва­ния тут.

Во-вто­рых, я обоб­щил кон­струк­тор Mu­Lamb­da до Mu­Var a => Mu­Lamb­da (ByteString -> a), рань­ше мож­но было толь­ко ByteString воз­вра­щать, а те­перь лю­бой тип, для ко­то­ро­го есть ин­станс клас­са Mu­Var. Удоб­но, как-то я рань­ше не со­об­ра­зил так сде­лать.

В-тре­тьих, Сам Bryan O'Sul­li­van (один из ав­то­ров кни­ги Real World Haskell), при­слал неболь­шой патч для has­tache и по­со­ве­то­вал ис­поль­зо­вать blaze-builder для за­пи­си ре­зуль­та­та ра­бо­ты шаб­ло­ни­за­то­ра. Blaze-builder пред­на­зна­чен для ге­не­ра­ции Lazy ByteString с кон­тро­лем ми­ни­маль­но­го раз­ме­ра фраг­мен­тов этой стро­ки. За счет это­го до­сти­га­ет­ся су­ще­ствен­ное уве­ли­че­ние ско­ро­сти даль­ней­шей ра­бо­ты с этой стро­кой. Вме­сто кучи мел­ких бло­ков (а имен­но так и по­лу­ча­ет­ся при ра­бо­те has­tache), име­ем несколь­ко круп­ных, ко­то­рые, к при­ме­ру, по сети уедут быст­рее (за счет ми­ни­ми­за­ции ко­ли­че­ства си­стем­ных вы­зо­вов). Так что те­перь и обыч­ный ре­зуль­тат has­tache со­сто­ит из удоб­ных круп­ных бло­ков внут­ри Lazy ByteString, и, та­к­же, мож­но по­лу­чить непо­сред­ствен­но объ­ект Builder биб­лио­те­ки blaze-builder и даль­ше уже ра­бо­тать пря­мо с ним.

Hastache — вложенные контексты

Октябрь 12, 2011, 12:19

Akaspin за­ре­пор­тил один непри­ят­ный баг в has­tache, за что ему вы­ра­жа­ет­ся вся­че­ская бла­го­дар­ность с за­не­се­ни­ем в кар­му. Про­бле­ма за­клю­ча­лась в том, что до­ста­точ­но ча­сто нуж­но иметь воз­мож­ность об­ра­тить­ся из вло­жен­но­го бло­ка шаб­ло­на к пе­ре­мен­ной опре­де­лен­ной где-то выше в иерар­хии кон­тек­стов. В ори­ги­наль­ном Mus­tache та­кая функ­ция есть, а я это дело бла­го­по­луч­но про­во­ро­нил. Ис­прав­ля­юсь. Мож­но по­чи­тать по­дроб­но­сти, и по­смот­реть ещё один при­мер из те­стов.

Сергей Лымарь © 2005-2014, Все права защищены.