private MobiusStore<String, Integer, Long> createStore() { return MobiusStore.create( new Init<String, Long>() { @Nonnull @Override public First<String, Long> init(String model) { return First.first(model + "!", ImmutableUtil.setOf(15L, 25L, 35L)); } }, new Update<String, Integer, Long>() { @Nonnull @Override public Next<String, Long> update(String model, Integer event) { if (event == 0) { return Next.noChange(); } Set<Long> effects = Sets.newHashSet(); for (int i = 0; i < event; i++) { effects.add(10L * (i + 1)); } return Next.next(model + "->" + event, effects); } }, "init"); } }
@Nonnull public static <M, E, F> MobiusStore<M, E, F> create( Init<M, F> init, Update<M, E, F> update, M startModel) { return new MobiusStore<>(init, update, startModel); }
synchronized void update(E event) { if (!initialised) { eventsReceivedBeforeInit.add(event); return; } Next<M, F> next = store.update(event); next.ifHasModel( new Consumer<M>() { @Override public void accept(M model) { dispatchModel(model); } }); dispatchEffects(next.effects()); }
synchronized void init() { if (initialised) { throw new IllegalStateException("already initialised"); } First<M, F> first = store.init(); dispatchModel(first.model()); dispatchEffects(first.effects()); initialised = true; for (E event : eventsReceivedBeforeInit) { update(event); } }
synchronized void init() { if (initialised) { throw new IllegalStateException("already initialised"); } First<M, F> first = store.init(); dispatchModel(first.model()); dispatchEffects(first.effects()); initialised = true; for (E event : eventsReceivedBeforeInit) { update(event); } }
@Override @Nonnull public MobiusLoop<M, E, F> startFrom(M startModel) { LoggingInit<M, F> loggingInit = new LoggingInit<>(init, logger); LoggingUpdate<M, E, F> loggingUpdate = new LoggingUpdate<>(update, logger); return MobiusLoop.create( MobiusStore.create(loggingInit, loggingUpdate, checkNotNull(startModel)), effectHandler, eventSource, checkNotNull(eventRunner.get()), checkNotNull(effectRunner.get())); }
@Nonnull public static <M, E, F> MobiusStore<M, E, F> create( Init<M, F> init, Update<M, E, F> update, M startModel) { return new MobiusStore<>(init, update, startModel); }
synchronized void update(E event) { if (!initialised) { eventsReceivedBeforeInit.add(event); return; } Next<M, F> next = store.update(event); next.ifHasModel( new Consumer<M>() { @Override public void accept(M model) { dispatchModel(model); } }); dispatchEffects(next.effects()); }
@Override @Nonnull public MobiusLoop<M, E, F> startFrom(M startModel) { LoggingInit<M, F> loggingInit = new LoggingInit<>(init, logger); LoggingUpdate<M, E, F> loggingUpdate = new LoggingUpdate<>(update, logger); return MobiusLoop.create( MobiusStore.create(loggingInit, loggingUpdate, checkNotNull(startModel)), effectHandler, eventSource, checkNotNull(eventRunner.get()), checkNotNull(effectRunner.get())); }
mobiusStore = MobiusStore.create(init, update, "init");
@Test public void shouldProcessInitBeforeEventsFromEventSource() throws Exception { mobiusStore = MobiusStore.create(m -> First.first("First" + m), update, "init"); eventSource = new EventSource<TestEvent>() { @Nonnull @Override public Disposable subscribe(Consumer<TestEvent> eventConsumer) { eventConsumer.accept(new TestEvent("1")); return new Disposable() { @Override public void dispose() { // do nothing } }; } }; setupWithEffects(new FakeEffectHandler(), immediateRunner); // in this scenario, the init and the first event get processed before the observer // is connected, meaning the 'Firstinit' state is never seen observer.assertStates("Firstinit->1"); }
mobiusStore = MobiusStore.create(init, update, "init"); TestWorkRunner testWorkRunner = new TestWorkRunner();
@Test public void shouldProcessInitBeforeEventsFromEffectHandler() throws Exception { mobiusStore = MobiusStore.create(m -> First.first("I" + m), update, "init"); // when an effect handler that emits events before returning the connection setupWithEffects( new Connectable<TestEffect, TestEvent>() { @Nonnull @Override public Connection<TestEffect> connect(Consumer<TestEvent> output) throws ConnectionLimitExceededException { output.accept(new TestEvent("1")); return new SimpleConnection<TestEffect>() { @Override public void accept(TestEffect value) { // do nothing } }; } }, immediateRunner); // in this scenario, the init and the first event get processed before the observer // is connected, meaning the 'Iinit' state is never seen observer.assertStates("Iinit->1"); }