packages feed

snaplet-sass (empty) → 0.1.0.0

raw patch · 8 files changed

+370/−0 lines, 8 filesdep +basedep +bytestringdep +configuratorsetup-changed

Dependencies added: base, bytestring, configurator, directory, filepath, mtl, process, snap, snap-core, transformers

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+## Changelog++#### 0.1.0.0++* Initial release
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2012, Adam Bergmark, 2014, Luke Randall++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Adam Bergmark nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,60 @@+snaplet-sass+===========++[Changelog](CHANGELOG.md)++snaplet-sass integrates [Snap](http://www.snapframework.com) with+[Sass](http://www.sass-lang.com).++Features+--------++* Compile and serve sass files on request, no need to restart the+  snap server.+* Production mode to pre-compile all sass files.+* Outputs sourcemaps to make debugging generated CSS easier.+* Writes CSS to disk to allow reading the generated source.++Example Usage+-------------++Site.hs:+```haskell+import Snap.Snaplet.Sass++routes = [..., ("/sass", with sass sassServe)]++app :: SnapletInit App App+app = makeSnaplet "app" "A snaplet example application." Nothing $ do+  s <- nestSnaplet "sass" sass initSass+  return $ App { _sass = s }+```++Application.hs:+```haskell+import Snap.Snaplet.Sass++data App = App { _sass :: Snaplet Sass }++makeLens ''App+```++Now run your application and try requesting a Sass file.++A snaplet config file will be generated at snaplets/sass/devel.cfg the+first time your application initializes the snaplet. The defaults are+the recommended ones for development.++Place your .sass or .scss files in snaplets/sass/src. Note that a default+devel.cfg will not be created if you have already created the sass+directory. If this happens to you, move snaplets/sass, start your+application, and then move the files back into snaplets/sass.++Any requests to the specified directory (in this case /sass/) will+compile the appropriate Sass file and serve it.+++Thanks+-------++This borrows hugely from [snaplet-fay](https://github.com/faylang/snaplet-fay).
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ resources/devel.cfg view
@@ -0,0 +1,15 @@+# "Development": Compile files on every request.+#+# "Production": Compile all files in snaplets/sass/src when the application is started and then serve them statically.+#+# Both methods will write files to disk for debugging purposes.+# Default is "Development".+compileMode = "Development"+# Output style. Can be nested (the Sass default), compact, compressed or expanded.+style = "nested"+# Output sourcemap (not supported by older versions of Sass).+sourcemap = on+# Print more or less information about what the snaplet is doing.+# Default is on.+verbose = on+
+ snaplet-sass.cabal view
@@ -0,0 +1,76 @@+name:                snaplet-sass+version:             0.1.0.0+synopsis:            Sass integration for Snap with request- and pre-compilation.+description:         +    Sass integration for Snap with request based compilation during development and precompilation in production.+    .+    Get started by reading through the <https://github.com/lukerandall/snaplet-sass README>.+    .+    = Brief overview+    .+    Add the snaplet to your App in Application.hs+    .+    > import Snap.Snaplet.Sass+    >+    > data App = App [+    >     _sass :: Snaplet Sass+    >     ] -- these should be curly braces but haddock doesn't allow it+    .+    In Site.hs, add a route for sass to serve from and initialize the snaplet+    .+    > routes = [..., ("/sass", with sass sassServe)]+    >+    > app :: SnapletInit App App+    > app = makeSnaplet "app" "A snaplet example application." Nothing $ do+    >   s <- nestSnaplet "sass" sass initSass+    > return $ App s+    .+    Now add your Sass files to snaplets\/sass\/src and they'll be served+    at \/sass\//FILE/.css. Take note that the .sass or .scss extension will+    be replaced with .css.+    .++license:             BSD3+license-file:        LICENSE+author:              Luke Randall+maintainer:          luke.randall@gmail.com+homepage:            https://github.com/lukerandall/snaplet-sass+bug-reports:         https://github.com/lukerandall/snaplet-sass/issues+category:            Web, Snap+build-type:          Simple+cabal-version:       >=1.8++extra-source-files:+  LICENSE+  README.md+  CHANGELOG.md++data-files:+  resources/devel.cfg++source-repository head+  type: git+  location: https://github.com/lukerandall/snaplet-sass.git++library+  ghc-options: -Wall+  hs-source-dirs: src++  exposed-modules:+    Snap.Snaplet.Sass+    Snap.Snaplet.Sass.Internal++  other-modules:+    Paths_snaplet_sass++  build-depends:+      base         >= 4       && < 5+    , bytestring   >= 0.9     && < 0.11+    , configurator == 0.2.*+    , directory    >= 1.1     && < 1.3+    , filepath     == 1.3.*+    , mtl          >= 2.1     && < 2.3+    , process      >= 1.1     && <= 1.3+    , snap         >= 0.11.1  && < 0.14+    , snap-core    >= 0.9.3.1 && < 0.10+    , transformers >= 0.3     && < 0.4 || > 0.4.1 && < 0.5
+ src/Snap/Snaplet/Sass.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Snap.Snaplet.Sass (+         Sass+       , initSass+       , sassServe+       ) where++------------------------------------------------------------------------------+import           Control.Monad+import           Control.Monad.Reader+import           Control.Monad.State.Class+import           Control.Monad.Trans.Writer+import           Data.Char (toLower)+import qualified Data.Configurator          as C+import           Data.List (intercalate)+import           Data.Maybe (isNothing)+import           Snap.Core (modifyResponse, setContentType)+import           Snap.Snaplet+import           Snap.Util.FileServe+import           System.Process (rawSystem)++import           Paths_snaplet_sass+import           Snap.Snaplet.Sass.Internal++-- | Snaplet initialization+initSass :: SnapletInit b Sass+initSass = makeSnaplet "sass" description datadir $ do+  config <- getSnapletUserConfig+  fp <- getSnapletFilePath++  (opts, errs) <- runWriterT $ do+    cmStr <- logErr "Must specify compileMode" $ C.lookup config "compileMode"+    cm    <- case cmStr of+                  Just x -> logErr "Invalid compileMode" . return $ compileModeFromString x+                  Nothing -> return Nothing+    stStr <- logErr "Must specify style" $ C.lookup config "style"+    st    <- case stStr of+                  Just x  -> logErr "Invalid style" . return $ styleFromString x+                  Nothing -> return Nothing+    sm    <- logErr "Must specify sourcemap" $ C.lookup config "sourcemap"+    v     <- logErr "Must specify verbose" $ C.lookup config "verbose"+    return (cm, st, sm, v)++  let sass = case opts of+              (Just cm, Just st, Just sm, Just v) ->+                Sass+                  { snapletFilePath = fp+                  , compileMode     = cm+                  , style           = st+                  , sourcemap       = sm+                  , verbose         = v+                  }+              _ -> error $ intercalate "\n" errs++  -- Make sure snaplet/sass, snaplet/sass/src, snaplet/sass/css are present.+  liftIO $ mapM_ createDirUnlessExists [fp, srcDir sass, destDir sass]++  when (Production == compileMode sass) (liftIO $ compileAll sass)++  return sass++  where+    datadir = Just $ liftM (++ "/resources") getDataDir++    description = "Automatic (re)compilation and serving of Sass files"++    logErr :: MonadIO m => t -> IO (Maybe a) -> WriterT [t] m (Maybe a)+    logErr err m = do+        res <- liftIO m+        when (isNothing res) (tell [err])+        return res+++-- | Serves the compiled Fay scripts using the chosen compile mode.+sassServe :: Handler b Sass ()+sassServe = do+  modifyResponse . setContentType $ "text/css;charset=utf-8"+  get >>= compileWithMode . compileMode+++-- | Compiles according to the specified mode.+compileWithMode :: CompileMode -> Handler b Sass ()+compileWithMode Development = do+    config <- get+    compileAll config+    compileWithMode Production+-- Production compilation has already been done.+compileWithMode Production = get >>= serveDirectory . destDir++compileAll :: MonadIO m => Sass -> m ()+compileAll cfg = liftIO $ compile >> return ()+  where+    compile = verboseLog >> rawSystem "sass" args+    verboseLog = verbosePut cfg $ "compiling " ++ srcDir cfg+    args = ["--update", ioDirs, "--style", st] ++ sm+    ioDirs = srcDir cfg ++ ":" ++ destDir cfg+    sm = if sourcemap cfg then ["--sourcemap"] else []+    st = map toLower . show $ style cfg
+ src/Snap/Snaplet/Sass/Internal.hs view
@@ -0,0 +1,82 @@+module Snap.Snaplet.Sass.Internal+    (+    -- * Sass types+      Sass (..)+    , CompileMode (..)+    , Style (..)+    -- * helper functions+    , srcDir+    , destDir+    , createDirUnlessExists+    , compileModeFromString+    , styleFromString+    , verbosePut+    ) where++import Control.Monad+import System.Directory+import System.FilePath ((</>))+++-- | Configuration+data Sass = Sass {+    snapletFilePath :: FilePath+  , compileMode     :: CompileMode+  , style           :: Style+  , sourcemap       :: Bool+  , verbose         :: Bool+  } deriving (Show)+++-- | Compile on every request or when Snap starts.+data CompileMode+     = Development+     | Production+       deriving (Eq, Show)+++-- | Style of generated CSS+data Style+     = Nested+     | Compact+     | Compressed+     | Expanded+       deriving (Eq, Show)+++-- | Location of Sass files+srcDir :: Sass -> FilePath+srcDir = (</> "src") . snapletFilePath+++-- | Location of CSS files+destDir :: Sass -> FilePath+destDir = (</> "css") . snapletFilePath+++-- | Create given directory unless it exists+createDirUnlessExists :: FilePath -> IO ()+createDirUnlessExists fp = do+    dirExists <- doesDirectoryExist fp+    unless dirExists $ createDirectory fp+++-- | Lookup CompileMode for string+compileModeFromString :: String -> Maybe CompileMode+compileModeFromString "Development" = Just Development+compileModeFromString "Production" = Just Production+compileModeFromString _ = Nothing+++-- | Lookup Style for string+styleFromString :: String -> Maybe Style+styleFromString "nested" = Just Nested+styleFromString "compact" = Just Compact+styleFromString "compressed" = Just Compressed+styleFromString "expanded" = Just Expanded+styleFromString _ = Nothing+++-- | Print log messages when the verbose flag is set+verbosePut :: Sass -> String -> IO ()+verbosePut config = when (verbose config) . putStrLn . ("snaplet-sass: " ++ )