Index: libraries.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/libraries/libraries.module,v
retrieving revision 1.14
diff -u -p -r1.14 libraries.module
--- libraries.module	10 Nov 2010 20:57:00 -0000	1.14
+++ libraries.module	11 Nov 2010 16:14:52 -0000
@@ -158,6 +158,7 @@ function libraries_scan_info_files() {
 
   return $files;
 }
+
 /**
  * Returns information about registered libraries.
  *
@@ -184,22 +185,28 @@ function libraries_info($name = NULL) {
     $libraries = array();
     // Gather information from hook_libraries_info().
     foreach (module_implements('libraries_info') as $module) {
-      foreach (module_invoke($module, 'libraries_info') as $machine_name => $properties) {
-        $properties['module'] = $module;
-        $libraries[$machine_name] = $properties;
+      foreach (module_invoke($module, 'libraries_info') as $machine_name => $library) {
+        $library['module'] = $module;
+        // Make all file declarations consistent.
+        $library['callbacks']['prepare'][] = 'libraries_prepare_files';
+
+        $libraries[$machine_name] = $library;
       }
     }
     // Gather information from .info files.
     // .info files override module definitions.
     foreach (libraries_scan_info_files() as $machine_name => $file) {
-      $properties = drupal_parse_info_file($file->uri);
-      $properties['info file'] = $file->uri;
-      $libraries[$machine_name] = $properties;
+      $library = drupal_parse_info_file($file->uri);
+      $library['info file'] = $file->uri;
+      // Make all file declarations consistent.
+      $library['callbacks']['prepare'][] = 'libraries_prepare_files';
+
+      $libraries[$machine_name] = $library;
     }
 
     // Provide defaults.
-    foreach ($libraries as $machine_name => &$properties) {
-      $properties += array(
+    foreach ($libraries as $machine_name => &$library) {
+      $library += array(
         'machine name' => $machine_name,
         'name' => $machine_name,
         'vendor url' => '',
@@ -213,6 +220,8 @@ function libraries_info($name = NULL) {
         'versions' => array(),
         'integration files' => array(),
       );
+      // Prepare the library.
+      libraries_invoke_library($library, 'prepare');
     }
 
     // Allow modules to alter the registered libraries.
@@ -351,6 +360,108 @@ function libraries_detect_library(&$libr
 }
 
 /**
+ * Helper function to apply a callback to all parts of a library.
+ *
+ * Because library declarations can include variants and versions, and those
+ * version declarations can in turn include variants, modifying e.g. the 'files'
+ * property everywhere it is declared can be quite cumbersome, in which case
+ * this helper function is useful.
+ *
+ * @param $library
+ *   An associative array of library information, passed by reference.
+ * @param $group
+ *   The name of callback group to apply to each part of the library. Each
+ *   callback should alter the passed in library part by reference.
+ */
+function libraries_invoke_library(&$library, $group) {
+  if (!isset($library['callbacks'][$group])) {
+    return;
+  }
+  $callbacks = array();
+  foreach ($library['callbacks'][$group] as $callback) {
+    if (function_exists($callback)) {
+      $callbacks[] = $callback;
+    }
+  }
+
+// @todo 
+  // Always apply the callback to the top-level library.
+  $callback($library);
+
+  // Apply callback to versions.
+  if (!empty($library['versions'])) {
+    foreach ($library['versions'] as &$version) {
+      // Versions can include variants as well.
+      if (!empty($version['variants'])) {
+        foreach ($version['variants'] as &$version_variant) {
+          $callback($version_variant);
+        }
+      }
+      $callback($version);
+    }
+  }
+
+  // Apply callback to variants.
+  if (!empty($library['variants'])) {
+    foreach ($library['variants'] as &$variant) {
+      $callback($variant);
+    }
+  }
+}
+
+/**
+ * Helper callback to make 'files' property of libraries consistent.
+ *
+ * This turns libraries' file information declared as e.g.
+ * @code
+ * $library['files']['js'] = array('example_1.js', 'example_2.js');
+ * @endcode
+ * into
+ * @code
+ * $library['files']['js'] = array(
+ *   'example_1.js' => array(),
+ *   'example_2.js' => array(),
+ * );
+ * @endcode
+ * It does the same for the 'integration files' property.
+ *
+ * @param $library
+ *   An associative array of library information or a part of it, passed by
+ *   reference.
+ *
+ * @see libraries_info()
+ * @see libraries_process_library()
+ */
+function libraries_prepare_files(&$library) {
+  // Both the 'files' property and the 'integration files' property contain file
+  // declarations, and we want to make both consistent.
+  $file_types = array();
+  if (isset($library['files'])) {
+    $file_types[] = &$library['files'];
+  }
+  if (isset($library['integration files'])) {
+    // Integration files are additionally keyed by module.
+    foreach ($library['integration files'] as &$integration_files) {
+      $file_types[] = &$integration_files;
+    }
+  }
+  foreach ($file_types as &$files) {
+    // Go through all supported types of files.
+    foreach (array('js', 'css', 'php') as $type) {
+      if (!empty($files[$type])) {
+        foreach ($files[$type] as $key => $value) {
+          // Unset numeric keys and turn the respective values into keys.
+          if (is_numeric($key)) {
+            $files[$type][$value] = array();
+            unset($files[$type][$key]);
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
  * Loads a library.
  *
  * @param $name
@@ -415,17 +526,13 @@ function libraries_load_files($library) 
   foreach (array('js', 'css') as $type) {
     if (!empty($library['files'][$type])) {
       foreach ($library['files'][$type] as $data => $options) {
-        // If the value is not an array, it's a filename and passed as first
-        // (and only) argument.
-        if (!is_array($options)) {
-          // Prepend the library path to the file name.
-          $data = "$path/$options";
-          $options = NULL;
-        }
+        // Prepend the library path to the file name.
+        $data = "$path/$data";
+
         // In some cases, the first parameter ($data) is an array. Arrays can't
         // be passed as keys in PHP, so we have to get $data from the value
         // array.
-        if (is_numeric($data)) {
+        if (isset($options['data']) && is_array($options['data'])) {
           $data = $options['data'];
           unset($options['data']);
         }
@@ -441,7 +548,7 @@ function libraries_load_files($library) 
 
   // Load PHP files.
   if (!empty($library['files']['php'])) {
-    foreach ($library['files']['php'] as $file) {
+    foreach ($library['files']['php'] as $file => $value) {
       $file_path = DRUPAL_ROOT . '/' . $path . '/' . $file;
       if (file_exists($file_path)) {
         require_once $file_path;
Index: tests/libraries.test
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/libraries/tests/libraries.test,v
retrieving revision 1.11
diff -u -p -r1.11 libraries.test
--- tests/libraries.test	10 Nov 2010 20:57:00 -0000	1.11
+++ tests/libraries.test	10 Nov 2010 22:30:04 -0000
@@ -39,9 +39,9 @@ class LibrariesTestCase extends DrupalWe
       'version callback' => '_libraries_test_return_version',
       'version arguments' => array('1'),
       'files' => array(
-        'js' => array('example_1.js'),
-        'css' => array('example_1.css'),
-        'php' => array('example_1.php'),
+        'js' => array('example_1.js' => array()),
+        'css' => array('example_1.css' => array()),
+        'php' => array('example_1.php' => array()),
       ),
     ));
     $this->verbose(var_export($expected, TRUE));
@@ -115,9 +115,9 @@ class LibrariesTestCase extends DrupalWe
     $library = libraries_info('example_simple');
     libraries_detect_library($library);
     $files = array(
-      'js' => array('example_1.js'),
-      'css' => array('example_1.css'),
-      'php' => array('example_1.php'),
+      'js' => array('example_1.js' => array()),
+      'css' => array('example_1.css' => array()),
+      'php' => array('example_1.php' => array()),
     );
     $this->verbose(var_export($library, TRUE));
     $this->assertEqual($library['files'], $files, 'Top-level files property works.');
@@ -126,9 +126,9 @@ class LibrariesTestCase extends DrupalWe
     $library = libraries_info('example_versions');
     libraries_detect_library($library);
     $files = array(
-      'js' => array('example_2.js'),
-      'css' => array('example_2.css'),
-      'php' => array('example_2.php'),
+      'js' => array('example_2.js' => array()),
+      'css' => array('example_2.css' => array()),
+      'php' => array('example_2.php' => array()),
     );
     $this->verbose(var_export($library, TRUE));
     $this->assertEqual($library['files'], $files, 'Version-specific library files found.');
