"""Allows you to create generic receivers for django's signal system

Why do you need generic recievers you ask?

Say you need want to record when a group of Models are saved and 
you want to record their publish date, but they have different field names

def record_pubdate(instance=instance, signal=None, sender=None, 
                   date_field=None):
  ip = ItemPublish(object_id=instance.id, 
                   pub_date=getattr(instance, date_field)
  ip.save()

receivers = []
for Model, date_field in ( (blog.Entry, 'pub_date', 
                           (bookmarks.Bookmark, 'timestamp'),
                           (rss.Entry, 'update_date')
                           ):
     receivers.append(generic_receiver(record_pubdate, date_field=date_field)
     dispatcher.connect(receivers[-1], signal=post_save, sender=Model)
"""
def generic_receiver(callable, *extra_args, **extra_kwargs):
    def inner(*args, **kwargs):
        args = args + extra_args
        kwargs.update(extra_kwargs)
        callable(*args, **kwargs)
    return inner


def test_kwarg_generic_receiver():
    from django.dispatch import dispatcher

    # This is needed to keep our anonymous functions alive
    # This is needed because the signals system removes the relationship
    # if the function looses scope
    scope = []
    def my_kwarg_receiver(signal=None, sender=None, date_field=None):
        result_list.append(date_field)

    test_signal = object()

    # Test the kwarg receiver
    time_field_list = ['time', 'pub_date']
    result_list = []

    for date_field in time_field_list:
        scope.append(generic_receiver(my_kwarg_receiver, 
                                      date_field=date_field))
        dispatcher.connect(scope[-1],
                           signal=test_signal)

    dispatcher.send(test_signal)

    
    assert result_list == ['time', 'pub_date']

def test_arg_generic_receiver():
    from django.dispatch import dispatcher

    # This is needed to keep our anonymous functions alive
    # This is needed because the signals system removes the relationship
    # if the function looses scope
    scope = []

    def my_kwarg_receiver(date_field, signal=None, sender=None):
        result_list.append(date_field)

    test_signal = object()

    # Test the kwarg receiver
    time_field_list = ['time', 'pub_date']
    result_list = []

    for date_field in time_field_list:
        scope.append(generic_receiver(my_kwarg_receiver, date_field))
        dispatcher.connect(scope[-1],
                           signal=test_signal)

    dispatcher.send(test_signal)

    
    assert result_list == ['time', 'pub_date']

def test_arg_kwarg_generic_receiver():
    from django.dispatch import dispatcher

    # This is needed to keep our anonymous functions alive
    # This is needed because the signals system removes the relationship
    # if the function looses scope
    scope = []
    result_list = []
    def my_kwarg_receiver(date_field, signal=None, sender=None, 
                          other_field=None):
        result_list.append( (date_field, other_field) )
        
    test_signal = object()

    # Test the kwarg receiver
    field_list = [('time', 1), ('pub_date', 2)]

    for date_field, other_field in field_list:
        scope.append(generic_receiver(my_kwarg_receiver, date_field, 
                                      other_field=other_field))
        dispatcher.connect(scope[-1],
                           signal=test_signal)

    dispatcher.send(test_signal)

    
    assert result_list == field_list


if __name__ == '__main__':
    test_arg_generic_receiver()
    test_kwarg_generic_receiver()
    test_arg_kwarg_generic_receiver()
