Introduction
The pushProps(..)
is defined for propagating applicable PropDefs from one propObj
to another.
A common use case is on scheme apply, pushProps(..)
is called. It will try to push matching PropDefs from the scheme data onto your snapper.
PushProps
There are few checkings in pushProps(..)
, when all checkings pass, it will push the props correctly to the target.
Prop type check
By default the type check in pushProps(..)
will be strict type checking, it ONLY allows the same type prop to be pushed, you can customize your own type check if needed.
There are some type check classes already created in cm/props/pushPropsTypeCheck.cm
PushPropsTypeCheck -- cm.props |---ExistanceTypeCheck -- cm.props |---FlexibleTypeCheck |---NoTypeCheck |---StrictTypeCheck
Prop allow push check
The source propObj will check allowPushProp(..)
, it can determine whether the pushProp(..)
is allowed.
Basically allowPushProp(..)
could be overridden when a specific prop should not be pushed in the propObj.
/** * Allow pushing the prop from this to 'z'? * Used in pushProp as 'z' to give say in what to push. */ extend public bool allowPushProp(str key, PropObj z) { return true; }
Prop push bail check
The target propObj will check pushPropBail(..)
, it can take care of domain checking and whether it allows the prop from target propObj, you can regard it as the "allowReceiveProp" method.
/** * Push prop bail? */ extend public bool pushPropBail(str key, PropObj z, SubSet ss, Object zv, StrBuf error=null) { if (ss) return zv !in ss; if (PropDef def = propDef(key)) if (#allowPush in def.attributes) return false; return true; }
Prop changed check and put
In the end, it will check whether the prop value is changed, and execute the put(..)
if (changed) { if (pusherEnv) pushValue = pusherEnv.interpretPushValue(z, translatedKey, pushValue, receiveType); if (pushValue in PropObj) put(key, copy(pushValue), env); else put(key, pushValue, env); return true; } else if (pushValue as PropObj) { if (?PropObj v = currentValue) // Recursion into sub-prop return v.pushProps(pushValue, receiverEnv=null, pusherEnv=pusherEnv, env=env, error=error); } else { if (error) error << "(unchanged)\n"; }
PushPropsEnv
The PushPropsEnv
is an improvement of the pushProps method. There are two methods in PropObj
, called pushPropsEnv(PropObj receiver)
and pullPropsEnv(PropObj
pusher)
, which are used to control/inject into the push props protocol on the true pushing side and true receiving side. It is also known as pusherEnv
and receiverEnv
.
The env will always take priority when a pushProp(..)
is called in propObj
, some methods should ONLY be overridden either pusherEnv/receiverEnv.
PusherEnv: allowPushProp(..)
, interpretPushValue(..)
ReceiverEnv: receiveType(..)
, pipeTranslation(..)
, pushPropBail(..)
PusherEnv and ReceiverEnv: typeCheck
(ReceiverEnv typeCheck will take priority)
Uses for PushPropsEnv
private void testMoreCorePropObjPushProps(bool xtrace=false) { A a(); B b(); test b."textA" => theA; test b."textB" => theA; test b."textC" => theA; test b."textD" => theA; test b."textE" => theA; b.pushProps(a); test b."textA" => theB; // push 'theB' is allowed test b."textB" => theA; // not allowed because 'theC' is not in the domain test b."textC" => theA; // not allowed because allowNull=false test b."textD" => theA; // not allowed because allowNull=false test b."textE" => theA; // not allowed because allowNull=false b.pushProps(a, AllowNullReceiverEnv(), null); //test b."textC" => theA; // null still not allowed because it's not in the domain test b."textC" => null; // now allowed (allowNull now has priority over domain) test b."textD" => null; // now allowed (null is in oDomainWithNull) test b."textE" => null; // now allowed (no domain present) } /** * Stuff. */ private Material mWhite() { return material("white_plastic", #"cm.core"); } private Material mBrown() { return material("brown_plastic", #"cm.core"); } private Material mGold() { return material("gold", #"cm.core"); } private MaterialDomain mDomain() { return MaterialDomain({mWhite, mBrown}); } private Str theA = "A"; private Str theB = "B"; private Str theC = "C"; private ObjectSubSet oDomain() { return ObjectSubSet([theA, theB]); } private ObjectSubSet oDomainWithNull() { return ObjectSubSet([theA, theB, null.:Str]); } private class A extends CorePropObj { public props { Str "textA" v=theB; Str "textB" v=theC; Str "textC" v=null; Str "textD" v=null; Str "textE" v=null; } } private class B extends CorePropObj { public props { Str "textA" v=theA : domain=oDomain; Str "textB" v=theA : domain=oDomain; Str "textC" v=theA : domain=oDomain; Str "textD" v=theA : domain=oDomainWithNull; Str "textE" v=theA; } } private class AllowNullReceiverEnv extends PushPropsEnv { public bool allowNull(PropObj receiver, str key, Object env) { return true; } } /** * Run it! */ minitest { testMoreCorePropObjPushProps(); }
PushPropsTypeCheck
The PushPropsTypeCheck is called in pushProps(..)
of PropObj
if any. The receiver env has priority here, the push env type checker is only used if the receiver type checker is null.
An example here is DsPDataPushPropsTypeCheck
.
/** * DsPData push props type check. */ public class DsPDataPushPropsTypeCheck extends PushPropsTypeCheck { /** * Check type. */ public bool check(Type receiveType, Type pushType, StrBuf error=null) { if (pushType == str or pushType == StrArray) return true; if (pushType in DsiPDataOption) return true; return false; } }
Comments
0 comments
Please sign in to leave a comment.