From 262a4d5da6519fc0c5cf5bc29229b8cedfdfffdf Mon Sep 17 00:00:00 2001 From: Steve Howell Date: Wed, 5 Apr 2017 20:40:40 -0700 Subject: [PATCH] Create topic_generator.js. --- frontend_tests/node_tests/topic_generator.js | 133 +++++++++++++++++ static/js/topic_generator.js | 141 +++++++++++++++++++ 2 files changed, 274 insertions(+) create mode 100644 frontend_tests/node_tests/topic_generator.js create mode 100644 static/js/topic_generator.js diff --git a/frontend_tests/node_tests/topic_generator.js b/frontend_tests/node_tests/topic_generator.js new file mode 100644 index 0000000000..2814822f9e --- /dev/null +++ b/frontend_tests/node_tests/topic_generator.js @@ -0,0 +1,133 @@ +var tg = require('js/topic_generator.js'); + +function is_even(i) { return i % 2 === 0; } +function is_odd(i) { return i % 2 === 1; } + +(function test_basics() { + var gen = tg.list_generator([10, 20, 30]); + assert.equal(gen.next(), 10); + assert.equal(gen.next(), 20); + assert.equal(gen.next(), 30); + assert.equal(gen.next(), undefined); + assert.equal(gen.next(), undefined); + + var gen1 = tg.list_generator([100, 200]); + var gen2 = tg.list_generator([300, 400]); + var outers = [gen1, gen2]; + gen = tg.chain(outers); + assert.equal(gen.next(), 100); + assert.equal(gen.next(), 200); + assert.equal(gen.next(), 300); + assert.equal(gen.next(), 400); + assert.equal(gen.next(), undefined); + assert.equal(gen.next(), undefined); + + gen = tg.wrap([5, 15, 25, 35], 25); + assert.equal(gen.next(), 25); + assert.equal(gen.next(), 35); + assert.equal(gen.next(), 5); + assert.equal(gen.next(), 15); + assert.equal(gen.next(), undefined); + assert.equal(gen.next(), undefined); + + gen = tg.wrap_exclude([5, 15, 25, 35], 25); + assert.equal(gen.next(), 35); + assert.equal(gen.next(), 5); + assert.equal(gen.next(), 15); + assert.equal(gen.next(), undefined); + assert.equal(gen.next(), undefined); + + gen = tg.wrap([5, 15, 25, 35], undefined); + assert.equal(gen.next(), 5); + + gen = tg.wrap_exclude([5, 15, 25, 35], undefined); + assert.equal(gen.next(), 5); + + gen = tg.wrap([5, 15, 25, 35], 17); + assert.equal(gen.next(), 5); + + gen = tg.wrap([], 42); + assert.equal(gen.next(), undefined); + + var ints = tg.list_generator([1, 2, 3, 4, 5]); + gen = tg.filter(ints, is_even); + assert.equal(gen.next(), 2); + assert.equal(gen.next(), 4); + assert.equal(gen.next(), undefined); + assert.equal(gen.next(), undefined); + + ints = tg.list_generator([]); + gen = tg.filter(ints, is_even); + assert.equal(gen.next(), undefined); + assert.equal(gen.next(), undefined); + +}()); + +(function test_fchain() { + var mults = function (n) { + var ret = 0; + return { + next: function () { + ret += n; + return (ret <= 100) ? ret : undefined; + }, + }; + }; + + var ints = tg.list_generator([29, 43]); + var gen = tg.fchain(ints, mults); + assert.equal(gen.next(), 29); + assert.equal(gen.next(), 58); + assert.equal(gen.next(), 87); + assert.equal(gen.next(), 43); + assert.equal(gen.next(), 86); + assert.equal(gen.next(), undefined); + assert.equal(gen.next(), undefined); + + ints = tg.wrap([33, 34, 37], 37); + ints = tg.filter(ints, is_odd); + gen = tg.fchain(ints, mults); + assert.equal(gen.next(), 37); + assert.equal(gen.next(), 74); + assert.equal(gen.next(), 33); + assert.equal(gen.next(), 66); + assert.equal(gen.next(), 99); + assert.equal(gen.next(), undefined); + assert.equal(gen.next(), undefined); + +}()); + + +(function test_topics() { + var streams = [1, 2, 3, 4]; + var topics = {}; + + topics[1] = ['read', 'read', '1a', '1b', 'read', '1c']; + topics[2] = []; + topics[3] = ['3a', 'read', 'read', '3b', 'read']; + topics[4] = ['4a']; + + function has_unread_messages(stream, topic) { + return topic !== 'read'; + } + + function get_topics(stream) { + return topics[stream]; + } + + function next_topic(curr_stream, curr_topic) { + return tg.next_topic( + streams, + get_topics, + has_unread_messages, + curr_stream, + curr_topic); + } + + assert.equal(next_topic(1, '1a'), '1b'); + assert.equal(next_topic(1, undefined), '1a'); + assert.equal(next_topic(2, 'bogus'), '3a'); + assert.equal(next_topic(3, '3b'), '3a'); + assert.equal(next_topic(4, '4a'), '1a'); + assert.equal(next_topic(undefined, undefined), '1a'); +}()); diff --git a/static/js/topic_generator.js b/static/js/topic_generator.js new file mode 100644 index 0000000000..3e74b2b00c --- /dev/null +++ b/static/js/topic_generator.js @@ -0,0 +1,141 @@ +var topic_generator = (function () { + +var exports = {}; + +exports.sub_list_generator = function (lst, lower, upper) { + // lower/upper has Python range semantics so if you pass + // in lower=5 and upper=8, you get elements 5/6/7 + var i = lower; + + return { + next: function () { + if (i >= upper) { + return; + } + var res = lst[i]; + i += 1; + return res; + }, + }; +}; + +exports.list_generator = function (lst) { + return exports.sub_list_generator(lst, 0, lst.length); +}; + +exports.fchain = function (outer_gen, get_inner_gen) { + var outer_val = outer_gen.next(); + var inner_gen; + + return { + next: function () { + while (outer_val !== undefined) { + if (inner_gen === undefined) { + inner_gen = get_inner_gen(outer_val); + if (!inner_gen || !inner_gen.next) { + blueslip.error('Invalid generator returned.'); + return; + } + } + var inner = inner_gen.next(); + if (inner !== undefined) { + return inner; + } + outer_val = outer_gen.next(); + inner_gen = undefined; + } + }, + }; +}; + +exports.chain = function (gen_lst) { + function get(which) { + return which; + } + + var outer_gen = exports.list_generator(gen_lst); + + return exports.fchain(outer_gen, get); +}; + +exports.wrap = function (lst, val) { + if (val === undefined) { + return exports.list_generator(lst); + } + + var i = _.indexOf(lst, val); + if (i < 0) { + return exports.list_generator(lst); + } + + var inners = [ + exports.sub_list_generator(lst, i, lst.length), + exports.sub_list_generator(lst, 0, i), + ]; + + return exports.chain(inners); +}; + +exports.wrap_exclude = function (lst, val) { + if (val === undefined) { + return exports.list_generator(lst); + } + + var i = _.indexOf(lst, val); + if (i < 0) { + return exports.list_generator(lst); + } + + var inners = [ + exports.sub_list_generator(lst, i+1, lst.length), + exports.sub_list_generator(lst, 0, i), + ]; + + return exports.chain(inners); +}; + +exports.filter = function (gen, filter_func) { + return { + next: function () { + while (true) { + var val = gen.next(); + if (val === undefined) { + return; + } + if (filter_func(val)) { + return val; + } + } + }, + }; +}; + +exports.next_topic = function (streams, get_topics, has_unread_messages, curr_stream, curr_topic) { + var stream_gen = exports.wrap(streams, curr_stream); + + function get_topic_gen(which_stream) { + var gen; + + if (which_stream === curr_stream) { + gen = exports.wrap_exclude(get_topics(which_stream), curr_topic); + } else { + gen = exports.list_generator(get_topics(which_stream)); + } + var has_unread = function (topic) { + return has_unread_messages(which_stream, topic); + }; + + return exports.filter(gen, has_unread); + } + + var outer_gen = exports.fchain(stream_gen, get_topic_gen); + return outer_gen.next(); +}; + + +return exports; +}()); + +if (typeof module !== 'undefined') { + module.exports = topic_generator; +}