def absent(name,
           destructive=False,
           delimiter=DEFAULT_TARGET_DELIM,
           force=False):
    '''
    .. versionadded:: 2014.7.0

    Delete a grain from the grains config file

    name
        The grain name

    destructive
        If destructive is True, delete the entire grain. If
        destructive is False, set the grain's value to None. Defaults to False.

    force
        If force is True, the existing grain will be overwritten
        regardless of its existing or provided value type. Defaults to False

        .. versionadded:: v2015.8.2

    delimiter
        A delimiter different from the default can be provided.

        .. versionadded:: v2015.8.2

    .. versionchanged:: v2015.8.2

    This state now support nested grains and complex values. It is also more
    conservative: if a grain has a value that is a list or a dict, it will
    not be removed unless the `force` parameter is True.

    .. code-block:: yaml

      grain_name:
        grains.absent
    '''

    _non_existent = object()

    name = re.sub(delimiter, DEFAULT_TARGET_DELIM, name)
    ret = {'name': name,
           'changes': {},
           'result': True,
           'comment': ''}
    grain = __salt__['grains.get'](name, _non_existent)
    if grain is None:
        if __opts__['test']:
            ret['result'] = None
            if destructive is True:
                ret['comment'] = 'Grain {0} is set to be deleted'.format(name)
                ret['changes'] = {'deleted': name}
            return ret
        ret = __salt__['grains.set'](name,
                                     None,
                                     destructive=destructive,
                                     force=force)
        if ret['result']:
            if destructive is True:
                ret['comment'] = 'Grain {0} was deleted'.format(name)
                ret['changes'] = {'deleted': name}
        ret['name'] = name
    elif grain is not _non_existent:
        if __opts__['test']:
            ret['result'] = None
            if destructive is True:
                ret['comment'] = 'Grain {0} is set to be deleted'.format(name)
                ret['changes'] = {'deleted': name}
            else:
                ret['comment'] = 'Value for grain {0} is set to be ' \
                                 'deleted (None)'.format(name)
                ret['changes'] = {'grain': name, 'value': None}
            return ret
        ret = __salt__['grains.set'](name,
                                     None,
                                     destructive=destructive,
                                     force=force)
        if ret['result']:
            if destructive is True:
                ret['comment'] = 'Grain {0} was deleted'.format(name)
                ret['changes'] = {'deleted': name}
            else:
                ret['comment'] = 'Value for grain {0} was set to None'.format(name)
                ret['changes'] = {'grain': name, 'value': None}
        ret['name'] = name
    else:
        ret['comment'] = 'Grain {0} does not exist'.format(name)
    return ret
.. versionadded:: 2014.7.0

    Delete a grain from the grains config file

    name
        The grain name

    destructive
        If destructive is True, delete the entire grain. If
        destructive is False, set the grain's value to None. Defaults to False.

    force
        If force is True, the existing grain will be overwritten
        regardless of its existing or provided value type. Defaults to False

        .. versionadded:: v2015.8.2

    delimiter
        A delimiter different from the default can be provided.

        .. versionadded:: v2015.8.2

    .. versionchanged:: v2015.8.2

    This state now support nested grains and complex values. It is also more
    conservative: if a grain has a value that is a list or a dict, it will
    not be removed unless the `force` parameter is True.

    .. code-block:: yaml

      grain_name:
        grains.absent