shakespeare-js 0.10.4 → 0.11.0
raw patch · 5 files changed
+197/−117 lines, 5 filesdep −processdep ~shakespearedep ~shakespeare-js
Dependencies removed: process
Dependency ranges changed: shakespeare, shakespeare-js
Files
- Text/Coffee.hs +55/−42
- Text/Julius.hs +52/−18
- shakespeare-js.cabal +25/−5
- test.hs +2/−2
- test/ShakespeareJsTest.hs +63/−50
Text/Coffee.hs view
@@ -3,66 +3,79 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fno-warn-missing-fields #-}+-- | A Shakespearean module for CoffeeScript, introducing type-safe,+-- compile-time variable and url interpolation. It is exactly the same as+-- "Text.Julius", except that the template is first compiled to Javascript with+-- the system tool @coffee@.+--+-- To use this module, @coffee@ must be installed on your system.+--+-- @#{...}@ is the Shakespearean standard for variable interpolation, but+-- CoffeeScript already uses that sequence for string interpolation. Therefore,+-- Shakespearean interpolation is introduced with @%{...}@.+--+-- Further reading:+--+-- 1. Shakespearean templates: <http://www.yesodweb.com/book/templates>+--+-- 2. CoffeeScript: <http://coffeescript.org/> module Text.Coffee- ( ToCoffee (..)- , CoffeeUrl- , Coffeescript- , coffee+ ( -- * Functions+ -- ** Template-Reading Functions+ -- | These QuasiQuoter and Template Haskell methods return values of+ -- type @'JavascriptUrl' url@. See the Yesod book for details.+ coffee , coffeeFile+ , coffeeFileReload , coffeeFileDebug- , renderCoffee++#ifdef TEST_EXPORT+ , coffeeSettings+#endif ) where import Language.Haskell.TH.Quote (QuasiQuoter (..)) import Language.Haskell.TH.Syntax-import Data.Text.Lazy.Builder (Builder, fromText, toLazyText, fromLazyText)-import qualified Data.Text as TS-import qualified Data.Text.Lazy as TL-import System.Process (readProcess)-import Data.Monoid import Text.Shakespeare--renderCoffee :: (url -> [(TS.Text, TS.Text)] -> TS.Text) -> CoffeeUrl url -> IO TL.Text-renderCoffee r s = do- out <- readProcess "coffee" ["-epb", TL.unpack $ toLazyText $ unCoffee $ s r] []- return $ TL.pack out- where unCoffee (Coffeescript c) = c--newtype Coffeescript = Coffeescript { unCoffeescript :: Builder }- deriving Monoid--type CoffeeUrl url = (url -> [(TS.Text, TS.Text)] -> TS.Text) -> Coffeescript---- the types that can be placed in a template-class ToCoffee c where- toCoffee :: c -> Builder-instance ToCoffee [Char] where toCoffee = fromLazyText . TL.pack-instance ToCoffee TS.Text where toCoffee = fromText-instance ToCoffee TL.Text where toCoffee = fromLazyText+import Text.Julius -settings :: Q ShakespeareSettings-settings = do- toExp <- [|toCoffee|]- wrapExp <- [|Coffeescript|]- unWrapExp <- [|unCoffeescript|]- return $ defaultShakespeareSettings { varChar = '%'- , toBuilder = toExp- , wrap = wrapExp- , unwrap = unWrapExp+coffeeSettings :: Q ShakespeareSettings+coffeeSettings = do+ jsettings <- javascriptSettings+ return $ jsettings { varChar = '%'+ , preConversion = Just PreConvert {+ preConvert = ReadProcess "coffee" ["-epb"]+ , preEscapeBegin = "`"+ -- ^ backticks means the Coffeescript compiler will pass-through to javascript.+ , preEscapeEnd = "`"+ , preEscapeIgnore = "'\"`"+ -- ^ backticks are ignored inside a quote+ } } +-- | Read inline, quasiquoted CoffeeScript. coffee :: QuasiQuoter coffee = QuasiQuoter { quoteExp = \s -> do- rs <- settings+ rs <- coffeeSettings quoteExp (shakespeare rs) s } +-- | Read in a CoffeeScript template file. This function reads the file once, at+-- compile time. coffeeFile :: FilePath -> Q Exp coffeeFile fp = do- rs <- settings+ rs <- coffeeSettings shakespeareFile rs fp -coffeeFileDebug :: FilePath -> Q Exp-coffeeFileDebug fp = do- rs <- settings+-- | Read in a CoffeeScript template file. This impure function uses+-- unsafePerformIO to re-read the file on every call, allowing for rapid+-- iteration.+coffeeFileReload :: FilePath -> Q Exp+coffeeFileReload fp = do+ rs <- coffeeSettings shakespeareFileDebug rs fp++-- | Deprecated synonym for 'coffeeFileReload'+coffeeFileDebug :: FilePath -> Q Exp+coffeeFileDebug = coffeeFileReload+{-# DEPRECATED coffeeFileDebug "Please use coffeeFileReload instead." #-}
Text/Julius.hs view
@@ -3,14 +3,21 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fno-warn-missing-fields #-}--- | This module is currently in an identity crisis. Originally called Julius, now being changed to just Javascript (shakespeare-javascript)+-- | A Shakespearean module for Javascript templates, introducing type-safe,+-- compile-time variable and url interpolation.--+-- To use this module, @coffee@ must be installed on your system.+--+-- You might consider trying 'Text.Coffee', which compiles down to Javascript.+--+-- Further reading: <http://www.yesodweb.com/book/templates>+--+-- This module is currently in an identity crisis. Originally called Julius, now being changed to just Javascript (shakespeare-javascript) module Text.Julius- ( JavascriptUrl- , Javascript (..)- , ToJavascript (..)- , renderJavascript- , renderJavascriptUrl- , js+ ( -- * Functions+ -- ** Template-Reading Functions+ -- | These QuasiQuoter and Template Haskell methods return values of+ -- type @'JavascriptUrl' url@. See the Yesod book for details.+ js , julius , juliusFile , jsFile@@ -18,6 +25,20 @@ , jsFileDebug , juliusFileReload , jsFileReload++ -- * Datatypes+ , JavascriptUrl+ , Javascript (..)++ -- * Typeclass for interpolated variables+ , ToJavascript (..)++ -- ** Rendering Functions+ , renderJavascript+ , renderJavascriptUrl++ -- ** internal, used by 'Text.Coffee'+ , javascriptSettings ) where import Language.Haskell.TH.Quote (QuasiQuoter (..))@@ -31,21 +52,32 @@ renderJavascript :: Javascript -> TL.Text renderJavascript (Javascript b) = toLazyText b +-- | render with route interpolation. If using this module standalone, apart+-- from type-safe routes, a dummy renderer can be used:+-- +-- > renderJavascriptUrl (\_ _ -> undefined) javascriptUrl+--+-- When using Yesod, a renderer is generated for you, which can be accessed+-- within the GHandler monad: 'Yesod.Handler.getUrlRenderParams'. renderJavascriptUrl :: (url -> [(TS.Text, TS.Text)] -> TS.Text) -> JavascriptUrl url -> TL.Text renderJavascriptUrl r s = renderJavascript $ s r +-- | Newtype wrapper of 'Builder'. newtype Javascript = Javascript { unJavascript :: Builder } deriving Monoid++-- | Return type of template-reading functions. type JavascriptUrl url = (url -> [(TS.Text, TS.Text)] -> TS.Text) -> Javascript +-- | A typeclass for types that can be interpolated in CoffeeScript templates. class ToJavascript a where toJavascript :: a -> Builder instance ToJavascript [Char] where toJavascript = fromLazyText . TL.pack instance ToJavascript TS.Text where toJavascript = fromText instance ToJavascript TL.Text where toJavascript = fromLazyText -settings :: Q ShakespeareSettings-settings = do+javascriptSettings :: Q ShakespeareSettings+javascriptSettings = do toJExp <- [|toJavascript|] wrapExp <- [|Javascript|] unWrapExp <- [|unJavascript|]@@ -56,7 +88,7 @@ js, julius :: QuasiQuoter js = QuasiQuoter { quoteExp = \s -> do- rs <- settings+ rs <- javascriptSettings quoteExp (shakespeare rs) s } @@ -64,19 +96,21 @@ jsFile, juliusFile :: FilePath -> Q Exp jsFile fp = do- rs <- settings+ rs <- javascriptSettings shakespeareFile rs fp juliusFile = jsFile -jsFileDebug, juliusFileDebug :: FilePath -> Q Exp-jsFileDebug fp = do- rs <- settings+jsFileReload, juliusFileReload :: FilePath -> Q Exp+jsFileReload fp = do+ rs <- javascriptSettings shakespeareFileDebug rs fp -juliusFileDebug = jsFileDebug+juliusFileReload = jsFileReload -jsFileReload, juliusFileReload :: FilePath -> Q Exp-juliusFileReload = jsFileDebug-jsFileReload = jsFileDebug+jsFileDebug, juliusFileDebug :: FilePath -> Q Exp+juliusFileDebug = jsFileReload+{-# DEPRECATED juliusFileDebug "Please use juliusFileReload instead." #-}+jsFileDebug = jsFileReload+{-# DEPRECATED jsFileDebug "Please use jsFileReload instead." #-}
shakespeare-js.cabal view
@@ -1,5 +1,5 @@ name: shakespeare-js-version: 0.10.4+version: 0.11.0 license: BSD3 license-file: LICENSE author: Michael Snoyman <michael@snoyman.com>@@ -29,28 +29,48 @@ library build-depends: base >= 4 && < 5- , shakespeare >= 0.10 && < 0.11+ , shakespeare >= 0.10.3 && < 0.11 , template-haskell , text >= 0.7 && < 0.12- , process >= 1.0 && < 1.2 exposed-modules: Text.Julius Text.Coffee ghc-options: -Wall+ if impl(ghc >= 7.4)+ cpp-options: -DGHC_7_4 + if flag(test_coffee)+ cpp-options: -DTEST_COFFEE++ if flag(test_export)+ cpp-options: -DTEST_EXPORT++flag test_export+ default: False++flag test_coffee+ description: render tests through coffeescript render function+ -- cabal configure --enable-tests -ftest_coffee && cabal build && dist/build/test/test+ default: False+ test-suite test hs-source-dirs: test main-is: ../test.hs type: exitcode-stdio-1.0 ghc-options: -Wall- build-depends: shakespeare-js >= 0.10 && < 0.11- , shakespeare >= 0.10 && < 0.11+ build-depends: shakespeare-js >= 0.11 && < 0.12+ , shakespeare >= 0.10.3 && < 0.11 , base >= 4 && < 5 , HUnit , hspec >= 0.8 && < 0.10 , text >= 0.7 && < 0.12+ , template-haskell++-- cabal bug+-- if flag(test_coffee)+-- cpp-options: -DTEST_COFFEE source-repository head
test.hs view
@@ -1,5 +1,5 @@-import Test.Hspec+import Test.Hspec.Monadic import ShakespeareJsTest (specs) main :: IO ()-main = hspecX $ descriptions [specs]+main = hspecX specs
test/ShakespeareJsTest.hs view
@@ -1,13 +1,18 @@ {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE CPP #-} module ShakespeareJsTest (specs) where import Test.HUnit hiding (Test) -import Test.Hspec +import Test.Hspec.Monadic import Test.Hspec.HUnit () import Prelude hiding (reverse) +#ifdef TEST_COFFEE +import Text.Coffee +#endif import Text.Julius +import Quoter (quote, quoteFile, quoteFileReload) import Data.List (intercalate) import qualified Data.Text.Lazy as T import qualified Data.List @@ -15,78 +20,85 @@ import Data.Text (Text, pack, unpack) import Data.Monoid (mappend) -specs :: [Spec] -specs = describe "shakespeare-js" - [ it "julius" $ do - let var = "var" +join :: [String] -> String +#ifdef TEST_COFFEE +join l = (intercalate ";\n" l) +#else +join = intercalate "\n" +#endif + +specs :: Specs +specs = describe "shakespeare-js" $ do + it "julius" $ do + let var = "x=2" let urlp = (Home, [(pack "p", pack "q")]) - flip jelper [julius|שלום -#{var} -@{Home} -@?{urlp} -^{jmixin} -|] $ intercalate "\r\n" - [ "שלום" - , var - , "url" - , "url?p=q" - , "var x;" - ] ++ "\r\n" + flip jelper [quote|['שלום', @{Home}, #{var}, '@?{urlp}', ^{jmixin} ]|] + $ intercalate " " + [ "['שלום'," + , "url, " ++ var ++ "," + , "'url?p=q'," + , "f(2) ]" + ] - , it "juliusFile" $ do - let var = "var" + it "juliusFile" $ do + let var = "x=2" let urlp = (Home, [(pack "p", pack "q")]) - flip jelper $(juliusFile "test/juliuses/external1.julius") $ unlines + flip jelper $(quoteFile "test/juliuses/external1.julius") $ join [ "שלום" , var , "url" , "url?p=q" - , "var x;" - ] + , "f(2)" + ] ++ "\n" - , it "juliusFileDebug" $ do - let var = "var" + it "juliusFileReload" $ do + let var = "x=2" let urlp = (Home, [(pack "p", pack "q")]) - flip jelper $(juliusFileDebug "test/juliuses/external1.julius") $ unlines + flip jelper $(quoteFileReload "test/juliuses/external1.julius") $ join [ "שלום" , var , "url" , "url?p=q" - , "var x;" - ] + , "f(2)" + ] ++ "\n" {- TODO - , it "juliusFileDebugChange" $ do - let var = "somevar" - test result = jelper result $(juliusFileDebug "test/juliuses/external2.julius") - writeFile "test/juliuses/external2.julius" "var #{var} = 1;" - test "var somevar = 1;" - writeFile "test/juliuses/external2.julius" "var #{var} = 2;" - test "var somevar = 2;" - writeFile "test/juliuses/external2.julius" "var #{var} = 1;" - -} + it "juliusFileDebugChange" $ do + let var = "somevar" + test result = jelper result $(juliusFileDebug "test/juliuses/external2.julius") + writeFile "test/juliuses/external2.julius" "var #{var} = 1;" + test "var somevar = 1;" + writeFile "test/juliuses/external2.julius" "var #{var} = 2;" + test "var somevar = 2;" + writeFile "test/juliuses/external2.julius" "var #{var} = 1;" + -} - , it "julius module names" $ + it "julius module names" $ let foo = "foo" double = 3.14 :: Double - int = -5 :: Int in - jelper "oof oof 3.14 -5" - [julius|#{Data.List.reverse foo} #{L.reverse foo} #{show double} #{show int}|] + int = -5 :: Int + in jelper "[oof, oof, 3.14, -5]" +#ifdef TEST_COFFEE + [quote|[%{Data.List.reverse foo}, %{L.reverse foo}, %{show double}, %{show int}]|] +#else + [quote|[#{Data.List.reverse foo}, #{L.reverse foo}, #{show double}, #{show int}]|] +#endif - , it "single dollar at and caret" $ do - jelper "$@^" [julius|$@^|] - jelper "#{@{^{" [julius|#\{@\{^\{|] - +-- not valid coffeescript +#ifndef TEST_COFFEE + it "single dollar at and caret" $ do + jelper "$@^" [quote|$@^|] + jelper "#{@{^{" [quote|#\{@\{^\{|] +#endif - , it "dollar operator" $ do + it "dollar operator" $ do let val = (1 :: Int, (2 :: Int, 3 :: Int)) - jelper "2" [julius|#{ show $ fst $ snd val }|] - jelper "2" [julius|#{ show $ fst $ snd $ val}|] - ] + jelper "2" [quote|#{ show $ fst $ snd val }|] + jelper "2" [quote|#{ show $ fst $ snd $ val}|] @@ -131,10 +143,11 @@ jmixin :: JavascriptUrl u -jmixin = [julius|var x;|] +jmixin = [quote|f(2)|] jelper :: String -> JavascriptUrl Url -> Assertion -jelper res h = T.pack res @=? renderJavascriptUrl render h +jelper res h = do + T.pack res @=? renderJavascriptUrl render h instance Show Url where show _ = "FIXME remove this instance show Url"