Επιχειρηματικοί κανόνες ως κείμενο με το NEWMACRO()
Το NEWMACRO(text, [nocompile], [isasync]) μετατρέπει μερικές γραμμές μιας μικρής γλώσσας σε μια συνάρτηση function(model, helpers). Προορίζεται για κανόνες που αλλάζουν συχνότερα από τον κώδικα: μια έκπτωση, μια τιμή, έναν έλεγχο δικαιωμάτων, μια επικύρωση που κάποιος που δεν γράφει JavaScript συντηρεί σε ένα αρχείο ή σε μια βάση δεδομένων.
Η γλώσσα, όπως ελέγχθηκε:
- Τα
IF condition,ELSE IF condition,ELSEκαιFI(το τέλος της συνθήκης) λειτουργούν όπως σε έναν κανόνα βασισμένο σε κείμενο. Οι συνθήκες χρησιμοποιούν>,<,>=,<=,=καιAND/OR. - Το
RETURN valueτελειώνει το macro με μια τιμή. ΤαYESκαιNO(επίσηςTRUE,FALSE,OK) είναι λογικές τιμές, το κείμενο ανάμεσα σε εισαγωγικά είναι κείμενο και οι αριθμοί είναι αριθμοί. - Μια λέξη είναι ιδιότητα του μοντέλου, γραμμένη με πεζά: το
ageδιαβάζει τοmodel.ageκαι τοtotal = price * qtyγράφει τοmodel.total. - Το
NAME(arguments)καλεί έναν helper, τη συνάρτηση με αυτό το όνομα (με πεζά) στο αντικείμενοhelpersπου περνάτε· μέσα της τοthisείναι το μοντέλο. Με τοisasyncίσο μεtrueτο macro είναι async συνάρτηση και περιμένει τους helpers. - Το
#nameείναι μια προσωρινή μεταβλητή της εκτέλεσης:#temp = num + 1καιRETURN #temp. - Χρησιμοποιήστε ονόματα με περισσότερα γράμματα: μια ιδιότητα ή μεταβλητή ενός γράμματος δεν αναγνωρίστηκε στους ελέγχους.
Το NEWMACRO() μεταγλωττίζει το κείμενο με new Function, άρα ένα macro είναι κώδικας: μεταγλωττίστε μόνο κείμενο που γράψατε εσείς ή που συντηρεί ένα αξιόπιστο πρόσωπο, ποτέ κείμενο που έστειλε ένας επισκέπτης. Με το nocompile ίσο με true επιστρέφει το JavaScript που παράγει αντί για τη συνάρτηση, κάτι χρήσιμο για να δείτε τι κάνει ένας κανόνας.
const helpers = {
percent: function(value, rate) {
return value * rate / 100;
}
};
const age = NEWMACRO("IF age >= 18\n\tRETURN 'adult'\nELSE\n\tRETURN 'minor'\nFI");
const level = NEWMACRO("IF points > 100\n\tRETURN 'gold'\nELSE IF points > 50\n\tRETURN 'silver'\nELSE\n\tRETURN 'bronze'\nFI");
const access = NEWMACRO("IF active AND score >= 5\n\tRETURN yes\nFI\nRETURN no");
const total = NEWMACRO("total = price * qty\nIF qty >= 10\n\ttotal = total - PERCENT(total, 10)\nFI\nRETURN total");
const temporary = NEWMACRO("#next = count + 1\nRETURN #next");
const slow = NEWMACRO("RETURN LOOKUP(code)", false, true);
exports.install = function() {
ROUTE('POST /rules/', rules);
ROUTE('GET /source/', source);
};
async function rules($) {
const model = $.body;
$.json({
age: age(model, helpers),
level: level(model, helpers),
access: access(model, helpers),
total: total(model, helpers),
model_total: model.total,
temporary: temporary(model, helpers),
slow: await slow(model, { lookup: async code => 'found ' + code })
});
}
function source($) {
$.plain(NEWMACRO("IF points > 100\n\tRETURN 'gold'\nFI", true));
}