!7 concept BInput > BEAObject { S text; toString { ret "[\*id*/] Input " + quote(text); } } concept BPattern > BEAObject { S pattern; toString { ret "[\*id*/] " + shortDynName(this) + " " + quote(pattern); } void reactWith(BInput input) {} } concept BStarPattern > BPattern { void reactWith(BInput input) { LS mapping = matchesToStringList(flexMatchIC_first(pattern, input.text)); if (mapping == null) ret; uniq BEAObject( type := "match", +input, pattern := this, +mapping); } } concept BAngleVarPattern > BPattern { void reactWith(BInput input) { SS mapping = flexMatchAngleBracketVarsIC_first(pattern, input.text); if (mapping == null) ret; uniq BEAObject( type := "match", +input, pattern := this, +mapping); } } concept BMatch { new Ref pattern; SS mapping; } cmodule2 > DynCRUD_v2 { transient Map> beaClasses = calcBeaClasses(); start { print(+beaClasses); crud.specialFieldsForItem = a -> { MapSO map = litorderedmap(crud.hID, str(a.id)); S j = crud.javaClassDescForItem(a); S type = getStringOpt type(a); mapPut(map, "Class/Type", joinUniqueNemptiesCI("/", j, type)); ret map; }; thread { uniq BInput(text := "UBports community delivers 'second-largest release of Ubuntu Touch ever'"); //uniq BPattern(pattern := "* delivers *"); uniq BAngleVarPattern(pattern := " delivers "); reactAll(); } } void reactAll { for (BPattern p) for (BInput i) pcall { p.reactWith(i); } } // e.g. "Input" => BInput Map> calcBEAClasses() { ret ciMapToKeys(c -> dropPrefix("B", shortClassName(c)), listMinusItem(BEAObject, myNonAbstractClassesImplementing(BEAObject))); } OrError migrateConceptToClass(Class c, BEAObject in) { try-OrError { A out = unlisted(c); for (S field : conceptFields(in)) { continue if eq(field, "type"); cset(out, cget(in, field)); // TODO: check Ref types } ret OrError.ok(out); } } }