? .DS_Store
? new_hooks.patch
? new_hooks_01.patch
? includes/.DS_Store
Index: atr.api.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/atr/Attic/atr.api.php,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 atr.api.php
--- atr.api.php	2 Jun 2009 18:13:01 -0000	1.1.2.1
+++ atr.api.php	5 Jun 2009 23:22:08 -0000
@@ -12,50 +12,57 @@
  * @return
  *  An associative array.
  */
-function hook_atr_review_info() {
+function hook_atr_method_info() {
   return array(
-    'similarity' => array( // The review method.
-      'all' => array( // Two-character language code as defined in
-      // _locale_get_predefined_list or 'all' to define the languages this
-      // callback can review.
-        '#callback' => 'atr_review_similar', // The name of the function.
-        '#module' => 'atr', // The module this function is from.
-        '#file' => 'includes/atr.review.inc', // The file within the module's
-        // directory the callback is located in.
-      ),
+    'similarity' => array( // The machine name of the review method.
+      '#title' => t('Similarity review'), // The human-readable name of the review method.
+      '#description' => t('Compare all strings to eachother and list all that are similar. To reduce the amount of different strings, the ones that are similar may be merged.'),
     ),
-    'blacklist' => array( // The review method.
-      'en' => array( // Two-character language code as defined in
-      // _locale_get_predefined_list or 'all' to define the languages this
-      // callback can review.
-        '#callback' => 'atr_review_blacklist', // The name of the function.
-        '#module' => 'atr', // The module this function is from.
-        '#file' => 'includes/atr.review.inc', // The file within the module's
-        // directory the callback is located in.
-      ),
+    'blacklist' => array( // The human-readable name of the review method.
+      '#title' => t('Blacklist review'), // The machine name of the review method.
+      '#description' => t('List all strings that contain blacklisted words.'),
     ),
   );
 }
 
 /**
- * Extend a $profile object when it's loaded.
- *
- * @param $profile
- *   A profile object.
+ * Define callbacks for review methods.
  *
  * @return
- *  An associative array that can be merged into the $profile object.
+ *  An associative array.
  */
-function hook_atr_profile_load($profile) {
-  $reviews = array();
-  if (variable_get('atr_profile_' . $profile->pid . '_similarity', FALSE)) {
-    $reviews[] = 'similarity';
-  }
-  if (variable_get('atr_profile_' . $profile->pid . '_blacklist', FALSE)) {
-    $reviews[] = 'blacklist';
-  }
-
+function atr_atr_method_callback() {
   return array(
-    'reviews' => $reviews,
+    'similarity' => array( // The machine name of the review method.
+      'all' => array( // The language these callbacks are for.
+        'process' => array( // The callback machine name.
+          '#callback' => 'atr_review_similar', // The callback's function name.
+          '#module' => 'atr', // The module the callback is in.
+          '#file' => 'includes/atr.review.inc', // The file the callback is in.
+        ),
+        'prepare' => array( // The callback machine name.
+          '#callback' => 'atr_review_similar_prepare', // The callback's
+          // function name.
+          '#module' => 'atr', // The module the callback is in.
+          '#file' => 'includes/atr.review.inc', // The file the callback is in.
+        ),
+        'review' => array( // The callback machine name.
+          '#callback' => 'atr_review_similar_review', // The callback's function
+          // name.
+          '#module' => 'atr', // The module the callback is in.
+          '#file' => 'includes/atr.review.inc', // The file the callback is in.
+        ),
+      ),
+    ),
+    'blacklist' => array( // The machine name of the review method.
+      'all' => array( // The language the callback is for.
+        'process' => array( // The callback machine name.
+          '#callback' => 'atr_review_blacklist', // The callback's function
+          // name.
+          '#module' => 'atr', // The module the callback is in.
+          '#file' => 'includes/atr.review.inc', // The file the callback is in.
+        ),
+      ),
+    ),
   );
 }
\ No newline at end of file
Index: atr.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/atr/Attic/atr.install,v
retrieving revision 1.1.2.6
diff -u -p -r1.1.2.6 atr.install
--- atr.install	2 Jun 2009 18:13:01 -0000	1.1.2.6
+++ atr.install	5 Jun 2009 23:22:08 -0000
@@ -33,6 +33,26 @@ function atr_schema() {
       ),
       'primary key' => array('pid'),
     ),
+    'atr_profile_method' => array(
+      'description' => 'The methods that are used for eveyr {atr_profile}.',
+      'fields' => array(
+        'pid' => array(
+          'description' => 'The {atr_profile}.pid of this record.',
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+        ),
+        'method' => array(
+          'description' => 'A review method that is used with this profile.',
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+        ),
+      ),
+      'indexes' => array(
+        'pid' => array('pid'),
+      ),
+    ),
     'atr_string' => array(
       'description' => 'The strings that are found in the files to review.',
       'fields' => array(
Index: atr.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/atr/Attic/atr.module,v
retrieving revision 1.1.2.6
diff -u -p -r1.1.2.6 atr.module
--- atr.module	2 Jun 2009 18:13:01 -0000	1.1.2.6
+++ atr.module	5 Jun 2009 23:22:08 -0000
@@ -115,46 +115,104 @@ function atr_theme() {
 }
 
 /**
- * Implementation of hook_atr_review_info().
+ * Implementation of hook_atr_method_info().
  */
-function atr_atr_review_info() {
+function atr_atr_method_info() {
+  return array(
+    'similarity' => array(
+      '#title' => t('Similarity review'),
+      '#description' => t('Compare all strings to eachother and list all that are similar. To reduce the amount of different strings, the ones that are similar may be merged.'),
+    ),
+    'blacklist' => array(
+      '#title' => t('Blacklist review'),
+      '#description' => t('List all strings that contain blacklisted words.'),
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_atr_method_callback().
+ */
+function atr_atr_method_callback() {
   return array(
     'similarity' => array(
       'all' => array(
-        '#callback' => 'atr_review_similar',
-        '#module' => 'atr',
-        '#file' => 'includes/atr.review.inc',
+        'process' => array(
+          '#callback' => 'atr_review_similar',
+          '#module' => 'atr',
+          '#file' => 'includes/atr.review.inc',
+        ),
+        'prepare' => array(
+          '#callback' => 'atr_review_similar_prepare',
+          '#module' => 'atr',
+          '#file' => 'includes/atr.review.inc',
+        ),
+        'review' => array(
+          '#callback' => 'atr_review_similar_review',
+          '#module' => 'atr',
+          '#file' => 'includes/atr.review.inc',
+        ),
       ),
     ),
     'blacklist' => array(
       'all' => array(
-        '#callback' => 'atr_review_blacklist',
-        '#module' => 'atr',
-        '#file' => 'includes/atr.review.inc',
+        'process' => array(
+          '#callback' => 'atr_review_blacklist',
+          '#module' => 'atr',
+          '#file' => 'includes/atr.review.inc',
+        ),
       ),
     ),
   );
 }
 
 /**
- * Implementation of hook_atr_profile_load().
+ * Load a review method.
+ *
+ * @param $name
+ *   The method's machine name.
+ * @param $language
+ *   The language to get callback information for.
+ * @return
+ *   Array with method and callback information.
  */
-function atr_atr_profile_load($profile) {
-  $reviews = array();
-  if (variable_get('atr_profile_' . $profile->pid . '_similarity', FALSE)) {
-    $reviews[] = 'similarity';
+function atr_method_load($name, $language) {
+  static $method_info = NULL;
+  static $method_callback = NULL;
+
+  if(!$method_info) {
+    $method_info = module_invoke_all('atr_method_info');
+    $method_callback = module_invoke_all('atr_method_callback');
   }
-  if (variable_get('atr_profile_' . $profile->pid . '_blacklist', FALSE)) {
-    $reviews[] = 'blacklist';
+
+  // Check for general and language-specific callback information.
+  if (isset($method_callback[$name]['all'])) {
+    $callbacks_all = $method_callback[$name]['all'];
+  }
+  if (isset($method_callback[$name][$language]) && $language != 'all') {
+    $callbacks_language = $method_callback[$name][$language];
   }
 
-  return array(
-    'reviews' => $reviews,
-  );
+  // Get the right callback information. Language-specific callbacks may
+  // overwrite general callbacks.
+  $callbacks = array();
+  if (isset($callbacks_all)) {
+    if (isset($callbacks_language)) {
+      $callbacks = array_merge($callbacks_all, $callbacks_language);
+    }
+    else {
+      $callbacks = $callbacks_all;
+    }
+  }
+  else {
+    $callbacks = $callbacks_language;
+  }
+
+  return array_merge($method_info[$name], array('#callbacks' => $callbacks));
 }
 
 /**
- * Load a profile.
+ * Load a settings profile.
  *
  * @param $pid
  *   The profile's ID.
@@ -164,20 +222,41 @@ function atr_atr_profile_load($profile) 
  */
 function atr_profile_load($pid) {
   if ($profile = db_fetch_object(db_query("SELECT * FROM {atr_profile} WHERE pid = %d", $pid))) {
-    $profile = (object) array_merge((array) $profile, module_invoke_all('atr_profile_load', $profile));
-    $review_info = module_invoke_all('atr_review_info');
-    foreach ($profile->reviews as $i => &$review) {
-      if (isset($review_info[$review][$profile->language])) {
-        $review = $review_info[$review][$profile->language];
-      }
-      elseif (isset($review_info[$review]['all'])) {
-        $review = $review_info[$review]['all'];
-      }
-      else {
-        unset($profile->reviews[$i]);
+    $result = db_query("SELECT method FROM {atr_profile_method} WHERE pid = %d", $pid);
+    while ($method_name = db_result($result)) {
+      $method = atr_method_load($method_name, $profile->language);
+      if ($method['#callbacks']) {
+        $profile->methods[$method_name] = $method;
       }
     }
     return $profile;
   }
   return FALSE;
+}
+
+/**
+ * Save a settings profile.
+ *
+ * @param $profile
+ *   The profile object to save.
+ */
+function atr_profile_save(&$profile) {
+  if (isset($profile->pid)) {
+    $update = 'pid';
+    db_query("DELETE FROM {atr_profile_method} WHERE pid = %d", $profile->pid);
+  }
+  else {
+    $update = array();
+  }
+  drupal_write_record('atr_profile', $profile, $update);
+  if (count($profile->methods)) {
+    $values = array();
+    $placeholders = array();
+    foreach (array_keys($profile->methods) as $method_name) {
+      $values[] = $profile->pid;
+      $values[] = $method_name;
+      $placeholders[] = "(%d, '%s')";
+    }
+    db_query("INSERT INTO {atr_profile_method} VALUES " . implode(',', $placeholders), $values);
+  }
 }
\ No newline at end of file
Index: includes/atr.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/atr/includes/Attic/atr.admin.inc,v
retrieving revision 1.1.2.9
diff -u -p -r1.1.2.9 atr.admin.inc
--- includes/atr.admin.inc	2 Jun 2009 18:13:01 -0000	1.1.2.9
+++ includes/atr.admin.inc	5 Jun 2009 23:22:08 -0000
@@ -125,23 +125,29 @@ function atr_form_settings(&$form_state,
     '#default_value' => $profile ? $profile->language : 'all',
   );
 
+  // Render a fieldset and 'Enable' checkbox for every review method.
+  $method_info = module_invoke_all('atr_method_info');
+  foreach ($method_info as $name => $method) {
+    $form[$name] = array(
+      '#type' => 'fieldset',
+      '#title' => $method['#title'],
+      '#description' => $method['#description'],
+    );
+    $form[$name][$name . '_toggle'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Enable @review_method', array('@review_method' => $method['#title'])),
+      '#default_value' => isset($profile->methods[$name]),
+      '#attributes' => array(
+        'class' => 'atr_settings_toggle',
+      ),
+    );
+    $form[$name]['settings'] = array(
+      '#prefix' => '<div id="' . $name . '_toggle" class="js-hide">',
+      '#suffix' => '</div>',
+    );
+  }
+
   // Blacklist settings.
-  $form['blacklist'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Blackist'),
-  );
-  $form['blacklist']['atr_blacklist'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Enable blacklist review'),
-    '#default_value' => $profile ? variable_get('atr_profile_' . $profile->pid . '_blacklist', FALSE) : FALSE,
-    '#attributes' => array(
-      'class' => 'atr_settings_toggle',
-    ),
-  );
-  $form['blacklist']['settings'] = array(
-    '#prefix' => '<div id="atr_blacklist" class="js-hide">',
-    '#suffix' => '</div>',
-  );
   $keywords = NULL;
   if ($profile) {
     $result = db_query("SELECT keyword FROM {atr_blacklist} WHERE pid = %d", $profile->pid);
@@ -157,22 +163,6 @@ function atr_form_settings(&$form_state,
   );
 
   // Similarity settings.
-  $form['similarity'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Similarity'),
-  );
-  $form['similarity']['atr_similarity'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Enable similarity review'),
-    '#default_value' => $profile ? variable_get('atr_profile_' . $profile->pid . '_similarity', FALSE) : FALSE,
-    '#attributes' => array(
-      'class' => 'atr_settings_toggle',
-    ),
-  );
-  $form['similarity']['settings'] = array(
-    '#prefix' => '<div id="atr_similarity" class="js-hide">',
-    '#suffix' => '</div>',
-  );
   $percentages = range(0, 100);
   foreach ($percentages as &$percentage) {
     $percentage .= '%';
@@ -213,7 +203,6 @@ function atr_form_settings_submit($form,
   if ($profile = $values['profile']) {
     $profile->title = $values['title'];
     $profile->language = $values['language'];
-    $update = 'pid';
     drupal_set_message(t('%profile has been updated.', array('%profile' => $profile->title)));
   }
   else {    
@@ -221,19 +210,22 @@ function atr_form_settings_submit($form,
       'title' => $values['title'],
       'language' => $values['language'],
     );
-    $update = array();
     drupal_set_message(t('%profile has been added.', array('%profile' => $profile->title)));
   }
-  drupal_write_record('atr_profile', $profile, $update);
+  $method_info = module_invoke_all('atr_method_info');
+  foreach ($method_info as $name => $method) {
+    if ($values[$name . '_toggle']) {
+      $profile->methods[$name] = $method;
+    }
+  }
+  atr_profile_save($profile);
   // Put the saved profile back in $form_state, so it can be used by other
   // submit handlers.
   $form_state['values']['profile'] = $profile;
 
   // Save all preferences.
-  variable_set('atr_profile_' . $profile->pid . '_similarity', $values['atr_similarity']);
   variable_set('atr_profile_' . $profile->pid . '_similarity_threshold', $values['similarity_threshold']);
   variable_set('atr_profile_' . $profile->pid . '_similarity_ignore', preg_split("#[\r\n]+#", $values['similarity_ignore']));
-  variable_set('atr_profile_' . $profile->pid . '_blacklist', $values['atr_blacklist']);
   // Blacklisted keywords are saved in a table of their own. Delete possible old
   // keywords and save the new ones.
   if ($profile->pid) {
Index: includes/atr.review.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/atr/includes/Attic/atr.review.inc,v
retrieving revision 1.1.2.15
diff -u -p -r1.1.2.15 atr.review.inc
--- includes/atr.review.inc	2 Jun 2009 18:31:30 -0000	1.1.2.15
+++ includes/atr.review.inc	5 Jun 2009 23:22:08 -0000
@@ -43,11 +43,11 @@ function atr_review($path, $profile) {
       array($path),
     ),
   );
-  foreach($profile->reviews as $review) {
+  foreach($profile->methods as $method) {
     $operations[] = array(
-      'atr_review_execute_method',
+      'atr_callback_execute',
       array(
-        $review,
+        $method['#callbacks']['process'],
         $profile,
       ),
     );
@@ -60,20 +60,20 @@ function atr_review($path, $profile) {
 }
 
 /**
- * Execute a review method.
+ * Execute a review method callback.
  *
- * @param $review
+ * @param $callback
  *   An associative array containing callback information as defined in
- *   hook_atr_review_info().
- * @param $profile
- *   The settings profile used for this review.
- * @param $context
- *   A batch operation context.
+ *   hook_atr_method_info().
+ * @param ...
+ *   Additional arguments to pass along to the callback.
  */
-function atr_review_execute_method($review, $profile, &$context) {
-  require_once('./'. drupal_get_path('module', $review['#module']) . '/' . $review['#file']);
+function atr_callback_execute($callback) {
+  require_once('./'. drupal_get_path('module', $callback['#module']) . '/' . $callback['#file']);
+  $args = func_get_args();
+  array_shift($args);
 
-  call_user_func_array($review['#callback'], array($profile, $context));
+  return call_user_func_array($callback['#callback'], $args);
 }
 
 /**
@@ -220,7 +220,9 @@ function atr_review_similar($profile, &$
   $threshold = (int) variable_get('atr_similarity_threshold', 90);
   for ($sid_a = $from; $sid_a < $max; $sid_a++) {
     for ($sid_b = $sid_a + 1; $sid_b < $total; $sid_b++) {
-      $similarity = atr_similar($strings[$sid_a], $strings[$sid_b], $profile->pid);
+      $string_a = atr_callback_execute($profile->methods['similarity']['#callbacks']['prepare'], $strings[$sid_a], $profile->pid);
+      $string_b = atr_callback_execute($profile->methods['similarity']['#callbacks']['prepare'], $strings[$sid_b], $profile->pid);
+      $similarity = atr_callback_execute($profile->methods['similarity']['#callbacks']['review'], $string_a, $string_b);
       if ($similarity > $threshold) {
         $values[] = $sid_a;
         $values[] = $sid_b;
@@ -254,9 +256,9 @@ function atr_review_similar($profile, &$
  * @return
  *   The strings' similarity in percents.
  */
-function atr_similar($string_a, $string_b, $pid) {
-  $words_a = atr_similar_preprocess($string_a, $pid);
-  $words_b = atr_similar_preprocess($string_b, $pid);
+function atr_review_similar_review($string_a, $string_b) {
+  $words_a = preg_split('#\s#', $string_a);
+  $words_b = preg_split('#\s#', $string_b);
   $word_count = count(array_unique(array_merge($words_a, $words_b)));
   $diff_count = count(array_unique(array_merge(array_intersect($words_a, $words_b), array_intersect($words_b, $words_a))));
 
@@ -269,15 +271,17 @@ function atr_similar($string_a, $string_
 }
 
 /**
- * Preprocess a string for similarity checks
+ * Prepare a string for similarity checks.
  *
  * @param $string
- *   The string to preprocess.
+ *   The string to prepare.
+ * @param $pid
+ *   The ID of the profile used for this review.
  *
  * @return
  *   The preprocessed string.
  */
-function atr_similar_preprocess($string, $pid) {
+function atr_review_similar_prepare($string, $pid) {
   static $strings = array();
   static $ignore = NULL;
 
@@ -286,15 +290,12 @@ function atr_similar_preprocess($string,
   }
 
   if (!isset($strings[$string])) {
-  	$string_preprocessed = &$strings[$string];
   	// HTML tags cannot be considered words.
     $strings[$string] = strip_tags($string);
     // Strip everything but words, whitespace and placeholder prefixes.
     $strings[$string] = preg_replace('#[^@!%a-z\s]#i', '', $strings[$string]);
-    // Convert the string to an array.
-    $strings[$string] = preg_split('#\s#', $strings[$string]);
     // Remove words that are on the ignore list.
-    $strings[$string] = array_diff($strings[$string], $ignore);
+    $strings[$string] = str_replace($ignore, '', $strings[$string]);
   }
 
   return $strings[$string];
