packages feed

herringbone 0.0.6 → 0.0.7

raw patch · 10 files changed

+359/−6 lines, 10 files

Files

+ README.md view
@@ -0,0 +1,42 @@+herringbone+===========++herringbone is a Haskell library for compiling and serving web assets.  It+aims to make it dead simple to create a 'Network.Wai.Middleware' or+'Network.Wai.Application' which deals with all of your static assets, including+preprocessing for languages like Fay, CoffeeScript, Sass, and LESS.++It takes most of its inspiration from the Ruby library, [Sprockets], hence the+name.++Status+------++Alpha.++How to use it+-------------++```haskell+import Web.Herringbone++fay, sass :: PP++hb = Herringbone+hb = herringbone+    ( addSourceDir "assets"+    . setDestDir   "compiled_assets"+    . addPreprocessors [fay, sass]+    )++-- You can now access assets programmatically+asset <- findAsset hb (fromJust . makeLogicalPath $ ["application.js"])++-- Or serve them with a Wai application+app = toApplication hb+```++For more information, go and look at the documentation on [Hackage]!++[Sprockets]: https://github.com/sstephenson/sprockets+[Hackage]: http://hackage.haskell.org/package/herringbone
herringbone.cabal view
@@ -1,5 +1,5 @@ name:                herringbone-version:             0.0.6+version:             0.0.7 synopsis:            A library for compiling and serving static web assets. description:         A library for compiling and serving static web assets. For more information, please see <https://github.com/hdgarrood/herringbone>. license:             MIT@@ -9,6 +9,9 @@ category:            Web build-type:          Simple cabal-version:       >=1.10+extra-source-files:+    README.md+    test/*.hs  source-repository head   type:     git@@ -83,8 +86,8 @@   default-language:     Haskell2010  executable herringbone-test-server-  hs-source-dirs:   test-  build-depends:    base, herringbone, text, warp-  main-is:          TestServer.hs-  default-language: Haskell2010-  default-extensions: OverloadedStrings+  hs-source-dirs:       test+  build-depends:        base, herringbone, text, warp+  main-is:              TestServer.hs+  default-language:     Haskell2010+  default-extensions:   OverloadedStrings
+ test/AssertionsHelper.hs view
@@ -0,0 +1,63 @@+module AssertionsHelper where++import Control.Applicative+import Control.Monad+import Data.Text (Text)+import Data.List (sort)+import Test.HUnit hiding (path)+import Prelude hiding (FilePath)+import Filesystem.Path.CurrentOS (FilePath, (</>))+import Prelude hiding (FilePath)+import qualified Filesystem as F++import LazinessHelper+import TestHerringbone+import Web.Herringbone++testWithInputs :: String -> (a -> Assertion) -> [a] -> Test+testWithInputs groupName f =+    TestLabel groupName . TestList . map mkTest . zipWith assignName ([1,2..] :: [Int])+    where+        mkTest (name, input) = TestLabel name (TestCase (f input))+        assignName n input   = ("input #" ++ show n, input)++resultsDir :: FilePath+resultsDir = "test/resources/results"++testWithExpectedResult :: Text -> Assertion+testWithExpectedResult logicalPathText = do+    let logicalPath = lp logicalPathText+    let filePath = toFilePath logicalPath+    result <- findAsset testHB logicalPath+    either (fail . show)+           (assertResultMatches filePath . assetFilePath)+           result++assertResultMatches :: FilePath -> FilePath -> Assertion+assertResultMatches resultName filePath = do+    let resultPath = resultsDir </> resultName+    assertFileContentsMatch resultPath filePath++-- Extra assertions+assertFileExists :: FilePath -> Assertion+assertFileExists path = do+    exists <- F.isFile path+    assertBool ("Expected a file to exist: " ++ es path) exists++assertFileContentsMatch :: FilePath -> FilePath -> Assertion+assertFileContentsMatch pathA pathB = do+    matches <- (==) <$> F.readFile pathA <*> F.readFile pathB+    assertBool ("expected file contents to match\n" +++                "this file:       " ++ es pathA ++ "\n" +++                "versus this one: " ++ es pathB ++ "\n") matches++assertEqual' :: (Eq a, Show a) => a -> a -> Assertion+assertEqual' = assertEqual ""++assertSameElems :: (Eq a, Show a, Ord a) => [a] -> [a] -> Assertion+assertSameElems xs ys = assertEqual' (sort xs) (sort ys)++assertIsRight :: Show a => Either a b -> Assertion+assertIsRight (Right _) = return ()+assertIsRight (Left x)  = assertFailure $+                            "Expected a Right value; got: Left " ++ show x
+ test/FindAssetSpec.hs view
@@ -0,0 +1,57 @@+module FindAssetSpec where++import Filesystem.Path.CurrentOS ((</>))+import Prelude hiding (FilePath)+import qualified Filesystem as F+import Test.Hspec+import Test.HUnit hiding (path)++import Web.Herringbone+import SpecHelper++spec :: Spec+spec = do+    let destDir = hbDestDir testHB++    context "without preprocessors" $ do+        let logPath = lp "buildNoPreprocessors.js"++        it "should copy a source file to the destination directory" $ do+            asset' <- findAsset testHB logPath++            assertIsRight asset'+            let Right asset = asset'+            assertFileExists (assetFilePath asset)+            assertFileContentsMatch (assetSourcePath asset)+                                    (assetFilePath asset)++        it "should get the modification time of the source file" $ do+            Right asset <- findAsset testHB logPath+            sourceMTime <- F.getModified (assetSourcePath asset)++            assertEqual' sourceMTime (assetModifiedTime asset)++        it "should not compile unless necessary" $ do+            Right asset  <- findAsset testHB logPath+            mTime        <- F.getModified (assetFilePath asset)+            Right asset' <- findAsset testHB logPath+            mTime'       <- F.getModified (assetFilePath asset')++            assertEqual' mTime mTime'++    context "with preprocessors" $ do+        it "should run a single preprocessor" $ do+            testWithExpectedResult "onePreprocessor.js"++        it "should run preprocessors in the correct order" $ do+            testWithExpectedResult "threePreprocessors.js"++    context "when there's a compile error" $ do+        it "should report the error" $ do+            Left result <- findAsset testHB (lp "compileError.css")+            assertEqual' (AssetCompileError "Oh snap!") result++        it "should not create the output file" $ do+            _ <- findAsset testHB (lp "compileError.css")+            exists <- F.isFile (destDir </> "compileError.css")+            assert (not exists)
+ test/LazinessHelper.hs view
@@ -0,0 +1,14 @@+module LazinessHelper where++import Web.Herringbone+import Data.Text (Text)+import qualified Data.Text as T+import Prelude hiding (FilePath)+import Filesystem.Path.CurrentOS (FilePath)+import qualified Filesystem.Path.CurrentOS as F++es :: FilePath -> String+es = F.encodeString++lp :: Text -> LogicalPath+lp = unsafeMakeLogicalPath . T.splitOn "/"
+ test/LocateAssetsSpec.hs view
@@ -0,0 +1,86 @@+module LocateAssetsSpec where++import Test.Hspec+import Test.Hspec.HUnit+import Test.HUnit hiding (path)+import Data.Text (Text)+import Filesystem.Path.CurrentOS (FilePath, (</>))+import Prelude hiding (FilePath)++import Web.Herringbone.LocateAssets+import Web.Herringbone.Types+import SpecHelper++spec :: Spec+spec = do+    fromHUnitTest $ testWithInputs "getExtraExtensions"+        test_getExtraExtensions+        data_getExtraExtensions++    fromHUnitTest $ testWithInputs "resolvePPs"+        test_resolvePPs+        data_resolvePPs++    fromHUnitTest $ testWithInputs "lookupPP"+        test_lookupPP+        data_lookupPP++    fromHUnitTest $ testWithInputs "locateAssets"+        test_locateAssets+        data_locateAssets++test_getExtraExtensions :: (FilePath, FilePath, Maybe [Text]) -> Assertion+test_getExtraExtensions (pathWithExts, path, expected) =+    assertEqual' expected (getExtraExtensions pathWithExts path)++data_getExtraExtensions :: [(FilePath, FilePath, Maybe [Text])]+data_getExtraExtensions =+    [ ("game.js"   , "game.js.coffee"     , Just ["coffee"])+    , ("style.css" , "game.js.coffee"     , Nothing)+    , ("game.js"   , "game.js.coffee.erb" , Just ["erb", "coffee"])+    ]++allPPs :: PPs+allPPs = fromList [pp1, pp2]++test_resolvePPs :: (PPs, FilePath, FilePath, Maybe [PP]) -> Assertion+test_resolvePPs (pps, assetPath, sourcePath, expected) =+    assertEqual' expected (resolvePPs pps assetPath sourcePath)++data_resolvePPs :: [(PPs, FilePath, FilePath, Maybe [PP])]+data_resolvePPs =+    [ (noPPs  , "test.js"   , "test.js"         , Just [])+    , (noPPs  , "test.js"   , "test.js.pp1"     , Nothing)+    , (allPPs , "test.js"   , "test.js.pp1"     , Just [pp1])+    , (allPPs , "test.js"   , "test.js.pp1.pp2" , Just [pp2, pp1])+    , (allPPs , "style.css" , "test.js.pp1"     , Nothing)+    ]++test_lookupPP :: (Text, PPs, Maybe PP) -> Assertion+test_lookupPP (ext, pps, expected) =+    assertEqual' expected (lookupPP ext pps)++data_lookupPP :: [(Text, PPs, Maybe PP)]+data_lookupPP =+    [ ("sass" , noPPs  , Nothing)+    , ("sass" , allPPs , Nothing)+    , ("pp1"  , allPPs , Just pp1)+    ]++test_locateAssets :: (LogicalPath, [(FilePath, [PP])]) -> Assertion+test_locateAssets (logPath, expected) = do+    assets <- locateAssets testHB logPath+    assertSameElems expected assets++data_locateAssets :: [(LogicalPath, [(FilePath, [PP])])]+data_locateAssets =+    [ (lp "locateAssets.js",  [(base1 </> "locateAssets.js", [])])+    , (lp "locateAssets.css", [ (base1 </> "locateAssets.css", [])+                              , (base1 </> "locateAssets.css.pp1", [pp1])+                              , (base2 </> "locateAssets.css", [])+                              ])+    , (lp "html/locateAssets.html", [(base1 </> "html/locateAssets.html", [])])+    ]+    where+    base1 = "test/resources/assets"+    base2 = "test/resources/assets2"
+ test/PreprocessStdIOSpec.hs view
@@ -0,0 +1,9 @@+module PreprocessStdIOSpec where++import Test.Hspec+import SpecHelper++spec :: Spec+spec = do+    it "should use stdIO" $ do+        testWithExpectedResult "hello.txt"
+ test/SpecHelper.hs view
@@ -0,0 +1,9 @@+module SpecHelper (+    module AssertionsHelper,+    module LazinessHelper,+    module TestHerringbone+) where++import AssertionsHelper+import LazinessHelper+import TestHerringbone
+ test/TestHerringbone.hs view
@@ -0,0 +1,55 @@+module TestHerringbone where++import Data.Text (Text)+import qualified Data.Text.Encoding as T+import Data.Monoid+import Network.Wai.Handler.Warp++import Web.Herringbone+import Web.Herringbone.Preprocessor.StdIO+import Web.Herringbone.Preprocessor.CoffeeScript+import Web.Herringbone.Preprocessor.Sass++mkMockPP :: Text -> PP+mkMockPP ext = PP { ppExtension = ext+                  , ppAction = \sourceData -> do+                        return . Right $+                            "Preprocessed as: " <> T.encodeUtf8 ext <> "\n" <>+                            sourceData+                  }++pp1 :: PP+pp1 = mkMockPP "pp1"++pp2 :: PP+pp2 = mkMockPP "pp2"++pp3 :: PP+pp3 = mkMockPP "pp3"++failingPP :: PP+failingPP = PP { ppExtension = "fails"+               , ppAction = const . return . Left $ "Oh snap!"+               }++sed :: PP+sed = makeStdIOPP "sed" "sed" ["-e", "s/e/u/"]++testHB :: Herringbone+testHB = herringbone+    ( addSourceDir  "test/resources/assets"+    . addSourceDir  "test/resources/assets2"+    . setDestDir    "test/resources/compiled_assets"+    . addPreprocessors [ pp1+                       , pp2+                       , pp3+                       , failingPP+                       , coffeeScript+                       , sass+                       , scss+                       , sed+                       ]+    )++runTestHB :: Int -> IO ()+runTestHB port = run port (toApplication testHB)
+ test/WaiAdapterTest.hs view
@@ -0,0 +1,15 @@+module WaiAdapterTest where++import Network.Wai+import Network.Wai.Handler.Warp++import Web.Herringbone+import SpecHelper++app :: Application+app = toApplication testHB++runApp :: IO ()+runApp = do+    putStrLn "running on port 3002..."+    run 3002 app