<commit_before>/**
 * Stampit
 **
 * Create objects from reusable, composable behaviors.
 **
 * Copyright (c) 2013 <NAME>
 * http://opensource.org/licenses/MIT
 **/
'use strict';
var forEach = require('lodash/collection/forEach');
var map = require('lodash/collection/map');
var forOwn = require('lodash/object/forOwn');
var deepClone = require('lodash/lang/cloneDeep');
var isFunction = require('lodash/lang/isFunction');
var isArray = require('lodash/lang/isArray');
var isObject = require('lodash/lang/isObject');
var create = require('lodash/object/create');
var slice = require('lodash/array/slice');

var mixer = require('./mixer');

// Avoiding JSHist W003 violations.
var stampit;

function extractFunctions(arg) {
  if (isFunction(arg)) {
    return map(slice(arguments), function (fn) {
      if (isFunction(fn)) {
        return fn;
      }
    });
  } else if (isObject(arg)) {
    var arr = [];
    forEach(slice(arguments), function (obj) {
      forOwn(obj, function (fn) {
        arr.push(fn);
      });
    });
    return arr;
  } else if (isArray(arg)) {
    return slice(arg);
  }
  return [];
}

function addMethods(fixed, methods) {
  var args = [fixed.methods].concat(methods);
  mixer.mixinFunctions.apply(null, args);
  return fixed.methods;
}
function addRefs(fixed, states) {
  var args = [fixed.refs || fixed.state].concat(states);
  fixed.refs = fixed.state = mixer.mixin.apply(null, args);
  return fixed.refs;
}
function addInit(fixed, inits) {
  inits = isArray(inits) ? extractFunctions.apply(null, inits) : extractFunctions(inits);
  fixed.init = fixed.enclose = (fixed.init || fixed.enclose).concat(inits);
  return fixed.init;
}
function addProps(fixed, propses) {
  var args = [fixed.props].concat(propses);
  fixed.props = mixer.merge.apply(null, args);
  return fixed.props;
}

function cloneAndExtend(fixed, extensionFunction, args) {
  args = arguments.length > 3 ? slice(arguments, 2, arguments.length) : args;
  // We might end up having two different stampit modules loaded and used in conjunction.
  // These || operators ensure that old stamps could be combined with the current version stamps.
  var stamp = stampit(fixed);
  extensionFunction(stamp.fixed, args);
  return stamp;
}

function compose(factories) {
  factories = isArray(factories) ? factories : slice(arguments);
  var result = stampit();
  forEach(factories, function (source) {
    if (source && source.fixed) {
      addMethods(result.fixed, source.fixed.methods);
      addRefs(result.fixed, source.fixed.refs || source.fixed.state); // 'state' is the old name for 'refs'
      addInit(result.fixed, source.fixed.init || source.fixed.enclose); // 'enclose' is the old name for 'init'
      addProps(result.fixed, source.fixed.props);
    }
  });
  return result;
}

/**
 * Return a factory function that will produce new objects using the
 * prototypes that are passed in or composed.
 *
 * @param  {Object} [options] Options to build stamp from: `{ methods, refs, init, props }`
 * @return {Function} factory A factory to produce objects using the given prototypes.
 * @return {Function} factory.create Just like calling the factory function.
 * @return {Object} factory.fixed An object map containing the fixed prototypes.
 * @return {Function} factory.methods Add methods to the prototype. Chainable.
 * @return {Function} factory.refs Add references to the prototype. Chainable.
 * @return {Function} factory.state Alias to refs(). Deprecated.
 * @return {Function} factory.init Add a closure which called on object instantiation. Chainable.
 * @return {Function} factory.enclose Alias to init(). Deprecated.
 * @return {Function} factory.props Add deeply cloned properties to the produced objects. Chainable.
 */
stampit = function stampit(options) {
  var fixed = {methods: {}, refs: {}, init: [], props: {}};
  fixed.state = fixed.refs; // Backward compatibility. 'state' is the old name for 'refs'.
  fixed.enclose = fixed.init; // Backward compatibility. 'enclose' is the old name for 'init'.
  if (options) {
    addMethods(fixed, options.methods);
    addRefs(fixed, options.refs);
    addInit(fixed, options.init);
    addProps(fixed, options.props);
  }

  var factory = function Factory(properties, args) {
    properties = properties ? mixer.merge({}, fixed.props, properties) : deepClone(fixed.props);
    var instance = mixer.mixin(create(fixed.methods), fixed.refs, properties); // props are taking over refs

    if (fixed.init.length > 0) {
      args = slice(arguments, 1, arguments.length);
      forEach(fixed.init, function (fn) {
        if (isFunction(fn)) {
          instance = fn.call(instance, { args: args, instance: instance, stamp: factory }) || instance;
        }
      });
    }

    return instance;
  };

  var refsMethod = cloneAndExtend.bind(null, fixed, addRefs);
  var initMethod = cloneAndExtend.bind(null, fixed, addInit);
  return mixer.mixin(factory, {
    create: factory,
    fixed: fixed,

    /**
     * Take n objects and add them to the methods prototype.
     * @return {Object} stamp  The factory in question (`this`).
     */
    methods: cloneAndExtend.bind(null, fixed, addMethods),

    /**
     * Take n objects and add them to the newly stamped objects.
     * @return {Object} stamp  The factory in question (`this`).
     */
    refs: refsMethod,

    /**
     * Alias to refs(). Deprecated.
     * @return {Object} stamp  The factory in question (`this`).
     */
    state: refsMethod,

    /**
     * Take n functions, an array of functions, or n objects and add
     * the functions to the enclose prototype.
     * @return {Object} The factory in question (`this`).
     */
    init: initMethod,

    /**
     * Alias to init(). Deprecated.
     * @return {Object} The factory in question (`this`).
     */
    enclose: initMethod,

    /**
     * Take n objects and add deep clone them to the instantiated object.
     * @return {Object} stamp  The factory in question (`this`).
     */
    props: cloneAndExtend.bind(null, fixed, addProps),

    /**
     * Take one or more factories produced from stampit() and
     * combine them with `this` to produce and return a new factory.
     * Combining overrides properties with last-in priority.
     * @param {[Function]|...Function} factories Stampit factories.
     * @return {Function} A new stampit factory composed from arguments.
     */
    compose: function (factories) {
      var args = isArray(factories) ? factories : slice(arguments);
      args = [this].concat(args);
      return compose(args);
    }
  });
};

// Static methods

function isStamp(obj) {
  return (
  isFunction(obj) &&
  isFunction(obj.methods) &&
  // isStamp can be called for old stampit factory object. We should check old names (state and enclose) too.
  (isFunction(obj.refs) || isFunction(obj.state)) &&
  (isFunction(obj.init) || isFunction(obj.enclose)) &&
  isFunction(obj.props) &&
  isObject(obj.fixed)
  );
}

function convertConstructor(Constructor) {
  var stamp = stampit();
  mixer.mixinChainFunctions(stamp.fixed.methods, Constructor.prototype);
  stamp.fixed.refs = stamp.fixed.state = mixer.mergeChainNonFunctions(stamp.fixed.refs, Constructor.prototype);
  addInit(stamp.fixed, function (opts) {
    return Constructor.apply(opts.instance, opts.args);
  });
  return stamp;
}

function shortcutMethod(extensionFunction) {
  var stamp = stampit();
  extensionFunction(stamp.fixed, slice(arguments, 1));
  return stamp;
}

module.exports = mixer.mixin(stampit, {

  methods: shortcutMethod.bind(null, addMethods),

  refs: shortcutMethod.bind(null, addRefs),

  init: shortcutMethod.bind(null, addInit),

  props: shortcutMethod.bind(null, addProps),

  /**
   * Take two or more factories produced from stampit() and
   * combine them to produce a new factory.
   * Combining overrides properties with last-in priority.
   * @param {[Function]|...Function} factories Stamps produced by stampit().
   * @return {Function} A new stampit factory composed from arguments.
   */
  compose: compose,

  /**
   * Alias for mixin
   */
  extend: mixer.mixin,
  /**
   * Alias for mixin
   */
  mixIn: mixer.mixin,
  /**
   * Alias for mixin
   */
  assign: mixer.mixin,
  /**
   * Take a destination object followed by one or more source objects,
   * and copy the source object properties to the destination object,
   * with last in priority overrides.
   * @param {Object} destination An object to copy properties to.
   * @param {...Object} source An object to copy properties from.
   * @returns {Object}
   */
  mixin: mixer.mixin,

  /**
   * Check if an object is a stamp.
   * @param {Object} obj An object to check.
   * @returns {Boolean}
   */
  isStamp: isStamp,

  /**
   * Take an old-fashioned JS constructor and return a stampit stamp
   * that you can freely compose with other stamps.
   * @param  {Function} Constructor
   * @return {Function}             A composable stampit factory
   *                                (aka stamp).
   */
  convertConstructor: convertConstructor
});
<commit_msg>More IE8 support dropped. :)<commit_after>/**
 * Stampit
 **
 * Create objects from reusable, composable behaviors.
 **
 * Copyright (c) 2013 <NAME>
 * http://opensource.org/licenses/MIT
 **/
'use strict';
var forEach = require('lodash/collection/forEach');
var map = require('lodash/collection/map');
var forOwn = require('lodash/object/forOwn');
var deepClone = require('lodash/lang/cloneDeep');
var isFunction = require('lodash/lang/isFunction');
var isArray = Array.isArray;
var isObject = require('lodash/lang/isObject');
var create = Object.create;
var slice = require('lodash/array/slice');

var mixer = require('./mixer');

// Avoiding JSHist W003 violations.
var stampit;

function extractFunctions(arg) {
  if (isFunction(arg)) {
    return map(slice(arguments), function (fn) {
      if (isFunction(fn)) {
        return fn;
      }
    });
  } else if (isObject(arg)) {
    var arr = [];
    forEach(slice(arguments), function (obj) {
      forOwn(obj, function (fn) {
        arr.push(fn);
      });
    });
    return arr;
  } else if (isArray(arg)) {
    return slice(arg);
  }
  return [];
}

function addMethods(fixed, methods) {
  var args = [fixed.methods].concat(methods);
  mixer.mixinFunctions.apply(null, args);
  return fixed.methods;
}
function addRefs(fixed, states) {
  var args = [fixed.refs || fixed.state].concat(states);
  fixed.refs = fixed.state = mixer.mixin.apply(null, args);
  return fixed.refs;
}
function addInit(fixed, inits) {
  inits = isArray(inits) ? extractFunctions.apply(null, inits) : extractFunctions(inits);
  fixed.init = fixed.enclose = (fixed.init || fixed.enclose).concat(inits);
  return fixed.init;
}
function addProps(fixed, propses) {
  var args = [fixed.props].concat(propses);
  fixed.props = mixer.merge.apply(null, args);
  return fixed.props;
}

function cloneAndExtend(fixed, extensionFunction, args) {
  args = arguments.length > 3 ? slice(arguments, 2, arguments.length) : args;
  // We might end up having two different stampit modules loaded and used in conjunction.
  // These || operators ensure that old stamps could be combined with the current version stamps.
  var stamp = stampit(fixed);
  extensionFunction(stamp.fixed, args);
  return stamp;
}

function compose(factories) {
  factories = isArray(factories) ? factories : slice(arguments);
  var result = stampit();
  forEach(factories, function (source) {
    if (source && source.fixed) {
      addMethods(result.fixed, source.fixed.methods);
      addRefs(result.fixed, source.fixed.refs || source.fixed.state); // 'state' is the old name for 'refs'
      addInit(result.fixed, source.fixed.init || source.fixed.enclose); // 'enclose' is the old name for 'init'
      addProps(result.fixed, source.fixed.props);
    }
  });
  return result;
}

/**
 * Return a factory function that will produce new objects using the
 * prototypes that are passed in or composed.
 *
 * @param  {Object} [options] Options to build stamp from: `{ methods, refs, init, props }`
 * @return {Function} factory A factory to produce objects using the given prototypes.
 * @return {Function} factory.create Just like calling the factory function.
 * @return {Object} factory.fixed An object map containing the fixed prototypes.
 * @return {Function} factory.methods Add methods to the prototype. Chainable.
 * @return {Function} factory.refs Add references to the prototype. Chainable.
 * @return {Function} factory.state Alias to refs(). Deprecated.
 * @return {Function} factory.init Add a closure which called on object instantiation. Chainable.
 * @return {Function} factory.enclose Alias to init(). Deprecated.
 * @return {Function} factory.props Add deeply cloned properties to the produced objects. Chainable.
 */
stampit = function stampit(options) {
  var fixed = {methods: {}, refs: {}, init: [], props: {}};
  fixed.state = fixed.refs; // Backward compatibility. 'state' is the old name for 'refs'.
  fixed.enclose = fixed.init; // Backward compatibility. 'enclose' is the old name for 'init'.
  if (options) {
    addMethods(fixed, options.methods);
    addRefs(fixed, options.refs);
    addInit(fixed, options.init);
    addProps(fixed, options.props);
  }

  var factory = function Factory(properties, args) {
    properties = properties ? mixer.merge({}, fixed.props, properties) : deepClone(fixed.props);
    var instance = mixer.mixin(create(fixed.methods), fixed.refs, properties); // props are taking over refs

    if (fixed.init.length > 0) {
      args = slice(arguments, 1, arguments.length);
      forEach(fixed.init, function (fn) {
        if (isFunction(fn)) {
          instance = fn.call(instance, { args: args, instance: instance, stamp: factory }) || instance;
        }
      });
    }

    return instance;
  };

  var refsMethod = cloneAndExtend.bind(null, fixed, addRefs);
  var initMethod = cloneAndExtend.bind(null, fixed, addInit);
  return mixer.mixin(factory, {
    create: factory,
    fixed: fixed,

    /**
     * Take n objects and add them to the methods prototype.
     * @return {Object} stamp  The factory in question (`this`).
     */
    methods: cloneAndExtend.bind(null, fixed, addMethods),

    /**
     * Take n objects and add them to the newly stamped objects.
     * @return {Object} stamp  The factory in question (`this`).
     */
    refs: refsMethod,

    /**
     * Alias to refs(). Deprecated.
     * @return {Object} stamp  The factory in question (`this`).
     */
    state: refsMethod,

    /**
     * Take n functions, an array of functions, or n objects and add
     * the functions to the enclose prototype.
     * @return {Object} The factory in question (`this`).
     */
    init: initMethod,

    /**
     * Alias to init(). Deprecated.
     * @return {Object} The factory in question (`this`).
     */
    enclose: initMethod,

    /**
     * Take n objects and add deep clone them to the instantiated object.
     * @return {Object} stamp  The factory in question (`this`).
     */
    props: cloneAndExtend.bind(null, fixed, addProps),

    /**
     * Take one or more factories produced from stampit() and
     * combine them with `this` to produce and return a new factory.
     * Combining overrides properties with last-in priority.
     * @param {[Function]|...Function} factories Stampit factories.
     * @return {Function} A new stampit factory composed from arguments.
     */
    compose: function (factories) {
      var args = isArray(factories) ? factories : slice(arguments);
      args = [this].concat(args);
      return compose(args);
    }
  });
};

// Static methods

function isStamp(obj) {
  return (
  isFunction(obj) &&
  isFunction(obj.methods) &&
  // isStamp can be called for old stampit factory object. We should check old names (state and enclose) too.
  (isFunction(obj.refs) || isFunction(obj.state)) &&
  (isFunction(obj.init) || isFunction(obj.enclose)) &&
  isFunction(obj.props) &&
  isObject(obj.fixed)
  );
}

function convertConstructor(Constructor) {
  var stamp = stampit();
  mixer.mixinChainFunctions(stamp.fixed.methods, Constructor.prototype);
  stamp.fixed.refs = stamp.fixed.state = mixer.mergeChainNonFunctions(stamp.fixed.refs, Constructor.prototype);
  addInit(stamp.fixed, function (opts) {
    return Constructor.apply(opts.instance, opts.args);
  });
  return stamp;
}

function shortcutMethod(extensionFunction) {
  var stamp = stampit();
  extensionFunction(stamp.fixed, slice(arguments, 1));
  return stamp;
}

module.exports = mixer.mixin(stampit, {

  methods: shortcutMethod.bind(null, addMethods),

  refs: shortcutMethod.bind(null, addRefs),

  init: shortcutMethod.bind(null, addInit),

  props: shortcutMethod.bind(null, addProps),

  /**
   * Take two or more factories produced from stampit() and
   * combine them to produce a new factory.
   * Combining overrides properties with last-in priority.
   * @param {[Function]|...Function} factories Stamps produced by stampit().
   * @return {Function} A new stampit factory composed from arguments.
   */
  compose: compose,

  /**
   * Alias for mixin
   */
  extend: mixer.mixin,
  /**
   * Alias for mixin
   */
  mixIn: mixer.mixin,
  /**
   * Alias for mixin
   */
  assign: mixer.mixin,
  /**
   * Take a destination object followed by one or more source objects,
   * and copy the source object properties to the destination object,
   * with last in priority overrides.
   * @param {Object} destination An object to copy properties to.
   * @param {...Object} source An object to copy properties from.
   * @returns {Object}
   */
  mixin: mixer.mixin,

  /**
   * Check if an object is a stamp.
   * @param {Object} obj An object to check.
   * @returns {Boolean}
   */
  isStamp: isStamp,

  /**
   * Take an old-fashioned JS constructor and return a stampit stamp
   * that you can freely compose with other stamps.
   * @param  {Function} Constructor
   * @return {Function}             A composable stampit factory
   *                                (aka stamp).
   */
  convertConstructor: convertConstructor
});

{'fraction_non_alphanumeric': 0.1254843352153216, 'fraction_numerical': 0.0013838149009188531, 'mean_word_length': 3.372458857696031, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6555192', 'n_tokens_mistral': 5519, 'n_tokens_neox': 5314, 'n_words': 1674}