Archive for the ‘Turbinado’ tag
A Plea For “cabal install”
Updated per Ganesh’s comments.
Over here, Adolfo commented:
“Hi,I tried to do follow the example, but I couldn’t even install the packages, hsx and hs-plugins were impossible. I tried with cabal and manually, and neither of those worked . any suggestion, known issue with this packages?”
I’ve been busy adding features to Turbinado and haven’t circled back around to making sure that it’s easy to build, so I can claim a lot of the blame for the build problems. Turns out to be really important that publicly released packages are easily buildable…
Thinking back, I have really struggled to build Turbinado… and I wrote Turbinado! Turbinado depends on some particular bugfix-ish library releases (e.g. GSomething 0.6.1). With GHC 6.10, a bunch of libraries have broken or have changed so much that they badly break Turbinado. (I need to specify better the versions in turbinado.cabal.)
At times, I’ve considered bundling the dependencies into Turbinado so that building Turbinado would be easy, but that’s always felt like a cop-out. So I’m pleading for “cabal install”. Given Turbinado’s dependence on particular versions of libraries, I would love to able to do:
cabal install turbinado OR (from /home/alson/turbinado) cabal build
Cabal Install
Most casual users of Ruby, Python, Perl, Java, etc, know that those languages have automagic build/dependencies system (respectively, gem, eggs, CPAN, maven). The tools may be of varying quality, but many tutorials include something like “First, use GEM to install the package: gem install rails” and demonstrate just how simple it is to get a useful piece of software installed.
This is not the case in Haskell. I’d guess that no more than 5% of Haskellers know about the cabal command line tool and “cabal install”. On the other hand, I’d guess that 95% of novice Rubyers know about “gem install”. These automated build/dependency system are now critical to the success of languages. As a beginner in Ruby, I always knew that I could easily try out various libraries by using GEM to install bits of software. I’m now fairly experienced with Haskell and, partly because of that experience, I don’t believe that I can easily try out various Haskell libraries.
Niklas Broberg’s HSP is a great example of the challenge of building Haskell programs. HSP is very nicely separated into modular libraries which: makes it easy to apply pieces of HSP’s functionality to a program; makes it hard for a human (at least for me) to build any one part of HSP because each part depends on so many other parts. A build/dependency tool would make HSP much easier to build into existing programs.
The Plea
I love using Haskell and Haskell will only get better if more people are able to use it. IMO, a pre-condition to the growth of the language is a solid, easy to use build/dependency system. Cabal is that system for GHC and the cabal command line tool is a key part of that system.
Unfortunately, the cabal command line tool isn’t bundled with GHC, but … Please get it, build it, use it, report any bugs, compliment the Cabal team, etc. It’ll be a great help to the Haskell community.
darcs get http://darcs.haskell.org/cabal-install cd cabal-install sh bootstrap.sh
Update: Haskell Platform
Ganesh points out the Haskell Platform Proposal, so it looks as though there is a plan to incorporate the cabal command line tool. See the following:
http://www.haskell.org/haskellwiki/Haskell_Platform
http://www.haskell.org/haskellwiki/Haskell_Platform/FAQ
P.S. Anyone know if the cabal command line tool is going to make it into GHC?
Links to cabal install information:
http://hackage.haskell.org/trac/hackage/wiki/CabalInstall
http://hackage.haskell.org/cgi-bin/hackage-scripts/package/cabal-install
http://ghcmutterings.wordpress.com/2008/11/10/bootstrapping-cabal-install/
A HAML parser for Haskell
HAML’s lovely. As I’ve been working with Turbinado, I’ve been having some issues with HSP. HSP is an insanely impressive piece of software, but its error messages can be a bit unclear. So I started playing around a bit with HAML. Got me wondering “How easy would be to write a HAML parser in Haskell?”
So I tried. Here’s a first-pass, to-be-updated [and somewhat incomplete] HAML parser for Haskell. Not all of the features are implemented, but it’s a start. It generates HTML bits suitable for compilation by GHC.
Input
f = content page = #content .left.column %h2 Welcome to our site! %p = print_information %p = print_inline .right.column = render [abba = ding, ding = abba] dinger
Output
f = (stringToHtml "content") page = ((tag "div"![strAttr "id" "content"]) ((tag "div"![strAttr "class" "left column"]) ((tag "h2") (stringToHtml "Welcome to our site!") ) +++ ((tag "p") (stringToHtml print_information) ) +++ ((tag "p") (stringToHtml print_inline) ) +++ ((tag "div"![strAttr "class" "right column"]) (stringToHtml render) ) +++ ((tag "div"![strAttr "abba" "ding", strAttr "ding" "abba"]) (stringToHtml "dinger") ) ) )
le Code
module Main where import Text.ParserCombinators.Parsec import Text.ParserCombinators.Parsec.Language import Text.ParserCombinators.Parsec.Pos import qualified Text.ParserCombinators.Parsec.Token as T import Data.Char import Data.List import Data.Maybe import System.IO.Unsafe main = do s <- getContents case (parse mainParser "stdin" s) of Left err -> putStrLn "Error: " >> print err Right hs -> putStrLn hs -- Try to parse HAML, otherwise re-output raw lines mainParser = do whiteSpace ls <- many1 (hamlCode <|> tilEOL) return $ unlines ls -- -- * HAML lexer -- hamlLexer = T.makeTokenParser emptyDef whiteSpace= T.whiteSpace hamlLexer lexeme = T.lexeme hamlLexer symbol = T.symbol hamlLexer natural = T.natural hamlLexer parens = T.parens hamlLexer semi = T.semi hamlLexer squares = T.squares hamlLexer stringLiteral= T.stringLiteral hamlLexer identifier= T.identifier hamlLexer reserved = T.reserved hamlLexer reservedOp= T.reservedOp hamlLexer commaSep1 = T.commaSep1 hamlLexer -- -- * Main HAML parsers -- -- hamlCode is just many identifiers (e.g. 'func a b c' followed by '=' followed by a hamlBlock -- func a b c = %somehaml hamlCode = try ( do is <- many1 identifier symbol "=" currentPos <- getPosition x <- manyTill1 (lexeme $ hamlBlock) (notSameIndent currentPos) return $ (concat $ intersperse " " is) ++ " = \n" ++ (concat $ (intersperse (indent currentPos ++ "+++\n") $ filter (not . null) $ x)) ) -- A Block may start with some whitespace, then has a valid bit of data hamlBlock = do currentPos <- getPosition bs <- manyTill1 (pTag <|> pText) (notSameIndent currentPos) return $ intercalate (indent currentPos ++ "+++\n") bs pTag = do currentPos <- getPosition try (do t <- lexeme tagParser ts <- (isInline currentPos >> char '/' >> return []) <|> (hamlBlock) return $ intercalate "\n" $ filter (not . null) $ [ (indent currentPos) ++ "((" ++ (if (null ts) then "i" else "") ++ t ++ ")" , if null ts then [] else ts , (indent currentPos) ++ ")\n"] ) pText = lexeme stringParser notSameIndent p = (eof >> return []) <|> (do innerPos <- getPosition case (sourceColumn p) == (sourceColumn innerPos) of True -> pzero False -> return [] ) -- -- * Various little parsers -- tagParser :: CharParser () String tagParser = do t <- optionMaybe tagParser' i <- optionMaybe idParser c <- optionMaybe (many1 classParser) a <- optionMaybe attributesParser if (isJust t || isJust i || isJust c || isJust a) then do return $ "tag \"" ++ (fromMaybe "div" t) ++ "\"" ++ (if not (isJust i || isJust c || isJust a) then "" else concat $ [ "![" , intercalate ", " $ filter (not . null) [ (maybe "" (\i' -> "strAttr \"id\" \"" ++ i' ++ "\"") i) , (maybe "" (\c' -> "strAttr \"class\" \"" ++ (intercalate " " c') ++ "\"") c) , (maybe "" (\kv -> intercalate ", " $ map (\(k,v) -> "strAttr \"" ++ k ++ "\" \"" ++ v ++ "\"") kv) a) ] , "]"] ) else pzero tagParser' :: CharParser () String tagParser' = do char '%' many1 termChar idParser :: CharParser () String idParser = do char '#' many1 termChar classParser :: CharParser () String classParser = do char '.' many1 termChar attributesParser :: CharParser () [(String, String)] attributesParser = squares (commaSep1 attributeParser) attributeParser :: CharParser () (String, String) attributeParser = do k <- identifier symbol "=" cs <- many1 identifier return (k, intercalate " " cs) stringParser :: CharParser () String stringParser = do currentPos <- getPosition modifier <- optionMaybe (char '=' <|> char '-') whiteSpace c <- alphaNum cs<- tilEOL case modifier of Just '-' -> return $ (indent currentPos) ++ "-" ++ c:cs Just '=' -> return $ (indent currentPos) ++ "(stringToHtml " ++ c:cs ++ ")" Nothing -> return $ (indent currentPos) ++ "(stringToHtml \"" ++ c:cs ++ "\")" -- -- * Utility functions -- isInline p = do p2 <- getPosition case (sourceLine p ) == (sourceLine p2) of True -> return [] False -> pzero isSameIndent p1 p2 = (sourceColumn p1) == (sourceColumn p2) tilEOL = manyTill1 (noneOf "\n") eol eol = newline <|> (eof >> return '\n') termChar = satisfy (\c -> (isAlphaNum c) || (c `elem` termPunctuation) ) termPunctuation = "-_" indent p = take (sourceColumn (p) - 1) (repeat ' ') manyTill1 p e = do ms <- manyTill p e case (null ms) of True -> pzero False -> return ms
Golly, but I wish that I’d cleaned up the code, but there it is in all of its raw, un-thought-through glory…
ANNOUNCE: Turbinado V0.1
Posted to the Haskell mailing list:
I'd like to announce Turbinado, a very young and raw MVC web framework for Haskell. While the framework doesn't exactly copy Ruby on Rails, it certainly rhymes... It's very early days for Turbinado, but the framework is moving along nicely. There are still issues to be ironed out and architectural details to be decided, so help/contribution would be very much appreciated.Turbinado can be found at: http://www.turbinado.org
The source can be found at: http://github.com/alsonkemp/turbinado/tree/master (see the /App directory for the code for www.turbinado.org)
Turbinado: * Provides a fast web server (based on HSP; see http://turbinado.org/Home/Performance); * Provides a straightforward organization for your website (courtesy of Rails); * Uses simple HTML-like templating (courtesy of HSX); * Is easily extensible (courtesy of an Environment built out of Map String Dynamic, not the most type-safe of beasties; Help!); * Configurable routing (see Config/Routes.hs).
Turbinado is currently lacking: * Documentation... * An easy install... * A database ORM based on HDBC (visibly incomplete and ugly in Turbinado/Database/ORM); * Many more HTML helpers; * Controllers for partials (lightweight "controls" ala ASP.NET); * Strong error reporting and handling; * Lots of functionality and plugins; * ... the favorite feature that you want to develop for Turbinado ...