Snap: compiled splices code example

こ雲淡風輕ζ 提交于 2019-12-04 11:26:26

Let's say you want to display information about a list of persons using compiled splices (assume that we start from the scaffolding generated by snap init.)

A very simple _persons.tpl template with dummy values would be something like

<body>
    <person>
        <div>
            <h1><name>dummy name</name></h1>
            <p><age>77</age></p> 
            <p><location>jauja</location></p> 
        </div>
    </person>
</body>

Where person, name, age, and location are the tags to be spliced.

We define a trivial Snaplet that holds the info

data Foo = Foo
    {
        _persons :: [Person]
    }

makeLenses ''Foo

data Person = Person
    {
        _name :: Text
    ,   _age :: Int
    ,   _location :: Text
    }   

makeLenses ''Person

and we add it to the App record:

data App = App
    { _heist :: Snaplet (Heist App)
    , _sess :: Snaplet SessionManager
    , _auth :: Snaplet (AuthManager App)
    , _foo :: Snaplet Foo
    }

we add the following to the app initializer

f <- nestSnaplet "foo" foo $ makeSnaplet "foo" "Foo Snaplet" Nothing $ return $ Foo $ 
        [ Person "Ricardo" 33 "Los Cantones" 
        , Person "Luis" 38 "Montealto" 
        ]

...

return $ App h s a f

This function constructs a Handler that returns the list of persons (using view from Control.Lens):

personH :: SnapletLens b Foo -> Handler b b [Person] 
personH l = withTop l $ view persons <$> get 

This function constructs the appropiate compiled splice from a RuntimeSplice that produces a list of Persons. RuntimeSplices represent information that can only be known at run time, as opposed to load time:

personSplice :: Monad n => RuntimeSplice n [Person] -> C.Splice n
personSplice = C.manyWithSplices C.runChildren splicefuncs 
    where
    splicefuncs = mconcat  
        [ "name" ## (C.pureSplice . C.textSplice $ view name)
        , "age" ## (C.pureSplice . C.textSplice $ T.pack . show . view age)
        , "location" ## (C.pureSplice . C.textSplice $ view location)
        ]

And this function can be used to register the splice in the global Heist configuration. Notice that we lift the Handler into a RuntimeSplice:

addPersonSplices :: HasHeist b => Snaplet (Heist b) -> 
                                  SnapletLens b Foo -> 
                                  Initializer b v ()
addPersonSplices h l = addConfig h $ mempty 
   {
      hcCompiledSplices = "person" ## (personSplice . lift $ personH l) 
   } 

Be sure to add this line to the app initializer:

addPersonSplices h foo

And to add the following pair to the app's routes:

("/persons",  cRender "_persons")

If you now run the server, navigating to http://127.0.0.1:8000/persons should show the list.

UPDATE

For the simpler case (no complex records, no lenses) in which you only want to show a list of strings.

The template could be something like:

<body>
    <strings>
        <p><string>dummy value</string></p>
    </strings>
</body>

The top-level splice would be:

stringSplice :: Monad n => C.Splice n
stringSplice = C.manyWithSplices C.runChildren splicefuncs (return ["aa","bb","cc"])
    where
    splicefuncs = "string" ## (C.pureSplice . C.textSplice $ id)

This means "when we encounter the tag associated to this splice, perform an action that produces a list of strings, and for each string, render the contents of the tag, substituting the current string for the string tag".

Notice that the signature of manyWithSplices forces the stuff to the right of the (##) to have type RuntimeSplice n Text -> Splice n. Here id has type Text -> Text. C.TextSplice transforms it into something of type Text -> Builder, and C.pureSplice performs the final transformation into a RuntimeSplice n Text -> Splice n.

In place of (return ["aa","bb","cc"]) you could provide a more complex action that connected a database and extracted the strings form there.

A function to register this splice would be:

addStringSplices :: HasHeist b => Snaplet (Heist b) -> Initializer b v ()
addStringSplices h = addConfig h $ mempty 
    {
          hcCompiledSplices = "strings" ## stringSplice
    }  
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!