hamlet 1.1.5 → 1.1.6
raw patch · 4 files changed
+72/−9 lines, 4 filesdep ~template-haskellPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: template-haskell
API changes (from Hackage documentation)
Files
- Text/Hamlet.hs +36/−2
- Text/Hamlet/Parse.hs +13/−2
- hamlet.cabal +1/−1
- test/HamletTest.hs +22/−4
Text/Hamlet.hs view
@@ -118,12 +118,46 @@ bindingPattern (BindConstr (Ident con) is) = do (patterns, scopes) <- fmap unzip $ mapM bindingPattern is return (ConP (mkName con) patterns, concat scopes)-bindingPattern (BindRecord (Ident con) fields) = do+bindingPattern (BindRecord (Ident con) fields wild) = do let f (Ident field,b) = do (p,s) <- bindingPattern b return ((mkName field,p),s) (patterns, scopes) <- fmap unzip $ mapM f fields- return (RecP (mkName con) patterns, concat scopes)+ (patterns1, scopes1) <- if wild+ then bindWildFields con $ map fst fields+ else return ([],[])+ return (RecP (mkName con) (patterns++patterns1), concat scopes ++ scopes1)++-- Wildcards bind all of the unbound fields to variables whose name+-- matches the field name.+--+-- For example: data R = C { f1, f2 :: Int }+-- C {..} is equivalent to C {f1=f1, f2=f2}+-- C {f1 = a, ..} is equivalent to C {f1=a, f2=f2}+-- C {f2 = a, ..} is equivalent to C {f1=f1, f2=a}+bindWildFields :: String -> [Ident] -> Q ([(Name, Pat)], [(Ident, Exp)])+bindWildFields conName fields = do+ fieldNames <- recordToFieldNames conName+ let available n = nameBase n `notElem` map unIdent fields+ let remainingFields = filter available fieldNames+ let mkPat n = do+ e <- newName (nameBase n)+ return ((n,VarP e), (Ident (nameBase n), VarE e))+ fmap unzip $ mapM mkPat remainingFields++-- Important note! reify will fail if the record type is defined in the+-- same module as the reify is used. This means quasi-quoted Hamlet+-- literals will not be able to use wildcards to match record types+-- defined in the same module.+recordToFieldNames :: String -> Q [Name]+recordToFieldNames conStr = do+ -- use 'lookupValueName' instead of just using 'mkName' so we reify the+ -- data constructor and not the type constructor if their names match.+ Just conName <- lookupValueName conStr+ DataConI _ _ typeName _ <- reify conName+ TyConI (DataD _ _ _ cons _) <- reify typeName+ [fields] <- return [fields | RecC name fields <- cons, name == conName]+ return [fieldName | (fieldName, _, _) <- fields] docToExp :: Env -> HamletRules -> Scope -> Doc -> Q Exp docToExp env hr scope (DocForall list idents inside) = do
Text/Hamlet/Parse.hs view
@@ -319,6 +319,8 @@ white = skipMany $ char ' ' + wildDots = string ".." >> white+ isVariable (Ident (x:_)) = not (isUpper x) isVariable (Ident []) = error "isVariable: bad identifier" @@ -351,12 +353,21 @@ guard (isConstructor c) return c choice- [ fmap (BindRecord c) (braces (recordField `sepBy` comma))+ [ record c , fmap (BindConstr c) (guard allowArgs >> many apat) , return (BindConstr c []) ] <?> "constructor" + record c = braces $ do+ (fields, wild) <- option ([], False) $ go+ return (BindRecord c fields wild)+ where+ go = (wildDots >> return ([], True))+ <|> (do x <- recordField+ (xs,wild) <- option ([],False) (comma >> go)+ return (x:xs,wild))+ recordField = do field <- ident p <- option (BindVar field) -- support punning@@ -644,7 +655,7 @@ data Binding = BindVar Ident | BindAs Ident Binding | BindConstr Ident [Binding] | BindTuple [Binding] | BindList [Binding]- | BindRecord Ident [(Ident, Binding)]+ | BindRecord Ident [(Ident, Binding)] Bool deriving (Eq, Show, Read, Data, Typeable) spaceTabs :: Parser String
hamlet.cabal view
@@ -1,5 +1,5 @@ name: hamlet-version: 1.1.5+version: 1.1.6 license: MIT license-file: LICENSE author: Michael Snoyman <michael@snoyman.com>
test/HamletTest.hs view
@@ -2,6 +2,8 @@ {-# LANGUAGE TemplateHaskell #-} module HamletTest (spec) where +import HamletTestTypes (ARecord(..)) + import Test.HUnit hiding (Test) import Test.Hspec @@ -76,6 +78,8 @@ it "hamlet tuple" caseTuple it "complex pattern" caseComplex it "record pattern" caseRecord + it "record wildcard pattern #1" caseRecordWildCard + it "record wildcard pattern #2" caseRecordWildCard1 @@ -945,13 +949,27 @@ #{a} #{b} #{c} #{e} #{f} #{g} |] -data ARecord = ARecCon { field1 :: Int, field2 :: Bool } - caseRecord :: Assertion caseRecord = do - let z = ARecCon 10 True + let z = ARecord 10 True helper "10" [hamlet| - $with ARecCon { field1, field2 = True } <- z + $with ARecord { field1, field2 = True } <- z + #{field1} + |] + +caseRecordWildCard :: Assertion +caseRecordWildCard = do + let z = ARecord 10 True + helper "10 True" [hamlet| + $with ARecord {..} <- z + #{field1} #{field2} + |] + +caseRecordWildCard1 :: Assertion +caseRecordWildCard1 = do + let z = ARecord 10 True + helper "10" [hamlet| + $with ARecord {field2 = True, ..} <- z #{field1} |]