!7
sinterface IBEAReactor {
A uniqResult(Class c, O... params);
}
extend BEAObject {
bool canReactWith(BEAObject o) {
ret isInstanceOfAny(o, (Cl) reactableWithClasses());
}
Cl> reactableWithClasses() {
ret (Cl) collectFirstMethodArguments(findMethodsNamed_nonSynthetic(this, "reactWith"));
}
}
beaConcept BReactor {}
beaConcept BInput {
S text;
toString { ret "[\*id*/] Input " + quote(text); }
}
beaConcept BOutput {
S text;
toString { ret "[\*id*/] Output " + quote(text); }
}
beaConcept BPattern {
S text;
toString { ret "[\*id*/] " + shortDynName(this) + " " + quote(text); }
void reactWith(BInput input, IBEAReactor reactor) {}
@Override Map _fieldMigrations() {
ret litmap(pattern := new FieldMigration("text"));
}
}
beaConcept BStarPattern > BPattern {
void reactWith(BInput input, IBEAReactor reactor) {
LS mapping = matchesToStringList(flexMatchIC_first(text, input.text));
if (mapping == null) ret;
reactor.uniqResult(BEAObject,
type := "match",
+input,
pattern := this,
+mapping);
}
}
beaConcept BAngleVarPattern > BPattern {
void reactWith(BInput input, IBEAReactor reactor) {
SS mapping = flexMatchAngleBracketVarsIC_first(text, input.text);
if (mapping == null) ret;
uniqPeer BEAObject(this,
type := "match",
+input,
pattern := this,
+mapping);
}
}
beaConcept BMatch {
new Ref pattern;
SS mapping;
}
beaConcept BMatchToScenario {
void reactWith(BMatch match, IBEAReactor reactor) {
reactor.uniqResult(BEAObject,
type := "scenario",
text := mapToLines(match.mapping,
(a, b) -> format_curly("* is a *.", a, b));
}
}
beaConcept BScenarioToOutput {
bool canReactWith(BEAObject o) {
ret o.typeIs("scenario");
}
void reactWith(BEAObject scenario, IBEAReactor reactor) {
reactor.uniqResult(BOutput,
type := "Output",
text := getString text(scenario));
}
}
concept Reactable {
BEAObject a, b;
}
cmodule2 > DynCRUD_v2 {
S input = "UBports community delivers 'second-largest release of Ubuntu Touch ever'", output;
transient new BEAUtils beaUtils;
transient new Concepts reactableConcepts;
transient ReliableSingleThread rstUpdateReactables = dm_rstWithDelay(this, 100, r updateReactables);
{ tableFontSize = 15; }
start {
crud.humanizeFieldNames = false;
crud.showBackRefs = true;
crud.specialFieldsForItem = a -> {
MapSO map = litorderedmap(crud.hID, str(a.id));
S j = crud.javaClassDescForItem(a);
mapPut(map, "Class/Type", joinUniqueNemptiesCI("/", j, a.type()));
ret map;
};
crud.itemToMap_inner = a -> {
MapSO map = crud.itemToMap_inner_base(a);
map.remove("type");
ret map;
};
onConceptChangesAndNow(rstUpdateReactables);
thread {
uniq BMatchToScenario();
uniq BScenarioToOutput();
//uniq BPattern(text := "* delivers *");
uniq BAngleVarPattern(text := " delivers ");
}
}
visualize {
JComponent c = jvsplit(0.2, jhsplit(jCenteredSection("Input",
withRightAlignedButtons(
dm_wordWrapTextArea input(),
"Load input", rThreadEnter loadInput)),
dm_wordWrapTextAreaAsSection output()),
jvsplit(0.75,
jCenteredSection("Objects", super.visualize()),
jCenteredSection("Reactables",
withRightAlignedButtons(
new JConceptsTable(reactableConcepts, Reactable),
"React all", rThreadEnter reactAll))));
tablePopupMenuFirst(table(), (menu, row) -> {
BEAObject o = getItem(row);
print("Item: " + o);
if (o == null) ret;
Class extends BEAObject> targetClass = beaUtils.defaultCustomClass(o);
print(+targetClass);
if (targetClass != null && targetClass != _getClass(o)) pcall-short {
beaUtils.migrateConceptToClass(targetClass, o);
addMenuItem(menu, "Convert to " + shortName(targetClass), r {
replaceConceptAndUpdateRefs(o, beaUtils.migrateConceptToClass(targetClass, o));
});
}
pcall {
L partners = filter(list(BEAObject),
partner -> o.canReactWith(partner));
if (nempty(partners))
addScrollingSubMenu(menu, "React with", menu2 -> {
for (BEAObject p : partners)
addMenuItem(menu2, str(p), rThread {
new BEAReactor("User reacts " + o + " with " + p).react(o, p);
});
});
}
});
addButton("Delete reactors", rThreadEnter deleteReactors);
ret c;
} // end of visualize
class BEAReactor {
BReactor reactorConcept;
*(S purpose) {
reactorConcept = cnew BReactor(+purpose);
}
void react(BEAObject a, BEAObject b) {
call(a, 'reactWith, b, new IBEAReactor {
public A uniqResult(Class c, O... params) {
A product = uniq(c, paramsPlus(params,
_reactor := reactorConcept,
_fromReaction := ll(a, b)));
onReactionProduct(product);
ret product;
}
});
}
}
void onReactionProduct(BEAObject a) pcall {
if (a.typeIs("output"))
setField(output := getStringOpt text(a));
}
void deleteReactors {
deleteConcepts(BEAObject,
o -> cget _reactor(o) != null || o.typeIs("reactor"));
}
void updateReactables {
deleteConcepts(reactableConcepts);
L objects = list(BEAObject);
for (BEAObject a : objects)
for (BEAObject b : filter(objects, b -> a.canReactWith(b)))
cnew(reactableConcepts, Reactable, +a, +b);
}
void reactAll {
Cl l = list(reactableConcepts, Reactable);
if (empty(l)) ret;
BEAReactor reactor = new("User clicks \"react all\"");
for (Reactable r : l) pcall {
reactor.react(r.a, r.b);
}
}
void loadInput {
deleteReactors();
deleteConcepts(BInput);
uniq BInput(text := input);
}
}