<commit_before>// returns special value that when passed to Cell#setValue initiates async set
// 'body' is a function that's passed cell-generated dataCallback
// 'body' is assumed to arrange async process of computing/getting new value
// 'body' should arrange call to given dataCallback when new value is available, passing it this new value
// Value returned from body is ignored
//
// see future.get for usage example
function future(body, options) {
  return new Future(body, options);
}
function Future(body, options) {
  this.thunk = body;
  _.extend(this, options || {});
}
Future.prototype = {
  removeNowValue: function () {
    var rv = this.nowValue;
    delete this.nowValue;
    return rv;
  },
  mkCallback: function (cell) {
    var async = this;
    return function (data) {
      if (async.action)
        async.action.finish();
      cell.deliverFutureValue(async, data);
    }
  },
  start: function (cell) {
    if (this.modal) {
      this.action = new ModalAction();
    }
    this.started = true;
    var thunk = this.thunk;
    this.thunk = undefined;
    thunk.call(cell.mkFormulaContext(), this.mkCallback(cell));
  }
};

future.get = function (ajaxOptions, valueTransformer, nowValue) {
  var options = {
    valueTransformer: valueTransformer,
    cancel: function () {
      Abortarium.abortRequest(xhr);
    },
    nowValue: nowValue
  }
  var xhr;
  if (ajaxOptions.url === undefined)
    throw new Error("url is undefined");
  return future(function (dataCallback) {
    xhr = $.ajax(_.extend({type: 'GET',
                           dataType: 'json',
                           success: dataCallback},
                          ajaxOptions));
  }, options);
}

// inspired in part by http://common-lisp.net/project/cells/
var Cell = mkClass({
  initialize: function (formula, sources) {
    this.changedSlot = new CallbackSlot();
    this.undefinedSlot = new CallbackSlot();
    this.dependenciesSlot = new CallbackSlot();
    this.formula = formula;
    this.effectiveFormula = formula;
    this.value = undefined;
    this.sources = [];
    this.context = {};
    this.argumentSourceNames = [];
    if (sources)
      this.setSources(sources);
    else if (this.formula)
      this.recalculate();
  },
  equality: function (a, b) {
    return a == b;
  },
  subscribe: function (cb, options) {
    options = _.extend({'undefined': false,
                        changed: true}, options || {});
    var slave = new Slave(cb);
    if (options["undefined"])
      this.undefinedSlot.subscribeWithSlave(slave);
    if (options.changed)
      this.changedSlot.subscribeWithSlave(slave);
    return slave;
  },
  subscribeAny: function (cb) {
    return this.subscribe(cb, {'undefined': true});
  },
  setSources: function (context) {
    var self = this;
    if (this.sources.length != 0)
      throw new Error('cannot adjust sources yet');
    if (!this.formula)
      throw new Error("formula-less cells cannot have sources");
    var cells = this.sources = _.values(context);
    this.context = _.extend({self: this}, context);
    if (_.any(cells, function (v) {return v == null;})) {
      var badSources = [];
      _.each(this.context, function (v, k) {
        if (!v)
          badSources.push(k);
      });
      throw new Error("null for following source cells: " + badSources.join(', '));
    }
<commit_msg>[cells] implementated subscribeOnUndefined helper<commit_after>// returns special value that when passed to Cell#setValue initiates async set
// 'body' is a function that's passed cell-generated dataCallback
// 'body' is assumed to arrange async process of computing/getting new value
// 'body' should arrange call to given dataCallback when new value is available, passing it this new value
// Value returned from body is ignored
//
// see future.get for usage example
function future(body, options) {
  return new Future(body, options);
}
function Future(body, options) {
  this.thunk = body;
  _.extend(this, options || {});
}
Future.prototype = {
  removeNowValue: function () {
    var rv = this.nowValue;
    delete this.nowValue;
    return rv;
  },
  mkCallback: function (cell) {
    var async = this;
    return function (data) {
      if (async.action)
        async.action.finish();
      cell.deliverFutureValue(async, data);
    }
  },
  start: function (cell) {
    if (this.modal) {
      this.action = new ModalAction();
    }
    this.started = true;
    var thunk = this.thunk;
    this.thunk = undefined;
    thunk.call(cell.mkFormulaContext(), this.mkCallback(cell));
  }
};

future.get = function (ajaxOptions, valueTransformer, nowValue) {
  var options = {
    valueTransformer: valueTransformer,
    cancel: function () {
      Abortarium.abortRequest(xhr);
    },
    nowValue: nowValue
  }
  var xhr;
  if (ajaxOptions.url === undefined)
    throw new Error("url is undefined");
  return future(function (dataCallback) {
    xhr = $.ajax(_.extend({type: 'GET',
                           dataType: 'json',
                           success: dataCallback},
                          ajaxOptions));
  }, options);
}

// inspired in part by http://common-lisp.net/project/cells/
var Cell = mkClass({
  initialize: function (formula, sources) {
    this.changedSlot = new CallbackSlot();
    this.undefinedSlot = new CallbackSlot();
    this.dependenciesSlot = new CallbackSlot();
    this.formula = formula;
    this.effectiveFormula = formula;
    this.value = undefined;
    this.sources = [];
    this.context = {};
    this.argumentSourceNames = [];
    if (sources)
      this.setSources(sources);
    else if (this.formula)
      this.recalculate();
  },
  equality: function (a, b) {
    return a == b;
  },
  subscribe: function (cb, options) {
    options = _.extend({'undefined': false,
                        changed: true}, options || {});
    var slave = new Slave(cb);
    if (options["undefined"])
      this.undefinedSlot.subscribeWithSlave(slave);
    if (options.changed)
      this.changedSlot.subscribeWithSlave(slave);
    return slave;
  },
  subscribeOnUndefined: function (cb) {
    return this.subscribe(cb, {'undefined': true, changed: false});
  },
  subscribeAny: function (cb) {
    return this.subscribe(cb, {'undefined': true});
  },
  setSources: function (context) {
    var self = this;
    if (this.sources.length != 0)
      throw new Error('cannot adjust sources yet');
    if (!this.formula)
      throw new Error("formula-less cells cannot have sources");
    var cells = this.sources = _.values(context);
    this.context = _.extend({self: this}, context);
    if (_.any(cells, function (v) {return v == null;})) {
      var badSources = [];
      _.each(this.context, function (v, k) {
        if (!v)
          badSources.push(k);
      });
      throw new Error("null for following source cells: " + badSources.join(', '));
    }

{'fraction_non_alphanumeric': 0.1305300043802015, 'fraction_numerical': 0.0002920134326179004, 'mean_word_length': 2.822544642857143, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5083894', 'n_tokens_mistral': 2018, 'n_tokens_neox': 1985, 'n_words': 572}