<commit_before>class ComputedFields
  fields: {}
  constructor: (@collection) ->
  add: (name, updateMethod) ->
    check name, String
    check updateMethod, Match.Optional Function
    unless @fields[name]?
      @fields[name] = new ComputedField @collection, name, updateMethod
    return @fields[name]

  get: (name) ->
    check name, String
    @fields[name] or @add(name)


class ComputedField
  constructor: (@collection, @name, @updateMethod) ->
    field = this
    return unless @updateMethod?
    @collection.after.insert (userId, doc, fieldNames) ->
      thisValue = field._getThis this, doc, userId, fieldNames, 'insert'
      field.updateMethod.call thisValue, @transform()
    @collection.after.update (userId, doc, fieldNames) ->
      thisValue = field._getThis this, doc, userId, fieldNames, 'update'
      field.updateMethod.call thisValue, @transform()
  _getThis: (hook, doc, userId, fieldNames, type) ->
    isUpdate: type is 'update'
    isInsert: type is 'insert'
    isRemove: type is 'remove'
    set: (value) =>
      field = {}
      field[@name] = value
      @collection.direct.update doc._id, $set: field

  addDependency: (collection, options) ->
    check collection, Match.Any
    check options,
      findId: Function
      update: Function
    field = this
    findDoc = (doc) ->
      _id = options.findId(doc)
      field.collection.findOne _id: _id
    collection.after.insert (userId, doc, fieldNames) ->
      fieldDoc = findDoc doc
      thisValue = field._getThis this, fieldDoc, userId, fieldNames, 'insert'
      options.update.call thisValue, fieldDoc, @transform()
    collection.after.update (userId, doc, fieldNames) ->


Meteor.addCollectionExtension (name, options) ->
  @computedFields = new ComputedFields this<commit_msg>added hooks for update and remove<commit_after>class ComputedFields
  fields: {}
  constructor: (@collection) ->
  add: (name, updateMethod) ->
    check name, String
    check updateMethod, Match.Optional Function
    unless @fields[name]?
      @fields[name] = new ComputedField @collection, name, updateMethod
    return @fields[name]

  get: (name) ->
    check name, String
    @fields[name] or @add(name)


class ComputedField
  constructor: (@collection, @name, @updateMethod) ->
    field = this
    return unless @updateMethod?
    @collection.after.insert (userId, doc, fieldNames) ->
      thisValue = field._getThis this, doc, userId, fieldNames, 'insert'
      field.updateMethod.call thisValue, @transform()
    @collection.after.update (userId, doc, fieldNames) ->
      thisValue = field._getThis this, doc, userId, fieldNames, 'update'
      field.updateMethod.call thisValue, @transform()
  _getThis: (hook, doc, userId, fieldNames, type) ->
    isUpdate: type is 'update'
    isInsert: type is 'insert'
    isRemove: type is 'remove'
    set: (value) =>
      field = {}
      field[@name] = value
      @collection.direct.update doc._id, $set: field

  addDependency: (collection, options) ->
    check collection, Match.Any
    check options,
      findId: Function
      update: Function
    field = this
    findDoc = (doc) ->
      _id = options.findId(doc)
      field.collection.findOne _id: _id
    collection.after.insert (userId, doc, fieldNames) ->
      fieldDoc = findDoc doc
      thisValue = field._getThis this, fieldDoc, userId, fieldNames, 'insert'
      options.update.call thisValue, fieldDoc, @transform()
    collection.after.update (userId, doc, fieldNames) ->
      fieldDoc = findDoc doc
      thisValue = field._getThis this, fieldDoc, userId, fieldNames, 'update'
      options.update.call thisValue, fieldDoc, @transform()
    collection.after.remove (userId, doc, fieldNames) ->
      fieldDoc = findDoc doc
      thisValue = field._getThis this, fieldDoc, userId, fieldNames, 'remove'
      options.update.call thisValue, fieldDoc, @transform()

Meteor.addCollectionExtension (name, options) ->
  @computedFields = new ComputedFields this
{'fraction_non_alphanumeric': 0.11453077699293643, 'fraction_numerical': 0.0, 'mean_word_length': 3.400665926748058, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 30, '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': '90097', 'n_tokens_mistral': 1157, 'n_tokens_neox': 1166, 'n_words': 334}