J'ai un JSON arbitraire (E) créé et envoyé sur le fil du client au serveur dans mon application Meteor. Il utilise RegExp
objets RegExp
pour mettre en zéro les résultats:
# on the client selector = "roles.user": { "$ne": null } "profile.email": /^admin@/gi
Tout est dandy bien du côté du client, mais si je le passe sur le serveur via Meteor.call
ou Meteor.subscribe
, le JSON résultant (E) prend cette forme:
# on the server selector = "roles.user": { "$ne": null } "profile.email": {}
… et quelque part un ingénieur meurt un peu à l'intérieur.
Il existe de nombreuses ressources sur le Web expliquant pourquoi RegEx est non JSON.stringify
via JSON.stringify
/ JSON.parse
ou les méthodes EJSON
équivalentes.
Je ne suis pas convaincu. La sérialisation RegEx est impossible. Alors, comment peut-on faire?
Après avoir examiné ce HowTo et les Meteor EJSON Docs , nous pouvons sérialiser RegEx à l'aide de la méthode EJSON.addType
.
Prolongez RegExp – Fournissez RegExp avec les méthodes EJSON.addType
pour la mise en œuvre.
RegExp::options = -> opts = [] opts.push 'g' if @global opts.push 'i' if @ignoreCase opts.push 'm' if @multiline return opts.join('') RegExp::clone = -> self = @ return new RegExp(self.source, self.options()) RegExp::equals = (other) -> self = @ if other isnt instanceOf RegExp return false return EJSON.stringify(self) is EJSON.stringify(other) RegExp::typeName = -> return "RegExp" RegExp::toJSONValue = -> self = @ return { 'regex': self.source 'options': self.options() }
Appelez EJSON.addType – Faites-le n'importe où. Il est préférable de le rendre disponible pour le client et le serveur. Cela va désérialiser l'objet défini dans toJSONValue
ci-dessus.
EJSON.addType "RegExp", (value) -> return new RegExp(value['regex'], value['options'])
Test dans votre console – Ne prenez pas ma parole pour cela. Voir par vous-même.
> o = EJSON.stringify(/^Mooo/ig) "{"$type":"RegExp","$value":{"regex":"^Mooo","options":"ig"}}" > EJSON.parse(o) /^Mooo/gi
Et là, vous avez un RegExp sérialisé et analysé sur le client et le serveur, capable de passer sur le fil, enregistré dans une session, et même éventuellement stocké dans une collection de requêtes!
EDITER à ajouter IE10 + Erreur: L'affectation aux propriétés en lecture seule n'est pas autorisée en mode strict. Avec l'aimable autorisation de @Tim Fletcher dans les commentaires
import { EJSON } from 'meteor/ejson'; function getOptions(self) { const opts = []; if (self.global) opts.push('g'); if (self.ignoreCase) opts.push('i'); if (self.multiline) opts.push('m'); return opts.join(''); } RegExp.prototype.clone = function clone() { return new RegExp(this.source, getOptions(this)); }; RegExp.prototype.equals = function equals(other) { if (!(other instanceof RegExp)) return false; return EJSON.stringify(this) === EJSON.stringify(other); }; RegExp.prototype.typeName = function typeName() { return 'RegExp'; }; RegExp.prototype.toJSONValue = function toJSONValue() { return { regex: this.source, options: getOptions(this) }; }; EJSON.addType('RegExp', value => new RegExp(value.regex, value.options));
Il existe une solution beaucoup plus simple: stringify votre RegExp via .toString()
, l'envoyer au serveur et ensuite l'analyser dans RegExp.