docs: function(key, value, options){
  
      var attrs, newKey, destination, props = [];
  
      if (typeof key === 'object') {
        attrs = (key.isModel) ? key.attributes : key;
        options = value;
      }
      else (attrs = {})[key] = value;
      options || (options = {});
  
      // Convert getters and setters to computed properties
      $.extractComputedProps(attrs);
  
      // If reset option passed, do a reset. If nothing passed, return.
      if(options.reset === true) return this.reset(attrs, options);
      if(options.defaults === true) this.defaults = attrs;
      if(_.isEmpty(attrs)){ return void 0; }
  
      // For each attribute passed:
      for(key in attrs){
        let val = attrs[key],
            paths = $.splitPath(key),
            attr  = (paths.pop() || ''),       // The key          ex: foo[0].bar --> bar
            target = this.get(paths.join('.')),  // The element    ex: foo.bar.baz --> foo.bar
            lineage;
  
        // If target currently doesnt exist, construct its tree
        if(_.isUndefined(target)){
          target = this;
          _.each(paths, function(part){
            var tmp = target.get(part);
            if(_.isUndefined(tmp)) tmp = target.set(part, {}).get(part);
            target = tmp;
          }, this);
        }
  
        // The old value of `attr` in `target`
        destination = target.get(attr, {raw: true}) || {};
  
        // Create this new object's lineage.
        lineage = {
          name: key,
          parent: target,
          root: this.__root__,
          path: pathGenerator(target, attr),
          silent: true,
          defaults: options.defaults
        };
        // - If val is `null` or `undefined`, set to default value.
        // - If val is a `Computed Property`, get its current cache object.
        // - If val (default value or evaluated computed property) is `null`, set to default value or (fallback `undefined`).
        // - Else If val is a primitive object instance, convert to primitive value.
        // - Else If `{raw: true}` option is passed, set the exact object that was passed. No promotion to a Rebound Data object.
        // - Else If this function is the same as the current computed property, continue.
        // - Else If this value is a `Function`, turn it into a `Computed Property`.
        // - Else If this is going to be a cyclical dependancy, use the original object, don't make a copy.
        // - Else If updating an existing object with its respective data type, let Backbone handle the merge.
        // - Else If this value is a `Model` or `Collection`, create a new copy of it using its constructor, preserving its defaults while ensuring no shared memory between objects.
        // - Else If this value is an `Array`, turn it into a `Collection`.
        // - Else If this value is a `Object`, turn it into a `Model`.
        // - Else val is a primitive value, set it accordingly.
  
  
        if(_.isNull(val) || _.isUndefined(val)) val = this.defaults[key];
        if(val && val.isComputedProperty) val = val.value();
        if(_.isNull(val) || _.isUndefined(val)) val = undefined;
        else if(val instanceof String) val = String(val);
        else if(val instanceof Number) val = Number(val);
        else if(val instanceof Boolean) val = Boolean(val.valueOf());
        else if(options.raw === true) val = val;
        else if(destination.isComputedProperty && destination.func === val) continue;
        else if(val.isComputedProto) val = new ComputedProperty(val.get, val.set, lineage);
        else if(val.isData && target.hasParent(val)) val = val;
        else if( destination.isComputedProperty ||
                ( destination.isCollection && ( _.isArray(val) || val.isCollection )) ||
                ( destination.isModel && ( _.isObject(val) || val.isModel ))){
          destination.set(val, options);
          continue;
        }
        else if(val.isData && options.clone !== false) val = new val.constructor(val.attributes || val.models, lineage);
        else if(_.isArray(val)) val = new Rebound.Collection(val, lineage); // TODO: Remove global referance
        else if(_.isObject(val)) val = new Model(val, lineage);
  
        // If val is a data object, let this object know it is now a parent
        this._hasAncestry = (val && val.isData || false);
  
        // Set the value
        Backbone.Model.prototype.set.call(target, attr, val, options); // TODO: Event cleanup when replacing a model or collection with another value
  
      }
  
      return this;
  
    }