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 +5/−0
- LICENSE +30/−0
- README.md +60/−0
- Setup.hs +2/−0
- resources/devel.cfg +15/−0
- snaplet-sass.cabal +76/−0
- src/Snap/Snaplet/Sass.hs +100/−0
- src/Snap/Snaplet/Sass/Internal.hs +82/−0
+ 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: " ++ )