Sunday, March 26, 2023
Learning Code
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#
No Result
View All Result
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#
No Result
View All Result
Learning Code
No Result
View All Result
Home Swift

Custom Leaf tags in Vapor 4

learningcode_x1mckf by learningcode_x1mckf
September 21, 2022
in Swift
0
Custom Leaf tags in Vapor 4
74
SHARES
1.2k
VIEWS
Share on FacebookShare on Twitter


2020/06/04

On this article I will present you methods to create some helpful customized tags for the Leaf template engine, written in Swift.

Vapor

The way to lengthen Leaf?

With the rebirth of Leaf we will really lengthen the template engine and customized tags are only a factor of the previous. You already know in earlier variations of Leaf every thing was known as a tag and there was no differentiation between these little bastards beginning with the # image. Now issues have modified. There are a lot of completely different entities in Leaf Tau.

  • Blocks (e.g. #for, #whereas, #if, #elseif, #else)
  • Features (e.g. #Date, #Timestamp, and so on.)
  • Strategies (e.g. .rely(), .isEmpty, and so on.)

This can be a great point and on high of this you’ll be able to create your very personal features, strategies and even blocks. This brings us to a completely extensible template engine that may render every thing in a non-blocking asynchronous means. How cool is that? 😎

Did I point out that Leaf you’ll be able to lengthen the context with customized LeafDataGenerators? Sure, that is a factor now, previously you can use the userInfo object to set a “international” accessible variable in Leaf, that was properly accessible in each single template file.

Now there are some particular variables accessible which you can lengthen:

The present context in fact is what you go to your template utilizing the render methodology written in Swift. It’s price to say that self is simply an alias to the present $context, so it would not issues which one you employ. The $app and $req scopes are empty by design, however you’ll be able to lengthen them. You’ll be able to even register your individual scope for instance $api and set every thing you want globally beneath that variable. I will present you ways to do that in a while.

As you’ll be able to see there are many choices accessible to increase Leaf. It’s a must to suppose twice which path you are taking, but it surely’s nice that we have now this many alternatives. Now we’ll stroll by of every of these items and I will present you methods to write customized extensions for Leaf Tau. 🥳



The way to lengthen Leaf contexts?

One of the simple means of extending Leaf is to offer customized context variables. We will simply write an extension for the Software and the Request object and return LeafDataGenerator values with particular keys and in a while we will register these as further context variables.


import Vapor
import Leaf

extension Software 
    var customLeafVars: [String: LeafDataGenerator] 
        [
            "isDebug": .lazy(LeafData.bool(!self.environment.isRelease && self.environment != .production))
        ]
    


extension Request 
    var customLeafVars: [String: LeafDataGenerator] 
        [
            "url": .lazy([
                        "isSecure": LeafData.bool(self.url.scheme?.contains("https")),
                        "host": LeafData.string(self.url.host),
                        "port": LeafData.int(self.url.port),
                        "path": LeafData.string(self.url.path),
                        "query": LeafData.string(self.url.query)
                    ]),
        ]
    


A LeafDataGenerator object may be lazy or speedy. Rapid values will probably be saved immediately, alternatively lazy values will produce generator blocks which might be going to be known as solely when the renderer wants them. Nothing particular, this works just like the lazy key phrase in Swift.


struct ScopeExtensionMiddleware: Middleware 

    func reply(to req: Request, chainingTo subsequent: Responder) -> EventLoopFuture<Response> 
        do 
            attempt req.leaf.context.register(turbines: req.utility.customLeafVars, toScope: "app")
            attempt req.leaf.context.register(turbines: req.customLeafVars, toScope: "req")
        
        catch 
            return req.eventLoop.future(error: error)
        
        return subsequent.reply(to: req)
    


We want an extension middleware that registers our generator variables to the given scope.


public func configure(_ app: Software) throws 

    app.middleware.use(ScopeExtensionMiddleware())

    

Attempt to print these values in a template file, you’ll be able to entry child-values utilizing the dot notation.

#(self)
#($context)

#($app)
#($app.isDebug)

#($req)
#($req.url)
#($req.url.host)
#($req.url.isSecure)
#($req.url.path)
#($req.url.port)
#($req.url.question)

Now we’re going to create a customized context to get some details about the host machine.

last class ServerLeafContextGenerator: LeafContextPublisher 

    var osName: String 
        #if os(macOS)
        return "macOS"
        #elseif os(Linux)
        return "Linux"
        #elseif os(Home windows)
        return "Home windows"
        #else
        return "Unknown"
        #endif
        
    

    lazy var leafVariables: [String: LeafDataGenerator] = [
        "os": .lazy([
            "name": LeafData.string(self.osName),
            "version": LeafData.string(ProcessInfo.processInfo.operatingSystemVersionString),
        ]),
        "cpu-cores": .speedy(ProcessInfo.processInfo.processorCount),
        "reminiscence": .speedy(ProcessInfo.processInfo.physicalMemory),
    ]

We will merely put this line subsequent to the opposite two within the scope extension middleware.

attempt req.leaf.context.register(turbines: ServerLeafContextGenerator().leafVariables, toScope: "server")

This fashion we will get some more information in regards to the server in our Leaf templates by utilizing the $server scope. One other means is to increase a scope regionally with a generator.

app.get("server-info")  req -> EventLoopFuture<View> in
    var context: LeafRenderer.Context = [
        "title": "Server info",
    ]
    attempt context.register(object: ServerLeafContextGenerator(), toScope: "server")
    return req.leaf.render(template: "server-info", context: context)

The distinction is that within the second case the server scope is simply accessible for a single endpoint, but when we register it by the middleware then it may be reached globally in each single Leaf file.

I feel scopes are very helpful, particularly Request associated ones. Previously we needed to create a customized Leaf tag to get the trail, however now we will use a scope extension and this data will probably be accessible in every single place. With the lazy load we additionally get some free efficiency enhancements.



Customized Leaf features and strategies

You’ll be able to create customized features and strategies for Leaf, I might say that this new API is the replacemenet of the outdated tag system. There are some variations and at first sight you may suppose that it is tougher to create a perform with the brand new instruments, however in time you will get used to it.


public struct Hey: LeafFunction, StringReturn, Invariant 
    public static var callSignature: [LeafCallParameter]  [.string] 

    public func consider(_ params: LeafCallValues) -> LeafData 
        guard let identify = params[0].string else 
            return .error("`Hey` have to be known as with a string parameter.")
        
        return .string("Hey (identify)!")
    

This can be a very fundamental perform. Each single perform has a name signature, which is only a record of type-safe arguments. Features can have return sorts, thankfully there are pre-made protocols for these, so you do not have to implement the required stuff, however you’ll be able to say that this features is e.g. a StringReturn perform. Invariant signifies that the perform will at all times return the identical output for a similar enter. That is what you need more often than not, it additionally lets you keep away from side-effects.

Within the consider perform you may get entry to all of the enter parameters and you need to return with a LeafData kind. If a parameter is lacking or it might probably’t be casted to the correct kind you’ll be able to at all times return with an error. Consider is wish to the outdated render methodology, but it surely’s far more superior.

LeafConfiguration.entities.use(Hey(), asFunction: "Hey")

You additionally must register this newly created perform beneath a give identify.

#Hey("Leaf Tau")

Oh by the way in which strategies are simply particular features so you’ll be able to construct them the identical means and register them by way of the asMethod: property. If you wish to see extra examples, it’s best to check out my different submit about what’s new in Leaf Tau or scroll all the way down to the final part of this text.



The way to construct customized Leaf blocks?

This can be a very fascinating and sophisticated matter. Blocks are particular type of LeafFunctions, similar to strategies, however issues are just a bit bit extra sophisticated on this case. Instance time:

import Vapor
import Leaf


struct MaybeBlock: LeafBlock, VoidReturn, Invariant 
    
    static var parseSignatures: ParseSignatures? = nil
    static var evaluable: Bool = false
    var scopeVariables: [String]? = nil

    static var callSignature: [LeafCallParameter]  [.double(labeled: "chance")] 
         
    static func instantiate(_ signature: String?, _ params: [String]) throws -> MaybeBlock  .init() 

    mutating func evaluateScope(_ params: LeafCallValues, _ variables: inout [String: LeafData]) -> EvalCount 
        params[0].double! > Double.random(in: 0..<1) ? .as soon as : .discard
    
    
    mutating func reEvaluateScope(_ variables: inout [String : LeafData]) -> EvalCount 
        fatalError("Error: `Possibly` blocks cannot be re-evaluated.")
    


This block has a name signature with a labeled argument known as likelihood. It has an instantiate methodology which is utilized by the Leaf engine to create this block. It will not have any parseSignatures or scope variables, we’ll depart that for the for block (go and examine the supply in LeafKit in case you are curious & courageous sufficient). We set evaluable to false since we do not wish to make it callable by way of the #consider perform. Now let’s discuss scope analysis actual fast.

The evaluateScope methodology will probably be known as first when the block inside your template will get evaluated. It’s a must to return an EvalCount on this methodology, which is able to determine what number of instances ought to we print out the contents in between your block (#[name]:THIS PART#finish[name]).

Principally when a LeafBlock is evaluated the primary time, it is by way of evaluateScope. If that returns a consequence moderately than nil, any additional calls will use reEvaluateScope as an alternative. – tdotclare

If EvalCount is about to discard then the contents will probably be discarded, in any other case it will be evaluated as many instances as you come back. If the rely is .as soon as meaning the top of the story, but when it get’s evaluated a number of instances and you do not want further params for additional analysis, then the reEvaluateScope will probably be known as for all the opposite cycles.


LeafConfiguration.entities.use(MaybeBlock.self, asBlock: "perhaps")


Do not forget that we have now to register this block with a given identify earlier than we may use it.


#perhaps(likelihood: 0.5):
    <p>Is that this going to occur? 50-50.</p>
#endmaybe


That is it, we have simply prolonged Leaf with a fundamental block, you’ll be able to attempt to construct your individual A/B testing Chained block if you wish to dig deeper, however that is fairly a complicated matter and there are not any docs accessible simply but so you’ve gotten to try the LeafKit supply recordsdata in many of the instances.




Helpful Leaf extensions.

I’ve made a bunch of helpful Leaf extensions accessible beneath the LeafFoundation repository. It is a work-in-progress mission, however hopefully it’ll comprise lot extra fascinating extensions by the point Leaf 4 will probably be formally launched. PR’s are welcomed. 😬




Source link

You might also like

Introducing – AI Utils for macOS

Encoding and decoding data using the Hummingbird framework

Hummingbird routing and requests – The.Swift.Dev.

Share30Tweet19
learningcode_x1mckf

learningcode_x1mckf

Recommended For You

Introducing – AI Utils for macOS

by learningcode_x1mckf
March 24, 2023
0
Introducing – AI Utils for macOS

⚠️ REQUIRES a FREE OpenAI API key. You will get one utilizing this hyperlink. ⚠️ Improve your productiveness with our AI powered utility application. - accessible...

Read more

Encoding and decoding data using the Hummingbird framework

by learningcode_x1mckf
March 22, 2023
0
Encoding and decoding data using the Hummingbird framework

HTTP is all about sending and receiving information over the community. Initially it was solely utilized to switch HTML paperwork, however these days we use HTTP to switch...

Read more

Hummingbird routing and requests – The.Swift.Dev.

by learningcode_x1mckf
March 17, 2023
0
Hummingbird routing and requests – The.Swift.Dev.

Routing on the server facet means the server goes to ship a response primarily based on the URL path that the consumer referred to as when firing up...

Read more

Building a Scrollable Custom Tab Bar in SwiftUI

by learningcode_x1mckf
March 10, 2023
0
Building a Scrollable Custom Tab Bar in SwiftUI

Whether or not you’re making a social media app or a productiveness device, the tab bar interface can improve the consumer expertise by making it extra intuitive and...

Read more

Beginner’s guide to server-side Swift using the Hummingbird framework

by learningcode_x1mckf
March 8, 2023
0
Beginner’s guide to server-side Swift using the Hummingbird framework

Swift on the Server in 2023 Three years in the past I began to focus on Vapor, the preferred web-framework written in Swift, which served me very...

Read more
Next Post
Reach Android/iOS with JavaScript, HTML and CSS — Visual Studio Magazine

Reach Android/iOS with JavaScript, HTML and CSS -- Visual Studio Magazine

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Related News

Companies are battling over Java developers. CEO and CTO provide job-search advice | by Divyesh Dharaiya | Nov, 2022

Companies are battling over Java developers. CEO and CTO provide job-search advice | by Divyesh Dharaiya | Nov, 2022

November 4, 2022
Is Java Ready for Cloud Native Computing?

Is Java Ready for Cloud Native Computing?

October 12, 2022
Filter JavaScript objects the easy way with Arquero

Filter JavaScript objects the easy way with Arquero

November 16, 2022

Browse by Category

  • C#
  • C++
  • Java
  • JavaScript
  • Python
  • Swift

RECENT POSTS

  • 2023 Java roadmap for developers – TheServerSide.com
  • YS Jagan launches Ragi Java in Jagananna Gorumudda, says focused on intellectual development of students – The Hans India
  • Disadvantages of Java – TheServerSide.com

CATEGORIES

  • C#
  • C++
  • Java
  • JavaScript
  • Python
  • Swift

© 2022 Copyright Learning Code

No Result
View All Result
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#

© 2022 Copyright Learning Code

Are you sure want to unlock this post?
Unlock left : 0
Are you sure want to cancel subscription?